1 /*
2 vectoroids.c
3
4 An asteroid shooting game with vector graphics.
5 Based on "Agendaroids."
6
7 by Bill Kendrick
8 bill@newbreedsoftware.com
9 http://www.newbreedsoftware.com/vectoroids/
10
11 November 30, 2001 - April 20, 2002
12 */
13
14 #define VER_VERSION "1.1.0"
15 #define VER_DATE "2002.04.20"
16
17 #ifndef EMBEDDED
18 #define STATE_FORMAT_VERSION "2001.12.01"
19 #else
20 #define STATE_FORMAT_VERSION "2001.12.01e"
21 #endif
22
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <SDL.h>
28 #include <SDL_image.h>
29 #ifndef NOSOUND
30 #include <SDL_mixer.h>
31 #endif
32
33
34 #ifndef DATA_PREFIX
35 #define DATA_PREFIX "data/"
36 #endif
37
38
39 /* Constraints: */
40
41 #ifndef EMBEDDED
42 #define NUM_BULLETS 2
43 #else
44 #define NUM_BULLETS 3
45 #endif
46
47 #ifndef EMBEDDED
48 #define NUM_ASTEROIDS 20
49 #define NUM_BITS 50
50 #else
51 #define NUM_ASTEROIDS 15
52 #define NUM_BITS 25
53 #endif
54
55 #define AST_SIDES 6
56 #ifndef EMBEDDED
57 #define AST_RADIUS 10
58 #define SHIP_RADIUS 20
59 #else
60 #define AST_RADIUS 7
61 #define SHIP_RADIUS 12
62 #endif
63
64 #define ZOOM_START 40
65 #define ONEUP_SCORE 10000
66 #define FPS 50
67
68 #ifndef EMBEDDED
69 #define WIDTH 480
70 #define HEIGHT 480
71 #else
72 #define WIDTH 240
73 #define HEIGHT 320
74 #endif
75
76
77
78 enum { FALSE, TRUE };
79
80 #define LEFT_EDGE 0x0001
81 #define RIGHT_EDGE 0x0002
82 #define TOP_EDGE 0x0004
83 #define BOTTOM_EDGE 0x0008
84
85
86 /* Types: */
87
88 typedef struct letter_type {
89 int x, y;
90 int xm, ym;
91 } letter_type;
92
93 typedef struct bullet_type {
94 int timer;
95 int x, y;
96 int xm, ym;
97 } bullet_type;
98
99 typedef struct shape_type {
100 int radius;
101 int angle;
102 } shape_type;
103
104 typedef struct asteroid_type {
105 int alive, size;
106 int x, y;
107 int xm, ym;
108 int angle, angle_m;
109 shape_type shape[AST_SIDES];
110 } asteroid_type;
111
112 typedef struct bit_type {
113 int timer;
114 int x, y;
115 int xm, ym;
116 } bit_type;
117
118 typedef struct color_type {
119 Uint8 r;
120 Uint8 g;
121 Uint8 b;
122 } color_type;
123
124
125 /* Data: */
126
127 enum {
128 SND_BULLET,
129 SND_AST1,
130 SND_AST2,
131 SND_AST3,
132 SND_AST4,
133 SND_THRUST,
134 SND_EXPLODE,
135 SND_GAMEOVER,
136 SND_EXTRALIFE,
137 NUM_SOUNDS
138 };
139
140 char * sound_names[NUM_SOUNDS] = {
141 DATA_PREFIX "sounds/bullet.wav",
142 DATA_PREFIX "sounds/ast1.wav",
143 DATA_PREFIX "sounds/ast2.wav",
144 DATA_PREFIX "sounds/ast3.wav",
145 DATA_PREFIX "sounds/ast4.wav",
146 DATA_PREFIX "sounds/thrust.wav",
147 DATA_PREFIX "sounds/explode.wav",
148 DATA_PREFIX "sounds/gameover.wav",
149 DATA_PREFIX "sounds/extralife.wav"
150 };
151
152 #define CHAN_THRUST 0
153
154 char * mus_game_name = DATA_PREFIX "music/decision.s3m";
155
156
157 #ifdef JOY_YES
158 #define JOY_A 0
159 #define JOY_B 1
160 #define JOY_X 0
161 #define JOY_Y 1
162 #endif
163
164
165 /* Globals: */
166
167 SDL_Surface * screen, * bkgd;
168 #ifndef NOSOUND
169 Mix_Chunk * sounds[NUM_SOUNDS];
170 Mix_Music * game_music;
171 #endif
172 #ifdef JOY_YES
173 SDL_Joystick *js;
174 #endif
175 bullet_type bullets[NUM_BULLETS];
176 asteroid_type asteroids[NUM_ASTEROIDS];
177 bit_type bits[NUM_BITS];
178 int use_sound, use_joystick, fullscreen, text_zoom;
179 char zoom_str[24];
180 int x, y, xm, ym, angle;
181 int player_alive, player_die_timer;
182 int lives, score, high, level, game_pending;
183
184
185 /* Trig junk: (thanks to Atari BASIC for this) */
186
187 int trig[12] = {
188 1024,
189 1014,
190 984,
191 935,
192 868,
193 784,
194 685,
195 572,
196 448,
197 316,
198 117,
199 0
200 };
201
202
203 /* Characters: */
204
205 int char_vectors[36][5][4] = {
206 {
207 /* 0 */
208 { 0, 0, 1, 0 },
209 { 1, 0, 1, 2 },
210 { 1, 2, 0, 2 },
211 { 0, 2, 0, 0 },
212 { -1, -1, -1, -1 }
213 },
214
215 {
216 /* 1 */
217 { 1, 0, 1, 2 },
218 { -1, -1, -1, -1 },
219 { -1, -1, -1, -1 },
220 { -1, -1, -1, -1 },
221 { -1, -1, -1, -1 }
222 },
223
224 {
225 /* 2 */
226 { 1, 0, 0, 0 },
227 { 1, 0, 1, 1 },
228 { 0, 1, 1, 1 },
229 { 0, 1, 0, 2 },
230 { 1, 2, 0, 2 },
231 },
232
233 {
234 /* 3 */
235 { 0, 0, 1, 0 },
236 { 1, 0, 1, 2 },
237 { 0, 1, 1, 1 },
238 { 0, 2, 1, 2 },
239 { -1, -1, -1, -1 }
240 },
241
242 {
243 /* 4 */
244 { 1, 0, 1, 2 },
245 { 0, 0, 0, 1 },
246 { 0, 1, 1, 1 },
247 { -1, -1, -1, -1 },
248 { -1, -1, -1, -1 }
249 },
250
251 {
252 /* 5 */
253 { 1, 0, 0, 0 },
254 { 0, 0, 0, 1 },
255 { 0, 1, 1, 1 },
256 { 1, 1, 1, 2 },
257 { 1, 2, 0, 2 }
258 },
259
260 {
261 /* 6 */
262 { 1, 0, 0, 0 },
263 { 0, 0, 0, 2 },
264 { 0, 2, 1, 2 },
265 { 1, 2, 1, 1 },
266 { 1, 1, 0, 1 }
267 },
268
269 {
270 /* 7 */
271 { 0, 0, 1, 0 },
272 { 1, 0, 1, 2 },
273 { -1, -1, -1, -1 },
274 { -1, -1, -1, -1 },
275 { -1, -1, -1, -1 }
276 },
277
278 {
279 /* 8 */
280 { 0, 0, 1, 0 },
281 { 0, 0, 0, 2 },
282 { 1, 0, 1, 2 },
283 { 0, 2, 1, 2 },
284 { 0, 1, 1, 1 }
285 },
286
287 {
288 /* 9 */
289 { 1, 0, 1, 2 },
290 { 0, 0, 1, 0 },
291 { 0, 0, 0, 1 },
292 { 0, 1, 1, 1 },
293 { -1, -1, -1, -1 }
294 },
295
296 {
297 /* A */
298 { 0, 2, 0, 1 },
299 { 0, 1, 1, 0 },
300 { 1, 0, 1, 2 },
301 { 0, 1, 1, 1 },
302 { -1, -1, -1, -1 }
303 },
304
305 {
306 /* B */
307 { 0, 2, 0, 0 },
308 { 0, 0, 1, 0 },
309 { 1, 0, 0, 1 },
310 { 0, 1, 1, 2 },
311 { 1, 2, 0, 2 }
312 },
313
314 {
315 /* C */
316 { 1, 0, 0, 0 },
317 { 0, 0, 0, 2 },
318 { 0, 2, 1, 2 },
319 { -1, -1, -1, -1 },
320 { -1, -1, -1, -1 }
321 },
322
323 {
324 /* D */
325 { 0, 0, 1, 1 },
326 { 1, 1, 0, 2 },
327 { 0, 2, 0, 0 },
328 { -1, -1, -1, -1 },
329 { -1, -1, -1, -1 }
330 },
331
332 {
333 /* E */
334 { 1, 0, 0, 0 },
335 { 0, 0, 0, 2 },
336 { 0, 2, 1, 2 },
337 { 0, 1, 1, 1 },
338 { -1, -1, -1, -1 }
339 },
340
341 {
342 /* F */
343 { 1, 0, 0, 0 },
344 { 0, 0, 0, 2 },
345 { 0, 1, 1, 1 },
346 { -1, -1, -1, -1 },
347 { -1, -1, -1, -1 }
348 },
349
350 {
351 /* G */
352 { 1, 0, 0, 0 },
353 { 0, 0, 0, 2 },
354 { 0, 2, 1, 2 },
355 { 1, 2, 1, 1 },
356 { -1, -1, -1, -1 }
357 },
358
359 {
360 /* H */
361 { 0, 0, 0, 2 },
362 { 1, 0, 1, 2 },
363 { 0, 1, 1, 1 },
364 { -1, -1, -1, -1 },
365 { -1, -1, -1, -1 }
366 },
367
368 {
369 /* I */
370 { 1, 0, 1, 2 },
371 { -1, -1, -1, -1 },
372 { -1, -1, -1, -1 },
373 { -1, -1, -1, -1 },
374 { -1, -1, -1, -1 }
375 },
376
377 {
378 /* J */
379 { 1, 0, 1, 2 },
380 { 1, 2, 0, 2 },
381 { 0, 2, 0, 1 },
382 { -1, -1, -1, -1 },
383 { -1, -1, -1, -1 }
384 },
385
386 {
387 /* K */
388 { 0, 0, 0, 2 },
389 { 1, 0, 0, 1 },
390 { 0, 1, 1, 2 },
391 { -1, -1, -1, -1 },
392 { -1, -1, -1, -1 }
393 },
394
395 {
396 /* L */
397 { 0, 0, 0, 2 },
398 { 0, 2, 1, 2 },
399 { -1, -1, -1, -1 },
400 { -1, -1, -1, -1 },
401 { -1, -1, -1, -1 }
402 },
403
404 {
405 /* M */
406 { 0, 0, 0, 2 },
407 { 1, 0, 1, 2 },
408 { 0, 0, 1, 1 },
409 { 0, 1, 1, 0 },
410 { -1, -1, -1, -1 }
411 },
412
413 {
414 /* N */
415 { 0, 2, 0, 0 },
416 { 0, 0, 1, 2 },
417 { 1, 2, 1, 0 },
418 { -1, -1, -1, -1 },
419 { -1, -1, -1, -1 }
420 },
421
422 {
423 /* O */
424 { 0, 0, 1, 0 },
425 { 1, 0, 1, 2 },
426 { 1, 2, 0, 2 },
427 { 0, 2, 0, 0 },
428 { -1, -1, -1, -1 }
429 },
430
431 {
432 /* P */
433 { 0, 2, 0, 0 },
434 { 0, 0, 1, 0 },
435 { 1, 0, 1, 1 },
436 { 1, 1, 0, 1 },
437 { -1, -1, -1, -1 }
438 },
439
440 {
441 /* Q */
442 { 0, 0, 1, 0 },
443 { 1, 0, 1, 2 },
444 { 1, 2, 0, 2 },
445 { 0, 2, 0, 0 },
446 { 0, 1, 1, 2 }
447 },
448
449 {
450 /* R */
451 { 0, 2, 0, 0 },
452 { 0, 0, 1, 0 },
453 { 1, 0, 1, 1 },
454 { 1, 1, 0, 1 },
455 { 0, 1, 1, 2 }
456 },
457
458 {
459 /* S */
460 { 1, 0, 0, 0 },
461 { 0, 0, 0, 1 },
462 { 0, 1, 1, 1 },
463 { 1, 1, 1, 2 },
464 { 1, 2, 0, 2 }
465 },
466
467 {
468 /* T */
469 { 0, 0, 1, 0 },
470 { 1, 0, 1, 2 },
471 { -1, -1, -1, -1 },
472 { -1, -1, -1, -1 },
473 { -1, -1, -1, -1 }
474 },
475
476 {
477 /* U */
478 { 0, 0, 0, 2 },
479 { 0, 2, 1, 2 },
480 { 1, 2, 1, 0 },
481 { -1, -1, -1, -1 },
482 { -1, -1, -1, -1 }
483 },
484
485 {
486 /* V */
487 { 0, 0, 0, 1 },
488 { 0, 1, 1, 2 },
489 { 1, 2, 1, 0 },
490 { -1, -1, -1, -1 },
491 { -1, -1, -1, -1 }
492 },
493
494 {
495 /* W */
496 { 0, 0, 0, 2 },
497 { 1, 0, 1, 2 },
498 { 0, 1, 1, 2 },
499 { 0, 2, 1, 1 },
500 { -1, -1, -1, -1 }
501 },
502
503 {
504 /* X */
505 { 0, 0, 1, 2 },
506 { 0, 2, 1, 0 },
507 { -1, -1, -1, -1 },
508 { -1, -1, -1, -1 },
509 { -1, -1, -1, -1 }
510 },
511
512 {
513 /* Y */
514 { 0, 0, 1, 1 },
515 { 1, 0, 1, 2 },
516 { -1, -1, -1, -1 },
517 { -1, -1, -1, -1 },
518 { -1, -1, -1, -1 }
519 },
520
521 {
522 /* Z */
523 { 0, 0, 1, 0 },
524 { 1, 0, 0, 2 },
525 { 0, 2, 1, 2 },
526 { -1, -1, -1, -1 },
527 { -1, -1, -1, -1 }
528 }
529 };
530
531
532
533 /* Local function prototypes: */
534
535 int title(void);
536 int game(void);
537 void finish(void);
538 void setup(int argc, char * argv[]);
539 void seticon(void);
540 int fast_cos(int v);
541 int fast_sin(int v);
542 void draw_line(int x1, int y1, color_type c1,
543 int x2, int y2, color_type c2);
544 int clip(int * x1, int * y1, int * x2, int * y2);
545 color_type mkcolor(int r, int g, int b);
546 void sdl_drawline(int x1, int y1, color_type c1,
547 int x2, int y2, color_type c2);
548 unsigned char encode(float x, float y);
549 void drawvertline(int x, int y1, color_type c1,
550 int y2, color_type c2);
551 void putpixel(SDL_Surface * surface, int x, int y, Uint32 pixel);
552 void draw_segment(int r1, int a1,
553 color_type c1,
554 int r2, int a2,
555 color_type c2,
556 int cx, int cy, int ang);
557 void add_bullet(int x, int y, int a, int xm, int ym);
558 void add_asteroid(int x, int y, int xm, int ym, int size);
559 void add_bit(int x, int y, int xm, int ym);
560 void draw_asteroid(int size, int x, int y, int angle, shape_type * shape);
561 void playsound(int snd);
562 void hurt_asteroid(int j, int xm, int ym, int exp_size);
563 void add_score(int amount);
564 void draw_char(char c, int x, int y, int r, color_type cl);
565 void draw_text(char * str, int x, int y, int s, color_type c);
566 void draw_thick_line(int x1, int y1, color_type c1,
567 int x2, int y2, color_type c2);
568 void reset_level(void);
569 void show_version(void);
570 void show_usage(FILE * f, char * prg);
571 SDL_Surface * set_vid_mode(unsigned flags);
572 void draw_centered_text(char * str, int y, int s, color_type c);
573
574
575 /* --- MAIN --- */
576
main(int argc,char * argv[])577 int main(int argc, char * argv[])
578 {
579 int done;
580 FILE * fi;
581 char statefile[256], buf[256];
582
583
584 setup(argc, argv);
585
586
587 /* Set defaults: */
588
589 score = 0;
590 high = 0;
591 game_pending = 0;
592
593
594 /* Load state from disk: */
595
596 #ifndef _WIN32
597 /* snprintf(statefile, sizeof(statefile), "%s/.vectoroids-state",
598 getenv("HOME")); */
599 sprintf(statefile, "%s/.vectoroids-state",
600 getenv("HOME"));
601 #else
602 sprintf(statefile, "vectoroids-state.dat");
603 #endif
604
605 fi = fopen(statefile, "r");
606 if (fi != NULL)
607 {
608 /* Skip comment line: */
609
610 fgets(buf, sizeof(buf), fi);
611
612
613 /* Grab statefile version: */
614
615 fgets(buf, sizeof(buf), fi);
616 buf[strlen(buf) - 1] = '\0';
617
618 if (strcmp(buf, STATE_FORMAT_VERSION) != 0)
619 {
620 fprintf(stderr, "Vectoroids state file format has been updated.\n"
621 "Old game state is unreadable. Sorry!\n");
622 }
623 else
624 {
625 game_pending = fgetc(fi);
626 lives = fgetc(fi);
627 level = fgetc(fi);
628 player_alive = fgetc(fi);
629 player_die_timer = fgetc(fi);
630 fread(&score, sizeof(int), 1, fi);
631 fread(&high, sizeof(int), 1, fi);
632 fread(&x, sizeof(int), 1, fi);
633 fread(&y, sizeof(int), 1, fi);
634 fread(&xm, sizeof(int), 1, fi);
635 fread(&ym, sizeof(int), 1, fi);
636 fread(&angle, sizeof(int), 1, fi);
637 fread(bullets, sizeof(bullet_type), NUM_BULLETS, fi);
638 fread(asteroids, sizeof(asteroid_type), NUM_ASTEROIDS, fi);
639 fread(bits, sizeof(bit_type), NUM_BITS, fi);
640 }
641
642 fclose(fi);
643 }
644
645
646
647 /* Main app loop! */
648
649 do
650 {
651 done = title();
652
653 if (!done)
654 {
655 done = game();
656 }
657 }
658 while (!done);
659
660
661 /* Save state: */
662
663 fi = fopen(statefile, "w");
664 if (fi == NULL)
665 {
666 perror(statefile);
667 }
668 else
669 {
670 fprintf(fi, "Vectoroids State File\n");
671 fprintf(fi, "%s\n", STATE_FORMAT_VERSION);
672
673 fputc(game_pending, fi);
674 fputc(lives, fi);
675 fputc(level, fi);
676 fputc(player_alive, fi);
677 fputc(player_die_timer, fi);
678 fwrite(&score, sizeof(int), 1, fi);
679 fwrite(&high, sizeof(int), 1, fi);
680 fwrite(&x, sizeof(int), 1, fi);
681 fwrite(&y, sizeof(int), 1, fi);
682 fwrite(&xm, sizeof(int), 1, fi);
683 fwrite(&ym, sizeof(int), 1, fi);
684 fwrite(&angle, sizeof(int), 1, fi);
685 fwrite(bullets, sizeof(bullet_type), NUM_BULLETS, fi);
686 fwrite(asteroids, sizeof(asteroid_type), NUM_ASTEROIDS, fi);
687 fwrite(bits, sizeof(bit_type), NUM_BITS, fi);
688
689 fclose(fi);
690 }
691
692 finish();
693
694 return(0);
695 }
696
697
698 /* Title screen: */
699
title(void)700 int title(void)
701 {
702 int done, quit;
703 int i, snapped, angle, size, counter, x, y, xm, ym, z1, z2, z3;
704 SDL_Event event;
705 SDLKey key;
706 Uint32 now_time, last_time;
707 char * titlestr = "VECTOROIDS";
708 char str[20];
709 letter_type letters[11];
710
711
712 /* Reset letters: */
713
714 snapped = 0;
715
716 for (i = 0; i < strlen(titlestr); i++)
717 {
718 letters[i].x = (rand() % WIDTH);
719 letters[i].y = (rand() % HEIGHT);
720 letters[i].xm = 0;
721 letters[i].ym = 0;
722 }
723
724 x = (rand() % WIDTH);
725 y = (rand() % HEIGHT);
726 xm = (rand() % 4) + 2;
727 ym = (rand() % 10) - 5;
728
729 counter = 0;
730 angle = 0;
731 size = 40;
732
733 done = 0;
734 quit = 0;
735
736 do
737 {
738 last_time = SDL_GetTicks();
739
740 counter++;
741
742
743 /* Rotate rock: */
744
745 angle = ((angle + 2) % 360);
746
747
748 /* Make rock grow: */
749
750 if ((counter % 3) == 0)
751 {
752 if (size > 1)
753 size--;
754 }
755
756
757 /* Move rock: */
758
759 x = x + xm;
760
761 if (x >= WIDTH)
762 x = x - WIDTH;
763
764 y = y + ym;
765
766 if (y >= HEIGHT)
767 y = y - HEIGHT;
768 else if (y < 0)
769 y = y + HEIGHT;
770
771
772 /* Handle events: */
773
774 while (SDL_PollEvent(&event) > 0)
775 {
776 if (event.type == SDL_QUIT)
777 {
778 done = 1;
779 quit = 1;
780 }
781 else if (event.type == SDL_KEYDOWN)
782 {
783 key = event.key.keysym.sym;
784
785 if (key == SDLK_SPACE)
786 {
787 done = 1;
788 }
789 else if (key == SDLK_ESCAPE)
790 {
791 done = 1;
792 quit = 1;
793 }
794 }
795 #ifdef JOY_YES
796 else if (event.type == SDL_JOYBUTTONDOWN)
797 {
798 done = 1;
799 }
800 #endif
801 else if (event.type == SDL_MOUSEBUTTONDOWN)
802 {
803 if (event.button.x >= (WIDTH - 50) / 2 &&
804 event.button.x <= (WIDTH + 50) / 2 &&
805 event.button.y >= 180 && event.button.y <= 195)
806 {
807 /* Start! */
808
809 game_pending = 0;
810 done = 1;
811 }
812 else if (event.button.x >= (WIDTH - 80) / 2 &&
813 event.button.x <= (WIDTH + 80) / 2 &&
814 event.button.y >= 200 && event.button.y <= 215 &&
815 game_pending)
816 {
817 done = 1;
818 }
819 }
820 }
821
822
823 /* Move title characters: */
824
825 if (snapped < strlen(titlestr))
826 {
827 for (i = 0; i < strlen(titlestr); i++)
828 {
829 letters[i].x = letters[i].x + letters[i].xm;
830 letters[i].y = letters[i].y + letters[i].ym;
831
832
833 /* Home in on final spot! */
834
835 if (letters[i].x > ((WIDTH - (strlen(titlestr) * 14)) / 2 +
836 (i * 14)) &&
837 letters[i].xm > -4)
838 letters[i].xm--;
839 else if (letters[i].x < ((WIDTH - (strlen(titlestr) * 14)) / 2 +
840 (i * 14)) &&
841 letters[i].xm < 4)
842 letters[i].xm++;
843
844 if (letters[i].y > 100 && letters[i].ym > -4)
845 letters[i].ym--;
846 else if (letters[i].y < 100 && letters[i].ym < 4)
847 letters[i].ym++;
848
849
850 /* Snap into place: */
851
852 if (letters[i].x >= ((WIDTH - (strlen(titlestr) * 14)) / 2 +
853 (i * 14)) - 8 &&
854 letters[i].x <= ((WIDTH - (strlen(titlestr) * 14)) / 2 +
855 (i * 14)) + 8 &&
856 letters[i].y >= 92 &&
857 letters[i].y <= 108 &&
858 (letters[i].xm != 0 ||
859 letters[i].ym != 0))
860 {
861 letters[i].x = ((WIDTH - (strlen(titlestr) * 14)) / 2 + (i * 14));
862 letters[i].xm = 0;
863
864 letters[i].y = 100;
865 letters[i].ym = 0;
866
867 snapped++;
868 }
869 }
870 }
871
872
873 /* Draw screen: */
874
875 /* (Erase first) */
876
877 SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
878
879
880 /* (Title) */
881
882 if (snapped != strlen(titlestr))
883 {
884 for (i = 0; i < strlen(titlestr); i++)
885 {
886 draw_char(titlestr[i], letters[i].x, letters[i].y, 10,
887 mkcolor(255, 255, 255));
888 }
889 }
890 else
891 {
892 for (i = 0; i < strlen(titlestr); i++)
893 {
894 z1 = (i + counter) % 255;
895 z2 = ((i + counter + 128) * 2) % 255;
896 z3 = ((i + counter) * 5) % 255;
897
898 draw_char(titlestr[i], letters[i].x, letters[i].y, 10,
899 mkcolor(z1, z2, z3));
900 }
901 }
902
903
904 /* (Credits) */
905
906 if (snapped == strlen(titlestr))
907 {
908 draw_centered_text("BY BILL KENDRICK", 140, 5,
909 mkcolor(128, 128,128));
910 draw_centered_text("NEW BREED SOFTWARE", 155, 5,
911 mkcolor(96, 96, 96));
912
913 sprintf(str, "HIGH %.6d", high);
914 draw_text(str, (WIDTH - 110) / 2, 5, 5, mkcolor(128, 255, 255));
915 draw_text(str, (WIDTH - 110) / 2 + 1, 6, 5, mkcolor(128, 255, 255));
916
917 if (score != 0 && (score != high || (counter % 20) < 10))
918 {
919 if (game_pending == 0)
920 sprintf(str, "LAST %.6d", score);
921 else
922 sprintf(str, "SCR %.6d", score);
923 draw_text(str, (WIDTH - 110) / 2, 25, 5, mkcolor(128, 128, 255));
924 draw_text(str, (WIDTH - 110) / 2 + 1, 26, 5, mkcolor(128, 128, 255));
925 }
926 }
927
928
929 draw_text("START", (WIDTH - 50) / 2, 180, 5, mkcolor(0, 255, 0));
930
931 if (game_pending)
932 draw_text("CONTINUE", (WIDTH - 80) / 2, 200, 5, mkcolor(0, 255, 0));
933
934
935 /* (Giant rock) */
936
937 draw_segment(40 / size, 0, mkcolor(255, 255, 255),
938 30 / size, 30, mkcolor(255, 255, 255),
939 x, y, angle);
940 draw_segment(30 / size, 30, mkcolor(255, 255, 255),
941 40 / size, 55, mkcolor(255, 255, 255),
942 x, y, angle);
943 draw_segment(40 / size, 55, mkcolor(255, 255, 255),
944 25 / size, 90, mkcolor(255, 255, 255),
945 x, y, angle);
946 draw_segment(25 / size, 90, mkcolor(255, 255, 255),
947 40 / size, 120, mkcolor(255, 255, 255),
948 x, y, angle);
949 draw_segment(40 / size, 120, mkcolor(255, 255, 255),
950 35 / size, 130, mkcolor(255, 255, 255),
951 x, y, angle);
952 draw_segment(35 / size, 130, mkcolor(255, 255, 255),
953 40 / size, 160, mkcolor(255, 255, 255),
954 x, y, angle);
955 draw_segment(40 / size, 160, mkcolor(255, 255, 255),
956 30 / size, 200, mkcolor(255, 255, 255),
957 x, y, angle);
958 draw_segment(30 / size, 200, mkcolor(255, 255, 255),
959 45 / size, 220, mkcolor(255, 255, 255),
960 x, y, angle);
961 draw_segment(45 / size, 220, mkcolor(255, 255, 255),
962 25 / size, 265, mkcolor(255, 255, 255),
963 x, y, angle);
964 draw_segment(25 / size, 265, mkcolor(255, 255, 255),
965 30 / size, 300, mkcolor(255, 255, 255),
966 x, y, angle);
967 draw_segment(30 / size, 300, mkcolor(255, 255, 255),
968 45 / size, 335, mkcolor(255, 255, 255),
969 x, y, angle);
970 draw_segment(45 / size, 335, mkcolor(255, 255, 255),
971 40 / size, 0, mkcolor(255, 255, 255),
972 x, y, angle);
973
974
975 /* Flush and pause! */
976
977 SDL_Flip(screen);
978
979 now_time = SDL_GetTicks();
980
981 if (now_time < last_time + (1000 / FPS))
982 {
983 SDL_Delay(last_time + 1000 / FPS - now_time);
984 }
985 }
986 while (!done);
987
988 return(quit);
989 }
990
991
992
993 /* --- GAME --- */
994
game(void)995 int game(void)
996 {
997 int done, quit, counter;
998 int i, j;
999 int num_asteroids_alive;
1000 SDL_Event event;
1001 SDLKey key;
1002 int left_pressed, right_pressed, up_pressed, shift_pressed;
1003 char str[10];
1004 Uint32 now_time, last_time;
1005
1006
1007 done = 0;
1008 quit = 0;
1009 counter = 0;
1010
1011 left_pressed = 0;
1012 right_pressed = 0;
1013 up_pressed = 0;
1014 shift_pressed = 0;
1015
1016 if (game_pending == 0)
1017 {
1018 lives = 3;
1019 score = 0;
1020
1021 player_alive = 1;
1022 player_die_timer = 0;
1023 angle = 90;
1024 x = (WIDTH / 2) << 4;
1025 y = (HEIGHT / 2) << 4;
1026 xm = 0;
1027 ym = 0;
1028
1029 level = 1;
1030 reset_level();
1031 }
1032
1033 game_pending = 1;
1034
1035
1036 /* Hide mouse cursor: */
1037
1038 if (fullscreen)
1039 SDL_ShowCursor(0);
1040
1041
1042 /* Play music: */
1043
1044 #ifndef NOSOUND
1045 if (use_sound)
1046 {
1047 if (!Mix_PlayingMusic())
1048 Mix_PlayMusic(game_music, -1);
1049 }
1050 #endif
1051
1052
1053 do
1054 {
1055 last_time = SDL_GetTicks();
1056 counter++;
1057
1058
1059 /* Handle events: */
1060
1061 while (SDL_PollEvent(&event) > 0)
1062 {
1063 if (event.type == SDL_QUIT)
1064 {
1065 /* Quit! */
1066
1067 done = 1;
1068 quit = 1;
1069 }
1070 else if (event.type == SDL_KEYDOWN ||
1071 event.type == SDL_KEYUP)
1072 {
1073 key = event.key.keysym.sym;
1074
1075 if (event.type == SDL_KEYDOWN)
1076 {
1077 if (key == SDLK_ESCAPE)
1078 {
1079 /* Return to menu! */
1080
1081 done = 1;
1082 }
1083
1084
1085 /* Key press... */
1086
1087 if (key == SDLK_RIGHT)
1088 {
1089 /* Rotate CW */
1090
1091 left_pressed = 0;
1092 right_pressed = 1;
1093 }
1094 else if (key == SDLK_LEFT)
1095 {
1096 /* Rotate CCW */
1097
1098 left_pressed = 1;
1099 right_pressed = 0;
1100 }
1101 else if (key == SDLK_UP)
1102 {
1103 /* Thrust! */
1104
1105 up_pressed = 1;
1106 }
1107 else if ((key == SDLK_SPACE) &&
1108 player_alive)
1109 {
1110 /* Fire a bullet! */
1111
1112 add_bullet(x >> 4, y >> 4, angle, xm, ym);
1113 }
1114
1115 if (key == SDLK_LSHIFT ||
1116 key == SDLK_RSHIFT)
1117 {
1118 /* Respawn now (if applicable) */
1119
1120 shift_pressed = 1;
1121 }
1122 }
1123 else if (event.type == SDL_KEYUP)
1124 {
1125 /* Key release... */
1126
1127 if (key == SDLK_RIGHT)
1128 {
1129 right_pressed = 0;
1130 }
1131 else if (key == SDLK_LEFT)
1132 {
1133 left_pressed = 0;
1134 }
1135 else if (key == SDLK_UP)
1136 {
1137 up_pressed = 0;
1138 }
1139
1140 if (key == SDLK_LSHIFT ||
1141 key == SDLK_RSHIFT)
1142 {
1143 /* Respawn now (if applicable) */
1144
1145 shift_pressed = 0;
1146 }
1147 }
1148 }
1149 #ifdef JOY_YES
1150 else if (event.type == SDL_JOYBUTTONDOWN &&
1151 player_alive)
1152 {
1153 if (event.jbutton.button == JOY_B)
1154 {
1155 /* Fire a bullet! */
1156
1157 add_bullet(x >> 4, y >> 4, angle, xm, ym);
1158 }
1159 else if (event.jbutton.button == JOY_A)
1160 {
1161 /* Thrust: */
1162
1163 up_pressed = 1;
1164 }
1165 else
1166 {
1167 shift_pressed = 1;
1168 }
1169 }
1170 else if (event.type == SDL_JOYBUTTONUP)
1171 {
1172 if (event.jbutton.button == JOY_A)
1173 {
1174 /* Stop thrust: */
1175
1176 up_pressed = 0;
1177 }
1178 else if (event.jbutton.button != JOY_B)
1179 {
1180 shift_pressed = 0;
1181 }
1182 }
1183 else if (event.type == SDL_JOYAXISMOTION)
1184 {
1185 if (event.jaxis.axis == JOY_X)
1186 {
1187 if (event.jaxis.value < -256)
1188 {
1189 left_pressed = 1;
1190 right_pressed = 0;
1191 }
1192 else if (event.jaxis.value > 256)
1193 {
1194 left_pressed = 0;
1195 right_pressed = 1;
1196 }
1197 else
1198 {
1199 left_pressed = 0;
1200 right_pressed = 0;
1201 }
1202 }
1203 }
1204 #endif
1205 }
1206
1207
1208 /* Rotate ship: */
1209
1210 if (right_pressed)
1211 {
1212 angle = angle - 8;
1213 if (angle < 0)
1214 angle = angle + 360;
1215 }
1216 else if (left_pressed)
1217 {
1218 angle = angle + 8;
1219 if (angle >= 360)
1220 angle = angle - 360;
1221 }
1222
1223
1224 /* Thrust ship: */
1225
1226 if (up_pressed && player_alive)
1227 {
1228 /* Move forward: */
1229
1230 xm = xm + ((fast_cos(angle >> 3) * 3) >> 10);
1231 ym = ym - ((fast_sin(angle >> 3) * 3) >> 10);
1232
1233
1234 /* Start thruster sound: */
1235 #ifndef NOSOUND
1236 if (use_sound)
1237 {
1238 if (!Mix_Playing(CHAN_THRUST))
1239 {
1240 #ifndef EMBEDDED
1241 Mix_PlayChannel(CHAN_THRUST, sounds[SND_THRUST], -1);
1242 #else
1243 Mix_PlayChannel(-1, sounds[SND_THRUST], 0);
1244 #endif
1245 }
1246 }
1247 #endif
1248 }
1249 else
1250 {
1251 /* Slow down (unrealistic, but.. feh!) */
1252
1253 if ((counter % 20) == 0)
1254 {
1255 xm = (xm * 7) / 8;
1256 ym = (ym * 7) / 8;
1257 }
1258
1259
1260 /* Stop thruster sound: */
1261
1262 #ifndef NOSOUND
1263 if (use_sound)
1264 {
1265 if (Mix_Playing(CHAN_THRUST))
1266 {
1267 #ifndef EMBEDDED
1268 Mix_HaltChannel(CHAN_THRUST);
1269 #endif
1270 }
1271 }
1272 #endif
1273 }
1274
1275
1276 /* Handle player death: */
1277
1278 if (player_alive == 0)
1279 {
1280 player_die_timer--;
1281
1282 if (player_die_timer <= 0)
1283 {
1284 if (lives > 0)
1285 {
1286 /* Reset player: */
1287
1288 player_die_timer = 0;
1289 angle = 90;
1290 x = (WIDTH / 2) << 4;
1291 y = (HEIGHT / 2) << 4;
1292 xm = 0;
1293 ym = 0;
1294
1295
1296 /* Only bring player back when it's alright to! */
1297
1298 player_alive = 1;
1299
1300 if (!shift_pressed)
1301 {
1302 for (i = 0; i < NUM_ASTEROIDS && player_alive; i++)
1303 {
1304 if (asteroids[i].alive)
1305 {
1306 if (asteroids[i].x >= (x >> 4) - (WIDTH / 5) &&
1307 asteroids[i].x <= (x >> 4) + (WIDTH / 5) &&
1308 asteroids[i].y >= (y >> 4) - (HEIGHT / 5) &&
1309 asteroids[i].y <= (y >> 4) + (HEIGHT / 5))
1310 {
1311 /* If any asteroid is too close for comfort,
1312 don't bring ship back yet! */
1313
1314 player_alive = 0;
1315 }
1316 }
1317 }
1318 }
1319 }
1320 else
1321 {
1322 done = 1;
1323 game_pending = 0;
1324 }
1325 }
1326 }
1327
1328
1329 /* Erase screen: */
1330
1331 SDL_BlitSurface(bkgd, NULL, screen, NULL);
1332
1333
1334 /* Move ship: */
1335
1336 x = x + xm;
1337 y = y + ym;
1338
1339
1340 /* Wrap ship around edges of screen: */
1341
1342 if (x >= (WIDTH << 4))
1343 x = x - (WIDTH << 4);
1344 else if (x < 0)
1345 x = x + (WIDTH << 4);
1346
1347 if (y >= (HEIGHT << 4))
1348 y = y - (HEIGHT << 4);
1349 else if (y < 0)
1350 y = y + (HEIGHT << 4);
1351
1352
1353 /* Move bullets: */
1354
1355 for (i = 0; i < NUM_BULLETS; i++)
1356 {
1357 if (bullets[i].timer >= 0)
1358 {
1359 /* Bullet wears out: */
1360
1361 bullets[i].timer--;
1362
1363
1364 /* Move bullet: */
1365
1366 bullets[i].x = bullets[i].x + bullets[i].xm;
1367 bullets[i].y = bullets[i].y + bullets[i].ym;
1368
1369
1370 /* Wrap bullet around edges of screen: */
1371
1372 if (bullets[i].x >= WIDTH)
1373 bullets[i].x = bullets[i].x - WIDTH;
1374 else if (bullets[i].x < 0)
1375 bullets[i].x = bullets[i].x + WIDTH;
1376
1377 if (bullets[i].y >= HEIGHT)
1378 bullets[i].y = bullets[i].y - HEIGHT;
1379 else if (bullets[i].y < 0)
1380 bullets[i].y = bullets[i].y + HEIGHT;
1381
1382
1383 /* Check for collision with any asteroids! */
1384
1385 for (j = 0; j < NUM_ASTEROIDS; j++)
1386 {
1387 if (bullets[i].timer > 0 && asteroids[j].alive)
1388 {
1389 if ((bullets[i].x + 5 >=
1390 asteroids[j].x - asteroids[j].size * AST_RADIUS) &&
1391 (bullets[i].x - 5<=
1392 asteroids[j].x + asteroids[j].size * AST_RADIUS) &&
1393 (bullets[i].y + 5 >=
1394 asteroids[j].y - asteroids[j].size * AST_RADIUS) &&
1395 (bullets[i].y - 5 <=
1396 asteroids[j].y + asteroids[j].size * AST_RADIUS))
1397 {
1398 /* Remove bullet! */
1399
1400 bullets[i].timer = 0;
1401
1402
1403 hurt_asteroid(j, bullets[i].xm, bullets[i].ym,
1404 asteroids[j].size * 3);
1405 }
1406 }
1407 }
1408 }
1409 }
1410
1411
1412 /* Move asteroids: */
1413
1414 num_asteroids_alive = 0;
1415
1416 for (i = 0; i < NUM_ASTEROIDS; i++)
1417 {
1418 if (asteroids[i].alive)
1419 {
1420 num_asteroids_alive++;
1421
1422 /* Move asteroid: */
1423
1424 if ((counter % 4) == 0)
1425 {
1426 asteroids[i].x = asteroids[i].x + asteroids[i].xm;
1427 asteroids[i].y = asteroids[i].y + asteroids[i].ym;
1428 }
1429
1430
1431 /* Wrap asteroid around edges of screen: */
1432
1433 if (asteroids[i].x >= WIDTH)
1434 asteroids[i].x = asteroids[i].x - WIDTH;
1435 else if (asteroids[i].x < 0)
1436 asteroids[i].x = asteroids[i].x + WIDTH;
1437
1438 if (asteroids[i].y >= HEIGHT)
1439 asteroids[i].y = asteroids[i].y - HEIGHT;
1440 else if (asteroids[i].y < 0)
1441 asteroids[i].y = asteroids[i].y + HEIGHT;
1442
1443
1444 /* Rotate asteroid: */
1445
1446 asteroids[i].angle = (asteroids[i].angle +
1447 asteroids[i].angle_m);
1448
1449
1450 /* Wrap rotation angle... */
1451
1452 if (asteroids[i].angle < 0)
1453 asteroids[i].angle = asteroids[i].angle + 360;
1454 else if (asteroids[i].angle >= 360)
1455 asteroids[i].angle = asteroids[i].angle - 360;
1456
1457
1458 /* See if we collided with the player: */
1459
1460 if (asteroids[i].x >= (x >> 4) - SHIP_RADIUS &&
1461 asteroids[i].x <= (x >> 4) + SHIP_RADIUS &&
1462 asteroids[i].y >= (y >> 4) - SHIP_RADIUS &&
1463 asteroids[i].y <= (y >> 4) + SHIP_RADIUS &&
1464 player_alive)
1465 {
1466 hurt_asteroid(i, xm >> 4, ym >> 4, NUM_BITS);
1467
1468 player_alive = 0;
1469 player_die_timer = 30;
1470
1471 playsound(SND_EXPLODE);
1472
1473 /* Stop thruster sound: */
1474
1475 #ifndef NOSOUND
1476 if (use_sound)
1477 {
1478 if (Mix_Playing(CHAN_THRUST))
1479 {
1480 #ifndef EMBEDDED
1481 Mix_HaltChannel(CHAN_THRUST);
1482 #endif
1483 }
1484 }
1485 #endif
1486
1487 lives--;
1488
1489 if (lives == 0)
1490 {
1491 #ifndef NOSOUND
1492 if (use_sound)
1493 {
1494 playsound(SND_GAMEOVER);
1495 playsound(SND_GAMEOVER);
1496 playsound(SND_GAMEOVER);
1497 /* Mix_PlayChannel(CHAN_THRUST,
1498 sounds[SND_GAMEOVER], 0); */
1499 }
1500 #endif
1501 player_die_timer = 100;
1502 }
1503 }
1504 }
1505 }
1506
1507
1508 /* Move bits: */
1509
1510 for (i = 0; i < NUM_BITS; i++)
1511 {
1512 if (bits[i].timer > 0)
1513 {
1514 /* Countdown bit's lifespan: */
1515
1516 bits[i].timer--;
1517
1518
1519 /* Move the bit: */
1520
1521 bits[i].x = bits[i].x + bits[i].xm;
1522 bits[i].y = bits[i].y + bits[i].ym;
1523
1524
1525 /* Wrap bit around edges of screen: */
1526
1527 if (bits[i].x >= WIDTH)
1528 bits[i].x = bits[i].x - WIDTH;
1529 else if (bits[i].x < 0)
1530 bits[i].x = bits[i].x + WIDTH;
1531
1532 if (bits[i].y >= HEIGHT)
1533 bits[i].y = bits[i].y - HEIGHT;
1534 else if (bits[i].y < 0)
1535 bits[i].y = bits[i].y + HEIGHT;
1536 }
1537 }
1538
1539
1540 /* Draw ship: */
1541
1542 if (player_alive)
1543 {
1544 draw_segment(SHIP_RADIUS, 0, mkcolor(128, 128, 255),
1545 SHIP_RADIUS / 2, 135, mkcolor(0, 0, 192),
1546 x >> 4, y >> 4,
1547 angle);
1548
1549 draw_segment(SHIP_RADIUS / 2, 135, mkcolor(0, 0, 192),
1550 0, 0, mkcolor(64, 64, 230),
1551 x >> 4, y >> 4,
1552 angle);
1553
1554 draw_segment(0, 0, mkcolor(64, 64, 230),
1555 SHIP_RADIUS / 2, 225, mkcolor(0, 0, 192),
1556 x >> 4, y >> 4,
1557 angle);
1558
1559 draw_segment(SHIP_RADIUS / 2, 225, mkcolor(0, 0, 192),
1560 SHIP_RADIUS, 0, mkcolor(128, 128, 255),
1561 x >> 4, y >> 4,
1562 angle);
1563
1564
1565 /* Draw flame: */
1566
1567 if (up_pressed)
1568 {
1569 #ifndef EMBEDDED
1570 draw_segment(0, 0, mkcolor(255, 255, 255),
1571 (rand() % 20), 180, mkcolor(255, 0, 0),
1572 x >> 4, y >> 4,
1573 angle);
1574 #else
1575 i = (rand() % 128) + 128;
1576
1577 draw_segment(0, 0, mkcolor(255, i, i),
1578 (rand() % 20), 180, mkcolor(255, i, i),
1579 x >> 4, y >> 4,
1580 angle);
1581 #endif
1582 }
1583 }
1584
1585
1586 /* Draw bullets: */
1587
1588 for (i = 0; i < NUM_BULLETS; i++)
1589 {
1590 if (bullets[i].timer >= 0)
1591 {
1592 draw_line(bullets[i].x - (rand() % 3) - bullets[i].xm * 2,
1593 bullets[i].y - (rand() % 3) - bullets[i].ym * 2,
1594 mkcolor((rand() % 3) * 128,
1595 (rand() % 3) * 128,
1596 (rand() % 3) * 128),
1597 bullets[i].x + (rand() % 3) - bullets[i].xm * 2,
1598 bullets[i].y + (rand() % 3) - bullets[i].ym * 2,
1599 mkcolor((rand() % 3) * 128,
1600 (rand() % 3) * 128,
1601 (rand() % 3) * 128));
1602
1603 draw_line(bullets[i].x + (rand() % 3) - bullets[i].xm * 2,
1604 bullets[i].y - (rand() % 3) - bullets[i].ym * 2,
1605 mkcolor((rand() % 3) * 128,
1606 (rand() % 3) * 128,
1607 (rand() % 3) * 128),
1608 bullets[i].x - (rand() % 3) - bullets[i].xm * 2,
1609 bullets[i].y + (rand() % 3) - bullets[i].ym * 2,
1610 mkcolor((rand() % 3) * 128,
1611 (rand() % 3) * 128,
1612 (rand() % 3) * 128));
1613
1614
1615
1616 draw_thick_line(bullets[i].x - (rand() % 5),
1617 bullets[i].y - (rand() % 5),
1618 mkcolor((rand() % 3) * 128 + 64,
1619 (rand() % 3) * 128 + 64,
1620 (rand() % 3) * 128 + 64),
1621 bullets[i].x + (rand() % 5),
1622 bullets[i].y + (rand() % 5),
1623 mkcolor((rand() % 3) * 128 + 64,
1624 (rand() % 3) * 128 + 64,
1625 (rand() % 3) * 128 + 64));
1626
1627 draw_thick_line(bullets[i].x + (rand() % 5),
1628 bullets[i].y - (rand() % 5),
1629 mkcolor((rand() % 3) * 128 + 64,
1630 (rand() % 3) * 128 + 64,
1631 (rand() % 3) * 128 + 64),
1632 bullets[i].x - (rand() % 5),
1633 bullets[i].y + (rand() % 5),
1634 mkcolor((rand() % 3) * 128 + 64,
1635 (rand() % 3) * 128 + 64,
1636 (rand() % 3) * 128 + 64));
1637 }
1638 }
1639
1640
1641 /* Draw asteroids: */
1642
1643 for (i = 0; i < NUM_ASTEROIDS; i++)
1644 {
1645 if (asteroids[i].alive)
1646 {
1647 draw_asteroid(asteroids[i].size,
1648 asteroids[i].x, asteroids[i].y,
1649 asteroids[i].angle,
1650 asteroids[i].shape);
1651 }
1652 }
1653
1654
1655 /* Draw bits: */
1656
1657 for (i = 0; i < NUM_BITS; i++)
1658 {
1659 if (bits[i].timer > 0)
1660 {
1661 draw_line(bits[i].x, bits[i].y, mkcolor(255, 255, 255),
1662 bits[i].x + bits[i].xm,
1663 bits[i].y + bits[i].ym, mkcolor(255, 255, 255));
1664 }
1665 }
1666
1667
1668 /* Draw score: */
1669
1670 #ifndef EMBEDDED
1671 sprintf(str, "%.6d", score);
1672 draw_text(str, 3, 3, 14, mkcolor(255, 255, 255));
1673 draw_text(str, 4, 4, 14, mkcolor(255, 255, 255));
1674 #else
1675 sprintf(str, "%.6d", score);
1676 draw_text(str, 3, 3, 10, mkcolor(255, 255, 255));
1677 draw_text(str, 4, 4, 10, mkcolor(255, 255, 255));
1678 #endif
1679
1680
1681 /* Level: */
1682
1683 #ifndef EMBEDDED
1684 sprintf(str, "%d", level);
1685 draw_text(str, (WIDTH - 14) / 2, 3, 14, mkcolor(255, 255, 255));
1686 draw_text(str, (WIDTH - 14) / 2 + 1, 4, 14, mkcolor(255, 255, 255));
1687 #else
1688 sprintf(str, "%d", level);
1689 draw_text(str, (WIDTH - 14) / 2, 3, 10, mkcolor(255, 255, 255));
1690 draw_text(str, (WIDTH - 14) / 2 + 1, 4, 10, mkcolor(255, 255, 255));
1691 #endif
1692
1693
1694 /* Draw lives: */
1695
1696 for (i = 0; i < lives; i++)
1697 {
1698 draw_segment(16, 0, mkcolor(255, 255, 255),
1699 4, 135, mkcolor(255, 255, 255),
1700 WIDTH - 10 - i * 10, 20,
1701 90);
1702
1703 draw_segment(8, 135, mkcolor(255, 255, 255),
1704 0, 0, mkcolor(255, 255, 255),
1705 WIDTH - 10 - i * 10, 20,
1706 90);
1707
1708 draw_segment(0, 0, mkcolor(255, 255, 255),
1709 8, 225, mkcolor(255, 255, 255),
1710 WIDTH - 10 - i * 10, 20,
1711 90);
1712
1713 draw_segment(8, 225, mkcolor(255, 255, 255),
1714 16, 0, mkcolor(255, 255, 255),
1715 WIDTH - 10 - i * 10, 20,
1716 90);
1717 }
1718
1719
1720 if (player_die_timer > 0)
1721 {
1722 if (player_die_timer > 30)
1723 j = 30;
1724 else
1725 j = player_die_timer;
1726
1727 draw_segment((16 * j) / 30, 0, mkcolor(255, 255, 255),
1728 (4 * j) / 30, 135, mkcolor(255, 255, 255),
1729 WIDTH - 10 - i * 10, 20,
1730 90);
1731
1732 draw_segment((8 * j) / 30, 135, mkcolor(255, 255, 255),
1733 0, 0, mkcolor(255, 255, 255),
1734 WIDTH - 10 - i * 10, 20,
1735 90);
1736
1737 draw_segment(0, 0, mkcolor(255, 255, 255),
1738 (8 * j) / 30, 225, mkcolor(255, 255, 255),
1739 WIDTH - 10 - i * 10, 20,
1740 90);
1741
1742 draw_segment((8 * j) / 30, 225, mkcolor(255, 255, 255),
1743 (16 * j) / 30, 0, mkcolor(255, 255, 255),
1744 WIDTH - 10 - i * 10, 20,
1745 90);
1746
1747 }
1748
1749
1750 /* Zooming level effect: */
1751
1752 if (text_zoom > 0)
1753 {
1754 if ((counter % 2) == 0)
1755 text_zoom--;
1756
1757 #ifndef EMBEDDED
1758 draw_text(zoom_str, (WIDTH - (strlen(zoom_str) * text_zoom)) / 2,
1759 (HEIGHT - text_zoom) / 2,
1760 text_zoom, mkcolor(text_zoom * (256 / ZOOM_START), 0, 0));
1761 #else
1762 draw_text(zoom_str, (WIDTH - (strlen(zoom_str) * text_zoom)) / 2,
1763 (HEIGHT - text_zoom) / 2,
1764 text_zoom, mkcolor(text_zoom * (256 / ZOOM_START), 128, 128));
1765 #endif
1766 }
1767
1768
1769 /* Game over? */
1770
1771 if (player_alive == 0 && lives == 0)
1772 {
1773 if (player_die_timer > 14)
1774 {
1775 draw_text("GAME OVER",
1776 (WIDTH - 9 * player_die_timer) / 2,
1777 (HEIGHT - player_die_timer) / 2,
1778 player_die_timer,
1779 mkcolor(rand() % 255,
1780 rand() % 255,
1781 rand() % 255));
1782 }
1783 else
1784 {
1785 draw_text("GAME OVER",
1786 (WIDTH - 9 * 14) / 2,
1787 (HEIGHT - 14) / 2,
1788 14,
1789 mkcolor(255, 255, 255));
1790
1791 }
1792 }
1793
1794
1795 /* Go to next level? */
1796
1797 if (num_asteroids_alive == 0)
1798 {
1799 level++;
1800
1801 reset_level();
1802 }
1803
1804
1805 /* Flush and pause! */
1806
1807 SDL_Flip(screen);
1808
1809 now_time = SDL_GetTicks();
1810
1811 if (now_time < last_time + (1000 / FPS))
1812 {
1813 SDL_Delay(last_time + 1000 / FPS - now_time);
1814 }
1815 }
1816 while (!done);
1817
1818
1819 /* Record, if a high score: */
1820
1821 if (score >= high)
1822 {
1823 high = score;
1824 }
1825
1826
1827 /* Display mouse cursor: */
1828
1829 if (fullscreen)
1830 SDL_ShowCursor(1);
1831
1832
1833 return(quit);
1834 }
1835
1836
finish(void)1837 void finish(void)
1838 {
1839 SDL_Quit();
1840 }
1841
1842
setup(int argc,char * argv[])1843 void setup(int argc, char * argv[])
1844 {
1845 int i;
1846 SDL_Surface * tmp;
1847
1848
1849 /* Options: */
1850
1851 score = 0;
1852 use_sound = TRUE;
1853 fullscreen = FALSE;
1854
1855
1856 /* Check command-line options: */
1857
1858 for (i = 1; i < argc; i++)
1859 {
1860 if (strcmp(argv[i], "--fullscreen") == 0 ||
1861 strcmp(argv[i], "-f") == 0)
1862 {
1863 fullscreen = TRUE;
1864 }
1865 else if (strcmp(argv[i], "--nosound") == 0 ||
1866 strcmp(argv[i], "-q") == 0)
1867 {
1868 use_sound = FALSE;
1869 }
1870 else if (strcmp(argv[i], "--help") == 0 ||
1871 strcmp(argv[i], "-h") == 0)
1872 {
1873 show_version();
1874
1875 printf("\n"
1876 "Programming: Bill Kendrick, New Breed Software - bill@newbreedsoftware.com\n"
1877 "Music: Mike Faltiss (Hadji/Digital Music Kings) - deadchannel@hotmail.com\n"
1878 "\n"
1879 "Keyboard controls:\n"
1880 " Left/Right - Rotate ship\n"
1881 " Up - Thrust engines\n"
1882 " Space - Fire weapons\n"
1883 " Shift - Respawn after death (or wait)\n"
1884 " Escape - Return to title screen\n"
1885 "\n"
1886 "Joystick controls:\n"
1887 " Left/Right - Rotate ship\n"
1888 " Fire-A - Thrust engines\n"
1889 " Fire-B - Fire weapons\n"
1890 "\n"
1891 "Run with \"--usage\" for command-line options...\n"
1892 "Run with \"--copying\" for copying information...\n"
1893 "\n");
1894
1895 exit(0);
1896 }
1897 else if (strcmp(argv[i], "--version") == 0 ||
1898 strcmp(argv[i], "-v") == 0)
1899 {
1900 show_version();
1901 printf("State format file version " STATE_FORMAT_VERSION "\n");
1902 exit(0);
1903 }
1904 else if (strcmp(argv[i], "--copying") == 0 ||
1905 strcmp(argv[i], "-c") == 0)
1906 {
1907 show_version();
1908 printf("\n"
1909 "This program is free software; you can redistribute it\n"
1910 "and/or modify it under the terms of the GNU General Public\n"
1911 "License as published by the Free Software Foundation;\n"
1912 "either version 2 of the License, or (at your option) any\n"
1913 "later version.\n"
1914 "\n"
1915 "This program is distributed in the hope that it will be\n"
1916 "useful and entertaining, but WITHOUT ANY WARRANTY; without\n"
1917 "even the implied warranty of MERCHANTABILITY or FITNESS\n"
1918 "FOR A PARTICULAR PURPOSE. See the GNU General Public\n"
1919 "License for more details.\n"
1920 "\n");
1921 printf("You should have received a copy of the GNU General Public\n"
1922 "License along with this program; if not, write to the Free\n"
1923 "Software Foundation, Inc., 59 Temple Place, Suite 330,\n"
1924 "Boston, MA 02111-1307 USA\n"
1925 "\n");
1926 exit(0);
1927 }
1928 else if (strcmp(argv[i], "--usage") == 0 ||
1929 strcmp(argv[i], "-u") == 0)
1930 {
1931 show_usage(stdout, argv[0]);
1932 exit(0);
1933 }
1934 else
1935 {
1936 show_usage(stderr, argv[0]);
1937 exit(1);
1938 }
1939 }
1940
1941
1942 /* Seed random number generator: */
1943
1944 srand(SDL_GetTicks());
1945
1946
1947 /* Init SDL video: */
1948
1949 if (SDL_Init(SDL_INIT_VIDEO) < 0)
1950 {
1951 fprintf(stderr,
1952 "\nError: I could not initialize video!\n"
1953 "The Simple DirectMedia error that occured was:\n"
1954 "%s\n\n", SDL_GetError());
1955 exit(1);
1956 }
1957
1958
1959 /* Init joysticks: */
1960
1961 #ifdef JOY_YES
1962 use_joystick = 1;
1963
1964 if (SDL_Init(SDL_INIT_JOYSTICK) < 0)
1965 {
1966 fprintf(stderr,
1967 "\nWarning: I could not initialize joystick.\n"
1968 "The Simple DirectMedia error that occured was:\n"
1969 "%s\n\n", SDL_GetError());
1970
1971 use_joystick = 0;
1972 }
1973 else
1974 {
1975 /* Look for joysticks: */
1976
1977 if (SDL_NumJoysticks() <= 0)
1978 {
1979 fprintf(stderr,
1980 "\nWarning: No joysticks available.\n");
1981
1982 use_joystick = 0;
1983 }
1984 else
1985 {
1986 /* Open joystick: */
1987
1988 js = SDL_JoystickOpen(0);
1989
1990 if (js == NULL)
1991 {
1992 fprintf(stderr,
1993 "\nWarning: Could not open joystick 1.\n"
1994 "The Simple DirectMedia error that occured was:\n"
1995 "%s\n\n", SDL_GetError());
1996
1997 use_joystick = 0;
1998 }
1999 else
2000 {
2001 /* Check for proper stick configuration: */
2002
2003 if (SDL_JoystickNumAxes(js) < 2)
2004 {
2005 fprintf(stderr,
2006 "\nWarning: Joystick doesn't have enough axes!\n");
2007
2008 use_joystick = 0;
2009 }
2010 else
2011 {
2012 if (SDL_JoystickNumButtons(js) < 2)
2013 {
2014 fprintf(stderr,
2015 "\nWarning: Joystick doesn't have enough "
2016 "buttons!\n");
2017
2018 use_joystick = 0;
2019 }
2020 }
2021 }
2022 }
2023 }
2024 #else
2025 use_joystick = 0;
2026 #endif
2027
2028
2029 /* Open window: */
2030
2031 if (fullscreen)
2032 {
2033 screen = set_vid_mode(SDL_FULLSCREEN | SDL_HWSURFACE);
2034
2035 if (screen == NULL)
2036 {
2037 fprintf(stderr,
2038 "\nWarning: I could not set up fullscreen video for "
2039 "%dx%d mode.\n"
2040 "The Simple DirectMedia error that occured was:\n"
2041 "%s\n\n", WIDTH, HEIGHT, SDL_GetError());
2042 fullscreen = 0;
2043 }
2044 }
2045
2046 if (!fullscreen)
2047 {
2048 screen = set_vid_mode(0);
2049
2050 if (screen == NULL)
2051 {
2052 fprintf(stderr,
2053 "\nError: I could not open the display.\n"
2054 "The Simple DirectMedia error that occured was:\n"
2055 "%s\n\n", SDL_GetError());
2056 exit(1);
2057 }
2058 }
2059
2060
2061 /* Load background image: */
2062
2063 #ifndef EMBEDDED
2064 tmp = IMG_Load(DATA_PREFIX "images/redspot.jpg");
2065
2066 if (tmp == NULL)
2067 {
2068 fprintf(stderr,
2069 "\nError: I could not open the background image:\n"
2070 DATA_PREFIX "images/redspot.jpg\n"
2071 "The Simple DirectMedia error that occured was:\n"
2072 "%s\n\n", SDL_GetError());
2073 exit(1);
2074 }
2075
2076 bkgd = SDL_DisplayFormat(tmp);
2077 if (bkgd == NULL)
2078 {
2079 fprintf(stderr,
2080 "\nError: I couldn't convert the background image"
2081 "to the display format!\n"
2082 "The Simple DirectMedia error that occured was:\n"
2083 "%s\n\n", SDL_GetError());
2084 exit(1);
2085 }
2086
2087 SDL_FreeSurface(tmp);
2088
2089 #else
2090
2091 tmp = SDL_LoadBMP(DATA_PREFIX "images/redspot-e.bmp");
2092
2093 if (tmp == NULL)
2094 {
2095 fprintf(stderr,
2096 "\nError: I could not open the background image:\n"
2097 DATA_PREFIX "images/redspot-e.bmp\n"
2098 "The Simple DirectMedia error that occured was:\n"
2099 "%s\n\n", SDL_GetError());
2100 exit(1);
2101 }
2102
2103 bkgd = SDL_DisplayFormat(tmp);
2104 if (bkgd == NULL)
2105 {
2106 fprintf(stderr,
2107 "\nError: I couldn't convert the background image"
2108 "to the display format!\n"
2109 "The Simple DirectMedia error that occured was:\n"
2110 "%s\n\n", SDL_GetError());
2111 exit(1);
2112 }
2113
2114 SDL_FreeSurface(tmp);
2115 #endif
2116
2117
2118 #ifndef NOSOUND
2119 /* Init sound: */
2120
2121 if (use_sound)
2122 {
2123 if (Mix_OpenAudio(22050, AUDIO_S16, 2, 512) < 0)
2124 {
2125 fprintf(stderr,
2126 "\nWarning: I could not set up audio for 22050 Hz "
2127 "16-bit stereo.\n"
2128 "The Simple DirectMedia error that occured was:\n"
2129 "%s\n\n", SDL_GetError());
2130 use_sound = FALSE;
2131 }
2132 }
2133
2134
2135 /* Load sound files: */
2136
2137 if (use_sound)
2138 {
2139 for (i = 0; i < NUM_SOUNDS; i++)
2140 {
2141 sounds[i] = Mix_LoadWAV(sound_names[i]);
2142 if (sounds[i] == NULL)
2143 {
2144 fprintf(stderr,
2145 "\nError: I could not load the sound file:\n"
2146 "%s\n"
2147 "The Simple DirectMedia error that occured was:\n"
2148 "%s\n\n", sound_names[i], SDL_GetError());
2149 exit(1);
2150 }
2151 }
2152
2153
2154 game_music = Mix_LoadMUS(mus_game_name);
2155 if (game_music == NULL)
2156 {
2157 fprintf(stderr,
2158 "\nError: I could not load the music file:\n"
2159 "%s\n"
2160 "The Simple DirectMedia error that occured was:\n"
2161 "%s\n\n", mus_game_name, SDL_GetError());
2162 exit(1);
2163 }
2164 }
2165 #endif
2166
2167
2168 seticon();
2169 SDL_WM_SetCaption("Vectoroids", "Vectoroids");
2170 }
2171
2172
2173 /* Set the window's icon: */
2174
seticon(void)2175 void seticon(void)
2176 {
2177 #ifndef EMBEDDED
2178 int masklen;
2179 Uint8 * mask;
2180 SDL_Surface * icon;
2181
2182
2183 /* Load icon into a surface: */
2184
2185 icon = IMG_Load(DATA_PREFIX "images/icon.png");
2186 if (icon == NULL)
2187 {
2188 fprintf(stderr,
2189 "\nError: I could not load the icon image: %s\n"
2190 "The Simple DirectMedia error that occured was:\n"
2191 "%s\n\n", DATA_PREFIX "images/icon.png", SDL_GetError());
2192 exit(1);
2193 }
2194
2195
2196 /* Create mask: */
2197
2198 masklen = (((icon -> w) + 7) / 8) * (icon -> h);
2199 mask = malloc(masklen * sizeof(Uint8));
2200 memset(mask, 0xFF, masklen);
2201
2202
2203 /* Set icon: */
2204
2205 SDL_WM_SetIcon(icon, mask);
2206
2207
2208 /* Free icon surface & mask: */
2209
2210 free(mask);
2211 SDL_FreeSurface(icon);
2212 #endif
2213 }
2214
2215
2216 /* Fast approximate-integer, table-based cosine! Whee! */
2217
fast_cos(int angle)2218 int fast_cos(int angle)
2219 {
2220 angle = (angle % 45);
2221
2222 if (angle < 12)
2223 return(trig[angle]);
2224 else if (angle < 23)
2225 return(-trig[10 - (angle - 12)]);
2226 else if (angle < 34)
2227 return(-trig[angle - 22]);
2228 else
2229 return(trig[45 - angle]);
2230 }
2231
2232
2233 /* Sine based on fast cosine... */
2234
fast_sin(int angle)2235 int fast_sin(int angle)
2236 {
2237 return(- fast_cos((angle + 11) % 45));
2238 }
2239
2240
2241 /* Draw a line: */
2242
draw_line(int x1,int y1,color_type c1,int x2,int y2,color_type c2)2243 void draw_line(int x1, int y1, color_type c1,
2244 int x2, int y2, color_type c2)
2245 {
2246 sdl_drawline(x1, y1, c1, x2, y2, c2);
2247
2248 if (x1 < 0 || x2 < 0)
2249 {
2250 sdl_drawline(x1 + WIDTH, y1, c1, x2 + WIDTH, y2, c2);
2251 }
2252 else if (x1 >= WIDTH || x2 >= WIDTH)
2253 {
2254 sdl_drawline(x1 - WIDTH, y1, c1, x2 - WIDTH, y2, c2);
2255 }
2256
2257 if (y1 < 0 || y2 < 0)
2258 {
2259 sdl_drawline(x1, y1 + HEIGHT, c1, x2, y2 + HEIGHT, c2);
2260 }
2261 else if (y1 >= HEIGHT || y2 >= HEIGHT)
2262 {
2263 sdl_drawline(x1, y1 - HEIGHT, c1, x2, y2 - HEIGHT, c2);
2264 }
2265 }
2266
2267
2268 /* Create a color_type struct out of RGB values: */
2269
mkcolor(int r,int g,int b)2270 color_type mkcolor(int r, int g, int b)
2271 {
2272 color_type c;
2273
2274 if (r > 255)
2275 r = 255;
2276 if (g > 255)
2277 g = 255;
2278 if (b > 255)
2279 b = 255;
2280
2281 c.r = (Uint8) r;
2282 c.g = (Uint8) g;
2283 c.b = (Uint8) b;
2284
2285 return c;
2286 }
2287
2288
2289 /* Draw a line on an SDL surface: */
2290
sdl_drawline(int x1,int y1,color_type c1,int x2,int y2,color_type c2)2291 void sdl_drawline(int x1, int y1, color_type c1,
2292 int x2, int y2, color_type c2)
2293 {
2294 int dx, dy;
2295 #ifndef EMBEDDED
2296 float cr, cg, cb, rd, gd, bd;
2297 #endif
2298 float m, b;
2299
2300
2301 if (clip(&x1, &y1, &x2, &y2))
2302 {
2303 dx = x2 - x1;
2304 dy = y2 - y1;
2305
2306 if (dx != 0)
2307 {
2308 m = ((float) dy) / ((float) dx);
2309 b = y1 - m * x1;
2310
2311 if (x2 >= x1)
2312 dx = 1;
2313 else
2314 dx = -1;
2315
2316 #ifndef EMBEDDED
2317 cr = c1.r;
2318 cg = c1.g;
2319 cb = c1.b;
2320
2321 rd = (float) (c2.r - c1.r) / (float) (x2 - x1) * dx;
2322 gd = (float) (c2.g - c1.g) / (float) (x2 - x1) * dx;
2323 bd = (float) (c2.b - c1.b) / (float) (x2 - x1) * dx;
2324 #endif
2325
2326 while (x1 != x2)
2327 {
2328 y1 = m * x1 + b;
2329 y2 = m * (x1 + dx) + b;
2330
2331 #ifndef EMBEDDED
2332 drawvertline(x1, y1, mkcolor(cr, cg, cb),
2333 y2, mkcolor(cr + rd, cg + gd, cb + bd));
2334 #else
2335 drawvertline(x1, y1, mkcolor(c1.r, c1.g, c1.b),
2336 y2, mkcolor(c1.r, c1.g, c1.b));
2337 #endif
2338
2339 x1 = x1 + dx;
2340
2341
2342 #ifndef EMBEDDED
2343 cr = cr + rd;
2344 cg = cg + gd;
2345 cb = cb + bd;
2346 #endif
2347 }
2348 }
2349 else
2350 drawvertline(x1, y1, c1, y2, c2);
2351 }
2352 }
2353
2354
2355 /* Clip lines to window: */
2356
clip(int * x1,int * y1,int * x2,int * y2)2357 int clip(int * x1, int * y1, int * x2, int * y2)
2358 {
2359 #ifndef EMBEDDED
2360
2361 float fx1, fx2, fy1, fy2, tmp;
2362 float m;
2363 unsigned char code1, code2;
2364 int done, draw, swapped;
2365 unsigned char ctmp;
2366 fx1 = (float) *x1;
2367 fy1 = (float) *y1;
2368 fx2 = (float) *x2;
2369 fy2 = (float) *y2;
2370
2371
2372 done = FALSE;
2373 draw = FALSE;
2374 m = 0;
2375 swapped = FALSE;
2376
2377
2378 while (!done)
2379 {
2380 code1 = encode(fx1, fy1);
2381 code2 = encode(fx2, fy2);
2382
2383 if (!(code1 | code2))
2384 {
2385 done = TRUE;
2386 draw = TRUE;
2387 }
2388 else if (code1 & code2)
2389 {
2390 done = TRUE;
2391 }
2392 else
2393 {
2394 if (!code1)
2395 {
2396 swapped = TRUE;
2397 tmp = fx1;
2398 fx1 = fx2;
2399 fx2 = tmp;
2400
2401 tmp = fy1;
2402 fy1 = fy2;
2403 fy2 = tmp;
2404
2405 ctmp = code1;
2406 code1 = code2;
2407 code2 = ctmp;
2408 }
2409
2410
2411 if (fx2 != fx1)
2412 m = (fy2 - fy1) / (fx2 - fx1);
2413 else
2414 m = 1;
2415
2416 if (code1 & LEFT_EDGE)
2417 {
2418 fy1 += ((0 - (fx1)) * m);
2419 fx1 = 0;
2420 }
2421 else if (code1 & RIGHT_EDGE)
2422 {
2423 fy1 += (((WIDTH - 1) - (fx1)) * m);
2424 fx1 = (WIDTH - 1);
2425 }
2426 else if (code1 & TOP_EDGE)
2427 {
2428 if (fx2 != fx1)
2429 fx1 += ((0 - (fy1)) / m);
2430 fy1 = 0;
2431 }
2432 else if (code1 & BOTTOM_EDGE)
2433 {
2434 if (fx2 != fx1)
2435 fx1 += (((HEIGHT - 1) - (fy1)) / m);
2436 fy1 = (HEIGHT - 1);
2437 }
2438 }
2439 }
2440
2441
2442 if (swapped)
2443 {
2444 tmp = fx1;
2445 fx1 = fx2;
2446 fx2 = tmp;
2447
2448 tmp = fy1;
2449 fy1 = fy2;
2450 fy2 = tmp;
2451 }
2452
2453
2454 *x1 = (int) fx1;
2455 *y1 = (int) fy1;
2456 *x2 = (int) fx2;
2457 *y2 = (int) fy2;
2458
2459 return(draw);
2460 #else
2461
2462 if (*x1 < 0 || *x1 >= WIDTH ||
2463 *y1 < 0 || *y1 >= HEIGHT ||
2464 *x2 < 0 || *x2 >= WIDTH ||
2465 *y2 < 0 || *y2 >= HEIGHT)
2466 return FALSE;
2467 else
2468 return TRUE;
2469
2470
2471 #endif
2472 }
2473
2474
2475 /* Where does this line clip? */
2476
encode(float x,float y)2477 unsigned char encode(float x, float y)
2478 {
2479 unsigned char code;
2480
2481 code = 0x00;
2482
2483 if (x < 0.0)
2484 code = code | LEFT_EDGE;
2485 else if (x >= (float) WIDTH)
2486 code = code | RIGHT_EDGE;
2487
2488 if (y < 0.0)
2489 code = code | TOP_EDGE;
2490 else if (y >= (float) HEIGHT)
2491 code = code | BOTTOM_EDGE;
2492
2493 return code;
2494 }
2495
2496
2497 /* Draw a verticle line: */
2498
drawvertline(int x,int y1,color_type c1,int y2,color_type c2)2499 void drawvertline(int x, int y1, color_type c1,
2500 int y2, color_type c2)
2501 {
2502 int tmp, dy;
2503 #ifndef EMBEDDED
2504 float cr, cg, cb, rd, gd, bd;
2505 #else
2506 int cr, cg, cb;
2507 #endif
2508
2509 if (y1 > y2)
2510 {
2511 tmp = y1;
2512 y1 = y2;
2513 y2 = tmp;
2514
2515 #ifndef EMBEDDED
2516 tmp = c1.r;
2517 c1.r = c2.r;
2518 c2.r = tmp;
2519
2520 tmp = c1.g;
2521 c1.g = c2.g;
2522 c2.g = tmp;
2523
2524 tmp = c1.b;
2525 c1.b = c2.b;
2526 c2.b = tmp;
2527 #endif
2528 }
2529
2530 cr = c1.r;
2531 cg = c1.g;
2532 cb = c1.b;
2533
2534 #ifndef EMBEDDED
2535 if (y1 != y2)
2536 {
2537 rd = (float) (c2.r - c1.r) / (float) (y2 - y1);
2538 gd = (float) (c2.g - c1.g) / (float) (y2 - y1);
2539 bd = (float) (c2.b - c1.b) / (float) (y2 - y1);
2540 }
2541 else
2542 {
2543 rd = 0;
2544 gd = 0;
2545 bd = 0;
2546 }
2547 #endif
2548
2549 for (dy = y1; dy <= y2; dy++)
2550 {
2551 putpixel(screen, x + 1, dy + 1, SDL_MapRGB(screen->format, 0, 0, 0));
2552
2553 putpixel(screen, x, dy, SDL_MapRGB(screen->format,
2554 (Uint8) cr,
2555 (Uint8) cg,
2556 (Uint8) cb));
2557
2558 #ifndef EMBEDDED
2559 cr = cr + rd;
2560 cg = cg + gd;
2561 cb = cb + bd;
2562 #endif
2563 }
2564 }
2565
2566
2567 /* Draw a single pixel into the surface: */
2568
putpixel(SDL_Surface * surface,int x,int y,Uint32 pixel)2569 void putpixel(SDL_Surface * surface, int x, int y, Uint32 pixel)
2570 {
2571 int bpp;
2572 Uint8 * p;
2573
2574
2575 /* Assuming the X/Y values are within the bounds of this surface... */
2576
2577 if (x >= 0 && y >= 0 && x < WIDTH && y < HEIGHT)
2578 {
2579 /* Determine bytes-per-pixel for the surface in question: */
2580
2581 bpp = surface->format->BytesPerPixel;
2582
2583
2584 /* Set a pointer to the exact location in memory of the pixel
2585 in question: */
2586
2587 p = (((Uint8 *) surface->pixels) + /* Start at beginning of RAM */
2588 (y * surface->pitch) + /* Go down Y lines */
2589 (x * bpp)); /* Go in X pixels */
2590
2591
2592 /* Set the (correctly-sized) piece of data in the surface's RAM
2593 to the pixel value sent in: */
2594
2595 if (bpp == 1)
2596 *p = pixel;
2597 else if (bpp == 2)
2598 *(Uint16 *)p = pixel;
2599 else if (bpp == 3)
2600 {
2601 if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
2602 {
2603 p[0] = (pixel >> 16) & 0xff;
2604 p[1] = (pixel >> 8) & 0xff;
2605 p[2] = pixel & 0xff;
2606 }
2607 else
2608 {
2609 p[0] = pixel & 0xff;
2610 p[1] = (pixel >> 8) & 0xff;
2611 p[2] = (pixel >> 16) & 0xff;
2612 }
2613 }
2614 else if (bpp == 4)
2615 {
2616 *(Uint32 *)p = pixel;
2617 }
2618 }
2619 }
2620
2621
2622
2623 /* Draw a line segment, rotated around a center point: */
2624
draw_segment(int r1,int a1,color_type c1,int r2,int a2,color_type c2,int cx,int cy,int a)2625 void draw_segment(int r1, int a1,
2626 color_type c1,
2627 int r2, int a2,
2628 color_type c2,
2629 int cx, int cy, int a)
2630 {
2631 draw_line(((fast_cos((a1 + a) >> 3) * r1) >> 10) + cx,
2632 cy - ((fast_sin((a1 + a) >> 3) * r1) >> 10),
2633 c1,
2634 ((fast_cos((a2 + a) >> 3) * r2) >> 10) + cx,
2635 cy - ((fast_sin((a2 + a) >> 3) * r2) >> 10),
2636 c2);
2637 }
2638
2639
2640 /* Add a bullet: */
2641
add_bullet(int x,int y,int a,int xm,int ym)2642 void add_bullet(int x, int y, int a, int xm, int ym)
2643 {
2644 int i, found;
2645
2646 found = -1;
2647
2648 for (i = 0; i < NUM_BULLETS && found == -1; i++)
2649 {
2650 if (bullets[i].timer <= 0)
2651 found = i;
2652 }
2653
2654 if (found != -1)
2655 {
2656 #ifndef EMBEDDED
2657 bullets[found].timer = 50;
2658 #else
2659 bullets[found].timer = 30;
2660 #endif
2661
2662 bullets[found].x = x;
2663 bullets[found].y = y;
2664
2665 bullets[found].xm = ((fast_cos(a >> 3) * 5) >> 10) + (xm >> 4);
2666 bullets[found].ym = - ((fast_sin(a >> 3) * 5) >> 10) + (ym >> 4);
2667
2668
2669 playsound(SND_BULLET);
2670 }
2671 }
2672
2673
2674 /* Add an asteroid: */
2675
add_asteroid(int x,int y,int xm,int ym,int size)2676 void add_asteroid(int x, int y, int xm, int ym, int size)
2677 {
2678 int i, found;
2679
2680
2681 /* Find a slot: */
2682
2683 found = -1;
2684
2685 for (i = 0; i < NUM_ASTEROIDS && found == -1; i++)
2686 {
2687 if (asteroids[i].alive == 0)
2688 found = i;
2689 }
2690
2691
2692 /* Hack: No asteroids should be stationary! */
2693
2694 while (xm == 0)
2695 {
2696 xm = (rand() % 3) - 1;
2697 }
2698
2699
2700 if (found != -1)
2701 {
2702 asteroids[found].alive = 1;
2703
2704 asteroids[found].x = x;
2705 asteroids[found].y = y;
2706 asteroids[found].xm = xm;
2707 asteroids[found].ym = ym;
2708
2709 asteroids[found].angle = (rand() % 360);
2710 asteroids[found].angle_m = (rand() % 6) - 3;
2711
2712 asteroids[found].size = size;
2713
2714 for (i = 0; i < AST_SIDES; i++)
2715 {
2716 asteroids[found].shape[i].radius = (rand() % 3);
2717 asteroids[found].shape[i].angle = i * 60 + (rand() % 40);
2718 }
2719 }
2720 }
2721
2722
2723 /* Add a bit: */
2724
add_bit(int x,int y,int xm,int ym)2725 void add_bit(int x, int y, int xm, int ym)
2726 {
2727 int i, found;
2728
2729 found = -1;
2730
2731 for (i = 0; i < NUM_BITS && found == -1; i++)
2732 {
2733 if (bits[i].timer <= 0)
2734 found = i;
2735 }
2736
2737
2738 if (found != -1)
2739 {
2740 bits[found].timer = 16;
2741
2742 bits[found].x = x;
2743 bits[found].y = y;
2744 bits[found].xm = xm;
2745 bits[found].ym = ym;
2746 }
2747 }
2748
2749
2750 /* Draw an asteroid: */
2751
draw_asteroid(int size,int x,int y,int angle,shape_type * shape)2752 void draw_asteroid(int size, int x, int y, int angle, shape_type * shape)
2753 {
2754 int i, b1, b2;
2755 int div;
2756
2757 #ifndef EMBEDDED
2758 div = 240;
2759 #else
2760 div = 120;
2761 #endif
2762
2763 for (i = 0; i < AST_SIDES - 1; i++)
2764 {
2765 b1 = (((shape[i].angle + angle) % 180) * 255) / div;
2766 b2 = (((shape[i + 1].angle + angle) % 180) * 255) / div;
2767
2768 draw_segment((size * (AST_RADIUS - shape[i].radius)),
2769 shape[i].angle, mkcolor(b1, b1, b1),
2770 (size * (AST_RADIUS - shape[i + 1].radius)),
2771 shape[i + 1].angle, mkcolor(b2, b2, b2),
2772 x, y,
2773 angle);
2774 }
2775
2776 b1 = (((shape[AST_SIDES - 1].angle + angle) % 180) * 255) / div;
2777 b2 = (((shape[0].angle + angle) % 180) * 255) / div;
2778
2779 draw_segment((size * (AST_RADIUS - shape[AST_SIDES - 1].radius)),
2780 shape[AST_SIDES - 1].angle, mkcolor(b1, b1, b1),
2781 (size * (AST_RADIUS - shape[0].radius)),
2782 shape[0].angle, mkcolor(b2, b2, b2),
2783 x, y,
2784 angle);
2785 }
2786
2787
2788 /* Queue a sound! */
2789
playsound(int snd)2790 void playsound(int snd)
2791 {
2792 int which, i;
2793
2794 #ifndef NOSOUND
2795 if (use_sound)
2796 {
2797 #ifdef EMBEDDED
2798 which = -1;
2799 #else
2800 which = (rand() % 3) + CHAN_THRUST;
2801 for (i = CHAN_THRUST; i < 4; i++)
2802 {
2803 if (!Mix_Playing(i))
2804 which = i;
2805 }
2806 #endif
2807
2808 Mix_PlayChannel(which, sounds[snd], 0);
2809 }
2810 #endif
2811 }
2812
2813
2814 /* Break an asteroid and add an explosion: */
2815
hurt_asteroid(int j,int xm,int ym,int exp_size)2816 void hurt_asteroid(int j, int xm, int ym, int exp_size)
2817 {
2818 int k;
2819
2820 add_score(100 / (asteroids[j].size + 1));
2821
2822 if (asteroids[j].size > 1)
2823 {
2824 /* Break the rock into two smaller ones! */
2825
2826 add_asteroid(asteroids[j].x,
2827 asteroids[j].y,
2828 ((asteroids[j].xm + xm) / 2),
2829 (asteroids[j].ym + ym),
2830 asteroids[j].size - 1);
2831
2832 add_asteroid(asteroids[j].x,
2833 asteroids[j].y,
2834 (asteroids[j].xm + xm),
2835 ((asteroids[j].ym + ym) / 2),
2836 asteroids[j].size - 1);
2837 }
2838
2839
2840 /* Make the original go away: */
2841
2842 asteroids[j].alive = 0;
2843
2844
2845 /* Add explosion: */
2846
2847 playsound(SND_AST1 + (asteroids[j].size) - 1);
2848
2849 for (k = 0; k < exp_size; k++)
2850 {
2851 add_bit((asteroids[j].x -
2852 (asteroids[j].size * AST_RADIUS) +
2853 (rand() % (AST_RADIUS * 2))),
2854 (asteroids[j].y -
2855 (asteroids[j].size * AST_RADIUS) +
2856 (rand() % (AST_RADIUS * 2))),
2857 ((rand() % (asteroids[j].size * 3)) -
2858 (asteroids[j].size) +
2859 ((xm + asteroids[j].xm) / 3)),
2860 ((rand() % (asteroids[j].size * 3)) -
2861 (asteroids[j].size) +
2862 ((ym + asteroids[j].ym) / 3)));
2863 }
2864 }
2865
2866
2867 /* Increment score: */
2868
add_score(int amount)2869 void add_score(int amount)
2870 {
2871 /* See if they deserve a new life: */
2872
2873 if (score / ONEUP_SCORE < (score + amount) / ONEUP_SCORE)
2874 {
2875 lives++;
2876 strcpy(zoom_str, "EXTRA LIFE");
2877 text_zoom = ZOOM_START;
2878 playsound(SND_EXTRALIFE);
2879 }
2880
2881
2882
2883 /* Add to score: */
2884
2885 score = score + amount;
2886 }
2887
2888
2889 /* Draw a character: */
2890
draw_char(char c,int x,int y,int r,color_type cl)2891 void draw_char(char c, int x, int y, int r, color_type cl)
2892 {
2893 int i, v;
2894
2895 /* Which vector is this character? */
2896
2897 v = -1;
2898 if (c >= '0' && c <= '9')
2899 v = (c - '0');
2900 else if (c >= 'A' && c <= 'Z')
2901 v = (c - 'A') + 10;
2902
2903
2904 if (v != -1)
2905 {
2906 for (i = 0; i < 5; i++)
2907 {
2908 if (char_vectors[v][i][0] != -1)
2909 {
2910 draw_line(x + (char_vectors[v][i][0] * r),
2911 y + (char_vectors[v][i][1] * r),
2912 cl,
2913 x + (char_vectors[v][i][2] * r),
2914 y + (char_vectors[v][i][3] * r),
2915 cl);
2916 }
2917 }
2918 }
2919 }
2920
2921
draw_text(char * str,int x,int y,int s,color_type c)2922 void draw_text(char * str, int x, int y, int s, color_type c)
2923 {
2924 int i;
2925
2926 for (i = 0; i < strlen(str); i++)
2927 draw_char(str[i], i * (s + 3) + x, y, s, c);
2928 }
2929
2930
draw_thick_line(int x1,int y1,color_type c1,int x2,int y2,color_type c2)2931 void draw_thick_line(int x1, int y1, color_type c1,
2932 int x2, int y2, color_type c2)
2933 {
2934 draw_line(x1, y1, c1, x2, y2, c2);
2935 draw_line(x1 + 1, y1 + 1, c1, x2 + 1, y2 + 1, c2);
2936 }
2937
2938
reset_level(void)2939 void reset_level(void)
2940 {
2941 int i;
2942
2943
2944 for (i = 0; i < NUM_BULLETS; i++)
2945 bullets[i].timer = 0;
2946
2947 for (i = 0; i < NUM_ASTEROIDS; i++)
2948 asteroids[i].alive = 0;
2949
2950 for (i = 0; i < NUM_BITS; i++)
2951 bits[i].timer = 0;
2952
2953 for (i = 0; i < (level + 1) && i < 10; i++)
2954 {
2955 #ifndef EMBEDDED
2956 add_asteroid(/* x */ (rand() % 40) + ((WIDTH - 40) * (rand() % 2)),
2957 /* y */ (rand() % HEIGHT),
2958 /* xm */ (rand() % 9) - 4,
2959 /* ym */ ((rand() % 9) - 4) * 4,
2960 /* size */ (rand() % 3) + 2);
2961 #else
2962 add_asteroid(/* x */ (rand() % WIDTH),
2963 /* y */ (rand() % 40) + ((HEIGHT - 40) * (rand() % 2)),
2964 /* xm */ ((rand() % 9) - 4) * 4,
2965 /* ym */ (rand() % 9) - 4,
2966 /* size */ (rand() % 3) + 2);
2967 #endif
2968 }
2969
2970
2971 sprintf(zoom_str, "LEVEL %d", level);
2972
2973 text_zoom = ZOOM_START;
2974 }
2975
2976
2977 /* Show program version: */
2978
show_version(void)2979 void show_version(void)
2980 {
2981 printf("Vectoroids - Version " VER_VERSION " (" VER_DATE ")\n");
2982 }
2983
2984
2985 /* Show usage display: */
2986
show_usage(FILE * f,char * prg)2987 void show_usage(FILE * f, char * prg)
2988 {
2989 fprintf(f, "Usage: %s {--help | --usage | --version | --copying }\n"
2990 " %s [--fullscreen] [--nosound]\n\n", prg, prg);
2991 }
2992
2993
2994 /* Set video mode: */
2995 /* Contributed to "Defendguin" by Mattias Engdegard <f91-men@nada.kth.se> */
2996
set_vid_mode(unsigned flags)2997 SDL_Surface * set_vid_mode(unsigned flags)
2998 {
2999 /* Prefer 16bpp, but also prefer native modes to emulated 16bpp. */
3000
3001 int depth;
3002
3003 depth = SDL_VideoModeOK(WIDTH, HEIGHT, 16, flags);
3004 return depth ? SDL_SetVideoMode(WIDTH, HEIGHT, depth, flags) : NULL;
3005 }
3006
3007
3008 /* Draw text, centered horizontally: */
3009
draw_centered_text(char * str,int y,int s,color_type c)3010 void draw_centered_text(char * str, int y, int s, color_type c)
3011 {
3012 draw_text(str, (WIDTH - strlen(str) * (s + 3)) / 2, y, s, c);
3013 }
3014
3015