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