1
2void drawtank
(int num
)/*{{{*/
3{
4 int x
= tanks
[num
].x
;
5 int y
= tanks
[num
].y
;
6 int dir
= tanks
[num
].dir
;
7
8 //draw tank body and turret
9 al_draw_filled_rectangle(x-11, y-11, x
+11, y
+11, tanks
[num
].color
);
10 al_draw_filled_rectangle(x-6, y-6, x
+6, y
+6, GREY
);
11
12 //draw the treads based on orientation
13 if (dir
== 0 || dir
== 2)
14 {
15 al_draw_filled_rectangle(x-16, y-16, x-11, y
+16, DARK_GREY
);
16 al_draw_filled_rectangle(x
+11, y-16, x
+16, y
+16, DARK_GREY
);
17 }
18 else
19 if (dir
== 1 || dir
== 3)
20 {
21 al_draw_filled_rectangle(x-16, y-16, x
+16, y-11, DARK_GREY
);
22 al_draw_filled_rectangle(x-16, y
+16, x
+16, y
+11, DARK_GREY
);
23 }
24
25 //draw the turret based on direction
26 switch (dir
)
27 {
28 case 0:
29 al_draw_filled_rectangle(x-1, y, x
+1, y-16, DARK_GREY
);
30 break;
31 case 1:
32 al_draw_filled_rectangle(x, y-1, x
+16, y
+1, DARK_GREY
);
33 break;
34 case 2:
35 al_draw_filled_rectangle(x-1, y, x
+1, y
+16, DARK_GREY
);
36 break;
37 case 3:
38 al_draw_filled_rectangle(x, y-1, x-16, y
+1, DARK_GREY
);
39 break;
40 }
41 al_flip_display();
42}/*}}}*/
43
44
45void erasetank
(int num
)/*{{{*/
46{
47 //calculate box to encompass the tank
48 int left
= tanks
[num
].x
- 17;
49 int top
= tanks
[num
].y
- 17;
50 int right
= tanks
[num
].x
+ 17;
51 int bottom
= tanks
[num
].y
+ 17;
52
53 //erase the tank
54 al_draw_filled_rectangle(left, top, right, bottom, BLACK
);
55 al_flip_display();
56}/*}}}*/
57
58
59void movetank
(int num
)/*{{{*/
60{
61 int dir
= tanks
[num
].dir
;
62 int speed
= tanks
[num
].speed
;
63
64 //update tank position based on direction
65 switch(dir
)
66 {
67 case 0:
68 tanks
[num
].y
-= speed
;
69 break;
70 case 1:
71 tanks
[num
].x
+= speed
;
72 break;
73 case 2:
74 tanks
[num
].y
+= speed
;
75 break;
76 case 3:
77 tanks
[num
].x
-= speed
;
78 }
79
80 //keep tank inside the screen
81 if (tanks
[num
].x
> WIDTH-22
)
82 {
83 tanks
[num
].x
= WIDTH-22
;
84 tanks
[num
].speed
= 0;
85 }
86 if (tanks
[num
].x
< 22)
87 {
88 tanks
[num
].x
= 22;
89 tanks
[num
].speed
= 0;
90 }
91 if (tanks
[num
].y
> HEIGHT-22
)
92 {
93 tanks
[num
].y
= HEIGHT-22
;
94 tanks
[num
].speed
= 0;
95 }
96 if (tanks
[num
].y
< 22)
97 {
98 tanks
[num
].y
= 22;
99 tanks
[num
].speed
= 0;
100 }
101}/*}}}*/
102
103
104void explode
(int num,
int x,
int y
)/*{{{*/
105{
106
107 int n
;
108
109 //retrieve location of enemy tank
110 int tx
= tanks
[!num
].x
;
111 int ty
= tanks
[!num
].y
;
112
113 //is bullet inside the boundary of the enemy tank?
114 if (x
> tx-16
&& x
< tx
+16 && y
> ty-16
&& y
< ty
+16)
115 score
(num
);
116
117 //draw some random circles for the "explosion"
118 for (n
= 0; n
< 10; n
++)
119 {
120 al_draw_filled_rectangle(x-16, y-16, x
+16, y
+16, RANDOM_COLOUR
);
121 /* rest(1); */
122 }
123
124 //clear the area of debris
125 al_draw_filled_rectangle(x-16, y-16, x
+16, y
+16, BLACK
);
126 al_flip_display();
127}/*}}}*/
128
129int cmp_colour
(int x,
int y,
char r,
char g,
char b
) {/*{{{*/
130 unsigned char pixelr, pixelg, pixelb
;
131
132 al_unmap_rgb(al_get_pixel(screen, x, y
),
&pixelr,
&pixelg,
&pixelb
);
133 if (r
== pixelr
&& g
== pixelg
&& b
== pixelb
)
134 return 1;
135 return 0;
136}/*}}}*/
137
138
139void updatebullet
(int num
)/*{{{*/
140{
141 int x
= bullets
[num
].x
;
142 int y
= bullets
[num
].y
;
143
144 if (bullets
[num
].alive
)
145 {
146 //erase bullet
147 al_draw_rectangle(x-1, y-1, x
+1, y
+1, BLACK,
0);
148
149 //move bullet
150 bullets
[num
].x
+= bullets
[num
].xspd
;
151 bullets
[num
].y
+= bullets
[num
].yspd
;
152 x
= bullets
[num
].x
;
153 y
= bullets
[num
].y
;
154
155 //stay within the screen
156 if (x
< 5 || x
> WIDTH-5
|| y
< 20 || y
> HEIGHT-5
)
157 {
158 bullets
[num
].alive
= 0;
159 return;
160 }
161
162 //draw bullet
163 x
= bullets
[num
].x
;
164 y
= bullets
[num
].y
;
165 al_draw_rectangle(x-1, y-1, x
+1, y
+1, YELLOW,
0);
166
167 //look for a hit
168 if (cmp_colour
(bullets
[num
].x, bullets
[num
].y,
0xff,
0xff,
0xff)) // black
169 {
170 bullets
[num
].alive
= 0;
171 explode
(num, x, y
);
172 }
173
174 //print the bullet's position
175 //al_draw_textf(font, al_map_rgb(255, 255, 255), WIDTH/2-50, 1, 2, "B1 %-3dx%-3d B2 %-3dx%-3d", bullets[0].x, bullets[0].y, bullets[1].x, bullets[1].y);
176 }
177 al_flip_display();
178}/*}}}*/
179
180
181int checkpath
(int x1,
int y1,
int x2,
int y2,
int x3,
int y3
)/*{{{*/
182{
183 if (cmp_colour
(x1, y1,
0xff,
0xff,
0xff) ||
184 cmp_colour
(x2, y2,
0xff,
0xff,
0xff) ||
185 cmp_colour
(x3, y3,
0xff,
0xff,
0xff))
186 return 1;
187 else
188 return 0;
189}/*}}}*/
190
191void clearpath
(int num
)/*{{{*/
192{
193 //shortcut vars
194 int dir
= tanks
[num
].dir
;
195 int speed
= tanks
[num
].speed
;
196 int x
= tanks
[num
].x
;
197 int y
= tanks
[num
].y
;
198
199 switch(dir
)
200 {
201 //check pixels north
202 case 0:
203 if (speed
> 0)
204 {
205 if (checkpath
(x-16, y-20, x, y-20, x
+16, y-20
))
206 tanks
[num
].speed
= 0;
207 }
208 else
209 //if reverse dir, check south
210 if (checkpath
(x-16, y
+20, x, y
+20, x
+16, y
+20))
211 tanks
[num
].speed
= 0;
212 break;
213
214 //check pixels east
215 case 1:
216 if (speed
> 0)
217 {
218 if (checkpath
(x
+20, y-16, x
+20, y, x
+20, y
+16))
219 tanks
[num
].speed
= 0;
220 }
221 else
222 //if reverse dir, check west
223 if (checkpath
(x-20, y-16, x-20, y, x-20, y
+16))
224 tanks
[num
].speed
= 0;
225 break;
226
227 //check pixels south
228 case 2:
229 if (speed
> 0)
230 {
231 if (checkpath
(x-16, y
+20, x, y
+20, x
+16, y
+20 ))
232 tanks
[num
].speed
= 0;
233 }
234 else
235 //if reverse dir, check north
236 if (checkpath
(x-16, y-20, x, y-20, x
+16, y-20
))
237 tanks
[num
].speed
= 0;
238 break;
239
240 //check pixels west
241 case 3:
242 if (speed
> 0)
243 {
244 if (checkpath
(x-20, y-16, x-20, y, x-20, y
+16))
245 tanks
[num
].speed
= 0;
246 }
247 else
248 //if reverse dir, check east
249 if (checkpath
(x
+20, y-16, x
+20, y, x
+20, y
+16))
250 tanks
[num
].speed
= 0;
251 break;
252 }
253}/*}}}*/
254
255
256void fireweapon
(int num
)/*{{{*/
257{
258 int x
= tanks
[num
].x
;
259 int y
= tanks
[num
].y
;
260
261 //ready to fire again?
262 if (!bullets
[num
].alive
)
263 {
264 bullets
[num
].alive
= 1;
265
266 //fire bullet in direction tank is facing
267 switch (tanks
[num
].dir
)
268 {
269 //north
270 case 0:
271 bullets
[num
].x
= x
;
272 bullets
[num
].y
= y-22
;
273 bullets
[num
].xspd
= 0;
274 bullets
[num
].yspd
= -BULLETSPEED
;
275 break;
276 //east
277 case 1:
278 bullets
[num
].x
= x
+22;
279 bullets
[num
].y
= y
;
280 bullets
[num
].xspd
= BULLETSPEED
;
281 bullets
[num
].yspd
= 0;
282 break;
283 //south
284 case 2:
285 bullets
[num
].x
= x
;
286 bullets
[num
].y
= y
+22;
287 bullets
[num
].xspd
= 0;
288 bullets
[num
].yspd
= BULLETSPEED
;
289 break;
290 //west
291 case 3:
292 bullets
[num
].x
= x-22
;
293 bullets
[num
].y
= y
;
294 bullets
[num
].xspd
= -BULLETSPEED
;
295 bullets
[num
].yspd
= 0;
296 }
297 }
298}
299void forward
(int num
)/*{{{*/
300{
301 tanks
[num
].speed
++;
302 if (tanks
[num
].speed
> MAXSPEED
)
303 tanks
[num
].speed
= MAXSPEED
;
304}/*}}}*/
305
306
307void backward
(int num
)/*{{{*/
308{
309 tanks
[num
].speed--
;
310 if (tanks
[num
].speed
< -MAXSPEED
)
311 tanks
[num
].speed
= -MAXSPEED
;
312}/*}}}*/
313
314
315void turnleft
(int num
)/*{{{*/
316{
317 tanks
[num
].dir--
;
318 if (tanks
[num
].dir
< 0)
319 tanks
[num
].dir
= 3;
320}
321
322void turnright
(int num
)/*{{{*/
323{
324 tanks
[num
].dir
++;
325 if (tanks
[num
].dir
> 3)
326 tanks
[num
].dir
= 0;
327}
328void getinput
()/*{{{*/
329{
330 ALLEGRO_EVENT ev
;
331 al_wait_for_event(event_queue,
&ev
);
332 if (ev.type
!= ALLEGRO_EVENT_KEY_DOWN
)
333 ;
334 else if (ev.keyboard.keycode
== ALLEGRO_KEY_ESCAPE
)
335 gameOver
= 1;
336 else if (ev.keyboard.keycode
== ALLEGRO_KEY_UP
)
337 forward
(1);
338 else if (ev.keyboard.keycode
== ALLEGRO_KEY_DOWN
)
339 backward
(1);
340 else if (ev.keyboard.keycode
== ALLEGRO_KEY_RIGHT
)
341 turnright
(1);
342 else if (ev.keyboard.keycode
== ALLEGRO_KEY_LEFT
)
343 turnleft
(1);
344 else if (ev.keyboard.keycode
== ALLEGRO_KEY_ENTER
)
345 fireweapon
(1);
346
347 else if (ev.keyboard.keycode
== ALLEGRO_KEY_W
)
348 forward
(0);
349 else if (ev.keyboard.keycode
== ALLEGRO_KEY_D
)
350 turnright
(0);
351 else if (ev.keyboard.keycode
== ALLEGRO_KEY_A
)
352 turnleft
(0);
353 else if (ev.keyboard.keycode
== ALLEGRO_KEY_S
)
354 backward
(0);
355 else if (ev.keyboard.keycode
== ALLEGRO_KEY_SPACE
)
356 fireweapon
(0);
357
358 //short delay after keypress
359 /* rest(10); */
360}
361void score
(int player
)/*{{{*/
362{
363 //update score
364 int points
= ++tanks
[player
].score
;
365
366 //display score
367 //al_draw_textf(font, BURST, WIDTH-70*(player+1), 1, 0, "P%d: %d", player+1, points);
368 al_flip_display();
369}
370
371void setuptanks
()/*{{{*/
372{
373 //player 1
374 tanks
[0].x
= 30;
375 tanks
[0].y
= 40;
376 tanks
[0].dir
= 1;
377 tanks
[0].speed
= 0;
378 tanks
[0].color
= BLUE
;
379 tanks
[0].score
= 0;
380
381 //player 2
382 tanks
[1].x
= WIDTH-30
;
383 tanks
[1].y
= HEIGHT-30
;
384 tanks
[1].dir
= 3;
385 tanks
[1].speed
= 0;
386 tanks
[1].color
= RED
;
387 tanks
[1].score
= 0;
388}/*}}}*/
389
390
391void setupdebris
()/*{{{*/
392{
393 int n,x,y,size,color
;
394
395 //fill the battlefield with random debris
396 for (n
= 0; n
< BLOCKS
; n
++)
397 {
398 x
= BLOCKSIZE
+ rand() %
(WIDTH-BLOCKSIZE
*2);
399 y
= BLOCKSIZE
+ rand() %
(HEIGHT-BLOCKSIZE
*2);
400 size
= (10 + rand() % BLOCKSIZE
)/2;
401 al_draw_filled_rectangle(x-size, y-size, x
+size, y
+size, RANDOM_COLOUR
);
402 }
403 al_flip_display();
404
405}/*}}}*/
406
407
408void setupscreen
()/*{{{*/
409{
410#if 0
411 //set video mode
412 int ret
= set_gfx_mode(MODE, WIDTH, HEIGHT,
0,
0);
413 if (ret
!= 0) {
414 allegro_message(allegro_error);
415 return;
416 }
417#endif
418
419 al_set_target_bitmap(screen);
420 //print title
421 //al_draw_textf(font, BURST, 1, 1, 0, "Tank War - %dx%d", WIDTH, HEIGHT);
422
423 //draw screen border
424 al_draw_rectangle(0,
12, WIDTH-1, HEIGHT-1, TAN,
0);
425 al_draw_rectangle(1,
13, WIDTH-2, HEIGHT-2, TAN,
0);
426 al_flip_display();
427}/*}}}*/
428
429
430int main
(int argc,
char **argv
)/*{{{*/
431{
432
433 bool done
= false;
434 bool render
= false;
435
436 float gameTime
= 0;
437 int frames
= 0;
438 int gameFPS
= 0;
439
440
441 ALLEGRO_DISPLAY *display
= NULL
;
442 ALLEGRO_EVENT_QUEUE *event_queue
= NULL
;
443 ALLEGRO_TIMER *timer
;
444 ALLEGRO_FONT *font;
445
446
447 al_install_keyboard();
448 al_init_image_addon();
449 al_init_font_addon();
450 al_init_ttf_addon();
451 al_init_primitives_addon();
452
453
454
455 font = al_load_font("arial.ttf",
18,
0);
456
457
458 event_queue
= al_create_event_queue();
459 timer
= al_create_timer(1.
0 / 60);
460
461 al_register_event_source(event_queue,
al_get_timer_event_source(timer
));
462 al_register_event_source(event_queue,
al_get_keyboard_event_source());
463
464 al_start_timer(timer
);
465 gameTime
= al_current_time
();
466
467 //initialize everything
468
469 if (!al_init()) {
470 printf("Failed to initialize Allegro library.\n");
471 return 1;
472 }
473
474 if (!al_install_keyboard()) {
475 printf("Failed to install keyboard.\n");
476 return 1;
477 }
478
479 /* install_timer(); */
480 srand(time(NULL
));
481 al_init_font_addon();
482 if (!(display
= al_create_display(640,
480))) {
483 printf("Failed to create display.\n");
484 return 1;
485 }
486
487 ALLEGRO_PATH
*path
= al_get_standard_path(ALLEGRO_RESOURCES_PATH
);
488 al_append_path_component(path,
"resources");
489 al_change_directory(al_path_cstr(path,
'/')); // change the working directory
490 printf("Should be in %s\n",
al_path_cstr(path,
'/'));
491 font = al_load_ttf_font("Airacobra Alt.ttf",
72,
0);
492 if (!font) {
493 printf("Error loading Airacobra Alt.ttf.\n");
494 return 1;
495 }
496 al_destroy_path(path
);
497
498 setupscreen
();
499 setupdebris
();
500 setuptanks
();
501
502 //game loop
503 while(!gameOver
)
504 {
505#if 0
506 //erase the tanks
507 erasetank
(0);
508 erasetank
(1);
509
510 //check for collisions
511 clearpath
(0);
512 clearpath
(1);
513
514 //move the tanks
515 movetank
(0);
516 movetank
(1);
517#endif
518
519 //draw the tanks
520 drawtank
(0);
521 drawtank
(1);
522
523#if 0
524 //update the bullets
525 updatebullet
(0);
526 updatebullet
(1);
527#endif
528
529 //check for keypresses
530 ALLEGRO_EVENT ev
;
531 al_wait_for_event(event_queue,
&ev
);
532 if (ev.type
== ALLEGRO_EVENT_KEY_DOWN
)
533 getinput
();
534
535 //slow the game down (adjust as necessary)
536 al_rest(30);
537 }
538
539 //end program
540 return 0;
541}/*}}}*/