;ChoongHong Oh

TITLE GAME :CASTLE DEFENDER
        EXTRN  SETUP_INT : NEAR, KEYBOARD_INT : NEAR
        EXTRN  TIMER_TICK : NEAR, SETUP_DISPLAY : NEAR
        EXTRN  MOVE_ELE : NEAR, MOVE_ARROW : NEAR
        EXTRN  SHOOT_ARROW : NEAR, MOVE_F_ENEMY : NEAR
        EXTRN  MOVE_W_ENEMY : NEAR, MOVE_C_ENEMY : NEAR
        EXTRN  GENERATE_ENE : NEAR, COLLISION : NEAR, ENDING : NEAR

        PUBLIC TIMER_FLAG, KEY_FLAG, SCAN_CODE
        PUBLIC ELE_TOP, ELE_BOTTOM, 
        PUBLIC ARROW1, ARROW2
        PUBLIC GENERATE_DELAY, NO_F_ENE
        PUBLIC F_ENE1, F_ENE2, F_ENE3
        PUBLIC F_ENE4, F_ENE5, GRAPHIC_F_ENE
        PUBLIC NO_W_ENE
        PUBLIC W_ENE1, W_ENE2, W_ENE3
        PUBLIC W_ENE4, W_ENE5, GRAPHIC_W_ENE
        PUBLIC NO_C_ENE, GRAPHIC_C_ENE
        PUBLIC AUX_X, AUX_Y
        PUBLIC SCORE

.MODEL SMALL
.STACK 100h

IF1
        INCLUDE G_MACRO.ASM
ENDIF

.DATA
  NEW_TIMER_VEC  DW  ?, ?
  OLD_TIMER_VEC  DW  ?, ?
  NEW_KEY_VEC    DW  ?, ?
  OLD_KEY_VEC    DW  ?, ?
  SCAN_CODE      DB  0
  KEY_FLAG       DB  0
  TIMER_FLAG     DB  0
  ELE_TOP        DW  300
  ELE_BOTTOM     DW  347
  ARROW1         DW  0FFFFh, 0FFFFh
  ARROW2         DW  0FFFFh, 0FFFFh
  GENERATE_DELAY DB  50
  NO_F_ENE       DB  0
  GRAPHIC_F_ENE  DB  0
  F_ENE1         DW  0FFFFh, 0FFFFh
  F_ENE2         DW  0FFFFh, 0FFFFh
  F_ENE3         DW  0FFFFh, 0FFFFh
  F_ENE4         DW  0FFFFh, 0FFFFh
  F_ENE5         DW  0FFFFh, 0FFFFh
  NO_W_ENE       DB  0
  GRAPHIC_W_ENE  DB  0
  W_ENE1         DW  0FFFFh
  W_ENE2         DW  0FFFFh
  W_ENE3         DW  0FFFFh
  W_ENE4         DW  0FFFFh
  W_ENE5         DW  0FFFFh
  NO_C_ENE      DB  0
  GRAPHIC_C_ENE  DB  0
  AUX_X          DW  ?
  AUX_Y          DW  ?
  SCORE          DB  0

;scan codes
  UP_ARROW = 48h
  DOWN_ARROW = 50h
  ENTER_KEY = 1Ch
  ESC_KEY = 1

.CODE

MAIN PROC
        MOV AX,@DATA
        MOV DS,AX      ;initialize DS

;set graphic mode and draw background
        CALL SETUP_DISPLAY

;set up timer interrupt vector
        MOV NEW_TIMER_VEC, OFFSET TIMER_TICK  ;offset
        MOV NEW_TIMER_VEC+2, CS               ;segment
        MOV AL, 1Ch          ;interrupt number
        LEA DI, OLD_TIMER_VEC
        LEA SI, NEW_TIMER_VEC
        CALL SETUP_INT
;set up keyboard interrupt vector
        MOV NEW_KEY_VEC, OFFSET KEYBOARD_INT  ;offset
        MOV NEW_KEY_VEC+2, CS                 ;segment
        MOV AL, 9h           ;interrupt number
        LEA DI, OLD_KEY_VEC
        LEA SI, NEW_KEY_VEC
        CALL SETUP_INT

;check key flag
TEST_KEY:
        CMP KEY_FLAG, 1   ;check key flag
        JNE TEST_TIMER    ;not set, go check timer flag
        MOV KEY_FLAG, 0   ;flag set, clear it and check
        CMP SCAN_CODE, ESC_KEY    ;Esc key?
        JNE TK_1          ;no, check an enter key
        JMP DONE          ;Esc, terminate program
TK_1:   
        CMP SCAN_CODE, ENTER_KEY  ;enter key?
        JNE TK_2          ;no, check arrow keys
        CALL SHOOT_ARROW  ;yes, shoot arrow
        JMP TEST_TIMER    ;go check timer flag
TK_2:
        CMP SCAN_CODE, UP_ARROW   ;up arrow?
        JNE TK_3          ;no, check down arrow
        MOV AX, -15        ;yes, move up 2 pixels
        CALL MOVE_ELE
        JMP TEST_TIMER    ;go check timer flag
TK_3:
        CMP SCAN_CODE, DOWN_ARROW ;down arrow?
        JNE TEST_TIMER    ;no, check timer flag
        MOV AX, 15         ;yes, move down 2 pixels
        CALL MOVE_ELE

;check timer flag
TEST_TIMER:
        CMP TIMER_FLAG, 1 ;flag set?
        JNE TEST_KEY      ;no, check key flag
        MOV TIMER_FLAG, 0 ;yes, clear it

        CALL MOVE_ARROW       ;update positions of arrows
        CALL MOVE_F_ENEMY     ;update positions of falling enemies
        CALL COLLISION        ;check if there is any collion between F_ENE and ARROW
        CMP NO_W_ENE, 0       ;if there is no walking enemy,
        JE  CHECK_C_ENE       ;check climbing enemies  
        CALL MOVE_W_ENEMY     ;else, update positions of falling enemies

CHECK_C_ENE:
        CMP NO_C_ENE, 0      ;there is no climbing enemy
        JE  GENERATOR        ;then go to GENERATE_ENE
        CMP NO_C_ENE, 5      ;else, if there are five climbing enemies
        JE  GAME_OVER        ;then, terminate the game 
        CALL MOVE_C_ENEMY    ;else, update position of climbing enemies 

GENERATOR:
        CMP NO_F_ENE, 5         ;if there are already 5 enemies,
        JE GO_BACK              ;it is impossible to generate a new enemy
        INC GENERATE_DELAY      ;if enough time has not passed yet
        CMP GENERATE_DELAY, 9   ;after the last enemy was generated,
        JL GO_BACK              ;it is impossible to generate a new enemy
        CALL GENERATE_ENE       ;generate new falling enemy, if possible

GO_BACK:
        JMP TEST_KEY         ;go back to check key flag

GAME_OVER:
        CALL ENDING

;reset timer interrupt vector
DONE:
        LEA DI, NEW_TIMER_VEC
        LEA SI, OLD_TIMER_VEC
        MOV AL, 1Ch
        CALL SETUP_INT
;set up keyboard interrupt vector
        LEA DI, NEW_KEY_VEC
        LEA SI, OLD_KEY_VEC
        MOV AL, 9h
        CALL SETUP_INT
;read key
        MOV AH, 0
        INT 16h
;reset to text mode
        MOV AH, 0       ;wait for input
        MOV AL, 3
        INT 10h
;return to DOS
        MOV AH, 4Ch
        INT 21h
MAIN ENDP
        END MAIN
        
