wok-tiny view bootris/stuff/tetranglix.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 ; Modified by nanochess for compatibility with VirtualBox.
2 ; to require only 8086 and also now it's in color.
4 BITS 16
6 BSS EQU 0x7E00
7 BSS_SIZE EQU 438
9 CUR_TETRAMINO EQU BSS ; 16 bytes.
10 ROT_TETRAMINO EQU BSS + 16 ; 16 bytes.
11 OFFSET EQU BSS + 32 ; 2 bytes.
12 STACK EQU BSS + 38 ; 4 bytes reserved in beginning, 400 bytes.
14 LEFT_SCANCODE EQU 0x4b
15 RIGHT_SCANCODE EQU 0x4d
17 UP_SCANCODE EQU 0x48
18 DOWN_SCANCODE EQU 0x50
20 SCORE_DIGITS EQU 5
22 SCREEN_SEGMENT EQU 0xB800
24 CPU 8086
26 ; Entry point.
27 ; cs:ip -> linear address (usually 0x7C00, but irrelevant because we are position independent).
28 start:
29 ; Stack.
30 push cs
31 pop ss
32 mov sp, SCREEN_SEGMENT ;why not
34 push cs
35 pop ds
36 push cs
37 pop es
39 ; Clear direction flag.
40 cld
42 ; Clear BSS
43 mov di, BSS
44 mov cx, di ;at least BSS_SIZE
45 xor ax, ax
46 rep stosb
48 ; Set to mode 0x03, or 80x25 text mode (ah is zero from above).
49 mov al, 0x03
50 int 0x10
52 ; Hide the hardware cursor.
53 mov ch, 0x26
54 mov ax, 0x103 ; Some BIOS crash without the 03.
55 int 0x10
57 mov es, sp
59 ; White spaces on black background.
60 xor di, di
61 mov ax, 0x0F00
62 mov ch, 8 ; At least 80x25x2.
63 rep stosw
64 call pop_check
66 ; Detects if CUR_TETRAMINO at OFFSET is colliding with any thing.
67 ; si -> OFFSET.
68 ; Output:
69 ; Carry set if colliding.
70 tetramino_collision_check:
72 lea bx, [bp + check_collision - tetramino_collision_check]
74 ; Processes the current tetramino, calling bx per "tetramino pixel".
75 ; bx -> where to call to; al contains tetramino pixel, di the address into stack.
76 tetramino_process:
77 push si
78 push ax
79 push di
80 push cx
82 ; Gets the offset into stack (i.e., address) into di.
83 ; si -> points at OFFSET.
84 ; Output:
85 ; si -> points at CUR_TETRAMINO.
86 ; di -> address into stack.
87 ; Trashes ax.
89 ; Calculate first index into screen.
90 lodsw
91 aad 0x10
93 mov cl, 0x10
95 cmp [si-1], cl
96 sbb ah, ah
97 xchg bx, ax
98 lea di, [si + (STACK - OFFSET) + 0xFE + bx]
99 xchg bx, ax
101 mov si, CUR_TETRAMINO
103 .loop:
104 test cl, 0x13;0b1011
105 jnz .load_loop
107 ; Go to next line in stack.
108 add di, 16 - 4
110 .load_loop:
111 lodsb
113 ; Call wherever the caller wants us to go.
114 call bx
116 inc di
117 loop .loop
119 pop cx
120 pop di
121 pop ax
122 pop si
123 ret
125 check_collision:
126 or al,al
127 jz .clear_carry
129 cmp di, STACK + 400
130 jae .colliding
132 cmp byte [di],0
134 .clear_carry:
135 ;clc
137 je .next_iter
139 ; Colliding!
140 .colliding:
142 stc
143 mov cl, 1
144 .next_iter:
145 ret
147 ; Used by the stack joining part.
148 merge:
149 or [di], al
150 ret
152 exit_game_over:
153 je start
154 exit_dos:
155 mov al,0x03 ; Clear screen
156 int 0x10
157 int 0x20 ; Return to bootOS
158 int 0x19
160 ; All tetraminos in bitmap format.
161 tetraminos:
162 db 0xF0;0b11110000 ; I
163 db 0xE2;0b11100010 ; J
164 db 0x2E;0b00101110 ; L
165 db 0x66;0b01100110 ; O
166 db 0x36;0b00110110 ; S
167 db 0xE4;0b11100100 ; T
168 db 0x63;0b01100011 ; Z
170 pop_check:
171 pop bp ; Save some bytes.
173 .borders:
174 mov si, STACK - 3
175 mov ax, 0x0101
177 .borders_init:
178 mov [si], ax
179 mov [si + 2], ax
180 mov [si + 4], ax
182 add si, 16
183 cmp si, STACK + 400 - 3
184 jbe .borders_init
186 ; Cleared dl implies "load new tetramino".
187 xor dl, dl
189 .event_loop:
190 mov si, OFFSET
192 ; For some reason this doesn't work with BootOS over VirtualBox 5.1.22
193 %if 0
194 mov bx, [0x046C]
195 inc bx
196 inc bx ; Wait for 2 PIT ticks.
198 .busy_loop:
199 cmp [0x046C], bx
200 jne .busy_loop
201 %else
202 push dx
203 clc
204 mov bx,0x1000
205 .busy_loop2:
206 pushf
207 .busy_loop1:
208 hlt ; Wait for clock interrupt
209 mov ah,0x00
210 int 0x1a
211 cmp [bx],dx
212 je .busy_loop1
213 mov [bx],dx
214 popf
215 cmc
216 jc .busy_loop2
217 pop dx
218 xor cx,cx ; Or rotation doesn't work
219 %endif
220 ; If we don't need to load a new tetramino, yayy!
221 test dl, dl
222 jnz .input
224 ; Load a tetramino to CUR_TETRAMINO, from the compressed bitmap format.
226 .choose_tetramino:
227 in al,(0x40)
229 ; Only 7 tetraminos, index as 1-7.
230 and ax, 7
231 je .choose_tetramino
233 ; Get the address of the tetramino (in bitmap format).
234 cwd
235 mov di,ax
236 mov ah,al
238 ; Load tetramino bitmap in dl.
239 mov dl, [bp + di + (tetraminos - tetramino_collision_check) - 1]
240 mov cl, 4
241 shl dx, cl
243 ; Convert from bitmap to array.
244 mov di, CUR_TETRAMINO
245 mov cl, 0x10
247 .loop_bitmap:
249 shl dx, 1
251 ; If the bit we just shifted off was set, store number of tetramino.
252 sbb al, al
253 and al, ah
254 mov [di], al
255 inc di
257 loop .loop_bitmap
259 ; Loaded.
260 mov dl, 6
262 mov word [si], dx
263 jmp .link_next_iter
265 ; Check for input.
266 .input:
267 ; Check for keystroke.
268 mov ah, 0x01
269 int 0x16
271 ; If no keystroke, increment vertical offset.
272 jz .vertical_increment
274 ; Clear the keyboard buffer.
275 xor ah, ah
276 int 0x16
278 .exit:
279 dec ah
280 je exit_dos
281 mov al, ah
283 ; Go left.
284 .left:
285 cmp al, LEFT_SCANCODE-1
286 je .call_bp
288 ; Go right.
289 .right:
290 cmp al, RIGHT_SCANCODE-1
291 jne .rotate
293 add byte [si],2
295 .call_bp:
296 dec byte [si]
297 xor al, (LEFT_SCANCODE-1) ^ (RIGHT_SCANCODE-1)
298 call bp
299 jc .left
301 ; Rotate it.
302 .rotate:
303 cmp al, UP_SCANCODE-1
304 jne .vertical_increment
306 inc cx
308 .rotate_loop:
309 ; Rotates CUR_TETRAMINO 90 degrees clock-wise.
310 ; Output:
311 ; CUR_TETRAMINO -> rotated tetramino.
312 push si
313 push di
314 push cx
315 push es
317 ; Reset ES.
318 push ds
319 pop es
321 mov si, CUR_TETRAMINO
322 mov di, ROT_TETRAMINO + 3
323 push si
324 mov cl, 4
326 .loop:
327 mov ch, 4
329 .tetramino_line:
330 movsb
331 scasw
332 inc di
333 dec ch
334 jnz .tetramino_line
336 sub di, 4*4+1
337 loop .loop
339 pop di
340 mov cl, 4*4/2 ; CH would be zero, from above.
341 rep movsw
343 pop es
344 pop cx
345 pop di
346 pop si
348 loop .rotate_loop
350 call bp
351 ; To restore, just rotate 3 more times.
352 mov cl, 3
353 jc .rotate_loop
355 .vertical_increment:
356 mov cl, 1
357 call upd_score
359 ; Check if we can go below one byte, successfully.
360 inc byte [si + 1]
361 call bp
362 .link_next_iter:
363 jnc .next_iter
365 ; If we can't, we need a new tetramino.
366 dec byte [si + 1]
367 je .game_over
368 cwd
370 ; Joins the current tetramino to the stack, and any complete lines together.
371 ; si -> OFFSET.
372 push es
374 push ds
375 pop es
377 lea bx, [bp + merge - tetramino_collision_check]
378 call tetramino_process
380 mov si, STACK + 15
381 std
383 .loop_lines:
384 push si
385 mov cl, 16
387 .line:
388 lodsb
389 test al, al
390 loopnz .line ; If it was a blank, exit loop to indicate failure.
392 jz .next_line
394 lea cx, [si - (STACK - 1)]
395 lea di, [si + 16]
396 rep movsb
397 mov cl, 64
398 call upd_score
400 .next_line:
401 pop si
402 add si, 16
403 cmp si, STACK + 15 + 400
404 jb .loop_lines
406 cld
407 pop es
409 jmp .borders
411 .game_over: ; Game Over
412 xor ax, ax
413 int 0x16 ; wait for and key
414 dec ah
415 jmp exit_game_over
417 .next_iter:
418 ; Display the stack.
419 push si
421 ; Add 24 characters padding in the front.
422 mov ah, 0x0F
423 mov di, 48
424 mov si, STACK
426 .loop_stack_lines:
427 ; Copy 32 characters.
428 mov cl, 16
430 .stack_line:
431 lodsb
432 mov ah,al
433 mov al,0xdb
434 ; Store one character as two -- to make stack "squarish" on 80x25 display.
435 stosw
436 stosw
438 loop .stack_line
440 ; Handle remaining 24 characters in row, and starting 24 in next row.
441 add di, 96
442 cmp di, (25 * 160) ; If we go beyond the last row, we're over.
443 jb .loop_stack_lines
445 pop si
447 ; Displays CUR_TETRAMINO at current OFFSET.
448 ; si -> OFFSET.
450 ; Calculate first index into screen.
451 mov al, 40
452 mul byte [si+1]
453 mov cl, 12
454 add cl, [si]
455 add ax, cx
457 ; One character takes 2 bytes in video memory.
458 shl ax, 1
459 shl ax, 1
460 xchg di, ax
462 ; Loops for 16 input characters.
463 mov cl, 0x10
464 mov si, CUR_TETRAMINO
466 mov ah, 0x0F
468 .loop_tetramino:
469 test cl, 0x13;0b1011
470 jnz .load_tetramino
472 ; Since each tetramino input is 4x4, we must go to next line
473 ; at every multiple of 4.
474 ; Since we output 2 characters for one input char, cover offset of 8.
475 add di, (80 - 8) * 2
477 .load_tetramino:
478 lodsb
479 or al,al
480 mov ah,al
481 mov al,0xdb
482 ; Output two characters for "squarish" output.
483 jne .load_tetramino2
484 mov ax, [es:di]
485 .load_tetramino2:
486 stosw
487 stosw
489 loop .loop_tetramino
491 jmp .event_loop
493 upd_score:
494 push ds
495 mov bx, SCREEN_SEGMENT
496 mov ds, bx
497 mov bx, SCORE_DIGITS * 2
499 .chk_score:
500 dec bx
501 dec bx
502 js pop_check.game_over
503 mov al, '0'
504 xchg [bx], al
505 or al, 0x30
506 cmp al, '9'
507 je .chk_score
508 inc ax
509 mov [bx], al
510 pop ds
512 loop upd_score
513 ret
515 ; IT'S A SECRET TO EVERYBODY.
516 db "ShNoXgSo"
518 ; Padding.
519 times 510 - ($ - $$) db 0
521 BIOS_signature:
522 dw 0xAA55