;======================================================================== ; Program Description ; Author: Chris Heng ; Description ; Minimalistic, multiplayer pacman game. ;======================================================================== DSEG SEGMENT ; data segment ; format: LABEL DATATYPE INITIAL_VALUE ; e.g. ; MESSAGE db 'HELLO WORLD!$' hex_tab db '0123456789abcdef' prefix db '0x$' curr_vmod db ? new_vmod db 12h BLACK equ 00h BLUE equ 01h GREEN equ 02h CYAN equ 03h RED equ 04h MAGENTA equ 05h BROWN equ 06h GREY equ 07h DARK_GREY equ 08h LIGHT_BLUE equ 09h LIGHT_GREEN equ 0ah LIGHT_CYAN equ 0bh LIGHT_RED equ 0ch LIGHT_MAGENTA equ 0dh YELLOW equ 0eh WHITE equ 0fh start_x equ 40 start_y equ 40 bsize equ 35 colors db CYAN,BLUE,CYAN,BLUE,BLUE,BLUE,CYAN,BLUE,CYAN db BLUE,RED,BLUE,RED,RED,RED,BLUE,RED,BLUE db CYAN,RED,CYAN,BLUE,CYAN,BLUE,CYAN,RED,CYAN db BLUE,RED,BLUE,RED,RED,RED,BLUE,RED,BLUE db CYAN,BLUE,CYAN,BLUE,CYAN,BLUE,CYAN,BLUE,CYAN db BLUE,RED,BLUE,RED,RED,RED,BLUE,RED,BLUE db CYAN,RED,CYAN,BLUE,CYAN,BLUE,CYAN,RED,CYAN db BLUE,RED,BLUE,RED,RED,RED,BLUE,RED,BLUE db CYAN,BLUE,CYAN,BLUE,BLUE,BLUE,CYAN,BLUE,CYAN colors_db db CYAN,BLUE,CYAN,BLUE,BLUE,BLUE,CYAN,BLUE,CYAN db BLUE,RED,BLUE,RED,RED,RED,BLUE,RED,BLUE db CYAN,RED,CYAN,BLUE,CYAN,BLUE,CYAN,RED,CYAN db BLUE,RED,BLUE,RED,RED,RED,BLUE,RED,BLUE db CYAN,BLUE,CYAN,BLUE,CYAN,BLUE,CYAN,BLUE,CYAN db BLUE,RED,BLUE,RED,RED,RED,BLUE,RED,BLUE db CYAN,RED,CYAN,BLUE,CYAN,BLUE,CYAN,RED,CYAN db BLUE,RED,BLUE,RED,RED,RED,BLUE,RED,BLUE db CYAN,BLUE,CYAN,BLUE,BLUE,BLUE,CYAN,BLUE,CYAN cur_x dw ? cur_y dw ? count dw ? pac_loc dw 76 gob_loc dw 4 player_loc dw ? player_color db ? player_turn dw ? player_choice db 2 opponent_choice db 2 pac_moves dw 0 gob_moves dw 0 pac_pill dw 0 ; player input keys right equ 4dh left equ 4bh up equ 48h down equ 50h esckey equ 1bh player_key db ? ;messages msg0 db 'WORLD',39,'S SMALLEST PACMAN GAME $' msg1 db '(p) Play as Pacman $' msg2 db '(g) Play as Goblin $' msg3 db '(s) Standalone game $' msg4 db '(n) Network game $' msg5 db '(Esc) Exit $' msgchoice db 'You are playing as: $' msgpac db 'Pacman $' msggob db 'Goblin $' msgmove1 db 'Your turn to move. $' msgmove2 db 'Your opponent',39,'s turn to move. $' msgwin db 'Congratulations! You have won the game. $' msglose db 'Oh no! You have lost the game. $' msgkey db 'Press any key to return to the main menu... $' msgblank db ' $' msgwait db 'Waiting for connection... $' msgwait2 db 'Opponent has chosen: $' msgwait3 db 'Your choice: $' msglink db 'Connection established. $' msgdisconnect db 'Your opponent has disconnected! $' network db 0 THR equ 03F8h MCR equ 03FCh MSR equ 03FEh LSR equ 03FDh RBR equ 03F8h DSEG ENDS SSEG SEGMENT STACK ; reserve space for stack db 256 DUP(?) SSEG ENDS CSEG SEGMENT ; code segment ASSUME CS:CSEG, DS:DSEG, SS:SSEG ; start is the entry procedure ; you can name it using anything PRINT_S macro msg,X,Y ;macro for printing strings push ax push dx mov ah,2 mov dh,Y mov dl,X int 10h mov dx,offset msg mov ah,09h int 21h pop ax pop dx endm PRINT_C macro char,X,Y ;macro for printing characters push ax push dx mov ah,2 mov dh,Y mov dl,X int 10h mov dl,char mov ah,02h int 21h pop ax pop dx endm drw_bx macro X1,Y1,colour local nxt_rw,nxt_cl push cx push bx push dx push ax mov dx,X1 nxt_rw: mov cx,Y1 nxt_cl: mov ah,0ch mov al,colour mov bh,0 int 10h inc cx mov bx,Y1 add bx,bsize cmp cx,bx jne nxt_cl inc dx mov bx,X1 add bx,bsize cmp dx,bx jne nxt_rw pop cx pop bx pop dx pop ax endm drw_xy macro loc,colour local col_loop,row_loop,drw_box push cx push bx push dx push ax mov dx,0 mov ax,loc mov bx,9 idiv bx mov bx,ax mov ax,start_y mov cur_y,ax mov ax,start_x mov cur_x,ax col_loop: cmp dx,0 je row_loop add cur_x,bsize+1 dec dx jnz col_loop row_loop: cmp bx,0 je drw_box add cur_y,bsize+1 dec bx jnz row_loop drw_box: drw_bx cur_y,cur_x,colour pop cx pop bx pop dx pop ax endm drw_m macro local drw_nextcol,drw_nextrow,drw_exit push cx push bx push dx push ax sub di,di sub si,si mov ax,start_y mov cur_y,ax mov ax,start_x mov cur_x,ax mov bx,0 drw_nextcol: drw_bx cur_y,cur_x,colors[si] inc si cmp si,81 je drw_exit inc di cmp di,9 je drw_nextrow add cur_x,bsize+1 jmp drw_nextcol drw_nextrow: mov ax,start_x mov cur_x,ax add cur_y,bsize+1 mov di,0 jmp drw_nextcol drw_exit: pop cx pop bx pop dx pop ax endm init_connection macro player_input local init_DSR,wait_DSR,init_CTS,wait_CTS,wait_abort,check_DSR,check_CTS push ax push dx call cs:clear_screen PRINT_S msgwait,24,14 mov ah,0h mov al,0E3h int 14h init_DSR: mov dx,MCR mov al,01h out dx,al wait_DSR: mov ah,01h int 16h jz check_DSR mov ah,00h int 16h cmp al,esckey je wait_abort check_DSR: mov dx,MSR in al,dx test al,20h jz wait_DSR init_CTS: PRINT_S msglink,24,15 mov dx,MCR mov al,03h out dx,al wait_CTS: mov ah,01h int 16h jz check_CTS mov ah,00h int 16h cmp al,esckey je wait_abort check_CTS: mov dx,MSR in al,dx test al,10h jz wait_CTS pop ax pop dx jmp mainmenu wait_abort: mov dx,MCR mov al,00h out dx,al pop ax pop dx jmp startmenu endm send_data macro data local wait1 push dx push ax mov dx,LSR wait1: in al,dx test al,20h jz wait1 mov dx,THR mov al,data out dx,al pop ax pop dx endm receive_data macro local wait2 push dx push ax mov dx,LSR wait2: in al,dx test al,1 jz wait2 mov dx,RBR in al,dx mov al,player_key pop ax pop dx endm initialize_player macro local init_me,init_pac,init_gob,init_message_turn,init_message_turn1 cmp player_turn,0 je init_me cmp opponent_choice,0 je init_pac jmp init_gob init_me: cmp player_choice,0 je init_pac jmp init_gob init_pac: mov ax,pac_loc mov player_loc,ax mov player_color,YELLOW jmp init_message_turn init_gob: mov ax,gob_loc mov player_loc,ax mov player_color,GREEN init_message_turn: cmp player_turn,0 je init_message_turn1 PRINT_S msgmove2,50,11 init_message_turn1: PRINT_S msgmove1,50,11 endm START PROC FAR ; initialization: initialize the DS to point to a proper segment MOV AX, DSEG MOV DS, AX ;==================================== ; MAIN CODE ;==================================== mov ah,0fh int 10h mov curr_vmod,al mov ah,00h mov al,new_vmod int 10h mov dx,MCR mov al,00h out dx,al startmenu: call cs:clear_screen PRINT_S msg0,28,10 PRINT_S msg3,30,11 PRINT_S msg4,30,12 PRINT_S msg5,30,13 ;initialize mov player_choice,2 mov opponent_choice,2 mov network,0 check_startkey: mov ah,01h int 16h jz check_startkey mov ah,00h int 16h cmp al,esckey jne check_startkey_next1 jmp exit check_startkey_next1: cmp al,73h jne check_startkey_next2 jmp game_init_sa check_startkey_next2: cmp al,6Eh je game_init_network jmp check_startkey game_init_network: mov network,1 init_connection game_init_sa: mov network,0 jmp mainmenu mainmenu: call cs:clear_screen PRINT_S msg0,28,10 PRINT_S msg1,30,11 PRINT_S msg2,30,12 PRINT_S msg5,30,13 PRINT_S msgwait2,30,15 PRINT_S msgwait3,30,16 check_menukey: check_opponent_choice: push ax push dx mov dx,LSR in al,dx test al,1 jz check_opponent_choice_next mov dx,RBR in al,dx mov player_key,al ;debug mov ah,2 mov dx,0 int 10h xor ax,ax mov al,player_key call cs:output ;end debug pop ax pop dx mov ah,opponent_choice cmp ah,2 jne jmp_opponent_choice_esc opponent_choice_gob: cmp player_key,67h jne opponent_choice_pac mov opponent_choice,1 PRINT_S msggob,51,15 mov ah,player_choice cmp ah,2 jne jmp_gameinit mov player_turn,1 jmp check_menukey_next jmp_opponent_choice_esc: jmp opponent_choice_esc check_opponent_choice_next: pop ax pop dx jmp_check_menukey_next: jmp check_menukey_next opponent_choice_pac: cmp player_key,70h jne opponent_choice_esc ;jne jmp_check_menukey_next mov opponent_choice,0 PRINT_S msgpac,51,15 mov ah,player_choice cmp ah,2 jne jmp_gameinit mov player_turn,1 jmp check_menukey_next opponent_choice_esc: cmp player_key,esckey jne check_menukey_next PRINT_S msgdisconnect,30,18 PRINT_S msgkey,30,19 press_anykey: mov ah,01h int 16h jz press_anykey mov ah,00h int 16h jmp startmenu jmp_gameinit: jmp game_init check_menukey_next: mov ah,01h int 16h jz jmp_no_menukey mov ah,00h int 16h cmp al,esckey jne check_player_choice mov al,esckey mov player_key,al send_data player_key jmp exit check_player_choice: mov ah,player_choice cmp ah,2 je check_menukey_pac jmp_no_menukey: jmp no_menukey check_menukey_pac: cmp al,70h jne check_menukey_gob mov ah,opponent_choice cmp ah,0 je jmp_nomenukey mov player_key,70h send_data player_key mov player_choice,0 mov ah,opponent_choice cmp ah,1 je game_init mov player_turn,0 PRINT_S msgpac,43,16 jmp check_menukey jmp_nomenukey: jmp no_menukey check_menukey_gob: cmp al,67h jne jmp_no_menukey mov ah,opponent_choice cmp ah,1 je jmp_no_menukey mov player_key,67h send_data player_key mov player_choice,1 cmp ah,0 je game_init mov player_turn,0 PRINT_S msggob,43,16 jmp check_menukey no_menukey: jmp check_menukey game_init: mov pac_loc,76 mov gob_loc,4 mov pac_moves,0 mov gob_moves,0 mov pac_pill,0 mov bx,0 colors_init: mov al,colors_db[bx] mov colors[bx],al inc bx cmp bx,81 jl colors_init call cs:clear_screen drw_m drw_xy gob_loc,GREEN drw_xy pac_loc,YELLOW cmp player_choice,1 je message_init_gob jmp message_init_pac message_init_pac: PRINT_S msgchoice,50,10 PRINT_S msgpac,70,10 jmp mainprog message_init_gob: PRINT_S msgchoice,50,10 PRINT_S msggob,70,10 jmp mainprog mainprog: ;clear line ;PRINT_S msgblank,50,11 ;check victory condition mov ax,gob_loc cmp ax,pac_loc je gob_victory mov ax,pac_pill cmp ax,23 je pac_victory initialize_player cmp player_turn,0 je jmp_check_key jmp receive_key jmp_check_key: jmp check_key gob_victory: cmp player_choice,1 je message_victory cmp player_choice,0 je message_defeat jmp message_anykey pac_victory: cmp player_choice,0 je message_victory cmp player_choice,1 je message_defeat jmp message_anykey message_victory: PRINT_S msgwin,10,25 jmp message_anykey message_defeat: PRINT_S msglose,10,25 jmp message_anykey message_anykey: PRINT_S msgkey,10,26 jmp press_any_key press_any_key: mov ah,01h int 16h jz press_any_key mov ah,00h int 16h jmp mainmenu receive_key: receive_data mov ah,player_key cmp ah,esckey jne check_key_next0 jmp mainmenu check_key_next0: cmp ah,right je jmp_moveright cmp ah,left je jmp_moveleft cmp ah,up je jmp_moveup cmp ah,down je jmp_movedown jmp receive_key jmp_moveright: jmp move_right jmp_moveleft: jmp move_left jmp_moveup: jmp move_up jmp_movedown: jmp move_down check_key: mov ah,01h int 16h jz no_key mov ah,00h int 16h ; int 21h ; cmp al,0ffh cmp al,esckey jne check_key_next1 mov player_key,al send_data player_key jmp mainmenu check_key_next1: cmp ah,right je moveright cmp ah,left je moveleft cmp ah,up je moveup cmp ah,down je movedown cmp network,0 je check_key_next2 jmp no_key check_key_next2: cmp al,67h je gobinit cmp al,70h je pacinit jmp no_key moveright: mov player_key,ah jmp move_right moveleft: mov player_key,ah jmp move_left moveup: mov player_key,ah jmp move_up movedown: mov player_key,ah jmp move_down gobinit: jmp gob_init pacinit: jmp pac_init gob_init: jmp no_key pac_init: jmp no_key no_key: jmp check_key ;==================================== ; END OF MAIN CODE ;==================================== ; terminate the program normally exit: mov ah,00h mov al,curr_vmod int 10h mov ah,4ch int 21h move_right: mov bx,player_loc cmp colors[bx+1],RED jne move_right_bound jmp check_key move_right_bound: mov ax,player_loc inc ax mov bx,9 mov dx,0 idiv bx cmp dx,0 jne move_right_draw jmp check_key move_right_draw: mov dx,0 mov di,player_loc drw_xy player_loc,colors[di] inc player_loc drw_xy player_loc,player_color jmp post_move move_left: mov bx,player_loc cmp colors[bx-1],RED jne move_left_bound jmp check_key move_left_bound: mov ax,player_loc inc ax mov bx,9 mov dx,0 idiv bx cmp dx,1 jne move_left_draw jmp check_key move_left_draw: mov dx,0 mov di,player_loc drw_xy player_loc,colors[di] dec player_loc drw_xy player_loc,player_color jmp post_move move_up: mov bx,player_loc cmp colors[bx-9],RED jne move_up_bound jmp check_key move_up_bound: mov ax,player_loc cmp ax,8 jg move_up_draw jmp check_key move_up_draw: mov di,player_loc drw_xy player_loc,colors[di] sub player_loc,9 drw_xy player_loc,player_color jmp post_move move_down: mov bx,player_loc cmp colors[bx+9],RED jne move_down_bound jmp check_key move_down_bound: mov ax,player_loc cmp ax,72 jl move_down_draw jmp check_key move_down_draw: mov di,player_loc drw_xy player_loc,colors[di] add player_loc,9 drw_xy player_loc,player_color jmp post_move post_move: cmp network,1 jne post_move_next send_data player_key post_move_next: cmp player_choice,0 je post_pac_move post_gob_move: inc gob_moves mov ax,player_loc mov gob_loc,ax ;mov ah,2 ;mov dx,0 ;int 10h ;mov ax,gob_moves ;call cs:output not player_turn jmp mainprog post_pac_move: inc pac_moves mov bx,player_loc mov pac_loc,bx ;eat pills cmp colors[bx],CYAN jne post_pac_nopill mov colors[bx],BLUE inc pac_pill post_pac_nopill: ;mov ah,2 ;mov dx,0 ;int 10h ;mov ax,pac_pill ;call cs:output not player_turn jmp mainprog ; end of `start' procedure START ENDP CLEAR_SCREEN PROC FAR PUSH AX ; save registers PUSH DS PUSH BX PUSH CX PUSH DI MOV AX, 40h MOV DS, AX ; for getting screen parameters. MOV AH, 06h ; scroll up function id. MOV AL, 0 ; scroll all lines! MOV BH, 0 ; attribute for new lines. MOV CH, 0 ; upper row. MOV CL, 0 ; upper col. MOV DI, 84h ; rows on screen -1, MOV DH, [DI] ; lower row (byte). MOV DI, 4Ah ; columns on screen, MOV DL, [DI] DEC DL ; lower col. INT 10h ; set cursor position to top ; of the screen: MOV BH, 0 ; current page. MOV DL, 0 ; col. MOV DH, 0 ; row. MOV AH, 02 INT 10h POP DI ; re-store registers... POP CX ; POP BX ; POP DS ; POP AX ; RET CLEAR_SCREEN ENDP OUTPUT PROC FAR ; This is the helper procedure for output ; save all registers PUSH CX PUSH BX PUSH DX PUSH AX ; output the prefix `0x'. ; you can customize the prefix. MOV AH, 09H LEA DX, prefix INT 21H ; 1. output higher 8-bit, which is in AH POP AX PUSH AX ; 1.1 output first 4-bit MOV AL, AH ; prepare to output higher 8-bit: copy it to AL MOV CH, AL ; save a copy in CH MOV CL, 4 ; about to shift, 4 is the slots to shift SHR AL, CL ; shift 4 slots to the right, first 4 bits remain MOV AH, 0 ; clear the AH, not useful any more MOV BX, AX ; move AX to BX. BX is then used to check the table MOV DL, hex_tab[BX] ; check the table now MOV AH, 02H ; select the output function INT 21H ; invoke ; 1.2 output next 4-bit: lower 4-bit of AH MOV AL, CH ; restore the saved copy from CH to AL AND AL, 00001111B ; mask the higher 4-bit out. We don’t need it MOV AH, 0 ; clear AH. MOV BX, AX ; mo AX to BX. BX is then used to check the table MOV DL, hex_tab[BX] ; check the table now MOV AH, 02H ; select the output function INT 21H ; invoke ; 2. output the lower 8-bit, which is in AL ; we use the same method as that for outputting AH. ; Comments are omitted POP AX PUSH AX MOV CH, AL ; save a copy MOV CL, 4 ; firstly highest 4-bit SHR AL, CL MOV AH, 0 MOV BX, AX MOV DL, hex_tab[BX] MOV AH, 02H INT 21H MOV AL, CH ; restore the saved copy AND AL, 00001111B ; mask MOV AH, 0 MOV BX, AX MOV DL, hex_tab[BX] MOV AH, 02H INT 21H ; restore registers POP AX POP DX POP BX POP CX RET OUTPUT ENDP ; end of code segment CSEG ENDS ; assign `start' as the entry point END START