├── .gitignore ├── Makefile ├── README ├── e.bat ├── old ├── pillman0.asm ├── pillman1.asm ├── pillman2.asm ├── pillman3.asm └── pillman4.asm ├── pillman.asm ├── pillman.com ├── pillman.img └── pillman.png /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | backup/ 3 | 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile contributed by jtsiomb 2 | 3 | src = pillman.asm 4 | 5 | .PHONY: all 6 | all: pillman.img pillman.com 7 | 8 | pillman.img: $(src) 9 | nasm -f bin -o $@ $(src) 10 | 11 | pillman.com: $(src) 12 | nasm -f bin -o $@ -Dcom_file=1 $(src) 13 | 14 | .PHONY: clean 15 | clean: 16 | $(RM) pillman.img pillman.com 17 | 18 | .PHONY: rundosbox 19 | rundosbox: pillman.com 20 | dosbox $< 21 | 22 | .PHONY: runqemu 23 | runqemu: pillman.img 24 | qemu-system-i386 -fda pillman.img 25 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | 2 | ______ __ __ __ __ __ ______ __ __ 3 | /\ == \ /\ \ /\ \ /\ \ /\ "-./ \ /\ __ \ /\ "-.\ \ 4 | \ \ _-/ \ \ \ \ \ \____ \ \ \____ \ \ \-./\ \ \ \ __ \ \ \ \-. \ 5 | \ \_\ \ \_\ \ \_____\ \ \_____\ \ \_\ \ \_\ \ \_\ \_\ \ \_\\"\_\ 6 | \/_/ \/_/ \/_____/ \/_____/ \/_/ \/_/ \/_/\/_/ \/_/ \/_/ 7 | 8 | 9 | Pillman game in 512 bytes (boot sector or COM file) 10 | by Oscar Toledo G. Jul/08/2019 11 | 12 | http://nanochess.org 13 | https://github.com/nanochess 14 | 15 | This a game about a yellow man eating pills in 512 bytes. It can be 16 | run as a COM file or put into a boot sector of a floppy disk to be 17 | run. 18 | 19 | Move with arrow keys, press Esc to exit (only COM file). 20 | 21 | It's compatible with 8088 (the original IBM PC). So you now have 22 | to look for a 8-bit compatible VGA card if you want to run it over 23 | original hardware ;) 24 | 25 | A small video of the game running under emulation: 26 | 27 | https://www.youtube.com/watch?v=ALBgsXOq11o 28 | 29 | If you want to assemble it, you must download the Netwide Assembler 30 | (nasm) from www.nasm.us 31 | 32 | Use this command line: 33 | 34 | nasm -f bin pillman.asm -Dcom_file=1 -o pillman.com 35 | nasm -f bin pillman.asm -Dcom_file=0 -o pillman.img 36 | 37 | Tested with VirtualBox for Mac OS X running Windows XP running this 38 | game, it also works with DosBox and probably with qemu: 39 | 40 | qemu-system-x86_64 -fda pillman.img 41 | 42 | Enjoy it! 43 | 44 | 45 | >> THE BOOK << 46 | 47 | Do you would like more details on the inner workings? This program 48 | is fully commented in my new book Programming Boot Sector Games 49 | and you'll also find a 8086/8088 crash course! 50 | 51 | Now available from Lulu: 52 | 53 | Soft-cover 54 | http://www.lulu.com/shop/oscar-toledo-gutierrez/programming-boot-sector-games/paperback/product-24188564.html 55 | 56 | Hard-cover 57 | http://www.lulu.com/shop/oscar-toledo-gutierrez/programming-boot-sector-games/hardcover/product-24188530.html 58 | 59 | eBook 60 | https://nanochess.org/store.html 61 | 62 | These are some of the example programs documented profusely 63 | in the book: 64 | 65 | * Guess the number. 66 | * Tic-Tac-Toe game. 67 | * Text graphics. 68 | * Mandelbrot set. 69 | * F-Bird game. 70 | * Invaders game. 71 | * Pillman game. 72 | * Toledo Atomchess. 73 | * bootBASIC language. 74 | -------------------------------------------------------------------------------- /e.bat: -------------------------------------------------------------------------------- 1 | nasm -f bin pillman.asm -Dcom_file=1 -o pillman.com 2 | nasm -f bin pillman.asm -o pillman.img 3 | rem pillman 4 | 5 | -------------------------------------------------------------------------------- /old/pillman0.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; Pillman 3 | ; 4 | ; by Oscar Toledo G. 5 | ; 6 | ; Creation date: Jun/11/2019. 7 | ; Revision date: Jun/12/2019. Draws level. 8 | ; Revision date: Jun/13/2019. Pillman can move. 9 | ; 10 | 11 | ; 12 | ; TODO: 13 | ; * Ghost can get stuck because cannot try a third direction. 14 | ; * Ghost should be transparent. 15 | ; * Pillman should not leave trash. 16 | ; 17 | 18 | %ifndef com_file ; If not defined create a boot sector 19 | com_file: equ 0 20 | %endif 21 | 22 | base: equ 0xfc80 ; Memory base (same segment as video) 23 | old_time: equ base+0x00 24 | frame: equ base+0x02 25 | dir: equ base+0x03 26 | intended_dir: equ base+0x04 27 | x_player: equ base+0x06 28 | y_player: equ base+0x08 29 | pos1: equ base+0x0a 30 | 31 | X_OFFSET: equ 0x0140 32 | 33 | MAZE_COLOR: equ 0x01 34 | PILL_COLOR: equ 0x0e 35 | PLAYER_COLOR: equ 0x0e 36 | GHOST1_COLOR: equ 0x09 37 | GHOST2_COLOR: equ 0x0a 38 | GHOST3_COLOR: equ 0x0b 39 | GHOST4_COLOR: equ 0x0c 40 | 41 | %if com_file 42 | org 0x0100 43 | %else 44 | org 0x7c00 45 | %endif 46 | mov ax,0x0013 ; Set mode 0x13 (320x200x256 VGA) 47 | int 0x10 ; Call BIOS 48 | cld 49 | mov ax,0xa000 50 | mov ds,ax 51 | mov es,ax 52 | xor ax,ax 53 | xor di,di 54 | xor cx,cx 55 | rep 56 | stosw 57 | mov di,8*X_OFFSET+32 58 | mov si,maze 59 | g2: cs lodsw 60 | push ax 61 | mov cx,16 62 | g3: shl ax,1 63 | call draw_maze 64 | loop g3 65 | pop ax 66 | mov cx,15 67 | shr ax,1 68 | g4: shr ax,1 69 | call draw_maze 70 | loop g4 71 | add di,X_OFFSET*8-31*8 72 | cmp si,maze+42 73 | jne g2 74 | 75 | mov byte [dir],0x10 76 | mov di,pos1 77 | mov ax,0x80*X_OFFSET+0x98 78 | stosw 79 | mov ax,0x0001*2 80 | stosw 81 | mov ax,0x48*X_OFFSET+0x90 82 | stosw 83 | mov ax,-X_OFFSET*2 84 | stosw 85 | mov ax,0x48*X_OFFSET+0x98 86 | stosw 87 | mov ax,-1*2 88 | stosw 89 | mov ax,0x48*X_OFFSET+0xa0 90 | stosw 91 | mov ax,-X_OFFSET*2 92 | stosw 93 | mov ax,0x48*X_OFFSET+0xa8 94 | stosw 95 | mov ax,1 96 | stosw 97 | game_loop: 98 | 99 | clock_wait: 100 | mov ah,0x00 101 | int 0x1a ; BIOS clock read 102 | cmp dx,[old_time] ; Wait for change 103 | je clock_wait 104 | mov [old_time],dx 105 | 106 | mov ah,0x01 ; BIOS Key available 107 | int 0x16 108 | mov ah,0x00 ; BIOS Read Key 109 | je g5 110 | int 0x16 111 | 112 | g5: mov bx,[intended_dir] 113 | cmp ah,0x48 114 | jne g6 115 | mov bx,-X_OFFSET*2 116 | g6: 117 | cmp ah,0x4b 118 | jne g7 119 | mov bx,-1*2 120 | g7: 121 | cmp ah,0x4d 122 | jne g8 123 | mov bx,1*2 124 | g8: 125 | cmp ah,0x50 126 | jne g9 127 | mov bx,X_OFFSET*2 128 | g9: 129 | mov [intended_dir],bx 130 | 131 | mov si,pos1 132 | lodsw 133 | xchg ax,di 134 | lodsw 135 | xchg ax,bx 136 | call move_sprite 137 | mov [x_player],dx 138 | mov [y_player],ax 139 | or al,dl 140 | and al,7 141 | jne g10 142 | mov bx,[intended_dir] 143 | push di 144 | call move_sprite 145 | pop ax 146 | cmp ax,di 147 | je g10 148 | xchg ax,di 149 | mov [pos1+2],bx 150 | g10: 151 | xor byte [frame],1 152 | mov ax,0x0e00 153 | je g1 154 | mov al,[dir] 155 | g1: 156 | call draw_sprite 157 | mov ah,GHOST1_COLOR 158 | call move_ghost 159 | mov ah,GHOST2_COLOR 160 | call move_ghost 161 | mov ah,GHOST3_COLOR 162 | call move_ghost 163 | mov ah,GHOST4_COLOR 164 | call move_ghost 165 | jmp game_loop 166 | 167 | ; 168 | ; Move ghost 169 | ; 170 | move_ghost: 171 | mov al,0x28 172 | push ax 173 | lodsw 174 | xchg ax,di 175 | lodsw 176 | xchg ax,bx 177 | call move_sprite 178 | mov cl,al 179 | or cl,dl 180 | and cl,7 181 | jne mg1 182 | cmp bh,0xff 183 | je mg2 184 | cmp bh,0x00 185 | je mg2 186 | ; Moving vertically 187 | cmp dx,[x_player] 188 | mov bx,-1*2 189 | jnc mg3 190 | neg bx 191 | jmp mg3 192 | 193 | ; Moving horizontally 194 | mg2: cmp ax,[y_player] 195 | mov bx,-X_OFFSET*2 196 | jnc mg3 197 | neg bx 198 | mg3: 199 | push di 200 | call move_sprite 201 | pop ax 202 | cmp ax,di 203 | je mg1 204 | xchg ax,di 205 | mov [si-2],bx 206 | mg1: 207 | pop ax 208 | jmp draw_sprite 209 | 210 | ; 211 | ; Try to move sprite in desired direction 212 | ; 213 | ; Input: 214 | ; DI = address on screen 215 | ; BX = offset of movement 216 | ; 217 | move_sprite: 218 | or bx,bx 219 | js ms1 220 | mov cl,2 221 | shl bx,cl 222 | mov al,[bx+di] 223 | sar bx,cl 224 | jmp ms3 225 | 226 | ; 227 | ; Moving in negative direction 228 | ; 229 | ms1: 230 | mov al,[bx+di] 231 | ms3: 232 | cmp al,MAZE_COLOR 233 | je ms2 ; Yes, don't move 234 | add di,bx ; No, move 235 | mov [si-4],di 236 | ms2: 237 | mov ax,di 238 | xor dx,dx 239 | mov cx,X_OFFSET 240 | div cx 241 | ret 242 | 243 | ; 244 | ; Draw a maze square. 245 | ; 246 | ; Input: 247 | ; Carry = 0 = Draw border 248 | ; 1 = Draw pill 249 | ; DI = address on screen 250 | ; 251 | ; Output: 252 | ; DI = Moved 8 pixels to right 253 | ; 254 | ; Destroys: 255 | ; BX 256 | ; 257 | draw_maze: 258 | push ax 259 | mov ax,MAZE_COLOR*0x0100+0x30 260 | jnc dm1 261 | mov ax,PILL_COLOR*0x0100+0x38 262 | dm1: call draw_sprite 263 | add di,8 264 | pop ax 265 | ret 266 | 267 | bitmaps: 268 | db 0x3c,0x7e,0xff,0xff,0xff,0xff,0x7e,0x3c 269 | db 0x00,0x42,0xe7,0xe7,0xff,0xff,0x7e,0x3c 270 | db 0x3c,0x7e,0xfc,0xf0,0xf0,0xfc,0x7e,0x3c 271 | db 0x3c,0x7e,0xff,0xff,0xe7,0xe7,0x42,0x00 272 | db 0x3c,0x7e,0x3f,0x0f,0x0f,0x3f,0x7e,0x3c 273 | db 0x3c,0x7e,0xdb,0xdb,0xff,0xff,0xff,0xa5 274 | db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff 275 | db 0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00 276 | 277 | maze: 278 | dw 0x0000 279 | dw 0x7ffe 280 | dw 0x4202 281 | dw 0x4202 282 | dw 0x7fff 283 | dw 0x4240 284 | dw 0x7e7e 285 | dw 0x0202 286 | dw 0x027f 287 | dw 0xffc0 288 | dw 0x0240 289 | dw 0x027f 290 | dw 0x0240 291 | dw 0x7ffe 292 | dw 0x4202 293 | dw 0x7bff 294 | dw 0x0a40 295 | dw 0x7e7e 296 | dw 0x4002 297 | dw 0x7fff 298 | dw 0x0000 299 | 300 | ; 301 | ; Draw 1 pixel inside reg. al (bit 7) 302 | ; 303 | bit: jc big_pixel 304 | zero: xor ax,ax 305 | big_pixel: 306 | stosb 307 | ret 308 | 309 | ; ah = sprite color 310 | ; al = sprite (x8) 311 | ; di = Target address 312 | draw_sprite: 313 | push cx 314 | push di 315 | in3: push ax 316 | mov bx,bitmaps 317 | cs xlat ; Extract one byte from bitmap 318 | xchg ax,bx 319 | mov cx,8 320 | in0: mov al,bh 321 | mov ah,bh 322 | shl bl,1 323 | call bit ; Draw pixel 324 | loop in0 325 | add di,X_OFFSET-8 ; Go to next video line 326 | pop ax 327 | inc ax ; Next bitmap byte 328 | test al,7 ; Sprite complete? 329 | jne in3 ; No, jump 330 | pop di 331 | pop cx 332 | ret 333 | 334 | %if com_file 335 | %else 336 | times 510-($-$$) db 0x4f 337 | db 0x55,0xaa ; Make it a bootable sector 338 | %endif 339 | -------------------------------------------------------------------------------- /old/pillman1.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; Pillman 3 | ; 4 | ; by Oscar Toledo G. 5 | ; 6 | ; Creation date: Jun/11/2019. 7 | ; Revision date: Jun/12/2019. Draws level. 8 | ; Revision date: Jun/13/2019. Pillman can move. 9 | ; Revision date: Jun/14/2019. Now ghosts don't get stuck. Ghost are 10 | ; transparent. Pillman doesn't leave 11 | ; trash. 12 | ; 13 | 14 | ; 15 | ; TODO: 16 | ; * Ghosts should kill pillman. 17 | ; * Detect all pills eaten? 18 | ; 19 | 20 | %ifndef com_file ; If not defined create a boot sector 21 | com_file: equ 0 22 | %endif 23 | 24 | base: equ 0xfc80 ; Memory base (same segment as video) 25 | old_time: equ base+0x00 26 | frame: equ base+0x02 27 | intended_dir: equ base+0x03 28 | x_player: equ base+0x04 29 | y_player: equ base+0x06 30 | pos1: equ base+0x08 31 | 32 | X_OFFSET: equ 0x0140 33 | 34 | SPEED: equ 2 35 | 36 | MAZE_COLOR: equ 0x37 ; No color should be higher or equal value 37 | PILL_COLOR: equ 0x02 38 | PLAYER_COLOR: equ 0x0e 39 | GHOST1_COLOR: equ 0x20 40 | GHOST2_COLOR: equ 0x2e 41 | GHOST3_COLOR: equ 0x28 42 | GHOST4_COLOR: equ 0x34 43 | 44 | %if com_file 45 | org 0x0100 46 | %else 47 | org 0x7c00 48 | %endif 49 | mov ax,0x0013 ; Set mode 0x13 (320x200x256 VGA) 50 | int 0x10 ; Call BIOS 51 | cld 52 | mov ax,0xa000 53 | mov ds,ax 54 | mov es,ax 55 | mov di,8*X_OFFSET+32 56 | mov si,maze 57 | g2: cs lodsw 58 | xchg ax,cx 59 | mov bx,30*8 60 | g3: shl cx,1 61 | mov ax,MAZE_COLOR*0x0100+0x10 62 | jnc dm1 63 | mov ax,PILL_COLOR*0x0100+0x30 64 | dm1: call draw_sprite 65 | add di,bx 66 | sub bx,16 67 | jc dm2 68 | call draw_sprite 69 | sub di,bx 70 | sub di,8 71 | jmp g3 72 | 73 | dm2: 74 | add di,X_OFFSET*8-15*8 75 | cmp si,maze+42 76 | jne g2 77 | 78 | mov di,pos1 79 | mov cx,5*2 80 | repz 81 | cs movsw 82 | 83 | game_loop: 84 | 85 | clock_wait: 86 | mov ah,0x00 87 | int 0x1a ; BIOS clock read 88 | cmp dx,[old_time] ; Wait for change 89 | je clock_wait 90 | mov [old_time],dx 91 | 92 | mov ah,0x01 ; BIOS Key available 93 | int 0x16 94 | mov ah,0x00 ; BIOS Read Key 95 | je g5 96 | int 0x16 97 | 98 | g5: mov al,[intended_dir] 99 | cmp ah,0x48 100 | jne g6 101 | mov al,0x01 102 | g6: 103 | cmp ah,0x4b 104 | jne g7 105 | mov al,0x08 106 | g7: 107 | cmp ah,0x4d 108 | jne g8 109 | mov al,0x02 110 | g8: 111 | cmp ah,0x50 112 | jne g9 113 | mov al,0x04 114 | g9: 115 | mov [intended_dir],al 116 | 117 | mov si,pos1 118 | lodsw 119 | xchg ax,di 120 | lodsw 121 | xchg ax,bx 122 | xor ax,ax ; Delete pillman 123 | call draw_sprite 124 | call move_sprite 125 | xor byte [frame],1 126 | mov ax,0x0e20 127 | je g1 128 | mov al,[pos1+2] 129 | mov cl,3 130 | shl al,cl 131 | sub al,8 132 | g1: 133 | call draw_sprite 134 | mov ah,GHOST1_COLOR 135 | call move_ghost 136 | mov ah,GHOST2_COLOR 137 | call move_ghost 138 | mov ah,GHOST3_COLOR 139 | call move_ghost 140 | mov ah,GHOST4_COLOR 141 | call move_ghost 142 | jmp game_loop 143 | 144 | ; 145 | ; DI = address on screen 146 | ; BL = wanted direction 147 | ; 148 | move_sprite: 149 | mov ax,di 150 | xor dx,dx 151 | mov cx,X_OFFSET 152 | div cx 153 | mov ah,al 154 | or ah,dl 155 | and ah,0x07 156 | jne ms1 157 | 158 | mov ah,0 159 | cmp byte [di-0x0001],MAZE_COLOR 160 | adc ah,ah 161 | cmp byte [di+X_OFFSET*8],MAZE_COLOR 162 | adc ah,ah 163 | cmp byte [di+0x0008],MAZE_COLOR 164 | adc ah,ah 165 | cmp byte [di-X_OFFSET],MAZE_COLOR 166 | adc ah,ah 167 | 168 | cmp bh,0 ; Is it pillman? 169 | jne ms4 170 | mov [x_player],dx 171 | mov [y_player],al 172 | ; 173 | ; Pillman 174 | ; 175 | mov al,[intended_dir] 176 | test ah,al 177 | je ms5 178 | mov bl,al 179 | jmp ms1 180 | 181 | ms5: 182 | and ah,bl ; Can pillman go in direction? 183 | je ms2 ; No, pillman stops 184 | jmp ms1 ; Yes, pillman moves 185 | 186 | ; 187 | ; Ghost 188 | ; 189 | ms4: test bl,0x05 190 | je ms6 191 | ; Current direction is up/down 192 | cmp dx,[x_player] 193 | mov bh,0x02 194 | jc ms8 195 | mov bh,0x08 196 | jmp ms8 197 | 198 | ; Current direction is left/right 199 | ms6: cmp al,[y_player] 200 | mov bh,0x04 201 | jc ms8 202 | mov bh,0x01 203 | ms8: 204 | test ah,bh 205 | je ms9 206 | mov bl,bh 207 | jmp ms1 208 | 209 | ms9: test ah,bl 210 | jne ms1 211 | shl bl,1 212 | cmp bl,0x10 213 | jne ms9 214 | mov bl,0x01 215 | jmp ms9 216 | 217 | ms1: mov [si-2],bl 218 | shr bl,1 219 | mov ax,-X_OFFSET*SPEED 220 | jc ms3 221 | shr bl,1 222 | mov ax,1*SPEED 223 | jc ms3 224 | shr bl,1 225 | mov ax,X_OFFSET*SPEED 226 | jc ms3 227 | mov ax,-1*SPEED 228 | ms3: add di,ax 229 | mov [si-4],di 230 | ms2: 231 | ret 232 | 233 | bitmaps: 234 | db 0x00,0x42,0xe7,0xe7,0xff,0xff,0x7e,0x3c 235 | db 0x3c,0x7e,0xfc,0xf0,0xf0,0xfc,0x7e,0x3c 236 | db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; Maze 237 | db 0x3c,0x7e,0xff,0xff,0xe7,0xe7,0x42,0x00 238 | db 0x3c,0x7e,0xff,0xff,0xff,0xff,0x7e,0x3c 239 | db 0x3c,0x7e,0xdb,0xdb,0xff,0xff,0xff,0xa5 ; Ghost 240 | db 0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00 ; Pill 241 | db 0x3c,0x7e,0x3f,0x0f,0x0f,0x3f,0x7e,0x3c 242 | 243 | maze: 244 | dw 0x0000 245 | dw 0x7ffe 246 | dw 0x4202 247 | dw 0x4202 248 | dw 0x7fff 249 | dw 0x4240 250 | dw 0x7e7e 251 | dw 0x0202 252 | dw 0x027f 253 | dw 0xffc0 254 | dw 0x0240 255 | dw 0x027f 256 | dw 0x0240 257 | dw 0x7ffe 258 | dw 0x4202 259 | dw 0x7bff 260 | dw 0x0a40 261 | dw 0x7e7e 262 | dw 0x4002 263 | dw 0x7fff 264 | dw 0x0000 265 | 266 | setup_data: 267 | dw 0x80*X_OFFSET+0x98 268 | dw 0x0002 269 | dw 0x48*X_OFFSET+0x90-X_OFFSET*SPEED 270 | dw 0x0101 271 | dw 0x48*X_OFFSET+0x98-1*SPEED 272 | dw 0x0108 273 | dw 0x48*X_OFFSET+0xa0-X_OFFSET*SPEED 274 | dw 0x0101 275 | dw 0x48*X_OFFSET+0xa8+1*SPEED 276 | dw 0x0102 277 | 278 | ; 279 | ; Move ghost 280 | ; 281 | move_ghost: 282 | mov al,0x28 283 | push ax 284 | lodsw 285 | xchg ax,di 286 | lodsw 287 | cmp ah,0x01 288 | xchg ax,bx 289 | pop ax 290 | push ax 291 | mov byte [si-1],0x02 292 | je mg1 293 | call draw_sprite 294 | mg1: 295 | call move_sprite 296 | pop ax 297 | ; ah = sprite color 298 | ; al = sprite (x8) 299 | ; di = Target address 300 | draw_sprite: 301 | push ax 302 | push bx 303 | push cx 304 | push di 305 | in3: push ax 306 | mov bx,bitmaps 307 | cs xlat ; Extract one byte from bitmap 308 | xchg ax,bx 309 | mov cx,8 310 | in0: mov al,bh 311 | shl bl,1 312 | jc in1 313 | xor ax,ax 314 | in1: 315 | cmp bh,0x10 316 | jc in2 317 | xor al,[di] 318 | in2: 319 | stosb 320 | loop in0 321 | add di,X_OFFSET-8 ; Go to next video line 322 | pop ax 323 | inc ax ; Next bitmap byte 324 | test al,7 ; Sprite complete? 325 | jne in3 ; No, jump 326 | pop di 327 | pop cx 328 | pop bx 329 | pop ax 330 | ret 331 | 332 | %if com_file 333 | %else 334 | times 510-($-$$) db 0x4f 335 | db 0x55,0xaa ; Make it a bootable sector 336 | %endif 337 | -------------------------------------------------------------------------------- /old/pillman2.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; Pillman 3 | ; 4 | ; by Oscar Toledo G. 5 | ; 6 | ; Creation date: Jun/11/2019. 7 | ; Revision date: Jun/12/2019. Draws level. 8 | ; Revision date: Jun/13/2019. Pillman can move. 9 | ; Revision date: Jun/14/2019. Now ghosts don't get stuck. Ghost are 10 | ; transparent. Pillman doesn't leave 11 | ; trash. 12 | ; Revision date: Jun/15/2019. Ghosts can catch pillman. 538 bytes. 13 | ; 14 | 15 | ; 16 | ; TODO: 17 | ; * Detect all pills eaten? 18 | ; 19 | 20 | %ifndef com_file ; If not defined create a boot sector 21 | com_file: equ 0 22 | %endif 23 | 24 | base: equ 0xfc80 ; Memory base (same segment as video) 25 | old_time: equ base+0x00 26 | x_player: equ base+0x04 27 | y_player: equ base+0x06 28 | frame: equ base+0x07 29 | intended_dir: equ base+0x08 30 | pos1: equ base+0x09 31 | 32 | X_OFFSET: equ 0x0140 33 | 34 | SPEED: equ 2 35 | 36 | MAZE_COLOR: equ 0x37 ; No color should be higher or equal value 37 | PILL_COLOR: equ 0x02 38 | PLAYER_COLOR: equ 0x0e ; Should be unique 39 | 40 | ; 41 | ; XOR combination of these plus PILL_COLOR shouldn't 42 | ; result in PLAYER_COLOR 43 | ; 44 | GHOST1_COLOR: equ 0x21 45 | GHOST2_COLOR: equ 0x2e 46 | GHOST3_COLOR: equ 0x28 47 | GHOST4_COLOR: equ 0x34 48 | 49 | %if com_file 50 | org 0x0100 51 | %else 52 | org 0x7c00 53 | %endif 54 | restart: 55 | mov ax,0x0013 ; Set mode 0x13 (320x200x256 VGA) 56 | int 0x10 ; Call BIOS 57 | cld 58 | mov ax,0xa000 ; Video segment 59 | mov ds,ax ; Use as source data segment 60 | mov es,ax ; Use as target data segment 61 | mov di,8*X_OFFSET+32 62 | mov si,maze 63 | g2: cs lodsw 64 | xchg ax,cx 65 | mov bx,30*8 66 | g3: shl cx,1 67 | mov ax,MAZE_COLOR*0x0100+0x18 68 | jnc dm1 69 | mov ax,PILL_COLOR*0x0100+0x38 70 | dm1: call draw_sprite 71 | add di,bx 72 | sub bx,16 73 | jc dm2 74 | call draw_sprite 75 | sub di,bx 76 | sub di,8 77 | jmp g3 78 | 79 | dm2: 80 | add di,X_OFFSET*8-15*8 81 | cmp si,maze+42 82 | jne g2 83 | 84 | mov di,pos1 85 | mov cx,5*2 86 | repz 87 | cs movsw 88 | 89 | game_loop: 90 | 91 | clock_wait: 92 | mov ah,0x00 93 | int 0x1a ; BIOS clock read 94 | cmp dx,[old_time] ; Wait for change 95 | je clock_wait 96 | mov [old_time],dx 97 | 98 | mov ah,0x01 ; BIOS Key available 99 | int 0x16 100 | mov ah,0x00 ; BIOS Read Key 101 | je g5 102 | int 0x16 103 | 104 | g5: mov al,[intended_dir] 105 | cmp ah,0x48 ; Up 106 | jne g6 107 | mov al,0x01 108 | g6: 109 | cmp ah,0x4b ; Left 110 | jne g7 111 | mov al,0x08 112 | g7: 113 | cmp ah,0x4d ; Right 114 | jne g8 115 | mov al,0x02 116 | g8: 117 | cmp ah,0x50 ; Down 118 | jne g9 119 | mov al,0x04 120 | g9: 121 | mov [intended_dir],al 122 | 123 | mov si,pos1 124 | lodsw 125 | xchg ax,di 126 | lodsw 127 | xchg ax,bx 128 | xor ax,ax ; Delete pillman 129 | call move_sprite2 ; Move 130 | xor byte [frame],0x80 131 | mov ax,0x0e28 ; Closed mouth 132 | js g1 133 | mov al,[pos1+2] 134 | mov cl,3 135 | shl al,cl ; Open mouth 136 | g1: 137 | call draw_sprite ; Draw 138 | xor bp,bp 139 | mov bh,GHOST1_COLOR 140 | call move_ghost 141 | mov bh,GHOST2_COLOR 142 | call move_ghost 143 | mov bh,GHOST3_COLOR 144 | call move_ghost 145 | mov bh,GHOST4_COLOR 146 | call move_ghost 147 | and bp,bp ; Pillman catched? 148 | je game_loop ; No, jump 149 | jmp restart ; Yes, restart 150 | 151 | ; 152 | ; DI = address on screen 153 | ; BL = wanted direction 154 | ; 155 | move_sprite3: 156 | je move_sprite 157 | move_sprite2: 158 | call draw_sprite ; Remove ghost 159 | move_sprite: 160 | mov ax,di 161 | xor dx,dx 162 | mov cx,X_OFFSET 163 | div cx 164 | mov ah,al 165 | or ah,dl 166 | and ah,0x07 167 | jne ms1 168 | ; AH is zero already 169 | ;mov ah,0 170 | cmp byte [di-0x0001],MAZE_COLOR 171 | adc ah,ah 172 | cmp byte [di+X_OFFSET*8],MAZE_COLOR 173 | adc ah,ah 174 | cmp byte [di+0x0008],MAZE_COLOR 175 | adc ah,ah 176 | cmp byte [di-X_OFFSET],MAZE_COLOR 177 | adc ah,ah 178 | 179 | test bh,bh ; Is it pillman? 180 | je ms4 181 | 182 | ; 183 | ; Ghost 184 | ; 185 | test bl,0x05 186 | je ms6 187 | ; Current direction is up/down 188 | cmp dx,[x_player] 189 | mov bh,0x02 190 | jc ms8 191 | mov bh,0x08 192 | jmp ms8 193 | 194 | ; Current direction is left/right 195 | ms6: cmp al,[y_player] 196 | mov bh,0x04 197 | jc ms8 198 | mov bh,0x01 199 | ms8: 200 | test ah,bh 201 | je ms9 202 | mov bl,bh 203 | jmp ms1 204 | 205 | ms9: test ah,bl 206 | jne ms1 207 | shr bl,1 208 | jne ms9 209 | mov bl,0x08 210 | jmp ms9 211 | 212 | ; 213 | ; Pillman 214 | ; 215 | ms4: 216 | mov [x_player],dx 217 | mov [y_player],al 218 | mov al,[intended_dir] 219 | test ah,al 220 | je ms5 221 | mov bl,al 222 | jmp ms1 223 | 224 | ms5: 225 | and ah,bl ; Can pillman go in direction? 226 | je ms2 ; No, pillman stops 227 | 228 | ms1: mov [si-2],bl 229 | test bl,5 230 | mov ax,-X_OFFSET*SPEED 231 | jne ms3 232 | mov ax,1*SPEED 233 | ms3: 234 | test bl,12 235 | je ms7 236 | neg ax 237 | ms7: 238 | add di,ax 239 | mov [si-4],di 240 | ms2: 241 | ret 242 | 243 | bitmaps: 244 | db 0x00,0x42,0xe7,0xe7,0xff,0xff,0x7e,0x3c 245 | db 0x3c,0x7e,0xfc,0xf0,0xf0,0xfc,0x7e,0x3c 246 | db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; Maze 247 | db 0x3c,0x7e,0xff,0xff,0xe7,0xe7,0x42,0x00 248 | db 0x3c,0x7e,0xff,0xff,0xff,0xff,0x7e,0x3c 249 | db 0x3c,0x7e,0xdb,0xdb,0xff,0xff,0xff,0xa5 ; Ghost 250 | db 0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00 ; Pill 251 | db 0x3c,0x7e,0x3f,0x0f,0x0f,0x3f,0x7e,0x3c 252 | 253 | maze: 254 | dw 0x0000 255 | dw 0x7ffe 256 | dw 0x4202 257 | dw 0x4202 258 | dw 0x7fff 259 | dw 0x4240 260 | dw 0x7e7e 261 | dw 0x0202 262 | dw 0x027f 263 | dw 0x03c0 264 | dw 0x0240 265 | dw 0x027f 266 | dw 0x0240 267 | dw 0x7ffe 268 | dw 0x4202 269 | dw 0x7bff 270 | dw 0x0a40 271 | dw 0x7e7e 272 | dw 0x4002 273 | dw 0x7fff 274 | dw 0x0000 275 | 276 | setup_data: 277 | dw 0x80*X_OFFSET+0x98 278 | dw 0x0002 279 | dw 0x48*X_OFFSET+0x90-X_OFFSET*SPEED 280 | dw 0x0101 281 | dw 0x48*X_OFFSET+0x98-1*SPEED 282 | dw 0x0108 283 | dw 0x48*X_OFFSET+0xa0-X_OFFSET*SPEED 284 | dw 0x0101 285 | dw 0x48*X_OFFSET+0xa8+1*SPEED 286 | dw 0x0102 287 | 288 | ; 289 | ; Move ghost 290 | ; 291 | move_ghost: 292 | lodsw 293 | xchg ax,di 294 | lodsw 295 | cmp ah,0x01 296 | xchg ax,bx 297 | mov al,0x30 298 | push ax 299 | mov byte [si-1],0x02 300 | call move_sprite3 301 | pop ax 302 | ; ah = sprite color 303 | ; al = sprite (x8) 304 | ; di = Target address 305 | draw_sprite: 306 | push ax 307 | push bx 308 | push cx 309 | push di 310 | ds0: push ax 311 | mov bx,bitmaps-8 312 | cs xlat ; Extract one byte from bitmap 313 | xchg ax,bx 314 | mov cx,8 315 | ds1: mov al,bh 316 | shl bl,1 317 | jc ds2 318 | xor ax,ax 319 | ds2: 320 | cmp bh,0x10 321 | jc ds4 322 | cmp byte [di],PLAYER_COLOR 323 | jne ds3 324 | inc bp 325 | ds3: 326 | xor al,[di] 327 | ds4: 328 | stosb 329 | loop ds1 330 | add di,X_OFFSET-8 ; Go to next video line 331 | pop ax 332 | inc ax ; Next bitmap byte 333 | test al,7 ; Sprite complete? 334 | jne ds0 ; No, jump 335 | pop di 336 | pop cx 337 | pop bx 338 | pop ax 339 | ret 340 | 341 | %if com_file 342 | %else 343 | times 510-($-$$) db 0x4f 344 | db 0x55,0xaa ; Make it a bootable sector 345 | %endif 346 | -------------------------------------------------------------------------------- /old/pillman3.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; Pillman 3 | ; 4 | ; by Oscar Toledo G. 5 | ; 6 | ; Creation date: Jun/11/2019. 7 | ; Revision date: Jun/12/2019. Draws level. 8 | ; Revision date: Jun/13/2019. Pillman can move. 9 | ; Revision date: Jun/14/2019. Now ghosts don't get stuck. Ghost are 10 | ; transparent. Pillman doesn't leave 11 | ; trash. 12 | ; Revision date: Jun/15/2019. Ghosts can catch pillman. 517 bytes. 13 | ; 14 | 15 | %ifndef com_file ; If not defined create a boot sector 16 | com_file: equ 0 17 | %endif 18 | 19 | base: equ 0xfc80 ; Memory base (same segment as video) 20 | old_time: equ base+0x00 21 | x_player: equ base+0x04 22 | y_player: equ base+0x06 23 | frame: equ base+0x07 24 | intended_dir: equ base+0x08 25 | pos1: equ base+0x09 26 | 27 | X_OFFSET: equ 0x0140 28 | 29 | MAZE_COLOR: equ 0x37 ; No color should be higher or equal value 30 | PILL_COLOR: equ 0x02 31 | PLAYER_COLOR: equ 0x0e ; Should be unique 32 | 33 | ; 34 | ; XOR combination of these plus PILL_COLOR shouldn't 35 | ; result in PLAYER_COLOR 36 | ; 37 | GHOST1_COLOR: equ 0x21 38 | GHOST2_COLOR: equ 0x2e 39 | GHOST3_COLOR: equ 0x28 40 | GHOST4_COLOR: equ 0x34 41 | 42 | %if com_file 43 | org 0x0100 44 | %else 45 | org 0x7c00 46 | %endif 47 | restart: 48 | mov ax,0x0013 ; Set mode 0x13 (320x200x256 VGA) 49 | int 0x10 ; Call BIOS 50 | cld 51 | mov ax,0xa000 ; Video segment 52 | mov ds,ax ; Use as source data segment 53 | mov es,ax ; Use as target data segment 54 | mov si,maze 55 | mov di,8*X_OFFSET+32 56 | draw_maze_row: 57 | cs lodsw 58 | xchg ax,cx 59 | mov bx,30*8 60 | draw_maze_col: 61 | shl cx,1 62 | mov ax,MAZE_COLOR*0x0100+0x18 63 | jnc dm1 64 | mov ax,PILL_COLOR*0x0100+0x38 65 | dm1: call draw_sprite 66 | add di,bx 67 | sub bx,16 68 | jc dm2 69 | call draw_sprite 70 | sub di,bx 71 | sub di,8 72 | jmp draw_maze_col 73 | 74 | dm2: 75 | add di,X_OFFSET*8-15*8 76 | cmp si,setup_data 77 | jne draw_maze_row 78 | 79 | ; CX is zero at this point 80 | 81 | mov di,pos1 82 | mov cl,5 83 | mov ax,2 84 | dm3: 85 | cs movsw 86 | stosw 87 | loop dm3 88 | 89 | game_loop: 90 | mov ah,0x00 91 | int 0x1a ; BIOS clock read 92 | cmp dx,[old_time] ; Wait for change 93 | je game_loop 94 | mov [old_time],dx 95 | 96 | mov ah,0x01 ; BIOS Key available 97 | int 0x16 98 | je no_key 99 | mov ah,0x00 ; BIOS Read Key 100 | int 0x16 101 | mov al,ah 102 | sub al,0x48 103 | jc no_key 104 | cmp al,0x09 105 | jnc no_key 106 | mov bx,dirs 107 | cs xlat 108 | mov [intended_dir],al 109 | no_key: 110 | mov si,pos1 111 | lodsw 112 | xchg ax,di 113 | lodsw 114 | xchg ax,bx 115 | xor ax,ax ; Delete pillman 116 | call move_sprite2 ; Move 117 | xor byte [frame],0x80 118 | mov ax,0x0e28 ; Closed mouth 119 | js close_mouth 120 | mov al,[pos1+2] 121 | mov cl,3 122 | shl al,cl ; Open mouth 123 | close_mouth: 124 | call draw_sprite ; Draw 125 | xor bp,bp 126 | mov bh,GHOST1_COLOR 127 | call move_ghost 128 | mov bh,GHOST2_COLOR 129 | call move_ghost 130 | mov bh,GHOST3_COLOR 131 | call move_ghost 132 | mov bh,GHOST4_COLOR 133 | call move_ghost 134 | and bp,bp ; Pillman catched? 135 | je game_loop ; No, jump 136 | jmp restart ; Yes, restart 137 | 138 | ; 139 | ; DI = address on screen 140 | ; BL = wanted direction 141 | ; 142 | move_sprite3: 143 | je move_sprite 144 | move_sprite2: 145 | call draw_sprite ; Remove ghost 146 | move_sprite: 147 | mov ax,di 148 | xor dx,dx 149 | mov cx,X_OFFSET 150 | div cx 151 | mov ah,dl 152 | or ah,al 153 | and ah,7 154 | jne ms0 155 | ; AH is zero already 156 | ;mov ah,0 157 | mov ch,MAZE_COLOR 158 | cmp [di-0x0001],ch 159 | adc ah,ah 160 | cmp [di+X_OFFSET*8],ch 161 | adc ah,ah 162 | cmp [di+0x0008],ch 163 | adc ah,ah 164 | cmp [di-X_OFFSET],ch 165 | adc ah,ah 166 | 167 | test bh,bh ; Is it pillman? 168 | je ms4 169 | 170 | ; 171 | ; Ghost 172 | ; 173 | test bl,0x05 174 | je ms6 175 | ; Current direction is up/down 176 | cmp dx,[x_player] 177 | mov al,0x02 178 | jc ms8 179 | mov al,0x08 180 | jmp ms8 181 | 182 | ; Current direction is left/right 183 | ms6: cmp al,[y_player] 184 | mov al,0x04 185 | jc ms8 186 | mov al,0x01 187 | ms8: 188 | test ah,al ; Can it go in wanted direction? 189 | jne ms1 ; Yes, go in direction 190 | 191 | mov al,bl 192 | ms9: test ah,al ; Can it go in current direction? 193 | jne ms1 ; Yes, jump 194 | shr al,1 ; Try another direction 195 | jne ms9 196 | mov al,0x08 ; Cycle direction 197 | jmp ms9 198 | 199 | ; 200 | ; Pillman 201 | ; 202 | ms4: 203 | mov [x_player],dx ; Save current X coordinate 204 | mov [y_player],al ; Save current Y coordinate 205 | 206 | mov al,[intended_dir] 207 | test ah,al ; Can it go in intended direction? 208 | jne ms1 ; Yes, go in that direction 209 | 210 | ms5: and ah,bl ; Can it go in current direction? 211 | je ms2 ; No, stops 212 | 213 | ms0: mov al,bl 214 | 215 | ms1: mov [si-2],al 216 | test al,5 217 | mov bx,-X_OFFSET*2 218 | jne ms3 219 | mov bx,1*2 220 | ms3: 221 | test al,12 222 | je ms7 223 | neg bx 224 | ms7: 225 | add di,bx 226 | mov [si-4],di 227 | ms2: 228 | ret 229 | 230 | bitmaps: 231 | db 0x00,0x42,0xe7,0xe7,0xff,0xff,0x7e,0x3c ; dir = 1 232 | db 0x3c,0x7e,0xfc,0xf0,0xf0,0xfc,0x7e,0x3c ; dir = 2 233 | db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; Maze 234 | db 0x3c,0x7e,0xff,0xff,0xe7,0xe7,0x42,0x00 ; dir = 4 235 | db 0x3c,0x7e,0xff,0xff,0xff,0xff,0x7e,0x3c ; Closed mouth 236 | db 0x3c,0x7e,0xdb,0xdb,0xff,0xff,0xff,0xa5 ; Ghost 237 | db 0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00 ; Pill 238 | db 0x3c,0x7e,0x3f,0x0f,0x0f,0x3f,0x7e,0x3c ; dir = 8 239 | 240 | maze: 241 | dw 0x0000 242 | dw 0x7ffe 243 | dw 0x4202 244 | dw 0x4202 245 | dw 0x7fff 246 | dw 0x4240 247 | dw 0x7e7e 248 | dw 0x0202 249 | dw 0x027f 250 | dw 0x03c0 251 | dw 0x0240 252 | dw 0x027f 253 | dw 0x0240 254 | dw 0x7ffe 255 | dw 0x4202 256 | dw 0x7bff 257 | dw 0x0a40 258 | dw 0x7e7e 259 | dw 0x4002 260 | dw 0x7fff 261 | dw 0x0000 262 | 263 | setup_data: 264 | dw 0x80*X_OFFSET+0x98 265 | dw 0x38*X_OFFSET+0x90 266 | dw 0x48*X_OFFSET+0x98 267 | dw 0x28*X_OFFSET+0xa0 268 | dw 0x38*X_OFFSET+0xa8 269 | 270 | dirs: 271 | db 0x01,0x01,0x01,0x08,0x08,0x02,0x04,0x04,0x04 272 | 273 | ; 274 | ; Move ghost 275 | ; bh = color 276 | ; 277 | move_ghost: 278 | lodsw 279 | xchg ax,di 280 | lodsw 281 | test ah,ah 282 | xchg ax,bx ; Color now in ah 283 | mov al,0x30 284 | push ax 285 | mov byte [si-1],0x02 286 | call move_sprite3 287 | pop ax 288 | ; ah = sprite color 289 | ; al = sprite (x8) 290 | ; di = Target address 291 | draw_sprite: 292 | push ax 293 | push bx 294 | push cx 295 | push di 296 | ds0: push ax 297 | mov bx,bitmaps-8 298 | cs xlat ; Extract one byte from bitmap 299 | xchg ax,bx 300 | mov cx,8 301 | ds1: mov al,bh 302 | shl bl,1 303 | jc ds2 304 | xor ax,ax 305 | ds2: 306 | cmp bh,0x10 307 | jc ds4 308 | cmp byte [di],PLAYER_COLOR 309 | jne ds3 310 | inc bp 311 | ds3: 312 | xor al,[di] 313 | ds4: 314 | stosb 315 | loop ds1 316 | add di,X_OFFSET-8 ; Go to next video line 317 | pop ax 318 | inc ax ; Next bitmap byte 319 | test al,7 ; Sprite complete? 320 | jne ds0 ; No, jump 321 | pop di 322 | pop cx 323 | pop bx 324 | pop ax 325 | ret 326 | 327 | %if com_file 328 | %else 329 | times 510-($-$$) db 0x4f 330 | db 0x55,0xaa ; Make it a bootable sector 331 | %endif 332 | -------------------------------------------------------------------------------- /old/pillman4.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; Pillman 3 | ; 4 | ; by Oscar Toledo G. 5 | ; 6 | ; Creation date: Jun/11/2019. 7 | ; Revision date: Jun/12/2019. Draws level. 8 | ; Revision date: Jun/13/2019. Pillman can move. 9 | ; Revision date: Jun/14/2019. Now ghosts don't get stuck. Ghost are 10 | ; transparent. Pillman doesn't leave 11 | ; trash. 12 | ; Revision date: Jun/15/2019. Ghosts can catch pillman. Optimized. 13 | ; 509 bytes. 14 | ; 15 | 16 | %ifndef com_file ; If not defined create a boot sector 17 | com_file: equ 0 18 | %endif 19 | 20 | base: equ 0xf9fe ; Memory base (same segment as video) 21 | intended_dir: equ base+0x00 22 | frame: equ base+0x01 23 | x_player: equ base+0x02 24 | y_player: equ base+0x04 25 | old_time: equ base+0x06 26 | 27 | ; 28 | ; Maze should start at x,y coordinate multiple of 8 29 | ; 30 | BASE_MAZE: equ 16*X_OFFSET+32 31 | pos1: equ BASE_MAZE+21*8*X_OFFSET 32 | 33 | X_OFFSET: equ 0x0140 34 | 35 | MAZE_COLOR: equ 0x37 ; No color should be higher or equal value 36 | PILL_COLOR: equ 0x02 37 | PLAYER_COLOR: equ 0x0e ; Should be unique 38 | 39 | ; 40 | ; XOR combination of these plus PILL_COLOR shouldn't 41 | ; result in PLAYER_COLOR 42 | ; 43 | GHOST1_COLOR: equ 0x21 44 | GHOST2_COLOR: equ 0x2e 45 | GHOST3_COLOR: equ 0x28 46 | GHOST4_COLOR: equ 0x34 47 | 48 | %if com_file 49 | org 0x0100 50 | %else 51 | org 0x7c00 52 | %endif 53 | restart: 54 | mov ax,0x0013 ; Set mode 0x13 (320x200x256 VGA) 55 | int 0x10 ; Call BIOS 56 | cld 57 | mov ax,0xa000 ; Video segment 58 | mov ds,ax ; Use as source data segment 59 | mov es,ax ; Use as target data segment 60 | mov si,maze 61 | mov di,BASE_MAZE 62 | draw_maze_row: 63 | cs lodsw 64 | xchg ax,cx 65 | mov bx,30*8 66 | draw_maze_col: 67 | shl cx,1 68 | mov ax,MAZE_COLOR*0x0100+0x18 69 | jnc dm1 70 | mov ax,PILL_COLOR*0x0100+0x38 71 | dm1: call draw_sprite 72 | add di,bx 73 | sub bx,16 74 | jc dm2 75 | call draw_sprite 76 | sub di,bx 77 | sub di,8 78 | jmp draw_maze_col 79 | 80 | dm2: 81 | add di,X_OFFSET*8-15*8 82 | cmp si,setup_data 83 | jne draw_maze_row 84 | 85 | ; CX is zero at this point 86 | ; DI is equal to pos1 at this point 87 | ;mov di,pos1 88 | mov cl,5 89 | mov ax,2 ; Going to right 90 | dm3: 91 | cs movsw 92 | stosw 93 | loop dm3 94 | 95 | game_loop: 96 | mov ah,0x00 97 | int 0x1a ; BIOS clock read 98 | cmp dx,[old_time] ; Wait for change 99 | je game_loop 100 | mov [old_time],dx 101 | 102 | mov ah,0x01 ; BIOS Key available 103 | int 0x16 104 | mov ah,0x00 ; BIOS Read Key 105 | je no_key 106 | int 0x16 107 | no_key: 108 | mov al,ah 109 | sub al,0x48 110 | jc no_key2 111 | cmp al,0x09 112 | jnc no_key2 113 | mov bx,dirs 114 | cs xlat 115 | mov [intended_dir],al 116 | no_key2: 117 | mov si,pos1 118 | lodsw 119 | xchg ax,di 120 | lodsw 121 | xchg ax,bx 122 | xor ax,ax ; Delete pillman 123 | call move_sprite2 ; Move 124 | xor byte [frame],0x80 125 | mov ax,0x0e28 ; Closed mouth 126 | js close_mouth 127 | mov al,[pos1+2] 128 | mov cl,3 129 | shl al,cl ; Open mouth 130 | close_mouth: 131 | call draw_sprite ; Draw 132 | mov bh,GHOST1_COLOR 133 | call move_ghost 134 | mov bh,GHOST2_COLOR 135 | call move_ghost 136 | mov bh,GHOST3_COLOR 137 | call move_ghost 138 | mov bh,GHOST4_COLOR 139 | call move_ghost 140 | jmp game_loop 141 | 142 | ; 143 | ; DI = address on screen 144 | ; BL = wanted direction 145 | ; 146 | move_sprite3: 147 | je move_sprite 148 | move_sprite2: 149 | call draw_sprite ; Remove ghost 150 | move_sprite: 151 | mov ax,di 152 | xor dx,dx 153 | mov cx,X_OFFSET 154 | div cx 155 | mov ah,dl 156 | or ah,al 157 | and ah,7 158 | jne ms0 159 | ; AH is zero already 160 | ;mov ah,0 161 | mov ch,MAZE_COLOR 162 | cmp [di-0x0001],ch 163 | adc ah,ah 164 | cmp [di+X_OFFSET*8],ch 165 | adc ah,ah 166 | cmp [di+0x0008],ch 167 | adc ah,ah 168 | cmp [di-X_OFFSET],ch 169 | adc ah,ah 170 | 171 | test bh,bh ; Is it pillman? 172 | je ms4 173 | 174 | ; 175 | ; Ghost 176 | ; 177 | test bl,0x05 178 | je ms6 179 | ; Current direction is up/down 180 | cmp dx,[x_player] 181 | mov al,0x02 182 | jc ms8 183 | mov al,0x08 184 | jmp ms8 185 | 186 | ; Current direction is left/right 187 | ms6: cmp al,[y_player] 188 | mov al,0x04 189 | jc ms8 190 | mov al,0x01 191 | ms8: 192 | test ah,al ; Can it go in wanted direction? 193 | jne ms1 ; Yes, go in direction 194 | 195 | mov al,bl 196 | ms9: test ah,al ; Can it go in current direction? 197 | jne ms1 ; Yes, jump 198 | shr al,1 ; Try another direction 199 | jne ms9 200 | mov al,0x08 ; Cycle direction 201 | jmp ms9 202 | 203 | ; 204 | ; Pillman 205 | ; 206 | ms4: 207 | mov [x_player],dx ; Save current X coordinate 208 | mov [y_player],al ; Save current Y coordinate 209 | 210 | mov al,[intended_dir] 211 | test ah,al ; Can it go in intended direction? 212 | jne ms1 ; Yes, go in that direction 213 | 214 | ms5: and ah,bl ; Can it go in current direction? 215 | je ms2 ; No, stops 216 | 217 | ms0: mov al,bl 218 | 219 | ms1: mov [si-2],al 220 | test al,5 221 | mov bx,-X_OFFSET*2 222 | jne ms3 223 | mov bx,1*2 224 | ms3: 225 | test al,12 226 | je ms7 227 | neg bx 228 | ms7: 229 | add di,bx 230 | mov [si-4],di 231 | ms2: 232 | ret 233 | 234 | bitmaps: 235 | db 0x00,0x42,0xe7,0xe7,0xff,0xff,0x7e,0x3c ; dir = 1 236 | db 0x3c,0x7e,0xfc,0xf0,0xf0,0xfc,0x7e,0x3c ; dir = 2 237 | db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; Maze 238 | db 0x3c,0x7e,0xff,0xff,0xe7,0xe7,0x42,0x00 ; dir = 4 239 | db 0x3c,0x7e,0xff,0xff,0xff,0xff,0x7e,0x3c ; Closed mouth 240 | db 0x3c,0x7e,0xdb,0xdb,0xff,0xff,0xff,0xa5 ; Ghost 241 | db 0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00 ; Pill 242 | db 0x3c,0x7e,0x3f,0x0f,0x0f,0x3f,0x7e,0x3c ; dir = 8 243 | 244 | maze: 245 | dw 0b0000_0000_0000_0000 246 | dw 0b0111_1111_1111_1110 247 | dw 0b0100_0010_0000_0010 248 | dw 0b0100_0010_0000_0010 249 | dw 0b0111_1111_1111_1111 250 | dw 0b0100_0010_0100_0000 251 | dw 0b0111_1110_0111_1110 252 | dw 0b0000_0010_0000_0010 253 | dw 0b0000_0010_0111_1111 254 | dw 0b0000_0011_1100_0000 255 | dw 0b0000_0010_0100_0000 256 | dw 0b0000_0010_0111_1111 257 | dw 0b0000_0010_0100_0000 258 | dw 0b0111_1111_1111_1110 259 | dw 0b0100_0010_0000_0010 260 | dw 0b0111_1011_1111_1111 261 | dw 0b0000_1010_0100_0000 262 | dw 0b0111_1110_0111_1110 263 | dw 0b0100_0000_0000_0010 264 | dw 0b0111_1111_1111_1111 265 | dw 0b0000_0000_0000_0000 266 | 267 | setup_data: 268 | dw BASE_MAZE+0x78*X_OFFSET+0x78 269 | dw BASE_MAZE+0x30*X_OFFSET+0x70 270 | dw BASE_MAZE+0x40*X_OFFSET+0x78 271 | dw BASE_MAZE+0x20*X_OFFSET+0x80 272 | dw BASE_MAZE+0x30*X_OFFSET+0x88 273 | 274 | dirs: 275 | db 0x01,0x00,0x00,0x08,0x00,0x02,0x00,0x00,0x04 276 | 277 | ; 278 | ; Move ghost 279 | ; bh = color 280 | ; 281 | move_ghost: 282 | lodsw 283 | xchg ax,di 284 | lodsw 285 | test ah,ah 286 | xchg ax,bx ; Color now in ah 287 | mov al,0x30 288 | push ax 289 | mov byte [si-1],0x02 290 | call move_sprite3 291 | pop ax 292 | ; ah = sprite color 293 | ; al = sprite (x8) 294 | ; di = Target address 295 | draw_sprite: 296 | push ax 297 | push bx 298 | push cx 299 | push di 300 | ds0: push ax 301 | mov bx,bitmaps-8 302 | cs xlat ; Extract one byte from bitmap 303 | xchg ax,bx 304 | mov cx,8 305 | ds1: mov al,bh 306 | shl bl,1 307 | jc ds2 308 | xor ax,ax 309 | ds2: 310 | cmp bh,0x10 311 | jc ds4 312 | cmp byte [di],PLAYER_COLOR 313 | jne ds3 314 | jmp restart ; It should crash after several hundred games 315 | ds3: 316 | xor al,[di] 317 | ds4: 318 | stosb 319 | loop ds1 320 | add di,X_OFFSET-8 ; Go to next video line 321 | pop ax 322 | inc ax ; Next bitmap byte 323 | test al,7 ; Sprite complete? 324 | jne ds0 ; No, jump 325 | pop di 326 | pop cx 327 | pop bx 328 | pop ax 329 | ret 330 | 331 | %if com_file 332 | %else 333 | times 510-($-$$) db 0x4f 334 | db 0x55,0xaa ; Make it a bootable sector 335 | %endif 336 | -------------------------------------------------------------------------------- /pillman.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; Pillman 3 | ; 4 | ; by Oscar Toledo G. 5 | ; http://nanochess.org/ 6 | ; 7 | ; (c) Copyright 2019 Oscar Toledo G. 8 | ; 9 | ; Creation date: Jun/11/2019. 10 | ; Revision date: Jun/12/2019. Draws level. 11 | ; Revision date: Jun/13/2019. Pillman can move. 12 | ; Revision date: Jun/14/2019. Now ghosts don't get stuck. Ghost are 13 | ; transparent. Pillman doesn't leave 14 | ; trash. 15 | ; Revision date: Jun/15/2019. Ghosts can catch pillman. Optimized. 16 | ; 509 bytes. 17 | ; Revision date: Jul/09/2019. Self-modifying code, move subroutine, 18 | ; cache routine address (Peter Ferrie). 19 | ; 504 bytes. 20 | ; Revision date: Jul/22/2019. Added Esc key to exit. 21 | ; 22 | 23 | cpu 8086 24 | 25 | %ifndef com_file ; If not defined create a boot sector 26 | com_file: equ 0 27 | %endif 28 | 29 | base: equ 0xf9fe ; Memory base (same segment as video) 30 | intended_dir: equ base+0x00 ; Next direction for player 31 | frame: equ base+0x01 ; Current video frame 32 | x_player: equ base+0x02 ; Saved X-coordinate of player 33 | y_player: equ ms6+0x01 ; Saved Y-coordinate of player 34 | old_time: equ base+0x06 ; Old time 35 | 36 | ; 37 | ; Maze should start at x,y coordinate multiple of 8 38 | ; 39 | BASE_MAZE: equ 16*X_OFFSET+32 40 | pos1: equ BASE_MAZE+21*8*X_OFFSET 41 | 42 | X_OFFSET: equ 0x0140 43 | 44 | MAZE_COLOR: equ 0x37 ; No color should be higher or equal value 45 | PILL_COLOR: equ 0x02 ; Color for pill 46 | PLAYER_COLOR: equ 0x0e ; Should be unique 47 | 48 | ; 49 | ; XOR combination of these plus PILL_COLOR shouldn't 50 | ; result in PLAYER_COLOR 51 | ; 52 | GHOST1_COLOR: equ 0x21 ; Ghost 1 color 53 | GHOST2_COLOR: equ 0x2e ; Ghost 2 color 54 | GHOST3_COLOR: equ 0x28 ; Ghost 3 color 55 | GHOST4_COLOR: equ 0x34 ; Ghost 4 color 56 | 57 | %if com_file 58 | org 0x0100 ; Start address for COM file 59 | %else 60 | org 0x7c00 ; Start address for boot sector 61 | %endif 62 | restart: 63 | mov ax,0x0013 ; Set mode 0x13 (320x200x256 VGA) 64 | int 0x10 ; Call BIOS 65 | cld 66 | mov ax,0xa000 ; Video segment 67 | mov ds,ax ; Use as source data segment 68 | mov es,ax ; Use as target data segment 69 | ; 70 | ; Draw the maze 71 | ; 72 | mov si,maze ; SI = Address of maze data 73 | mov di,BASE_MAZE ; DI = Address for drawing maze 74 | draw_maze_row: 75 | cs lodsw ; Load one word of data from Code Segment 76 | xchg ax,cx ; Put into AX 77 | mov bx,30*8 ; Offset of mirror position 78 | draw_maze_col: 79 | shl cx,1 ; Extract one tile of maze 80 | mov ax,MAZE_COLOR*0x0100+0x18 ; Carry = 0 = Wall 81 | jnc dm1 ; If bit was zero, jump to dm1 82 | mov ax,PILL_COLOR*0x0100+0x38 ; Carry = 1 = Pill 83 | dm1: call draw_sprite ; Draw tile 84 | add di,bx ; Go to mirror position 85 | sub bx,16 ; Mirror finished? 86 | jc dm2 ; Yes, jump 87 | call draw_sprite ; Draw tile 88 | sub di,bx ; Restore position 89 | sub di,8 ; Advance tile 90 | jmp draw_maze_col ; Repeat until finished 91 | 92 | ; 93 | ; Move ghost 94 | ; bh = color 95 | ; 96 | move_ghost: 97 | lodsw ; Load screen position 98 | xchg ax,di 99 | lodsw ; Load direction 100 | test ah,ah 101 | xchg ax,bx ; Color now in ah 102 | mov al,0x30 103 | push ax 104 | mov byte [si-1],0x02 ; Remove first time setup flag 105 | call move_sprite3 106 | pop ax 107 | ; 108 | ; Draw the sprite/tile 109 | ; 110 | ; ah = sprite color 111 | ; al = sprite (x8) 112 | ; di = Target address 113 | draw_sprite: 114 | push ax 115 | push bx 116 | push cx 117 | push di 118 | ds0: push ax 119 | mov bx,bitmaps-8 120 | cs xlat ; Extract one byte from bitmap 121 | xchg ax,bx 122 | mov cx,8 123 | ds1: mov al,bh 124 | shl bl,1 ; Extract one bit 125 | jc ds2 126 | xor ax,ax ; Background color 127 | ds2: 128 | cmp bh,0x10 ; Color < 0x10 129 | jc ds4 ; Yes, jump 130 | cmp byte [di],PLAYER_COLOR ; "Eats" player? 131 | je restart ; Yes, it should crash after several hundred games 132 | ds3: 133 | xor al,[di] ; XOR ghost again pixel 134 | ds4: 135 | stosb 136 | loop ds1 137 | add di,X_OFFSET-8 ; Go to next video line 138 | pop ax 139 | inc ax ; Next bitmap byte 140 | test al,7 ; Sprite complete? 141 | jne ds0 ; No, jump 142 | pop di 143 | pop cx 144 | pop bx 145 | pop ax 146 | ret 147 | 148 | dm2: 149 | add di,X_OFFSET*8-15*8 ; Go to next row 150 | cmp si,setup_data ; Maze completed? 151 | jne draw_maze_row ; No, jump 152 | 153 | ; 154 | ; Setup characters 155 | ; 156 | ; CX is zero at this point 157 | ; DI is equal to pos1 at this point 158 | ;mov di,pos1 159 | mov cl,5 ; 5 elements (player + ghosts) 160 | mov ax,2 ; Going to right 161 | dm3: 162 | cs movsw ; Copy position from Code Segment 163 | stosw ; Store desired direction 164 | loop dm3 ; Loop 165 | 166 | ; 167 | ; Main game loop 168 | ; 169 | game_loop: 170 | mov ah,0x00 171 | int 0x1a ; BIOS clock read 172 | cmp dx,[old_time] ; Wait for time change 173 | je game_loop 174 | mov [old_time],dx ; Save new time 175 | 176 | mov ah,0x01 ; BIOS Key available 177 | int 0x16 178 | mov ah,0x00 ; BIOS Read Key 179 | je no_key 180 | int 0x16 181 | no_key: 182 | mov al,ah 183 | cmp al,0x01 ; Esc key 184 | jne no_esc 185 | int 0x20 186 | no_esc: 187 | sub al,0x48 ; Code for arrow up? 188 | jc no_key2 ; Out of range, jump. 189 | cmp al,0x09 ; Farther than arrow down? 190 | jnc no_key2 ; Out of range, jump. 191 | mov bx,dirs 192 | cs xlat ; Translate direction to internal code 193 | mov [intended_dir],al ; Save as desired direction 194 | no_key2: 195 | mov si,pos1 ; SI points to data for player 196 | lodsw ; Load screen position 197 | xchg ax,di 198 | lodsw ; Load direction/type 199 | xchg ax,bx 200 | xor ax,ax ; Delete pillman 201 | call move_sprite2 ; Move 202 | xor byte [frame],0x80 ; Alternate frame 203 | mov ax,0x0e28 ; Closed mouth 204 | js close_mouth ; Jump if sign set. 205 | mov al,[pos1+2] ; Using current direction 206 | mov cl,3 ; Multiply by 8 207 | shl al,cl ; Show open mouth 208 | close_mouth: 209 | call draw_sprite ; Draw 210 | ; 211 | ; Move ghosts 212 | ; 213 | mov bp, move_ghost 214 | mov bh,GHOST1_COLOR 215 | call bp 216 | mov bh,GHOST2_COLOR 217 | call bp 218 | mov bh,GHOST3_COLOR 219 | call bp 220 | mov bh,GHOST4_COLOR 221 | call bp 222 | jmp game_loop 223 | 224 | ; 225 | ; DI = address on the screen 226 | ; BL = wanted direction 227 | ; 228 | move_sprite3: 229 | je move_sprite ; If zero, won't remove first time 230 | move_sprite2: 231 | call draw_sprite ; Remove ghost 232 | move_sprite: 233 | mov ax,di ; Prepare to extract pixel row/column 234 | xor dx,dx 235 | mov cx,X_OFFSET 236 | div cx 237 | ; Now AX = Row, DX = Column 238 | mov ah,dl 239 | or ah,al 240 | and ah,7 ; Both aligned at 8 pixels? 241 | jne ms0 ; No, jump because cannot change direction. 242 | ; AH is zero already 243 | ;mov ah,0 244 | ; 245 | ; Get available directions 246 | ; 247 | mov ch,MAZE_COLOR 248 | cmp [di-0x0001],ch ; Left 249 | adc ah,ah ; AH = 0000 000L 250 | cmp [di+X_OFFSET*8],ch ; Down 251 | adc ah,ah ; AH = 0000 00LD 252 | cmp [di+0x0008],ch ; Right 253 | adc ah,ah ; AH = 0000 0LDR 254 | cmp [di-X_OFFSET],ch ; Up 255 | adc ah,ah ; AH = 0000 LDRU 256 | 257 | test bh,bh ; Is it pillman? 258 | je ms4 ; Yes, jump 259 | 260 | ; 261 | ; Ghost 262 | ; 263 | test bl,0x05 ; Test BL for .... .D.U 264 | je ms6 ; No, jump 265 | ; Current direction is up/down 266 | cmp dx,[x_player] ; Compare X coordinate with player 267 | mov al,0x02 ; Go right 268 | jc ms8 ; Jump if X ghost < X player 269 | mov al,0x08 ; Go left 270 | jmp ms8 271 | 272 | ; Current direction is left/right 273 | ms6: cmp al,0x00 ; (SMC) Compare Y coordinate with player 274 | mov al,0x04 ; Go down 275 | jc ms8 ; Jump if Y ghost < Y player 276 | mov al,0x01 ; Go up 277 | ms8: 278 | test ah,al ; Can it go in intended direction? 279 | jne ms1 ; Yes, go in direction 280 | 281 | mov al,bl 282 | ms9: test ah,al ; Can it go in current direction? 283 | jne ms1 ; Yes, jump 284 | shr al,1 ; Try another direction 285 | jne ms9 286 | mov al,0x08 ; Cycle direction 287 | jmp ms9 288 | 289 | ; 290 | ; Pillman 291 | ; 292 | ms4: 293 | mov [x_player],dx ; Save current X coordinate 294 | cs mov [y_player],al ; Save current Y coordinate 295 | 296 | mov al,[intended_dir] 297 | test ah,al ; Can it go in intended direction? 298 | jne ms1 ; Yes, go in that direction 299 | 300 | ms5: and ah,bl ; Can it go in current direction? 301 | je ms2 ; No, stops 302 | 303 | ms0: mov al,bl 304 | 305 | ms1: mov [si-2],al ; Save new direction 306 | test al,5 ; If going up/down... 307 | mov bx,-X_OFFSET*2 ; ...bx = vertical movement 308 | jne ms3 309 | mov bx,1*2 ; ...bx = horizontal movement 310 | ms3: 311 | test al,12 312 | je ms7 313 | neg bx ; Reverse direction 314 | ms7: 315 | add di,bx ; Do move 316 | mov [si-4],di ; Save the new screen position 317 | ms2: 318 | ret 319 | 320 | ; 321 | ; Game bitmaps 322 | ; 323 | bitmaps: 324 | db 0x00,0x42,0xe7,0xe7,0xff,0xff,0x7e,0x3c ; dir = 1 325 | db 0x3c,0x7e,0xfc,0xf0,0xf0,0xfc,0x7e,0x3c ; dir = 2 326 | db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; Maze 327 | db 0x3c,0x7e,0xff,0xff,0xe7,0xe7,0x42,0x00 ; dir = 4 328 | db 0x3c,0x7e,0xff,0xff,0xff,0xff,0x7e,0x3c ; Closed mouth 329 | db 0x3c,0x7e,0xdb,0xdb,0xff,0xff,0xff,0xa5 ; Ghost 330 | db 0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00 ; Pill 331 | db 0x3c,0x7e,0x3f,0x0f,0x0f,0x3f,0x7e,0x3c ; dir = 8 332 | 333 | ; 334 | ; Maze shape 335 | ; 336 | maze: 337 | dw 0b0000_0000_0000_0000 338 | dw 0b0111_1111_1111_1110 339 | dw 0b0100_0010_0000_0010 340 | dw 0b0100_0010_0000_0010 341 | dw 0b0111_1111_1111_1111 342 | dw 0b0100_0010_0100_0000 343 | dw 0b0111_1110_0111_1110 344 | dw 0b0000_0010_0000_0010 345 | dw 0b0000_0010_0111_1111 346 | dw 0b0000_0011_1100_0000 347 | dw 0b0000_0010_0100_0000 348 | dw 0b0000_0010_0111_1111 349 | dw 0b0000_0010_0100_0000 350 | dw 0b0111_1111_1111_1110 351 | dw 0b0100_0010_0000_0010 352 | dw 0b0111_1011_1111_1111 353 | dw 0b0000_1010_0100_0000 354 | dw 0b0111_1110_0111_1110 355 | dw 0b0100_0000_0000_0010 356 | dw 0b0111_1111_1111_1111 357 | dw 0b0000_0000_0000_0000 358 | 359 | ; 360 | ; Starting positions 361 | ; 362 | setup_data: 363 | dw BASE_MAZE+0x78*X_OFFSET+0x78 364 | dw BASE_MAZE+0x30*X_OFFSET+0x70 365 | dw BASE_MAZE+0x40*X_OFFSET+0x78 366 | dw BASE_MAZE+0x20*X_OFFSET+0x80 367 | dw BASE_MAZE+0x30*X_OFFSET+0x88 368 | 369 | ; 370 | ; Convert arrow codes to internal directions 371 | ; 372 | dirs: 373 | db 0x01 ; 0x48 = Up arrow 374 | db 0x00 375 | db 0x00 376 | db 0x08 ; 0x4b = Left arrow 377 | db 0x00 378 | db 0x02 ; 0x4d = Right arrow 379 | db 0x00 380 | db 0x00 381 | db 0x04 ; 0x50 = Down arrow 382 | 383 | %if com_file 384 | %else 385 | times 510-($-$$) db 0x4f 386 | db 0x55,0xaa ; Make it a bootable sector 387 | %endif 388 | -------------------------------------------------------------------------------- /pillman.com: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nanochess/Pillman/d3945524359134f7db890affe64742515b1d25bd/pillman.com -------------------------------------------------------------------------------- /pillman.img: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nanochess/Pillman/d3945524359134f7db890affe64742515b1d25bd/pillman.img -------------------------------------------------------------------------------- /pillman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nanochess/Pillman/d3945524359134f7db890affe64742515b1d25bd/pillman.png --------------------------------------------------------------------------------