1org 0x7C00
2
3; Entry point: BIOS loads this at 0x7C00 and jumps here
4start:
5 ; Set video mode to 13h: 320x200 pixels, 256 colors
6 mov ax, 0x0013
7 int 0x10
8
9 ; ES = 0xA000 is the segment for VGA memory
10 push 0xA000
11 pop es
12
13 ; Clear AX and set Data Segment to 0
14 xor ax, ax
15 mov ds, ax
16
17 ; Initialize game variables
18 mov word [player_x], 155
19 mov word [enemy_x], 100
20 mov word [enemy_y], 0
21 mov byte [bullet_active], 0
22 mov word [score], 0
23
24game_loop:
25 ; Use BIOS timer (ticks at 18.2Hz) for consistent game speed
26 mov ah, 0x00
27 int 0x1A
28 mov bx, dx
29
30timer_wait:
31 int 0x1A
32 cmp dx, bx
33 je timer_wait
34
35 ; Wait for vertical retrace to prevent screen flickering
36 mov dx, 0x3DA
37
38retrace_wait:
39 in al, dx
40 test al, 8
41 jz retrace_wait
42
43 ; Clear the entire screen (64000 pixels) with color 0 (black)
44 xor di, di
45 xor al, al
46 mov cx, 64000
47 rep stosb
48
49 ; Move cursor to (0,0) and print the current score
50 xor dx, dx
51 mov ah, 0x02
52 xor bh, bh
53 int 0x10
54 mov ax, [score]
55 call print_num
56
57 ; Check if a key is waiting in the keyboard buffer
58 mov ah, 0x01
59 int 0x16
60 jz update_physics
61
62 ; Get the actual key pressed
63 mov ah, 0x00
64 int 0x16
65
66 ; Handle Arrow keys (scan codes) and Space bar
67 cmp ah, 0x4B ; Left Arrow
68 je move_left
69 cmp ah, 0x4D ; Right Arrow
70 je move_right
71 cmp ah, 0x39 ; Space Bar
72 je fire_bullet
73 jmp update_physics
74
75move_left:
76 sub word [player_x], 10
77 jnc update_physics
78 mov word [player_x], 0
79 jmp update_physics
80
81move_right:
82 add word [player_x], 10
83 cmp word [player_x], 310
84 jbe update_physics
85 mov word [player_x], 310
86 jmp update_physics
87
88fire_bullet:
89 ; Allow only one bullet on screen at a time
90 cmp byte [bullet_active], 0
91 jnz update_physics
92 mov byte [bullet_active], 1
93 mov ax, [player_x]
94 add ax, 4 ; Center bullet relative to player ship
95 mov [bullet_x], ax
96 mov word [bullet_y], 175
97
98update_physics:
99 ; Process bullet movement if active
100 cmp byte [bullet_active], 0
101 jz update_enemy
102 sub word [bullet_y], 10
103 jnc bullet_in_bounds
104 mov byte [bullet_active], 0
105 jmp update_enemy
106
107bullet_in_bounds:
108 ; Collision check: Bullet vs Enemy (Bounding box)
109 mov ax, [bullet_y]
110 sub ax, [enemy_y]
111 add ax, 4
112 cmp ax, 19
113 ja update_enemy
114 mov ax, [bullet_x]
115 sub ax, [enemy_x]
116 add ax, 2
117 cmp ax, 17
118 ja update_enemy
119
120 ; If hit: Kill bullet, increase score, and respawn enemy
121 mov byte [bullet_active], 0
122 inc word [score]
123 jmp respawn_enemy
124
125update_enemy:
126 ; Move enemy down by 2 pixels
127 add word [enemy_y], 2
128 cmp word [enemy_y], 200
129 jae respawn_enemy
130
131 ; Collision check: Player vs Enemy
132 mov ax, [enemy_y]
133 add ax, 15 ; Enemy height
134 cmp ax, 185 ; Player Y start
135 jb draw_game
136
137 ; Bounding box check for X axis
138 mov ax, [player_x]
139 sub ax, [enemy_x]
140 add ax, 10
141 cmp ax, 25
142 jbe game_over
143
144respawn_enemy:
145 ; Reset enemy to top at a "random" X position based on system clock
146 mov word [enemy_y], 0
147 xor ax, ax
148 int 0x1A
149 mov ax, dx
150 xor dx, dx
151 mov bx, 305
152 div bx ; Divide clock ticks by 305 to get X in screen range
153 mov [enemy_x], dx
154
155draw_game:
156 ; Render Player (10x5 Blue rectangle)
157 mov ax, 185
158 mov bx, [player_x]
159 mov si, 10
160 mov dx, 5
161 mov cl, 1 ; Color Blue
162 call rect
163
164 ; Render Bullet (2x4 Yellow rectangle) if active
165 cmp byte [bullet_active], 0
166 jz skip_bullet_draw
167 mov ax, [bullet_y]
168 mov bx, [bullet_x]
169 mov si, 2
170 mov dx, 4
171 mov cl, 14 ; Color Yellow
172 call rect
173
174skip_bullet_draw:
175 ; Render Enemy (15x15 Red rectangle)
176 mov ax, [enemy_y]
177 mov bx, [enemy_x]
178 mov si, 15
179 mov dx, 15
180 mov cl, 4 ; Color Red
181 call rect
182 jmp game_loop
183
184game_over:
185 ; Display Game Over message in middle of screen
186 mov dx, 0x0C0E ; Position: Row 12, Column 14
187 mov ah, 0x02
188 xor bh, bh
189 int 0x10
190 mov si, msg_gameover
191
192print_msg:
193 lodsb
194 test al, al
195 jz wait_key
196 mov ah, 0x0E
197 int 0x10
198 jmp print_msg
199
200wait_key:
201 ; Wait for any key press to restart the game
202 mov ah, 0x00
203 int 0x16
204 jmp start
205
206; Subroutine: Convert number in AX to decimal and print to screen
207print_num:
208 mov bx, 10
209 xor cx, cx
210
211digit_loop:
212 xor dx, dx
213 div bx
214 push dx
215 inc cx
216 test ax, ax
217 jnz digit_loop
218
219char_loop:
220 pop ax
221 add al, '0'
222 mov ah, 0x0E
223 int 0x10
224 loop char_loop
225 ret
226
227; Subroutine: Draw a rectangle
228; Inputs: AX=Y, BX=X, SI=Width, DX=Height, CL=Color
229rect:
230 mov bp, dx
231 mov dx, 320
232 mul dx
233 add ax, bx
234 mov di, ax ; Destination offset in VGA memory
235 mov al, cl
236
237draw_rect_loop:
238 push di
239 mov cx, si
240 rep stosb ; Fill row with color
241 pop di
242 add di, 320 ; Move to next pixel row
243 dec bp
244 jnz draw_rect_loop
245 ret
246
247; Game variables and strings
248player_x dw 0
249enemy_x dw 0
250enemy_y dw 0
251bullet_active db 0
252bullet_x dw 0
253bullet_y dw 0
254score dw 0
255msg_gameover db 'GAME OVER', 0
256
257; Pad file to 510 bytes and add the 0xAA55 boot signature
258times 510-($-$$) db 0
259dw 0xAA55