wok-tiny annotate bootsokoban/stuff/sokoban.asm @ rev 182

Update bootpillman & bootsokoban
author Pascal Bellard <pascal.bellard@slitaz.org>
date Sun Sep 24 17:53:05 2023 +0000 (8 months ago)
parents e05af9592e8b
children 1e55ea7da8de
rev   line source
pascal@180 1 bits 16 ; tell NASM this is 16 bit code
pascal@180 2 cpu 8086
pascal@180 3
pascal@180 4 %define CURRENT_LEVEL 0x7E00
pascal@180 5 %define CURRENT_LEVEL_4 0x7E04
pascal@180 6 %define SCREEN_DS 0xb800
pascal@180 7
pascal@182 8 %define MOVE_COUNT
pascal@182 9
pascal@180 10 boot:
pascal@180 11 ; clear screen (re-set text mode)
pascal@182 12 mov ax, 0x0001 ; text mode 40x25 16 colours
pascal@182 13 %define COLS 40
pascal@182 14 %define LINES 25
pascal@180 15 int 0x10
pascal@180 16
pascal@180 17 ; disable cursor
pascal@180 18 mov ah, 0x01
pascal@180 19 mov ch, 0x3f
pascal@180 20 int 0x10
pascal@180 21
pascal@180 22 ; set up stack
pascal@180 23 push cs
pascal@180 24 pop ss
pascal@180 25 xor sp, sp
pascal@180 26
pascal@180 27 push cs
pascal@180 28 pop ds
pascal@180 29 push cs
pascal@180 30 pop es
pascal@180 31
pascal@180 32 call get_data
pascal@180 33
pascal@180 34 ; data section:
pascal@180 35
pascal@180 36 ; 0000 0000 EMPTY
pascal@180 37 ; 0000 0001 SPOT
pascal@180 38 ; 0000 0010 BRICK
pascal@180 39 ; 0000 0011 BRICK ON SPOT
pascal@180 40 ; 0000 0100 WALL
pascal@180 41 ; 0000 1000 PLAYER
pascal@180 42 ; 0000 1001 PLAYER ON SPOT
pascal@180 43 test_level:
pascal@180 44
pascal@182 45 %define p(a,b,c) ((c&7)+((b&7)*6)+((a&7)*6*6))
pascal@182 46 %if 1
pascal@182 47 db 15, 14 ;width, height
pascal@182 48 dw 15*7+13 ;playerxy
pascal@182 49 %define PLAYER 9
pascal@182 50 db p(4,4,4), p(4,5,5), p(5,5,5), p(4,4,4), p(4,5,5)
pascal@182 51 db p(4,0,0), p(4,4,4), p(4,4,4), p(4,1,1), p(4,4,4)
pascal@182 52 db p(4,0,2), p(0,2,0), p(2,0,0), p(4,1,1), p(1,1,4)
pascal@182 53 db p(4,0,2), p(0,0,0), p(2,2,0), p(4,3,3), p(3,1,4)
pascal@182 54 db p(4,0,2), p(0,2,0), p(2,0,0), p(4,1,1), p(3,1,4)
pascal@182 55 db p(4,0,0), p(2,0,2), p(0,2,0), p(4,3,1), p(3,1,4)
pascal@182 56 db p(4,4,0), p(2,0,2), p(0,2,0), p(1,3,1), p(3,1,4)
pascal@182 57 db p(4,0,0), p(2,0,2), p(0,2,0), p(1,3,1), p(3,PLAYER,4)
pascal@182 58 db p(4,0,0), p(2,0,2), p(0,2,0), p(4,3,1), p(3,1,4)
pascal@182 59 db p(4,0,2), p(0,2,0), p(2,0,0), p(4,1,1), p(3,1,4)
pascal@182 60 db p(4,0,2), p(0,0,0), p(2,2,0), p(4,3,3), p(3,1,4)
pascal@182 61 db p(4,0,2), p(0,2,0), p(2,0,0), p(4,1,1), p(1,1,4)
pascal@182 62 db p(4,0,0), p(4,4,4), p(4,4,4), p(4,1,1), p(4,4,4)
pascal@182 63 db p(4,4,4), p(4,5,5), p(5,5,5), p(4,4,4), p(4,5,5)
pascal@182 64 %else
pascal@182 65 db 21, 18 ;width, height
pascal@182 66 dw 21+8 ;playerxy
pascal@182 67 %define PLAYER 8
pascal@182 68 db p(5,5,5), p(5,5,5), p(5,4,4), p(4,5,5), p(5,5,5), p(5,5,5), p(5,5,5)
pascal@182 69 db p(5,5,4), p(4,4,4), p(4,0,8), p(0,4,4), p(4,4,4), p(4,4,5), p(5,5,5)
pascal@182 70 db p(5,5,4), p(0,0,0), p(4,0,2), p(0,4,0), p(0,0,0), p(0,4,4), p(5,5,5)
pascal@182 71 db p(5,4,4), p(0,2,0), p(4,4,0), p(0,4,2), p(0,0,0), p(0,0,4), p(4,5,5)
pascal@182 72 db p(5,4,0), p(2,0,2), p(0,4,0), p(0,4,0), p(2,4,4), p(0,2,0), p(4,5,5)
pascal@182 73 db p(4,4,0), p(3,1,1), p(0,4,4), p(0,4,2), p(0,4,4), p(2,0,0), p(4,5,5)
pascal@182 74 db p(4,0,2), p(1,1,3), p(0,0,4), p(0,4,0), p(2,0,0), p(0,0,4), p(4,5,5)
pascal@182 75 db p(4,0,3), p(2,4,2), p(3,0,4), p(2,0,0), p(0,2,0), p(0,4,4), p(5,5,5)
pascal@182 76 db p(4,1,1), p(0,4,0), p(1,1,4), p(0,0,4), p(4,4,2), p(4,4,5), p(5,5,5)
pascal@182 77 db p(4,0,4), p(4,4,4), p(4,0,4), p(0,2,0), p(0,2,0), p(0,4,4), p(5,5,5)
pascal@182 78 db p(4,0,2), p(0,4,0), p(2,0,0), p(2,0,2), p(0,2,0), p(2,0,4), p(4,5,5)
pascal@182 79 db p(4,0,1), p(1,4,1), p(1,0,2), p(0,4,0), p(0,0,2), p(0,2,0), p(4,5,5)
pascal@182 80 db p(4,0,1), p(1,2,1), p(1,0,4), p(0,4,0), p(2,4,4), p(0,0,0), p(4,5,5)
pascal@182 81 db p(4,0,1), p(1,1,1), p(1,2,4), p(0,4,0), p(0,0,0), p(0,2,0), p(4,5,5)
pascal@182 82 db p(4,0,1), p(1,1,1), p(1,0,4), p(0,4,2), p(2,2,0), p(2,0,4), p(4,5,5)
pascal@182 83 db p(4,0,1), p(1,1,1), p(1,2,4), p(0,4,0), p(0,0,0), p(0,4,4), p(5,5,5)
pascal@182 84 db p(4,0,1), p(1,1,1), p(1,0,4), p(0,4,4), p(4,4,4), p(4,4,5), p(5,5,5)
pascal@182 85 db p(5,4,4), p(4,4,4), p(4,4,5), p(4,5,5), p(5,5,5), p(5,5,5), p(5,5,5)
pascal@182 86 %endif
pascal@180 87
pascal@180 88
pascal@182 89 display_chars: db 0, 0x07 ; blank
pascal@182 90 db 249, 0x07 ; spot
pascal@182 91 db 0xFE, 0x0A ; brick
pascal@182 92 db 0xFE, 0x0C ; brick on spot
pascal@182 93 db 176, 0x71 ; wall
pascal@182 94 db 0, 0x07 ; out blank
pascal@182 95 db "6", 0x07 ; (no 6)
pascal@182 96 db "7", 0x07 ; (no 7)
pascal@182 97 db 1, 0x0F ; player
pascal@182 98 db 1, 0x0F ; player on spot
pascal@180 99
pascal@180 100 str_you_win: db 'YOU WIN! ',1,1,1,0
pascal@180 101
pascal@180 102 get_data:
pascal@180 103 pop bp
pascal@180 104
pascal@180 105 ; set current level to test level by copying
pascal@180 106 mov si, bp
pascal@180 107
pascal@180 108 ; get width and height and multiply by each other
pascal@182 109 lodsw
pascal@182 110
pascal@182 111 mov di, CURRENT_LEVEL ; next address to copy to
pascal@182 112
pascal@182 113 ; copy map size and player position ("uncompressed")
pascal@182 114 stosw
pascal@180 115 mul ah
pascal@180 116
pascal@180 117 ; set multiplied width and height + 4 as counter
pascal@180 118 mov cx, ax
pascal@180 119 ;add cx, 4
pascal@180 120
pascal@182 121 lodsw
pascal@182 122 stosw
pascal@180 123
pascal@182 124 xchg ax,bx
pascal@182 125 add bx,di ;save player location
pascal@182 126 mov dx,36*256+6
pascal@180 127
pascal@180 128 .copy_level_loop:
pascal@182 129 ; load one "compressed" byte and store 3 "uncompressed" bytes
pascal@182 130 lodsb
pascal@182 131 mov ah,0
pascal@182 132 div dh
pascal@182 133 stosb ; p/6/6
pascal@182 134 mov al,ah
pascal@182 135 cbw
pascal@182 136 div dl
pascal@182 137 stosw ; p/6%6 p%6
pascal@180 138
pascal@180 139 loop .copy_level_loop
pascal@182 140 mov byte [bx],PLAYER
pascal@180 141
pascal@180 142 call draw_current_level
pascal@180 143
pascal@180 144 .mainloop:
pascal@180 145 ; read key
pascal@180 146 xor ax, ax
pascal@180 147 int 0x16
pascal@180 148
pascal@180 149 mov al, byte [CURRENT_LEVEL] ; (width of current level) to the right = 1 down
pascal@180 150 dec ah ; esc
pascal@180 151 jne .not_boot
pascal@180 152 .exit:
pascal@182 153 mov al, 0x03 ; text mode 80x25 16 colours
pascal@180 154 int 0x10
pascal@180 155 int 0x20
pascal@182 156 int 0x19
pascal@180 157
pascal@180 158 .not_boot:
pascal@180 159 cmp ah, 0x50-1 ; down arrow
pascal@180 160 je .try_move_down
pascal@180 161
pascal@180 162 cmp ah, 0x48-1 ; up arrow
pascal@180 163 je .try_move_up
pascal@180 164
pascal@180 165 mov al, 1
pascal@180 166 cmp ah, 0x4d-1 ; right arrow
pascal@180 167 je .try_move_right
pascal@180 168
pascal@180 169 cmp ah, 0x4b-1 ; left arrow
pascal@180 170 jne .redraw
pascal@180 171
pascal@180 172 .try_move_left:
pascal@180 173 .try_move_up:
pascal@180 174 neg al
pascal@180 175 .try_move_right:
pascal@180 176 .try_move_down:
pascal@182 177 %ifdef MOVE_COUNT
pascal@180 178 push ax
pascal@180 179 push ds
pascal@180 180 mov bx, SCREEN_DS
pascal@180 181 mov ds, bx
pascal@182 182 mov bx, COLS + 2 + (LINES-1)*COLS*2
pascal@180 183
pascal@180 184 .chk_score:
pascal@180 185 dec bx
pascal@180 186 dec bx
pascal@180 187 mov al, '0'
pascal@180 188 xchg [bx], al
pascal@180 189 or al, 0x30
pascal@180 190 cmp al, '9'
pascal@180 191 je .chk_score
pascal@180 192 inc ax
pascal@180 193 mov [bx], al
pascal@180 194 pop ds
pascal@180 195 pop ax
pascal@180 196 %endif
pascal@180 197 call try_move
pascal@180 198
pascal@180 199 .redraw:
pascal@180 200 call draw_current_level
pascal@180 201
pascal@180 202 .check_win:
pascal@180 203
pascal@180 204 ; get width and height
pascal@180 205 mov ax, [CURRENT_LEVEL] ; al = width; ah = height
pascal@180 206 mul ah
pascal@180 207 mov cx, ax ; cx = size of map
pascal@180 208
pascal@180 209 xor bx, bx ; bx = number of bricks-NOT-on-a-spot
pascal@180 210
pascal@180 211 mov si, CURRENT_LEVEL_4
pascal@180 212 .check_win_loop:
pascal@180 213 lodsb
pascal@180 214 cmp al, 2
pascal@180 215 jne .not_a_brick
pascal@180 216 inc bx
pascal@180 217 .not_a_brick:
pascal@180 218 loop .check_win_loop
pascal@180 219
pascal@180 220 ; so, did we win? is the number of spotless bricks == 0??
pascal@180 221 cmp bx, 0
pascal@180 222 je win
pascal@180 223 jmp .mainloop
pascal@180 224
pascal@180 225
pascal@180 226 win:
pascal@180 227 ; print a nice win message to the middle of the screen
pascal@180 228 lea si, [bp+str_you_win-test_level]
pascal@180 229
pascal@180 230 ; destination position on screen
pascal@180 231 mov ax, SCREEN_DS
pascal@180 232 mov es, ax
pascal@182 233 mov di, (COLS * 12 + COLS/2 - 6) * 2
pascal@180 234
pascal@180 235 mov ah, 0x0F
pascal@180 236 .loop:
pascal@180 237 cs lodsb
pascal@180 238
pascal@180 239 cmp al, 0
pascal@180 240 je wait_for_esc
pascal@180 241
pascal@180 242 stosw
pascal@180 243 jmp .loop
pascal@180 244
pascal@180 245 wait_for_esc:
pascal@180 246 ; read key
pascal@180 247 xor ax, ax
pascal@180 248 int 0x16
pascal@180 249
pascal@180 250 dec ah ; esc
pascal@180 251 je get_data.exit
pascal@182 252 jmp boot
pascal@180 253 ; halt:
pascal@180 254 ; cli ; clear interrupt flag
pascal@180 255 ; hlt ; halt execution
pascal@180 256
pascal@180 257
pascal@180 258 ;; functions:
pascal@180 259
pascal@180 260 draw_current_level:
pascal@180 261 ; get width and height
pascal@180 262 mov cx, [CURRENT_LEVEL] ; cl = width; ch = height
pascal@180 263 push cx ; put it in the stack for later reuse
pascal@180 264
pascal@180 265 ; print in the middle and not in the corner
pascal@182 266 mov di, 25*COLS; middle of screen
pascal@180 267
pascal@180 268 ; offset by half of width
pascal@180 269 mov bx, 0x00FE
pascal@180 270 and bl, cl
pascal@180 271 sub di, bx
pascal@180 272
pascal@180 273 ; offset by half of height
pascal@180 274 mov cl, ch
pascal@180 275 and cx, 0x00FE
pascal@182 276 mov ax, COLS
pascal@180 277 mul cx
pascal@180 278 sub di, ax
pascal@180 279
pascal@180 280
pascal@180 281 mov si, CURRENT_LEVEL_4 ; source byte
pascal@180 282
pascal@180 283 ; screen memory in text mode
pascal@180 284 mov ax, SCREEN_DS
pascal@180 285 mov es, ax
pascal@180 286
pascal@180 287 .loop:
pascal@180 288 push si
pascal@180 289 lodsb
pascal@180 290 cbw
pascal@180 291 xchg ax, si
pascal@180 292 add si, si
pascal@182 293 mov ax, [bp+si+display_chars-test_level]
pascal@180 294 pop si
pascal@180 295
pascal@180 296 stosw
pascal@180 297
pascal@180 298 inc si
pascal@180 299 pop cx ; get counters
pascal@180 300 dec cl ; subtract 1 from X axis counter
pascal@180 301 jz .nextrow
pascal@180 302 push cx
pascal@180 303 jmp .loop
pascal@180 304
pascal@180 305 .nextrow:
pascal@180 306 dec ch ; subtract 1 from Y axis counter
pascal@180 307 jz .finished
pascal@180 308 mov cl, [CURRENT_LEVEL]
pascal@180 309 push cx
pascal@180 310
pascal@180 311 ; jump to next row down
pascal@180 312 xor ch, ch
pascal@180 313 neg cx
pascal@182 314 add cx, COLS
pascal@180 315 add cx, cx
pascal@180 316 add di, cx
pascal@180 317
pascal@180 318 jmp .loop
pascal@180 319
pascal@180 320 .finished:
pascal@180 321 ret
pascal@180 322
pascal@180 323 try_move:
pascal@180 324 ; try to move the player
pascal@180 325 ; al = offset of how much to move by
pascal@180 326
pascal@180 327 ; extend al into ax (signed)
pascal@180 328 test al, al ; check if negative
pascal@180 329 js .negative_al
pascal@180 330 xor ah, ah
pascal@180 331 jmp .after_al
pascal@180 332 .negative_al:
pascal@180 333 mov ah, 0xFF
pascal@180 334 .after_al:
pascal@180 335 push ax
pascal@180 336
pascal@180 337 mov di,CURRENT_LEVEL_4
pascal@180 338
pascal@180 339 ; calculate total level size
pascal@180 340 mov ax, [CURRENT_LEVEL]
pascal@180 341 mul ah
pascal@180 342
pascal@180 343 ; calculate requested destination position
pascal@180 344 pop bx
pascal@180 345 push bx
pascal@180 346 mov dx, [di - 2]
pascal@180 347 add bx, dx
pascal@180 348
pascal@180 349 ; check if in bounds
pascal@180 350 cmp bx, 0
pascal@180 351 jl .finished
pascal@180 352 cmp bx, ax
pascal@180 353 jg .finished
pascal@180 354
pascal@180 355 ; get value at destination position
pascal@180 356 mov cl, [bx + di]
pascal@180 357 cmp cl, 4
pascal@180 358 je .cant_push ; it's a wall
pascal@180 359 test cl, 0x02
pascal@180 360 jz .dont_push ; it's not a brick (on spot, or not), so don't try pushing
pascal@180 361
pascal@180 362 ; try pushing brick
pascal@180 363 pop cx ; get move offset
pascal@180 364 push bx ; store player's destination position (brick's current position)
pascal@180 365
pascal@180 366 mov dx, bx ; dx = current brick position
pascal@180 367 add bx, cx ; bx = next brick position
pascal@180 368
pascal@180 369 ; check bounds
pascal@180 370 cmp bx, 0
pascal@180 371 jl .cant_push
pascal@180 372 cmp bx, ax
pascal@180 373 jg .cant_push
pascal@180 374
pascal@180 375 ; get value at destination position
pascal@180 376 mov ch, [bx + di]
pascal@180 377 test ch, 0x0E ; test if the destination is occupied at all by ANDing with 0000 1110
pascal@180 378 jnz .cant_push
pascal@180 379
pascal@180 380 ; all checks passed! push the brick
pascal@180 381
pascal@180 382 ; add new brick to screen
pascal@180 383 or ch, 0x02 ; add brick bit, by ORing with 0000 0010
pascal@180 384 mov [bx + di], ch
pascal@180 385
pascal@180 386 ; remove old brick from screen
pascal@180 387 add di, dx
pascal@180 388 mov cl, [di]
pascal@180 389 and cl, 0xFD ; remove brick bit, by ANDing with 1111 1101
pascal@180 390 mov [di], cl
pascal@180 391 sub di, dx
pascal@180 392
pascal@180 393 mov dx, [di - 2] ; dx = current player position
pascal@180 394 pop bx ; bx = next player position
pascal@180 395 jmp .redraw_player
pascal@180 396
pascal@180 397 .cant_push:
pascal@180 398 pop bx
pascal@180 399 jmp .finished
pascal@180 400
pascal@180 401 .dont_push:
pascal@180 402 pop cx ; don't need to have this offset in the stack anymore
pascal@180 403
pascal@180 404 .redraw_player:
pascal@180 405 ; remove old player from screen
pascal@180 406 add di, dx
pascal@180 407 mov cl, [di]
pascal@180 408 and cl, 0xF7 ; remove player bit, by ANDing with 1111 0111
pascal@180 409 mov [di], cl
pascal@180 410 sub di, dx
pascal@180 411
pascal@180 412 ; add new player to screen
pascal@180 413 mov ch, [bx + di]
pascal@180 414 or ch, 0x08 ; add player bit, by ORing with 0000 1000
pascal@180 415 mov [bx + di], ch
pascal@180 416
pascal@180 417 ; update player position in memory
pascal@180 418 mov [di - 2], bx
pascal@180 419
pascal@180 420 .finished:
pascal@180 421 ret
pascal@180 422
pascal@180 423
pascal@180 424 times 510 - ($-$$) db 0 ; pad remaining 510 bytes with zeroes
pascal@180 425 dw 0xaa55 ; magic bootloader magic - marks this 512 byte sector bootable!