wok-tiny annotate bootpillman/stuff/pillman.asm @ rev 183

linux: fix bundle.S
author Pascal Bellard <pascal.bellard@slitaz.org>
date Tue Sep 26 17:09:38 2023 +0000 (8 months ago)
parents bbb34fe4904d
children
rev   line source
pascal@180 1 ;
pascal@180 2 ; Pillman
pascal@180 3 ;
pascal@180 4 ; by Oscar Toledo G.
pascal@180 5 ; http://nanochess.org/
pascal@180 6 ;
pascal@180 7 ; (c) Copyright 2019 Oscar Toledo G.
pascal@180 8 ;
pascal@180 9 ; Creation date: Jun/11/2019.
pascal@180 10 ; Revision date: Jun/12/2019. Draws level.
pascal@180 11 ; Revision date: Jun/13/2019. Pillman can move.
pascal@180 12 ; Revision date: Jun/14/2019. Now ghosts don't get stuck. Ghost are
pascal@180 13 ; transparent. Pillman doesn't leave
pascal@180 14 ; trash.
pascal@180 15 ; Revision date: Jun/15/2019. Ghosts can catch pillman. Optimized.
pascal@180 16 ; 509 bytes.
pascal@180 17 ; Revision date: Jul/09/2019. Self-modifying code, move subroutine,
pascal@180 18 ; cache routine address (Peter Ferrie).
pascal@180 19 ; 504 bytes.
pascal@180 20 ; Revision date: Jul/22/2019. Added Esc key to exit.
pascal@180 21 ;
pascal@180 22 ; Revision date: Sep/11/2023. Remove screen garbage, setup stack,
pascal@180 23 ; position independant code, reset screen
pascal@180 24 ; at exit, slow down Pillman blink.
pascal@180 25 ;
pascal@180 26
pascal@180 27 cpu 8086
pascal@180 28
pascal@180 29 base: equ 0xfa00 ; Memory base (same segment as video)
pascal@180 30 pos1: equ base
pascal@180 31 intended_dir: equ pos1+20 ; Next direction for player
pascal@180 32
pascal@180 33 X_OFFSET: equ 0x0140
pascal@180 34
pascal@180 35 ;
pascal@180 36 ; Maze should start at x,y coordinate multiple of 8
pascal@180 37 ;
pascal@180 38 BASE_MAZE: equ 16*X_OFFSET+32
pascal@180 39
pascal@180 40 MAZE_COLOR: equ 0x37 ; No color should be higher or equal value
pascal@180 41 PILL_COLOR: equ 0x02 ; Color for pill
pascal@180 42 PLAYER_COLOR: equ 0x0e ; Should be unique
pascal@180 43
pascal@180 44 ;
pascal@180 45 ; XOR combination of these plus PILL_COLOR shouldn't
pascal@180 46 ; result in PLAYER_COLOR
pascal@180 47 ;
pascal@180 48 GHOST1_COLOR: equ 0x21 ; Ghost 1 color
pascal@180 49 GHOST2_COLOR: equ 0x2e ; Ghost 2 color
pascal@180 50 GHOST3_COLOR: equ 0x28 ; Ghost 3 color
pascal@180 51 GHOST4_COLOR: equ 0x34 ; Ghost 4 color
pascal@180 52
pascal@180 53 old_time:
pascal@183 54 sti
pascal@180 55 cld
pascal@183 56 frame:
pascal@180 57 push cs
pascal@180 58 pop ss
pascal@180 59 restart:
pascal@183 60 mov sp,0xa000 ; Video segment
pascal@183 61 mov ds,sp ; Use as source data segment
pascal@183 62 mov es,sp ; Use as target data segment
pascal@180 63
pascal@180 64 mov ax,0x0013 ; Set mode 0x13 (320x200x256 VGA)
pascal@180 65 int 0x10 ; Call BIOS
pascal@180 66
pascal@180 67 call get_tables
pascal@180 68 tables:
pascal@180 69 ;
pascal@180 70 ; Ghost colors
pascal@180 71 ;
pascal@180 72 ghost_colors:
pascal@180 73 db GHOST4_COLOR,GHOST3_COLOR,GHOST2_COLOR,GHOST1_COLOR
pascal@180 74
pascal@180 75 ;
pascal@180 76 ; Maze shape
pascal@180 77 ;
pascal@180 78 maze:
pascal@180 79 dw 0b0000_0000_0000_0000
pascal@180 80 dw 0b0111_1111_1111_1110
pascal@180 81 dw 0b0100_0010_0000_0010
pascal@180 82 dw 0b0100_0010_0000_0010
pascal@180 83 dw 0b0111_1111_1111_1111
pascal@180 84 dw 0b0100_0010_0100_0000
pascal@180 85 dw 0b0111_1110_0111_1110
pascal@180 86 dw 0b0000_0010_0000_0010
pascal@182 87 dw 0b0111_1110_0111_1111
pascal@182 88 dw 0b0100_0011_1100_0000
pascal@182 89 dw 0b0100_0010_0100_0000
pascal@182 90 dw 0b0111_1110_0111_1111
pascal@180 91 dw 0b0000_0010_0100_0000
pascal@180 92 dw 0b0111_1111_1111_1110
pascal@180 93 dw 0b0100_0010_0000_0010
pascal@180 94 dw 0b0111_1011_1111_1111
pascal@180 95 dw 0b0000_1010_0100_0000
pascal@180 96 dw 0b0111_1110_0111_1110
pascal@180 97 dw 0b0100_0000_0000_0010
pascal@180 98 dw 0b0111_1111_1111_1111
pascal@180 99 dw 0b0000_0000_0000_0000
pascal@180 100
pascal@180 101 ;
pascal@180 102 ; Starting positions
pascal@180 103 ;
pascal@180 104 setup_data:
pascal@180 105 dw BASE_MAZE+0x78*X_OFFSET+0x78
pascal@180 106 dw BASE_MAZE+0x30*X_OFFSET+0x70
pascal@180 107 dw BASE_MAZE+0x40*X_OFFSET+0x78
pascal@180 108 dw BASE_MAZE+0x20*X_OFFSET+0x80
pascal@180 109 dw BASE_MAZE+0x30*X_OFFSET+0x88
pascal@180 110
pascal@180 111 ;
pascal@180 112 ; Convert arrow codes to internal directions
pascal@180 113 ;
pascal@180 114 dirs:
pascal@180 115 db 0x01 ; 0x48 = Up arrow
pascal@180 116 go_restart:
pascal@180 117 jmp restart ; 0x49 = Page Up ; 0x4a = Keypad -
pascal@180 118 db 0x04 ; 0x4b = Left arrow
pascal@180 119 db 0x00 ; 0x4c = Keypad 5
pascal@180 120 db 0x08 ; 0x4d = Right arrow
pascal@180 121 x_player:
pascal@180 122 dw 0x00 ; 0x4e = Keypad + ; 0x4f = End
pascal@180 123 db 0x02 ; 0x50 = Down arrow
pascal@180 124
pascal@180 125 ;
pascal@180 126 ; Game bitmaps
pascal@180 127 ;
pascal@180 128 bitmaps:
pascal@180 129 db 0x00,0x42,0xe7,0xe7,0xff,0xff,0x7e,0x3c ; dir = 1
pascal@180 130 db 0x3c,0x7e,0xff,0xff,0xe7,0xe7,0x42,0x00 ; dir = 2
pascal@180 131 db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; Maze
pascal@180 132 db 0x3c,0x7e,0x3f,0x0f,0x0f,0x3f,0x7e,0x3c ; dir = 4
pascal@180 133 db 0x3c,0x7e,0xff,0xff,0xff,0xff,0x7e,0x3c ; Closed mouth
pascal@180 134 db 0x3c,0x7e,0xdb,0xdb,0xff,0xff,0xff,0xa5 ; Ghost
pascal@180 135 db 0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00 ; Pill
pascal@180 136 db 0x3c,0x7e,0xfc,0xf0,0xf0,0xfc,0x7e,0x3c ; dir = 8
pascal@180 137
pascal@180 138 ;
pascal@180 139 ; Move ghost
pascal@180 140 ; bh = color
pascal@180 141 ;
pascal@180 142 move_ghost:
pascal@180 143 lodsw ; Load screen position
pascal@180 144 xchg ax,di
pascal@180 145 lodsw ; Load direction
pascal@180 146 test ah,ah
pascal@180 147 xchg ax,bx ; Color now in ah
pascal@180 148 mov al,0x30
pascal@180 149 push ax
pascal@180 150 mov byte [si-1],0x02 ; Remove first time setup flag
pascal@180 151 call move_sprite3
pascal@180 152 pop ax
pascal@180 153 ;
pascal@180 154 ; Draw the sprite/tile
pascal@180 155 ;
pascal@180 156 ; ah = sprite color
pascal@180 157 ; al = sprite (x8)
pascal@180 158 ; di = Target address
pascal@180 159 draw_sprite:
pascal@180 160 push ax
pascal@180 161 push bx
pascal@180 162 push cx
pascal@180 163 push di
pascal@180 164 ds0: push ax
pascal@180 165 lea bx,[bp+bitmaps_-8]
pascal@180 166 cs xlat ; Extract one byte from bitmap
pascal@180 167 xchg ax,bx
pascal@180 168 mov cx,8
pascal@180 169 ds1: mov al,bh
pascal@180 170 shl bl,1 ; Extract one bit
pascal@180 171 jc ds2
pascal@180 172 xor ax,ax ; Background color
pascal@180 173 ds2: cmp bh,0x10 ; Color < 0x10
pascal@180 174 jc ds3 ; Yes, jump
pascal@180 175 cmp byte [di],PLAYER_COLOR ; "Eats" player?
pascal@180 176 je go_restart ; No, it should not crash after several hundred games
pascal@180 177 xor al,[di] ; XOR ghost again pixel
pascal@180 178 ds3: stosb
pascal@180 179 loop ds1
pascal@180 180 add di,X_OFFSET-8 ; Go to next video line
pascal@180 181 pop ax
pascal@180 182 inc ax ; Next bitmap byte
pascal@180 183 test al,7 ; Sprite complete?
pascal@180 184 jne ds0 ; No, jump
pascal@180 185 pop di
pascal@180 186 pop cx
pascal@180 187 pop bx
pascal@180 188 pop ax
pascal@180 189 ret
pascal@180 190
pascal@180 191 get_tables:
pascal@180 192 pop bp ; SS:BP = tables
pascal@180 193
pascal@180 194 ghost_colors_ equ 0
pascal@180 195 bitmaps_ equ bitmaps-ghost_colors ; Game bitmaps
pascal@180 196 maze_ equ maze-ghost_colors ; Maze shape
pascal@180 197 setup_data_ equ setup_data-ghost_colors ; Starting positions
pascal@180 198 dirs_ equ dirs-ghost_colors ; Convert arrow codes to internal directions
pascal@180 199 frame_ equ frame-ghost_colors ; Current video frame
pascal@180 200 x_player_ equ x_player-ghost_colors ; Saved X-coordinate of player
pascal@180 201 y_player_ equ y_player_loc-ghost_colors ; Saved Y-coordinate of player
pascal@180 202 old_time_ equ old_time-ghost_colors ; Old time
pascal@180 203 ;
pascal@180 204 ; Draw the maze
pascal@180 205 ;
pascal@180 206 lea si,[bp+maze_] ; SI = Address of maze data
pascal@180 207 mov di,BASE_MAZE ; DI = Address for drawing maze
pascal@180 208 draw_maze_row:
pascal@180 209 cs lodsw ; Load one word of data from Code Segment
pascal@180 210 xchg ax,cx ; Put into AX
pascal@180 211 mov bx,30*8 ; Offset of mirror position
pascal@180 212 draw_maze_col:
pascal@180 213 shl cx,1 ; Extract one tile of maze
pascal@180 214 mov ax,MAZE_COLOR*0x0100+0x18 ; Carry = 0 = Wall
pascal@180 215 jnc dm1 ; If bit was zero, jump to dm1
pascal@180 216 mov ax,PILL_COLOR*0x0100+0x38 ; Carry = 1 = Pill
pascal@180 217 dm1: call draw_sprite ; Draw tile
pascal@180 218 add di,bx ; Go to mirror position
pascal@180 219 sub bx,16 ; Mirror finished?
pascal@180 220 jc dm2 ; Yes, jump
pascal@180 221 call draw_sprite ; Draw tile
pascal@180 222 sub di,bx ; Restore position
pascal@180 223 sub di,8 ; Advance tile
pascal@180 224 jmp draw_maze_col ; Repeat until finished
pascal@180 225
pascal@180 226 dm2:
pascal@180 227 add di,X_OFFSET*8-15*8 ; Go to next row
pascal@180 228 lea ax,[bp+setup_data_]
pascal@180 229 sub ax,si ; Maze completed?
pascal@180 230 jne draw_maze_row ; No, jump
pascal@180 231
pascal@180 232 ;
pascal@180 233 ; Setup characters
pascal@180 234 ;
pascal@180 235 ; CX is zero at this point
pascal@180 236 ; DI is equal to pos1 at this point
pascal@180 237 %if pos1 != BASE_MAZE+21*8*X_OFFSET
pascal@180 238 mov di,pos1
pascal@180 239 %endif
pascal@180 240 mov cl,5 ; 5 elements (player + ghosts)
pascal@180 241 mov al,8 ; Going to right
pascal@180 242 dm3:
pascal@180 243 cs movsw ; Copy position from Code Segment
pascal@180 244 stosw ; Store desired direction
pascal@180 245 loop dm3 ; Loop
pascal@180 246
pascal@180 247 ;
pascal@180 248 ; Main game loop
pascal@180 249 ;
pascal@180 250 game_loop:
pascal@182 251 hlt ; Wait for clock interrupt
pascal@180 252 mov ah,0x00
pascal@180 253 int 0x1a ; BIOS clock read
pascal@180 254 cmp dx,[bp+old_time_] ; Wait for time change
pascal@180 255 je game_loop
pascal@180 256 mov [bp+old_time_],dx ; Save new time
pascal@180 257
pascal@180 258 mov ah,0x01 ; BIOS Key available
pascal@180 259 int 0x16
pascal@180 260 cbw ; BIOS Read Key
pascal@180 261 je no_key
pascal@180 262 int 0x16
pascal@182 263 dec ah
pascal@180 264 mov al,ah
pascal@180 265 jne no_esc
pascal@182 266 mov al,0x03 ; Restore text mode
pascal@180 267 int 0x10
pascal@180 268 int 0x20
pascal@182 269 int 0x19
pascal@180 270 no_esc:
pascal@182 271 sub al,0x48-1 ; Code for arrow up?
pascal@182 272 jc no_key ; Out of range, jump.
pascal@180 273 cmp al,0x09 ; Farther than arrow down?
pascal@182 274 jnc no_key ; Out of range, jump.
pascal@180 275 lea bx,[bp+dirs_]
pascal@180 276 cs xlat ; Translate direction to internal code
pascal@180 277 mov [intended_dir],al ; Save as desired direction
pascal@182 278 no_key:
pascal@180 279 mov si,pos1 ; SI points to data for player
pascal@180 280 lodsw ; Load screen position
pascal@180 281 xchg ax,di
pascal@180 282 lodsw ; Load direction/type
pascal@180 283 xchg ax,bx
pascal@180 284 xor ax,ax ; Delete pillman
pascal@180 285 call move_sprite2 ; Move
pascal@180 286 mov ax,0x0e28 ; Closed mouth
pascal@180 287 add byte [bp+frame_],al ; Alternate frame
pascal@180 288 js close_mouth ; Jump if sign set.
pascal@180 289 mov al,[pos1+2] ; Using current direction
pascal@180 290 mov cl,3 ; Multiply by 8
pascal@180 291 shl al,cl ; Show open mouth
pascal@180 292 close_mouth:
pascal@180 293 call draw_sprite ; Draw
pascal@180 294 ;
pascal@180 295 ; Move ghosts
pascal@180 296 ;
pascal@180 297 mov di,3 ; ghost_colors+3
pascal@180 298 close_mouth_lp:
pascal@180 299 mov bh,[bp+di]
pascal@180 300 push di
pascal@180 301 call move_ghost
pascal@180 302 pop di
pascal@180 303 dec di
pascal@180 304 jns close_mouth_lp
pascal@180 305 jmp game_loop
pascal@180 306
pascal@180 307 ;
pascal@180 308 ; DI = address on the screen
pascal@180 309 ; BL = wanted direction
pascal@180 310 ;
pascal@180 311 move_sprite3:
pascal@180 312 je move_sprite ; If zero, won't remove first time
pascal@180 313 move_sprite2:
pascal@180 314 call draw_sprite ; Remove ghost
pascal@180 315 move_sprite:
pascal@180 316 cwd ; ah = GHOST[1234]_COLOR
pascal@180 317 ; xor dx,dx
pascal@180 318 mov ax,di ; Prepare to extract pixel row/column
pascal@180 319 mov cx,X_OFFSET
pascal@180 320 div cx
pascal@180 321 ; Now AX = Row, DX = Column
pascal@180 322 mov ah,dl
pascal@180 323 or ah,al
pascal@180 324 and ah,7 ; Both aligned at 8 pixels?
pascal@180 325 jne ms0 ; No, jump because cannot change direction.
pascal@180 326 ; AH is zero already
pascal@180 327 ;mov ah,0
pascal@180 328 ;
pascal@180 329 ; Get available directions
pascal@180 330 ;
pascal@180 331 mov ch,MAZE_COLOR
pascal@180 332 cmp [di+0x0008],ch ; Right
pascal@180 333 adc ah,ah ; AH = 0000 000R
pascal@180 334 cmp [di-0x0001],ch ; Left
pascal@180 335 adc ah,ah ; AH = 0000 00RL
pascal@180 336 cmp [di+X_OFFSET*8],ch ; Down
pascal@180 337 adc ah,ah ; AH = 0000 0RLD
pascal@180 338 cmp [di-X_OFFSET],ch ; Up
pascal@180 339 adc ah,ah ; AH = 0000 RLDU
pascal@180 340
pascal@180 341 test bh,bh ; Is it pillman?
pascal@180 342 je ms4 ; Yes, jump
pascal@180 343
pascal@180 344 ;
pascal@180 345 ; Ghost
pascal@180 346 ;
pascal@180 347 test bl,0x03 ; Test BL for .... ..DU
pascal@180 348 je ms6 ; No, jump
pascal@180 349 ; Current direction is up/down
pascal@180 350 cmp dx,[bp+x_player_] ; Compare X coordinate with player
pascal@180 351 mov al,0x88 ; Go right if X ghost < X player
pascal@180 352 jmp ms10
pascal@180 353
pascal@180 354 ; Current direction is left/right
pascal@180 355 ms6: cmp al,0x00 ; (SMC) Compare Y coordinate with player
pascal@180 356 y_player_loc equ $-1
pascal@180 357 mov al,0x22 ; Go down
pascal@180 358 ms10:
pascal@180 359 jc ms8 ; Jump if Y ghost < Y player
pascal@180 360 shr al,1 ; Go up or right
pascal@180 361 ms8:
pascal@180 362 test ah,al ; Can it go in intended direction?
pascal@180 363 jne ms1 ; Yes, go in direction
pascal@180 364
pascal@180 365 mov al,bl
pascal@180 366 ms9: test ah,al ; Can it go in current direction?
pascal@180 367 jne ms1 ; Yes, jump
pascal@180 368 ror al,1 ; Try another direction
pascal@180 369 jmp ms9
pascal@180 370
pascal@180 371 ;
pascal@180 372 ; Pillman
pascal@180 373 ;
pascal@180 374 ms4:
pascal@180 375 mov [bp+x_player_],dx ; Save current X coordinate
pascal@180 376 mov [bp+y_player_],al ; Save current Y coordinate
pascal@180 377
pascal@180 378 mov al,[intended_dir]
pascal@180 379 test ah,al ; Can it go in intended direction?
pascal@180 380 jne ms1 ; Yes, go in that direction
pascal@180 381
pascal@180 382 ms5: and ah,bl ; Can it go in current direction?
pascal@180 383 je ms2 ; No, stops
pascal@180 384
pascal@180 385 ms0: mov al,bl
pascal@180 386
pascal@180 387 ms1: mov [si-2],al ; Save new direction
pascal@180 388 test al,3 ; If going up/down...
pascal@180 389 mov bx,-X_OFFSET*2 ; ...bx = vertical movement
pascal@180 390 jne ms3
pascal@180 391 mov bx,1*2 ; ...bx = horizontal movement
pascal@180 392 ms3:
pascal@180 393 test al,6 ; If going left/down...
pascal@180 394 je ms7
pascal@180 395 neg bx ; ...reverse direction
pascal@180 396 ms7:
pascal@180 397 add di,bx ; Do move
pascal@180 398 mov [si-4],di ; Save the new screen position
pascal@180 399 ms2:
pascal@180 400 ret
pascal@180 401
pascal@180 402 times 510-($-$$) db 0x4f
pascal@180 403 db 0x55,0xaa ; Make it a bootable sector