rev |
line source |
pascal@180
|
1 ;
|
pascal@180
|
2 ; Bricks game in one boot sector
|
pascal@180
|
3 ;
|
pascal@180
|
4 ; by Oscar Toledo G.
|
pascal@180
|
5 ;
|
pascal@180
|
6 ; Creation date: Nov/02/2019.
|
pascal@180
|
7 ;
|
pascal@180
|
8
|
pascal@180
|
9 cpu 8086
|
pascal@180
|
10
|
pascal@180
|
11 ;
|
pascal@180
|
12 ; Press Left Shift to start the game
|
pascal@180
|
13 ; Press Left Ctrl to move the paddle to the left
|
pascal@180
|
14 ; Press Left Alt to move the paddle to the right
|
pascal@180
|
15 ;
|
pascal@180
|
16
|
pascal@186
|
17 old_time: equ 16 ; word: Old time
|
pascal@180
|
18 ball_x: equ 14 ; X-coordinate of ball (8.8 fraction)
|
pascal@180
|
19 ball_y: equ 12 ; Y-coordinate of ball (8.8 fraction)
|
pascal@180
|
20 ball_xs: equ 10 ; X-speed of ball (8.8 fraction)
|
pascal@180
|
21 ball_ys: equ 8 ; Y-speed of ball (8.8 fraction)
|
pascal@186
|
22 beep: equ 6 ; byte: Frame count to turn off sound
|
pascal@186
|
23 bricks: equ 4 ; word: Remaining bricks
|
pascal@186
|
24 score: equ 2 ; word: Current score
|
pascal@186
|
25 balls: equ 0 ; byte: Remaining balls
|
pascal@186
|
26
|
pascal@186
|
27 %define MDA_SUPPORT
|
pascal@180
|
28
|
pascal@180
|
29 ;
|
pascal@180
|
30 ; Start of the game
|
pascal@180
|
31 ;
|
pascal@180
|
32 start:
|
pascal@186
|
33 cld
|
pascal@184
|
34 sti ; Allow interrupts
|
pascal@186
|
35 push cs
|
pascal@186
|
36 pop ss
|
pascal@186
|
37 mov sp,0xb800 ; Address of video screen
|
pascal@186
|
38 .set_segments:
|
pascal@186
|
39 mov ds,sp ; Setup DS
|
pascal@186
|
40 mov es,sp ; Setup ES
|
pascal@186
|
41 %ifdef MDA_SUPPORT
|
pascal@186
|
42 xor di,di
|
pascal@186
|
43 mov sp,0xb000 ; Address of video screen
|
pascal@186
|
44 inc word [di]
|
pascal@186
|
45 jz .set_segments
|
pascal@186
|
46 xchg ax,di
|
pascal@186
|
47 %else
|
pascal@186
|
48 xor ax,ax
|
pascal@186
|
49 %endif
|
pascal@180
|
50 push ax ; Reset score
|
pascal@180
|
51 mov al,4
|
pascal@180
|
52 push ax ; Balls remaining
|
pascal@180
|
53 mov bp,sp ; Setup stack frame for globals
|
pascal@182
|
54 mov al,0x02 ; Text mode 80x25x16 colors
|
pascal@182
|
55 int 0x10 ; Setup
|
pascal@186
|
56 %if 0
|
pascal@186
|
57 ; Disable VGA text mode cursor
|
pascal@186
|
58 ; https://wiki.osdev.org/Text_Mode_Cursor#Disabling_the_Cursor
|
pascal@186
|
59 mov ah, 0x01
|
pascal@186
|
60 mov ch, 0x3f
|
pascal@186
|
61 int 0x10
|
pascal@186
|
62 %endif
|
pascal@180
|
63 ;
|
pascal@180
|
64 ; Start another level
|
pascal@180
|
65 ;
|
pascal@180
|
66 another_level:
|
pascal@180
|
67 mov word [bp+bricks],273 ; 273 bricks on screen
|
pascal@180
|
68 xor di,di
|
pascal@180
|
69 mov ax,0x01b1 ; Draw top border
|
pascal@180
|
70 mov cx,80
|
pascal@180
|
71 rep stosw
|
pascal@180
|
72 mov cl,24 ; 24 rows
|
pascal@180
|
73 .1:
|
pascal@180
|
74 stosw ; Draw left border
|
pascal@180
|
75 mov ax,0x20 ; No bricks on this row
|
pascal@180
|
76 push cx
|
pascal@180
|
77 cmp cl,23
|
pascal@180
|
78 jnb .2
|
pascal@180
|
79 sub cl,15
|
pascal@180
|
80 jbe .2
|
pascal@180
|
81 mov al,0xdb ; Bricks on this row
|
pascal@180
|
82 mov ah,cl
|
pascal@180
|
83 .2:
|
pascal@180
|
84 mov cl,39 ; 39 bricks per row
|
pascal@180
|
85 .3:
|
pascal@186
|
86 test ah,0x07
|
pascal@186
|
87 jne .4
|
pascal@186
|
88 %ifdef MDA_SUPPORT
|
pascal@186
|
89 mov ah,0x02
|
pascal@186
|
90 %else
|
pascal@186
|
91 mov ah,0x01
|
pascal@186
|
92 %endif
|
pascal@186
|
93 .4:
|
pascal@180
|
94 stosw
|
pascal@180
|
95 stosw
|
pascal@180
|
96 inc ah ; Increase attribute color
|
pascal@180
|
97 loop .3
|
pascal@180
|
98 pop cx
|
pascal@180
|
99
|
pascal@180
|
100 mov ax,0x01b1 ; Draw right border
|
pascal@180
|
101 stosw
|
pascal@180
|
102 loop .1
|
pascal@180
|
103
|
pascal@180
|
104 ;
|
pascal@180
|
105 ; Start another ball
|
pascal@180
|
106 ;
|
pascal@180
|
107 mov di,0x0f4a ; Position of paddle
|
pascal@180
|
108 another_ball:
|
pascal@180
|
109 mov byte [bp+ball_x+1],0x28 ; Center X
|
pascal@180
|
110 mov byte [bp+ball_y+1],0x14 ; Center Y
|
pascal@186
|
111 and word [bp+ball_xs],0 ; Static on screen
|
pascal@186
|
112 and word [bp+ball_ys],0
|
pascal@180
|
113 mov byte [bp+beep],0x01
|
pascal@180
|
114
|
pascal@180
|
115 mov si,0x0ffe ; Don't erase ball yet
|
pascal@180
|
116 game_loop:
|
pascal@180
|
117 call wait_frame ; Wait 1/18.2 secs.
|
pascal@180
|
118
|
pascal@182
|
119 and word [si],0x0000 ; Erase ball
|
pascal@180
|
120
|
pascal@180
|
121 call update_score ; Update score
|
pascal@180
|
122
|
pascal@182
|
123 mov ah,0x01 ; Check for keys
|
pascal@182
|
124 int 0x16
|
pascal@182
|
125 jz .0
|
pascal@182
|
126 cbw ; Eat key
|
pascal@182
|
127 int 0x16
|
pascal@182
|
128 cmp al,27 ; ESC key ?
|
pascal@185
|
129 jnz .0
|
pascal@185
|
130 call wait_frame.2 ; Turn off sound
|
pascal@185
|
131 mov ax,0x0003 ; Text mode 80x25x16 colors
|
pascal@185
|
132 int 0x10 ; Setup
|
pascal@185
|
133 int 0x20 ; Exit to DOS / bootOS
|
pascal@185
|
134 int 0x19
|
pascal@182
|
135 .0:
|
pascal@180
|
136 mov ah,0x02 ; Read modifier keys
|
pascal@180
|
137 int 0x16
|
pascal@180
|
138 test al,0x04 ; Left ctrl
|
pascal@180
|
139 je .1
|
pascal@180
|
140 mov byte [di+6],0 ; Erase right side of paddle
|
pascal@180
|
141 mov byte [di+8],0
|
pascal@180
|
142 sub di,byte 4 ; Move paddle to left
|
pascal@180
|
143 cmp di,0x0f02 ; Limit
|
pascal@180
|
144 ja .1
|
pascal@180
|
145 mov di,0x0f02
|
pascal@180
|
146 .1:
|
pascal@180
|
147 test al,0x08 ; Left alt
|
pascal@180
|
148 je .2
|
pascal@180
|
149 xor ax,ax ; Erase left side of paddle
|
pascal@180
|
150 stosw
|
pascal@180
|
151 stosw ; DI increased automatically
|
pascal@180
|
152 cmp di,0x0f94 ; Limit
|
pascal@180
|
153 jb .2
|
pascal@180
|
154 mov di,0x0f94
|
pascal@180
|
155 .2:
|
pascal@180
|
156 test al,0x02 ; Left shift
|
pascal@180
|
157 je .15
|
pascal@180
|
158 mov ax,[bp+ball_xs] ; Ball moving?
|
pascal@180
|
159 add ax,[bp+ball_ys]
|
pascal@180
|
160 jne .15 ; Yes, jump
|
pascal@180
|
161 ; Setup movement of ball
|
pascal@180
|
162 mov word [bp+ball_xs],0xff40
|
pascal@180
|
163 mov word [bp+ball_ys],0xff80
|
pascal@180
|
164 .15:
|
pascal@180
|
165 mov ax,0x0adf ; Paddle graphic and color
|
pascal@180
|
166 push di
|
pascal@180
|
167 stosw ; Draw paddle
|
pascal@180
|
168 stosw
|
pascal@180
|
169 stosw
|
pascal@180
|
170 stosw
|
pascal@180
|
171 stosw
|
pascal@180
|
172 pop di
|
pascal@180
|
173
|
pascal@180
|
174 mov bx,[bp+ball_x] ; Draw ball
|
pascal@180
|
175 mov ax,[bp+ball_y]
|
pascal@180
|
176 call locate_ball ; Locate on screen
|
pascal@180
|
177 test byte [bp+ball_y],0x80 ; Y-coordinate half fraction?
|
pascal@180
|
178 mov ah,0x60 ; Interchange colors for smooth mov.
|
pascal@180
|
179 je .12
|
pascal@180
|
180 mov ah,0x06
|
pascal@180
|
181 .12: mov al,0xdc ; Graphic
|
pascal@180
|
182 mov [bx],ax ; Draw
|
pascal@180
|
183 push bx
|
pascal@180
|
184 pop si
|
pascal@180
|
185
|
pascal@180
|
186 .14:
|
pascal@180
|
187 mov bx,[bp+ball_x] ; Ball position
|
pascal@180
|
188 mov ax,[bp+ball_y]
|
pascal@180
|
189 add bx,[bp+ball_xs] ; Add movement speed
|
pascal@180
|
190 add ax,[bp+ball_ys]
|
pascal@180
|
191 push ax
|
pascal@180
|
192 push bx
|
pascal@180
|
193 call locate_ball ; Locate on screen
|
pascal@180
|
194 mov al,[bx]
|
pascal@180
|
195 cmp al,0xb1 ; Touching borders
|
pascal@180
|
196 jne .3
|
pascal@186
|
197 mov cl,5423/256 ; 1193180 / 220
|
pascal@180
|
198 call speaker ; Generate sound
|
pascal@180
|
199 pop bx
|
pascal@180
|
200 pop ax
|
pascal@180
|
201 cmp bh,0x4f
|
pascal@180
|
202 je .8
|
pascal@180
|
203 test bh,bh
|
pascal@180
|
204 jne .7
|
pascal@180
|
205 .8:
|
pascal@180
|
206 neg word [bp+ball_xs] ; Negate X-speed if it touches a side
|
pascal@180
|
207 .7:
|
pascal@180
|
208 test ah,ah
|
pascal@180
|
209 jnz .9
|
pascal@180
|
210 neg word [bp+ball_ys] ; Negate Y-speed if it touches a side
|
pascal@180
|
211 .9: jmp .14
|
pascal@180
|
212
|
pascal@180
|
213 .3:
|
pascal@180
|
214 cmp al,0xdf ; Touching paddle
|
pascal@180
|
215 jne .4
|
pascal@180
|
216 sub bx,di ; Subtract paddle position
|
pascal@180
|
217 sub bx,byte 4
|
pascal@180
|
218 mov cl,6 ; Multiply by 64
|
pascal@180
|
219 shl bx,cl
|
pascal@180
|
220 mov [bp+ball_xs],bx ; New X speed for ball
|
pascal@180
|
221 mov word [bp+ball_ys],0xff80 ; Update Y speed for ball
|
pascal@186
|
222 mov cl,2711/256 ; 1193180 / 440
|
pascal@180
|
223 call speaker ; Generate sound
|
pascal@186
|
224 .16: pop bx
|
pascal@180
|
225 pop ax
|
pascal@180
|
226 jmp .14
|
pascal@180
|
227
|
pascal@180
|
228 .4:
|
pascal@180
|
229 cmp al,0xdb ; Touching brick
|
pascal@180
|
230 jne .5
|
pascal@186
|
231 mov cl,1355/256 ; 1193180 / 880
|
pascal@180
|
232 call speaker ; Generate sound
|
pascal@180
|
233 test bl,2 ; Aligned with brick?
|
pascal@180
|
234 jne .10 ; Yes, jump
|
pascal@180
|
235 dec bx ; Align
|
pascal@180
|
236 dec bx
|
pascal@186
|
237 .10: and word [bx],0 ; Erase brick
|
pascal@186
|
238 and word [bx+2],0
|
pascal@180
|
239 inc word [bp+score] ; Increase score
|
pascal@180
|
240 neg word [bp+ball_ys] ; Negate Y speed (rebound)
|
pascal@186
|
241 dec word [bp+bricks] ; One brick less on screen
|
pascal@186
|
242 jne .16 ; Fully completed? No, jump.
|
pascal@180
|
243 pop bx
|
pascal@180
|
244 pop ax
|
pascal@180
|
245 jmp another_level ; Start another level
|
pascal@180
|
246
|
pascal@180
|
247 .5:
|
pascal@180
|
248 pop bx
|
pascal@180
|
249 pop ax
|
pascal@180
|
250 .6:
|
pascal@180
|
251 mov [bp+ball_x],bx ; Update ball position
|
pascal@180
|
252 mov [bp+ball_y],ax
|
pascal@180
|
253 cmp ah,0x19 ; Ball exited through bottom?
|
pascal@180
|
254 je ball_lost ; Yes, jump
|
pascal@180
|
255 jmp game_loop ; No, repeat game loop
|
pascal@180
|
256
|
pascal@180
|
257 ;
|
pascal@180
|
258 ; Ball lost
|
pascal@180
|
259 ;
|
pascal@180
|
260 ball_lost:
|
pascal@186
|
261 mov cl,10846/256 ; 1193180 / 110
|
pascal@180
|
262 call speaker ; Generate sound
|
pascal@180
|
263
|
pascal@182
|
264 and word [si],0 ; Erase ball
|
pascal@180
|
265 dec byte [bp+balls] ; One ball less
|
pascal@180
|
266 js .1 ; All finished? Yes, jump
|
pascal@180
|
267 jmp another_ball ; Start another ball
|
pascal@180
|
268
|
pascal@180
|
269 .1: call wait_frame.2 ; Turn off sound
|
pascal@180
|
270 jmp start
|
pascal@180
|
271
|
pascal@180
|
272 wait_frame:
|
pascal@180
|
273 .0:
|
pascal@182
|
274 hlt ; Wait for clock interrupt
|
pascal@180
|
275 mov ah,0x00 ; Read ticks
|
pascal@180
|
276 int 0x1a ; Call BIOS
|
pascal@180
|
277 cmp dx,[bp+old_time] ; Wait for change
|
pascal@180
|
278 je .0
|
pascal@180
|
279 mov [bp+old_time],dx
|
pascal@180
|
280
|
pascal@186
|
281 dec byte [bp+beep] ; Decrease time to turn off beep
|
pascal@186
|
282 jne speaker.2
|
pascal@180
|
283 .2:
|
pascal@180
|
284 in al,0x61
|
pascal@180
|
285 and al,0xfc ; Turn off
|
pascal@186
|
286 jmp speaker.1
|
pascal@180
|
287
|
pascal@180
|
288 ;
|
pascal@180
|
289 ; Generate sound on PC speaker
|
pascal@180
|
290 ;
|
pascal@180
|
291 speaker:
|
pascal@186
|
292 mov byte [bp+beep],3 ; Duration
|
pascal@180
|
293 mov al,0xb6 ; Setup timer 2
|
pascal@180
|
294 out 0x43,al
|
pascal@186
|
295 out 0x42,al ; Low byte of timer count
|
pascal@186
|
296 xchg ax,cx ; High byte of timer count
|
pascal@180
|
297 out 0x42,al
|
pascal@180
|
298 in al,0x61
|
pascal@180
|
299 or al,0x03 ; Connect PC speaker to timer 2
|
pascal@186
|
300 .1: out 0x61,al
|
pascal@186
|
301 .2: ret
|
pascal@180
|
302
|
pascal@180
|
303 ;
|
pascal@180
|
304 ; Locate ball on screen
|
pascal@180
|
305 ;
|
pascal@180
|
306 locate_ball:
|
pascal@180
|
307 mov al,0xa0
|
pascal@180
|
308 mul ah ; AH = Y coordinate (row)
|
pascal@180
|
309 mov bl,bh ; BH = X coordinate (column)
|
pascal@180
|
310 mov bh,0
|
pascal@186
|
311 add bx,bx
|
pascal@180
|
312 add bx,ax
|
pascal@180
|
313 ret
|
pascal@180
|
314
|
pascal@180
|
315 ;
|
pascal@180
|
316 ; Update score indicator (from bootRogue)
|
pascal@180
|
317 ;
|
pascal@180
|
318 update_score:
|
pascal@180
|
319 mov bx,0x0f98 ; Point to bottom right corner
|
pascal@180
|
320 mov ax,[bp+score]
|
pascal@180
|
321 call .1
|
pascal@180
|
322 mov al,[bp+balls]
|
pascal@180
|
323 .1:
|
pascal@180
|
324 xor cx,cx ; CX = Quotient
|
pascal@180
|
325 .2: inc cx
|
pascal@180
|
326 sub ax,10 ; Division by subtraction
|
pascal@180
|
327 jnc .2
|
pascal@180
|
328 add ax,0x0a3a ; Convert remainder to ASCII digit + color
|
pascal@180
|
329 call .3 ; Put on screen
|
pascal@180
|
330 xchg ax,cx
|
pascal@180
|
331 dec ax ; Quotient is zero?
|
pascal@180
|
332 jnz .1 ; No, jump to show more digits.
|
pascal@180
|
333
|
pascal@180
|
334 .3: mov [bx],ax
|
pascal@180
|
335 dec bx
|
pascal@180
|
336 dec bx
|
pascal@180
|
337 ret
|
pascal@180
|
338
|
pascal@180
|
339 times 510-($-$$) db 0x4f
|
pascal@180
|
340 db 0x55,0xaa ; Make it a bootable sector
|