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