wok-tiny view bootpillman/stuff/pillman.asm @ rev 189

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