EXTRN BLUE:byte,GREEN:byte,CYAN:byte,RED:byte,PURPLE:byte EXTRN BROWN:byte,WHITE:byte,GRAY:byte,LIGHT_BLUE:byte EXTRN LIGHT_GREEN:byte,LIGHT_CYAN:byte,LIGHT_RED:byte, EXTRN LIGHT_MAGENTA:byte,YELLOW:byte, INT_WHITE:byte EXTRN buildings, buildings_p, n_buildings:byte EXTRN buildings_hit:byte, score, end_game_code PUBLIC key_flag PUBLIC scan_code PUBLIC timer_flag EXTRN kbd_int:NEAR EXTRN setup_int:NEAR EXTRN timer_tick:NEAR PUBLIC Game PUBLIC Score2dec .MODEL SMALL .STACK 200h ;----------------------------------------------------------------------- INCLUDE GRAPHS.LIB ; Includes file with graph-mode macros INCLUDE IMAGES.LIB ; Includes the routines that will draw INCLUDE MY_MACRO.LIB ; the images. ;------DATA SEGMENT---------------------------------------------------- .DATA interval DB 0 ; Movements counter. max_interval EQU 15 ; How many movements of the ; plane is needed for next ; bomb to be dropped. max_bombs EQU 6 ; Number of bombs in the air at the ; same time. esc_key EQU 1 ; ESCAPE left_arrow EQU 75 ; LEFT-ARROW right_arrow EQU 77 ; RIGHT-ARROW up_arrow EQU 72 ; UP-ARROW gun_y EQU 400 ; Y-position of the gun gun_x DW 50 ; Starting X-position of the gun gun_speed DW 8 ; Increment (velocity) of the gun. size_of_gun DW 40 ; Gun's length size_of_plane DW 80 ; Length of the plane plane_speed DW 5 ; Velocity of the plane plane_x DW 10 ; X-coordinate of the plane plane_y DW 50 ; Y-coordinate of the plane bomb_speed DW 5 ; Bomb's velocity number_bombs DB 0 ; Number of bombs in the air. bomb_x DW max_bombs dup (0) ; Arrays with bombs' bomb_y DW max_bombs dup (0) ; XY coordinates. size_of_bomb DW 8 ; Length of a bomb size_of_building DW 40 ; Length of the building new_timer_vec DW ?,? ; Interrupts' vectors. old_timer_vec DW ?,? ; new_key_vec DW ?,? ; old_key_vec DW ?,? ; scan_code DB 0 ; Scan-Code of the key pressed. key_flag DB 0 ; 1 if any key was pressed timer_flag DB 0 ; Tick of the tmer. misl_x DW 0 ; Missile X-position misl_y DW 0 ; Missile y_position misl_way DW 0 ; Will hold the length bullet's way. ;----------------------------------------------------------------------- .CODE GAME PROC push ax push bx push cx push dx push ds mov ax,@DATA mov ds,ax mov new_timer_vec,offset timer_tick ; Setting timer's mov new_timer_vec + 2,cs ; interrupt mov al,1ch ; lea di,old_timer_vec ; lea si,new_timer_vec ; call setup_int ; mov new_key_vec,offset kbd_int ; Setting keyboard's mov new_key_vec + 2,cs ; interrupt mov al,09h ; lea di,old_key_vec ; lea si,new_key_vec ; call setup_int ; call update_score ; Initialization test_key: ; Main cycle cmp key_flag,1 ; IF any_key was pressed je key_pressed ; THEN check which one jmp test_timer ; ELSE check timer_tick key_pressed: ; Key was pressed mov key_flag,0 ; Set flag. cmp scan_code,esc_key ; IF pressed jne mov_left ; THEN EXIT mov end_game_code,1 jmp lGame_over ; mov_left: ; IF key was cmp scan_code,left_arrow ; pressed, then jne mov_right ; set direction flag in CL mov cl,0 ; move the gun and call move_gun ; check timer_tick jmp test_timer mov_right: ; IF key was cmp scan_code,right_arrow ; pressed, then jne test_shot ; set direction flag in CL mov cl,1 ; move the gun and call move_gun ; check timer_tick. jmp test_timer ; test_shot: cmp scan_code, up_arrow ; Did we draw the shot ? jne test_timer ; if no, go check time_tick, else mov misl_way,350 ; set initial length of bullet's way ; which will hit the sky (heaven ?). mov cx,gun_x ; Use CX as input = gun's X-position. call destroy_bomb ; Check if any of the bombs was shot cmp al,0 ; If NO je test_plane ; May be we shot the plane ? ; Otherwise : ; AL holds bomb's number mov cx,380 ; Top gun's pixel sub cx,dx ; Calculate the length mov misl_way,cx ; of the shot into misl_way. ; Optimizing the bombs array mov cl,al ; by shifhting to the left call del_bomb ; up to position AL jmp real_shot ; Show shot. test_plane: mov cx,gun_x ; Place Gun's X-position into CX call destroy_plane ; check if plane is hit. cmp al,-1 ; If ALL planes jne some_planes_left ; the game is over. jmp lGame_Over ; But it could be just one of them some_planes_left: ; cmp al,0 ; If not so, je real_shot ; just hit the sky ; ELSE mov cx,380 ; adjust the length sub cx,40 ; of bullet way mov misl_way,cx ; and put it into misl_way real_shot: movw misl_x,gun_x ; Show the shot as two lines going from movw misl_y,gun_y ; top 2 pixels of the gun. call shot ; Do it. test_timer: ; cmp timer_flag,1 ; IF timer_tick occured je start_move_plane ; THEN move all the objects jmp test_key ; ELSE go handle key_pressing. start_move_plane: ; Perform the next step of game mov timer_flag,0 ; Clear timer_tick call move_plane ; Plane is moved one position to right. inc interval ; Counter increased. ; Check if it is the time cmp interval,max_interval ; to drop the bomb, jne no_new_bomb ; else, do not drop new bomb. mov interval,0 ; Clear the counter cmp number_bombs,max_bombs ; IF allowed amount of bombs is in the je no_new_bomb ; air, do not drop more. call add_bomb ; ELSE new bomb is dropped. no_new_bomb: ; xor bx,bx ; mov cx,1 ; Counter of falling bombs in CX cont_bomb: ; Cycle to move down all cmp cl,number_bombs ; avaible bombs. jbe drop ; There are some ! jmp test_key ; No, all objects were moved, quitting ; the cycle drop: ; mov bl,cl ; Calculate position in bomb's dec bl ; array. shl bl,1 ; BL points to current bomb. inc cl ; Increase counter of falling bombs call move_bomb ; Move curennt bomb mov dx,bomb_y[bx] ; Place it's Y-position in DX cmp dx,gun_y ; Bomb is higher the gun (and buildings) jbe cont_bomb ; So, move the next one (CL is set). sub dx,10 ; Check lower bound of gun cmp dx,gun_y ; If bomb passed the gun, then jae below_gun ; go check buildings push cx ; Saving CX mov cx,bomb_x[bx] ; Putting bombs X-position in it. call destroy_gun ; check if gun is hit ; (we'll check for buildings later) cmp al,1 ; Gun is it. jne gun_not_hit ; pop cx ; restoring CX, jmp lGame_over ; but the game is over! ; Since building are located below the gun we check them after checking of ; gun. gun_not_hit: ; Restoring CX and recalling pop cx ; that DX still holds Y-position of the below_gun: ; Bomb has passed the gun mov dx,bomb_y[bx] cmp dx,476 ; bomb. Compare it to 476 - buildngs level. jbe cont_bomb ; Building is not hit - go on bombing. push cx ; CX is used as input. mov cx,bomb_x[bx] ; Building is hit. call destr_build ; Destroy it. pop cx ; restore CX cmp al,-1 ; IF all the buildings were destroyed je lGame_over ; THEN game is over ; ELSE dec cl ; Bomb does't exist any longer call del_bomb ; remove it from the array inc cl ; and shift next bomb to the left. jmp cont_bomb ; Go on bombing. lGame_over: ; Game Over lea di,new_timer_vec ; Restoring lea si,old_timer_vec ; original mov al,1ch ; interrup handlers call setup_int ; for ; timer lea di,new_key_vec ; and lea si,old_key_vec ; keyboard mov al,09h ; call setup_int ; pop ds ; pop dx ; pop cx ; Restoring registers pop bx ; pop ax ; ret ; Return to Main module GAME ENDP ; End of Game procedure ;----------------------------------------------------------------------- ;Below are stored the procedures we use to handle all the events of the game. ;----------------------------------------------------------------------- Move_Gun PROC ;Procedure move_gun moves gun when one of the two appropriate keys ;was pressed. ;Input CL - direction 0 - left, 1 - right ;Output - none push ax push bx push cx push dx push si push di draw_gun gun_x,gun_y,0,0,0,0 ; Hide the gun ; on its original position. mov ax,gun_x ; X-position in AX if_left: cmp cl,0 ; Moving to the left jne if_right cmp ax,gun_speed ; check if we hit the left jb done_gun ; boundary of the screen sub ax,gun_speed ; if not mov gun_x,ax ; mov the gun to the left jmp done_gun ; amd exit if_right: ; Moving to the right mov ax,gun_x ; Checking if add ax,size_of_gun ; the right boundary of the add ax,gun_speed ; screen, where cmp ax,640 ; 640 = Resolution. ja done_gun ; If not so, sub ax,size_of_gun ; move the gun and mov gun_x,ax ; exit. done_gun: ; Drawing the gun on new position draw_gun gun_x,gun_y,INT_WHITE,GREEN,BROWN,0 pop di pop si pop dx pop cx pop bx pop ax ret ENDP ;----------------------------------------------------------------------- SHOT PROC ;Input - Variable misl_way is set in calling procedure. ;Output - None cmp misl_way,0 ; If bomb is immideately jg show_shot ; above the gun then mov misl_way,20 ; No shot will be shown show_shot: mov ax,misl_way add misl_x,19 ;Gun's middle pixel sub misl_y,ax ;Draw line from above to sub misl_y,20 ;gun's top pixel v_line misl_x,misl_y,misl_way,RED,0 ;Draw first line inc misl_x ;Increase X-position v_line misl_x,misl_y,misl_way,RED,0 ;Draw second line v_line misl_x,misl_y,misl_way,0,0 ;Hide old second line dec misl_x ;Decrease X-Position v_line misl_x,misl_y,misl_way,0,0 ;Hide old first line ret ;Return ENDP ;----------------------------------------------------------------------- MOVE_PLANE PROC ;Input - Variables plane_x and plane_y are set in calling procedure ;Output - None push ax ;Save Ax draw_plane plane_x,plane_y,0,0,0,0 ;Hide plane mov ax,plane_x ;Increase X-position of add ax,size_of_plane ;the plane to make add ax,plane_speed ;sure it does not hit cmp ax,640 ;640 - Resolution of the jb cont_cycle ;screen. If so, mov plane_x,0 ;make it zero, jmp redraw ;otherwise cont_cycle: ; sub ax,size_of_plane ;Restore original X-position mov plane_x,ax ;put it into plane_x redraw: ;and ;draw the plane draw_plane plane_x, plane_y,LIGHT_RED,YELLOW,LIGHT_GREEN,0 pop ax ;restore AX ret ;Return ENDP ;----------------------------------------------------------------------- MOVE_BOMB PROC ;Input BX - position of the bomb in bombs array push ax ; Save registers push bx ; mov ax,bomb_speed ; Y - incremwnt is put in AX bomb bomb_x[bx],bomb_y[bx],0,0 ; Hide bomb add word ptr bomb_y[bx],ax ; Increase Y_position bomb bomb_x[bx],bomb_y[bx],BROWN,0 ; Draw bomb. pop bx ; Restore registers pop ax ; ret ;Return ENDP ;---------------------------------------------------------------------- ADD_BOMB PROC push ax ;Save registers push bx ; inc number_bombs ;Number of bombs in the air increases mov bl,number_bombs ;Put this number in BL dec bl ;Calculate new bomb's position in shl bl,1 ;bombs array xor bh,bh ; mov ax,plane_x ;Assign plane's coordinates to mov word ptr bomb_x[bx],ax ;the bomb add word ptr bomb_x[bx],60 ;and mov ax,plane_y ;adjust them mov word ptr bomb_y[bx],ax ;accordingly. add word ptr bomb_y[bx],10 ; pop bx ;Restore registers pop ax ; ret ;Return ENDP ;------------------------------------------------------------------------ DEL_BOMB PROC ; This procedure optimazes the bombs array so it does not have empty ; positions inside. ;Input CL - index of bomb that was shot bu the gun or hit the surface etc. push ax ;Save registers push bx ; push cx ; push dx ; xor bh,bh ; Clear BH transfer: cmp cl,number_bombs ; If not available bombs were checked je finish ; then mov bl,cl ; get bomb position in shl bl,1 ; bomb_x_y array mov ax,word ptr bomb_x[bx] ; Take next bomb's mov dx,word ptr bomb_y[bx] ; coordinates sub bl,2 ; and put them mov word ptr bomb_x[bx],ax ; into previous mov word ptr bomb_y[bx],dx ; position. inc cl ; Get to next bomb jmp transfer ; and check it. finish: dec number_bombs ; Decreasing number of bombs pop dx ; that are in the air in the same pop cx ; time, pop bx ; restoring registers, pop ax ; ret ; quitting. DEL_BOMB ENDP ;----------------------------------------------------------------------- Destr_Build PROC ;Input CX - Bomb's X_position ;Output AL = index of destroyed building OR ; AL = 0 IF no buildings were destroyed ; AL = - 1 if ALL buildings were destroyed and game is over. push bx ; push cx ; Saving registers push dx ; xor al,al ; Clearing AL (default) xor bh,bh ; and BH mov ah,1 ; AH = index of building begin_check: cmp ah,n_buildings ; Check if all buildings are checked. jbe not_all ; If so, exit with AL = 0 jmp exit_destr_build ; otherwise not_all: ; mov bl,ah ; Use AH dec bl ; to get building's index into BX shl bl,1 ; bx=2*(ah-1) inc ah ;Increase AH cmp word ptr buildings_p[bx],0 ;If presence byte is 0, je begin_check ;check next building, else mov dx,buildings[bx] ;DX contains X-position of building. add cx,size_of_bomb ; Check if building is hit. cmp cx,dx ;IF it's to the left from current building ja if_hit ;THEN exit, because all left buildings were jmp exit_destr_build ;checked before. if_hit: ;Else sub cx,size_of_bomb ;If it's not to the rigth from the building add dx,size_of_building ;it's a hit! cmp cx,dx ;Otherwise, jae begin_check ;Check next building available. mov word ptr buildings_p[bx],0 ;Put 0 into presense byte draw_building buildings[bx],466,0,0,0,0 ;and hide the building mov al,ah ; AL contains number of erased building dec al ; Return AL. inc buildings_hit ; Increase counter of buildings hit call update_score mov bl,buildings_hit ; We can use BX by this moment. cmp bl,n_buildings ; IF all of them were destroyed jb exit_destr_build ; THEN change AL to return -1 mov al,-1 ; to indicate that the game is over. exit_destr_build: ; pop dx ; pop cx ; Restoring registers pop bx ; ret ; Return destr_build ENDP ;----------------------------------------------------------------------- DESTROY_BOMB PROC ;Input CX - X_position of gun ;Output AL = index of the bomb which was destroyed or ; AL = 0 no bombs were destroyed ; DX = Y_position of the destroyed bomb add cx,20 ; Shot is drawn from the middle push bx ; of the gun xor al,al ; Clearing (0 - no bombs) xor bh,bh ; registers. mov ah,1 ; Beginning with 1st Bomb scan_bombs: cmp ah,number_bombs ;IF all bombs are checked jbe erasing_bomb ;THEN exit jmp exit_destroy_bomb ;ELSE erasing_bomb: mov bl,ah ; BL=2*(AH-1) - this moves dec bl ; BL in bombs array. shl bl,1 ; inc ah ;(Move AX toward next bomb) mov dx,word ptr bomb_x[bx] ;DX = X_position of the bomb cmp cx,dx ;Compare positions of the bomb and gun jb scan_bombs ;If to_the_left of the bomb - check next one. add dx,size_of_bomb ; Check cmp cx,dx ;IF to_the_ right of the bomb-check next one ja scan_bombs ;ELSE add score,25 call update_score dec ah ;There is a hit! mov al,ah ;AL contains number of destroyed bomb mov dx,word ptr bomb_y[bx] ; Define the misl_way bomb bomb_x[bx],bomb_y[bx],0,0 ; Hiding the bomb exit_destroy_bomb: pop bx ; Restoring registers ret ; Return ENDP ;----------------------------------------------------------------------- DESTROY_PLANE PROC ;Input cx - X_position of gun ; Output AL=1 if plane was destroyed ; AL=0 if plane was not destroyed push bx ; Save BX add cx,20 ;Adjust gun's position to the middle. xor al,al ;Set AL to default value - 0 . mov dx,plane_x ;DX contains current X_position of plane cmp cx,dx ;Checking if the plane was hit jae s_inside ; jmp exit_destroy_plane ; To_the_left s_inside: ; add dx,size_of_plane ; cmp cx,dx ; jbe s1_inside ; jmp exit_destroy_plane ; To_the_right s1_inside: ; or al,1 ; HIT! add score,10 call update_score ; draw_plane plane_x,plane_y,0,0,0,0 ; Hiding the plane on it's position mov plane_x,0 ; Setting the plane at 0-position exit_destroy_plane: ; return pop bx ret ENDP ;----------------------------------------------------------------------- DESTROY_GUN PROC ;Input CX - X_position of bomb ;Output AL=1 if gun was destroyed ; AL=0 if gun was not destroyed push cx ; Saving registers push dx ; add cx,size_of_bomb ; Set CX to right edge of the bomb xor al,al ; Set AL to default mov dx,gun_x ; Set DX to gun's X_Position cmp cx,dx ; Compare jae s3_inside ; IF the possibility still extis jmp exit_destroy_gun ; Check it, else EXIT s3_inside: ; sub cx,size_of_bomb ; Set CX to left edge of the bomb add dx,size_of_gun ; Set DX to the right edge of the gun cmp cx,dx ; Compare jbe gun_is_hit ; IF CX < DX there is a hit jmp exit_destroy_gun ; ELSE exit gun_is_hit: ; or al,1 ; Set AL draw_gun gun_x,gun_y,0,0,0,0 ; Hide the gun mov end_game_code,2 ; exit_destroy_gun: ; pop dx ; Restorimg registers pop cx ; ret ; return ENDP ;----------------------------------------------------------------------- Update_score Proc ; Procedure updates number of buldings and planes left push ax push dx move_cursor 1,15,0 ; Set cursor mov dl,n_buildings ; Get number of hits sub dl,buildings_hit ; Get number of buildings add dl,30h ; left, convert to ASCII mov ah,02 ; Print int 21h ; move_cursor 1,69,0 ; Set Cursor call score2dec ; Print score pop dx ; pop ax ; ret ; EndP ;------------------------------------------------------------------------ Score2Dec Proc ; (The method used is taken from the text-book) ; Input - in variable SCORE ; Output - prints SCORE in ASCII on the sreen push ax push bx push cx ; Saving Registers push dx mov ax,score ;ax contains score xor cx,cx ;cx counts decimal digits mov bx,10 ;bx has divisor repeat1: xor dx,dx ;prepare high word of dividend div bx ;ax=quotient, dx=remainder push dx ;save remainder on stack inc cx ;count=count+1 or ax,ax ;quotient=0? jne repeat1 ;no,keep going mov ah,2 ;print char function print_loop: pop dx ;digit in dl or dl,30h ;convert to character int 21h ;print digit loop print_loop pop dx pop cx ;Restoring Registers. pop bx pop ax ret ; Return to Update_Score Endp ;----------------------------------------------------------------------- END