;            ****************************************************
;            ***                                              ***
;            ***            Trainer for *******               ***
;            ***                                              ***
;            ***   (c) 1995 by ABACUS/1994 by DATA Becker     ***
;            ***                                              ***
;            ***   Author: Boris Bertelsons                   ***
;            ***                                              ***
;            ****************************************************
;
;

.286
  w equ word ptr
  b equ byte ptr
code segment public
public insthand
public handler21
public reslim
public oldint21
public oldint65
public ID
public IDlen
public check_inst

assume cs:code,ds:code
ID: db 'ABACUS'
oldint21: dd 0
oldint65: dd 0
procedure: dd ?
IDlen equ offset oldint21 - offset ID


;  *********************************************************************
;  ***                                                               ***
;  ***  The actual Trainer routines are here                         ***
;  ***                                                               ***
;  *********************************************************************


;  **********************************************************************
;  ***                                                                ***
;  ***  The new INT 21h. The procedure checks whether the             ***
;  ***  "in al,60h" command is in the specified location in memory,   ***
;  ***  and if necessary, replaces it                                 ***
;  ***  with "int 65h" !                                              ***
;  ***                                                                ***
;  **********************************************************************
handler21 proc pascal
  pushf
  push bp
  push ds
  push bx
  mov  bp,sp
  mov  bx,[bp+10]  ; cs at time of interrupt to BX, DOS !!!
                   ; IMPORTANT ! In TD [bp+16] !!!
  add  bx,0366h    ; CS of 1st int 21h + 2136h = CS of keyboard routine
  mov  ds,bx       ; cs of keyboard routine to ds
  mov  bx,568Bh    ; 8B56h = mov dx,[bp+06]
  cmp  ds:word ptr [0005h],bx     ; is it in the keyboard routine ?
  jne  not_change
  mov  ds:word ptr [0005h],9090h  ; write in int 65h !
  mov  ds:word ptr [0007h],65CDh  ; write in int 65h !
not_change:
  pop  bx
  pop  ds
  pop  bp
  popf
  jmp dword ptr cs:oldint21       ; call old int 21h
handler21 endp

;  *************************************************************************
;  ***                                                                   ***
;  ***  Int 65h procedure. It reads in a character via "in al,60h"       ***
;  ***  and checks whether the read character was defined as the         ***
;  ***  Trainer key. If the answer is yes, the allocated memory          ***
;  ***  changes and procedure calls are executed. Enter your training    ***
;  ***  variables here !!!                                               ***
;  ***                                                                   ***
;  *************************************************************************

handler65 proc far
  pushf
  push bp
  push ds
  push bx
  mov  bp,sp
  mov  bx,[bp+10]  ; cs at time of interrupt to BX
  in  al,60h       ; read character
  cmp al,63        ; F5 key
  je  Full_Shoots_j
  cmp al,64        ; F6 key
  je  Full_Lives_J
  cmp al,65        ; F7 key
  je Weapon_new_j  ;
  cmp al,66        ; F8 key
  je Weapon_new_j  ;
  cmp al,67        ; F9 key
  je Weapon_new_j  ;
  cmp al,68        ; F10 key
  je  More_Points_J

End_Keyb:
  pop bx
  pop ds
  pop bp
  popf
  iret

Full_Shoots_j:
  jmp Full_Shoots
Full_Lives_j:
  jmp Full_Lives
More_Points_j:
  jmp More_Points
Weapon_new_j:
  jmp Weapon_new

Full_Shoots:
  pushf
  PUSHA
  sub  bx,0    ; since already correct CS
  mov word ptr procedure+2,bx
  mov  bx,1401h    ; es:[bx]  =  14EF:1401
  mov word ptr procedure,bx
;--------
  mov ds:byte ptr [0DA3h],20h
  mov ax,20h
  push ax
  call dword ptr [procedure]
  POPA
  popf
  jmp End_Keyb

Full_Lives:
  pushf
  pusha
  sub  bx,0  ;
  mov word ptr procedure+2,bx
  mov  bx,1317h  ; es:[bx]  =  14EF:1317
  mov word ptr procedure,bx
;-----------
  mov ds:byte ptr [0DA3h],0009
  mov ax,9
  push ax
  call dword ptr [procedure]
  popa
  popf
  jmp End_Keyb

Weapon_new:
  pushf
  pusha
  sub  bx,0  ;
  mov word ptr procedure+2,bx
  mov  bx,1454h  ; es:[bx]  =  14EF:1454
  mov word ptr procedure,bx
;-----------
  sub al,65
  mov ah,0
  mov ds:byte ptr [0DA2h],al
  push ax
  call dword ptr [procedure]
  popa
  popf
  jmp End_Keyb

More_Points:
  pushf
  pusha
  sub  bx,0  ;
  mov word ptr procedure+2,bx
  mov  bx,1BD0h  ; es:[bx]  =  14EF:1BD0
  mov word ptr procedure,bx
;-----------
  mov ax,1000
  push ax
  call dword ptr [procedure]
  popa
  popf
  jmp End_Keyb

handler65 endp

insthand proc pascal
reslim label byte
  push ds
  pop ds
  mov ax,3521h                    ; store old INT 21
  int 21h
  mov w oldint21,bx
  mov w oldint21 + 2,es
  mov ax,3565h                    ; store old INT 65h
  int 21h
  mov w oldint65,bx
  mov w oldint65 + 2,es
  mov ax,2521h                    ; bend/deflect INT 21h to custom routine
  lea dx,handler21
  int 21h
  mov ax,2565h                    ; INT 65h to custom keyboard routine
  lea dx,handler65
  int 21h
 	ret
insthand endp

check_inst proc near
  mov ax,3521h                    ; get interrupt vector
  int 21h
  mov di,bx
  mov si,offset ID
  mov di,si
  mov cx,IDlen
  repe cmpsb                      ; check for ID
	ret
check_inst endp

code ends
end
