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