rev |
line source |
pascal@180
|
1 ;
|
pascal@180
|
2 ; F-bird text game in a bootsector
|
pascal@180
|
3 ;
|
pascal@180
|
4 ; by Oscar Toledo G.
|
pascal@180
|
5 ; http://nanochess.org/
|
pascal@180
|
6 ;
|
pascal@180
|
7 ; Creation date: Jun/04/2017. A messy unoptimized thing.
|
pascal@180
|
8 ; Revision date: Jun/05/2017. Better usage of graphic charset.
|
pascal@180
|
9 ; Removed a non-8088 long jump. Added
|
pascal@180
|
10 ; sound. Solved bug when overwriting
|
pascal@180
|
11 ; previous score.
|
pascal@180
|
12 ;
|
pascal@180
|
13
|
pascal@180
|
14 use16
|
pascal@180
|
15 cpu 8086
|
pascal@180
|
16
|
pascal@180
|
17 restart:
|
pascal@180
|
18 mov ax,0x0002 ; Set 80x25 text mode
|
pascal@180
|
19 int 0x10 ; Call BIOS
|
pascal@180
|
20 ;
|
pascal@180
|
21 ; Game restart
|
pascal@180
|
22 ;
|
pascal@180
|
23 fb21: cld ; Reset direction flag (so stosw increments registers)
|
pascal@183
|
24 sti ; Allow interrupts
|
pascal@180
|
25 mov ax,0xb800 ; Point to video segment
|
pascal@180
|
26 mov ds,ax ; Both the source (common access)
|
pascal@180
|
27 mov es,ax ; and target segments
|
pascal@180
|
28 mov di,pipe ; Init variables in video segment (saves big bytes)
|
pascal@180
|
29 cbw
|
pascal@180
|
30 stosw ; pipe
|
pascal@180
|
31 stosw ; score
|
pascal@180
|
32 stosw ; grav
|
pascal@180
|
33 mov al,0xa0
|
pascal@180
|
34 stosw ; next
|
pascal@180
|
35 mov al,0x60
|
pascal@180
|
36 stosw ; bird
|
pascal@180
|
37
|
pascal@180
|
38 mov di,0x004a ; Game title
|
pascal@180
|
39 mov ax,0x0f46 ; 'F' in white, good old ASCII
|
pascal@180
|
40 stosw
|
pascal@180
|
41 mov al,0x2d ; '-'
|
pascal@180
|
42 stosw
|
pascal@180
|
43 mov al,0x42 ; 'B'
|
pascal@180
|
44 stosw
|
pascal@180
|
45 mov al,0x49 ; 'I'
|
pascal@180
|
46 stosw
|
pascal@180
|
47 mov al,0x52 ; 'R'
|
pascal@180
|
48 stosw
|
pascal@180
|
49 mov al,0x44 ; 'D'
|
pascal@180
|
50 stosw
|
pascal@182
|
51 mov bp,80 ; Introduce 80 columns of scenery
|
pascal@182
|
52 fb1: call scroll_scenery
|
pascal@182
|
53 dec bp
|
pascal@182
|
54 jnz fb1
|
pascal@180
|
55
|
pascal@180
|
56 fb23: mov ah,0x01 ; Check if key pressed
|
pascal@180
|
57 int 0x16
|
pascal@180
|
58 pushf
|
pascal@180
|
59 xor ax,ax ; Wait for a key
|
pascal@180
|
60 int 0x16
|
pascal@180
|
61 popf
|
pascal@180
|
62 jnz fb23 ; Jump if key was accumulated, if not already waited for key ;)
|
pascal@180
|
63
|
pascal@180
|
64 ;
|
pascal@180
|
65 ; Main loop
|
pascal@180
|
66 ;
|
pascal@180
|
67 fb12: mov si,bird
|
pascal@180
|
68 lodsw ; Bird falls...
|
pascal@180
|
69 add al,[grav] ; ...because of gravity...
|
pascal@180
|
70 mov [bird],al ; ...into new position.
|
pascal@180
|
71 and al,0xf8 ; Row is a 5.3 fraction, nullify fraction
|
pascal@180
|
72 mov ah,0x14 ; Given integer is x8, multiply by 20 to get 160 per line
|
pascal@180
|
73 mul ah ; Row into screen
|
pascal@180
|
74 add ax,$0020 ; Fixed column
|
pascal@180
|
75 xchg ax,di ; Pass to DI (AX cannot be used as pointer)
|
pascal@180
|
76 lodsb ; mov al,[frame]
|
pascal@180
|
77 and al,4 ; Wing movement each 4 frames
|
pascal@180
|
78 jz fb15
|
pascal@180
|
79 mov al,[di-160] ; Get character below
|
pascal@180
|
80 mov word [di-160],$0d1e ; Draw upper wing
|
pascal@180
|
81 add al,[di] ; Add another character below
|
pascal@180
|
82 shr al,1 ; Normalize
|
pascal@180
|
83 mov word [di],$0d14 ; Draw body
|
pascal@180
|
84 jmp short fb16
|
pascal@180
|
85
|
pascal@180
|
86 fb15: mov al,[di] ; Get character below
|
pascal@180
|
87 mov word [di],$0d1f ; Draw body
|
pascal@180
|
88 fb16: add al,[di+2] ; Get character below head
|
pascal@180
|
89 mov word [di+2],$0d10 ; Draw head
|
pascal@180
|
90 cmp al,0x40 ; Collision with scenery?
|
pascal@180
|
91 jz fb19
|
pascal@180
|
92 ;
|
pascal@180
|
93 ; Stars and game over
|
pascal@180
|
94 ;
|
pascal@180
|
95 mov byte [di],$2a ; '*' Asterisks to indicate crashing
|
pascal@180
|
96 mov byte [di+2],$2a
|
pascal@180
|
97 mov di,0x07CA
|
pascal@180
|
98 mov ax,0x0f42 ; 'B' in white, good old ASCII
|
pascal@180
|
99 stosw
|
pascal@180
|
100 mov al,0x4F ; 'O'
|
pascal@180
|
101 stosw
|
pascal@180
|
102 mov al,0x4E ; 'N'
|
pascal@180
|
103 stosw
|
pascal@180
|
104 mov al,0x4B ; 'K'
|
pascal@180
|
105 stosw
|
pascal@180
|
106 mov al,0x21 ; '!'
|
pascal@180
|
107 stosw
|
pascal@182
|
108 mov bp,100 ; Wait 100 frames
|
pascal@182
|
109 fb20: call wait_frame
|
pascal@182
|
110 dec bp
|
pascal@182
|
111 jnz fb20
|
pascal@180
|
112 jmp fb21 ; Restart
|
pascal@180
|
113
|
pascal@180
|
114 fb19: call wait_frame ; Wait for frame
|
pascal@180
|
115 mov al,[frame]
|
pascal@180
|
116 and al,7 ; 8 frames have passed?
|
pascal@180
|
117 jnz fb17 ; No, jump
|
pascal@180
|
118 inc word [grav] ; Increase gravity
|
pascal@180
|
119 fb17:
|
pascal@180
|
120 mov al,$20
|
pascal@180
|
121 mov [di-160],al ; Delete bird from screen
|
pascal@180
|
122 mov [di+2],al
|
pascal@180
|
123 stosb
|
pascal@180
|
124 call scroll_scenery ; Scroll scenery
|
pascal@180
|
125 call scroll_scenery ; Scroll scenery
|
pascal@180
|
126 cmp byte [0x00a0],0xb0 ; Passed a column?
|
pascal@180
|
127 jz fb27
|
pascal@180
|
128 cmp byte [0x00a2],0xb0 ; Passed a column?
|
pascal@180
|
129 fb27: jnz fb24
|
pascal@180
|
130 inc word [score] ; Increase score
|
pascal@180
|
131 mov ax,[score]
|
pascal@180
|
132 mov di,0x008e ; Show current score
|
pascal@180
|
133 fb25: xor dx,dx ; Extend AX to 32 bits
|
pascal@180
|
134 mov bx,10 ; Divisor is 10
|
pascal@180
|
135 div bx ; Divide
|
pascal@180
|
136 add dx,0x0c30 ; Convert remaining 0-9 to ASCII, also put color
|
pascal@180
|
137 xchg ax,dx
|
pascal@180
|
138 std
|
pascal@180
|
139 stosw
|
pascal@180
|
140 mov byte [di],0x20 ; Clean at least one character of prev. score
|
pascal@180
|
141 cld
|
pascal@180
|
142 xchg ax,dx
|
pascal@180
|
143 or ax,ax ; Score digits still remain?
|
pascal@180
|
144 jnz fb25 ; Yes, jump
|
pascal@180
|
145 fb24: mov ah,0x01 ; Any key pressed?
|
pascal@180
|
146 int 0x16
|
pascal@180
|
147 jz fb26 ; No, go to main loop
|
pascal@180
|
148 mov ah,0x00
|
pascal@180
|
149 int 0x16 ; Get key
|
pascal@180
|
150 dec ah ; Escape key?
|
pascal@180
|
151 jne fb4 ; No, jump
|
pascal@180
|
152 mov al,3
|
pascal@180
|
153 int 0x10
|
pascal@180
|
154 int 0x20 ; Exit to DOS or to oblivion (boot sector)
|
pascal@182
|
155 int 0x19
|
pascal@180
|
156 fb4: mov ax,[bird]
|
pascal@180
|
157 sub ax,0x10 ; Move bird two rows upward
|
pascal@180
|
158 cmp ax,0x08 ; Make sure the bird doesn't fly free outside screen
|
pascal@180
|
159 jb fb18
|
pascal@180
|
160 mov [bird],ax
|
pascal@180
|
161 fb18: mov byte [grav],0 ; Reset gravity
|
pascal@180
|
162 mov al,0xb6 ; Flap sound
|
pascal@180
|
163 out (0x43),al
|
pascal@180
|
164 mov al,0x90
|
pascal@180
|
165 out (0x42),al
|
pascal@180
|
166 mov al,0x4a
|
pascal@180
|
167 out (0x42),al
|
pascal@180
|
168 in al,(0x61)
|
pascal@180
|
169 or al,0x03 ; Turn on sound
|
pascal@180
|
170 out (0x61),al
|
pascal@180
|
171 fb26: jmp fb12
|
pascal@180
|
172
|
pascal@180
|
173 ;
|
pascal@180
|
174 ; Scroll scenery one column at a time
|
pascal@180
|
175 ;
|
pascal@180
|
176 scroll_scenery:
|
pascal@180
|
177 ;
|
pascal@180
|
178 ; Move whole screen
|
pascal@180
|
179 ;
|
pascal@180
|
180 mov si,0x00a2 ; Point to row 1, column 1 in SI
|
pascal@180
|
181 mov di,0x00a0 ; Point to row 1, column 0 in DI
|
pascal@180
|
182 fb2: mov cx,79 ; 79 columns
|
pascal@180
|
183 repz ; Scroll!!!
|
pascal@180
|
184 movsw
|
pascal@180
|
185 mov ax,0x0e20 ; Clean last character
|
pascal@180
|
186 stosw
|
pascal@180
|
187 lodsw ; Advance source to keep pair source/target
|
pascal@180
|
188 cmp si,0x0fa2 ; All scrolled?
|
pascal@180
|
189 jnz fb2 ; No, jump
|
pascal@180
|
190 ;
|
pascal@180
|
191 ; Insert houses
|
pascal@180
|
192 ;
|
pascal@180
|
193 mov word [0x0f9e],0x02df ; Terrain
|
pascal@180
|
194 in al,(0x40) ; Get "random" number
|
pascal@180
|
195 and al,0x70
|
pascal@180
|
196 jz fb5
|
pascal@180
|
197 mov bx,0x0408 ; House of one floor
|
pascal@180
|
198 mov [0x0efe],bx
|
pascal@180
|
199 mov di,0x0e5e
|
pascal@180
|
200 and al,0x20 ; Check "random" number
|
pascal@180
|
201 jz fb3
|
pascal@180
|
202 mov [di],bx ; House of two floors
|
pascal@180
|
203 sub di,0x00a0
|
pascal@180
|
204 fb3: mov word [di],0x091e ; Add roof
|
pascal@180
|
205 ;
|
pascal@180
|
206 ; Check if it's time to insert a column
|
pascal@180
|
207 ;
|
pascal@180
|
208 fb5: dec word [next] ; Decrease time (column really) for next pipe
|
pascal@180
|
209 mov bx,[next]
|
pascal@180
|
210 cmp bx,0x03 ; bx = 3,2,1,0 for the four columns making the pipe
|
pascal@180
|
211 ja fb6
|
pascal@180
|
212 jne fb8
|
pascal@180
|
213 in al,(0x40) ; Get "random" number
|
pascal@180
|
214 and ax,0x0007 ; Between 0 and 7
|
pascal@180
|
215 add al,0x04 ; Between 4 and 11
|
pascal@180
|
216 mov [tall],ax ; This will tell how tall the pipe is
|
pascal@180
|
217 fb8: mov cx,[tall]
|
pascal@180
|
218 or bx,bx ; Rightmost?
|
pascal@180
|
219 mov dl,0xb0
|
pascal@180
|
220 jz fb7 ; Yes, jump
|
pascal@180
|
221 mov dl,0xdb
|
pascal@180
|
222 cmp bx,0x03 ; Leftmost?
|
pascal@180
|
223 jb fb7 ; No, jump
|
pascal@180
|
224 mov dl,0xb1
|
pascal@180
|
225 fb7: mov di,0x013e ; Start from top of screen
|
pascal@180
|
226 mov ah,0x0a
|
pascal@180
|
227 mov al,dl
|
pascal@180
|
228 mov dx,0x009e
|
pascal@180
|
229 fb9: stosw
|
pascal@180
|
230 add di,dx
|
pascal@180
|
231 loop fb9
|
pascal@180
|
232 mov al,0xc4
|
pascal@180
|
233 stosw
|
pascal@180
|
234 add di,0x009e*6+10
|
pascal@180
|
235 mov al,0xdf
|
pascal@180
|
236 stosw
|
pascal@180
|
237 add di,dx
|
pascal@180
|
238 fb10: mov al,dl
|
pascal@180
|
239 stosw
|
pascal@180
|
240 add di,dx
|
pascal@180
|
241 cmp di,0x0f00
|
pascal@180
|
242 jb fb10
|
pascal@180
|
243 or bx,bx
|
pascal@180
|
244 jnz fb6
|
pascal@180
|
245 mov ax,[pipe]
|
pascal@180
|
246 inc ax ; Increase total pipes shown
|
pascal@180
|
247 mov [pipe],ax
|
pascal@180
|
248 mov cl,3
|
pascal@180
|
249 shr ax,cl
|
pascal@180
|
250 mov ah,0x50 ; Decrease distance between pipes
|
pascal@180
|
251 sub ah,al
|
pascal@180
|
252 cmp ah,0x10
|
pascal@180
|
253 ja fb11
|
pascal@180
|
254 mov ah,0x10
|
pascal@180
|
255 fb11: mov [next],ah ; Time for next pipe
|
pascal@180
|
256 fb6: ret
|
pascal@180
|
257
|
pascal@180
|
258 ;
|
pascal@180
|
259 ; Wait for a frame
|
pascal@180
|
260 ;
|
pascal@180
|
261 wait_frame:
|
pascal@180
|
262
|
pascal@180
|
263 mov bx, tick
|
pascal@182
|
264 fb14: hlt ; Wait for clock interrupt
|
pascal@182
|
265 mov ah,0x00 ; Use base clock tick
|
pascal@180
|
266 int 0x1a
|
pascal@180
|
267 cmp dx,[bx]
|
pascal@180
|
268 jz fb14
|
pascal@180
|
269 mov [bx],dx
|
pascal@180
|
270 inc word [bx+frame-tick] ; Increase frame count
|
pascal@180
|
271 in al,(0x61)
|
pascal@180
|
272 and al,0xfc ; Turn off sound
|
pascal@180
|
273 out (0x61),al
|
pascal@180
|
274 ret
|
pascal@180
|
275
|
pascal@180
|
276 times 507 - ($-$$) db 0 ; pad remaining 507 bytes with zeroes
|
pascal@180
|
277
|
pascal@180
|
278 db "OTG" ; 3 unused bytes
|
pascal@180
|
279
|
pascal@180
|
280 db 0x55,0xaa ; Bootable signature
|
pascal@180
|
281
|
pascal@180
|
282 pipe: equ 0x0fa0
|
pascal@180
|
283 score: equ 0x0fa2
|
pascal@180
|
284 grav: equ 0x0fa4
|
pascal@180
|
285 next: equ 0x0fa6
|
pascal@180
|
286 bird: equ 0x0fa8
|
pascal@180
|
287 frame: equ 0x0faa
|
pascal@180
|
288 tall: equ 0x0fac
|
pascal@180
|
289 tick: equ 0x0fae
|