1 /*
2 brickout.c
3
4 A break-the-bricks style game for X11 or SDL, originally made for the
5 Agenda VR3 Linux- and X-Window-based PDA, but also ported to the
6 Sharp Zaurus SL-5500 Linux- and Qtopia-based PDA (using SDL).
7
8 by Bill Kendrick
9 bill@newbreedsoftware.com
10 http://www.newbreedsoftware.com/brickout/
11
12 With contributions from Tom Satter
13 tsatter@purecode.com
14
15 May 17, 2001 - June 9, 2002
16 */
17
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22
23 #ifndef USE_SDL
24
25 #include <X11/Xlib.h>
26 #include <X11/xpm.h>
27 #include <X11/keysym.h>
28 #include <X11/Xutil.h>
29 #include <X11/Xatom.h>
30
31 #define XBUTTON xbutton
32 #define SDL_X_OFF 0
33 #define SDL_Y_OFF 0
34
35 #else
36
37 #include "SDL.h"
38 #include "SDL_mixer.h"
39
40 typedef SDL_Surface * Window;
41 typedef SDL_Surface * Pixmap;
42 typedef SDL_Surface * Drawable;
43 typedef int Display;
44 typedef Uint32 GC;
45 typedef SDL_Event XEvent;
46 typedef SDLKey KeySym;
47
48 #define XBUTTON button
49
50 #define ButtonPress SDL_MOUSEBUTTONDOWN
51 #define MotionNotify SDL_MOUSEMOTION
52 #define KeyPress SDL_KEYDOWN
53 #define KeyRelease SDL_KEYUP
54
55 #define XK_Left SDLK_LEFT
56 #define XK_Right SDLK_RIGHT
57 #define XK_Page_Up SDLK_UNKNOWN
58 #define XK_Page_Down SDLK_UNKNOWN
59 #define XK_space SDLK_SPACE
60 #define XK_Escape SDLK_ESCAPE
61
62 #define SDL_X_OFF 40
63 #define SDL_Y_OFF 40
64
65 #endif
66
67 #include <unistd.h>
68 #include <sys/time.h>
69
70 #ifndef USE_SDL
71
72 #include IMAGEDIR "ball.xpm"
73 #include IMAGEDIR "brick1.xpm"
74 #include IMAGEDIR "brick2.xpm"
75 #include IMAGEDIR "brick3.xpm"
76 #include IMAGEDIR "brick4.xpm"
77 #include IMAGEDIR "brick5.xpm"
78 #include IMAGEDIR "conton.xpm"
79 #include IMAGEDIR "contoff.xpm"
80 #include IMAGEDIR "done.xpm"
81 #include IMAGEDIR "launchoff.xpm"
82 #include IMAGEDIR "launchon.xpm"
83 #include IMAGEDIR "leftpipe.xpm"
84 #include IMAGEDIR "numbers.xpm"
85 #include IMAGEDIR "paddle.xpm"
86 #include IMAGEDIR "pause.xpm"
87 #include IMAGEDIR "soundoff.xpm"
88 #include IMAGEDIR "soundon.xpm"
89 #include IMAGEDIR "negoff.xpm"
90 #include IMAGEDIR "negon.xpm"
91 #include IMAGEDIR "posoff.xpm"
92 #include IMAGEDIR "poson.xpm"
93 #include IMAGEDIR "start.xpm"
94 #include IMAGEDIR "stats.xpm"
95 #include IMAGEDIR "stats_leftpipe.xpm"
96 #include IMAGEDIR "stats_rightpipe.xpm"
97 #include IMAGEDIR "stats_toppipe.xpm"
98 #include IMAGEDIR "title.xpm"
99 #include IMAGEDIR "water.xpm"
100
101 #else
102
103 const char
104 * ball_xpm = IMAGEDIR "ball.bmp",
105 * brick1_xpm = IMAGEDIR "brick1.bmp",
106 * brick2_xpm = IMAGEDIR "brick2.bmp",
107 * brick3_xpm = IMAGEDIR "brick3.bmp",
108 * brick4_xpm = IMAGEDIR "brick4.bmp",
109 * brick5_xpm = IMAGEDIR "brick5.bmp",
110 * conton_xpm = IMAGEDIR "conton.bmp",
111 * contoff_xpm = IMAGEDIR "contoff.bmp",
112 * done_xpm = IMAGEDIR "done.bmp",
113 * launchoff_xpm = IMAGEDIR "launchoff.bmp",
114 * launchon_xpm = IMAGEDIR "launchon.bmp",
115 * leftpipe_xpm = IMAGEDIR "leftpipe.bmp",
116 * numbers_xpm = IMAGEDIR "numbers.bmp",
117 * paddle_xpm = IMAGEDIR "paddle.bmp",
118 * pause_xpm = IMAGEDIR "pause.bmp",
119 * soundoff_xpm = IMAGEDIR "soundoff.bmp",
120 * soundon_xpm = IMAGEDIR "soundon.bmp",
121 * musicoff_xpm = IMAGEDIR "musicoff.bmp",
122 * musicon_xpm = IMAGEDIR "musicon.bmp",
123 * negoff_xpm = IMAGEDIR "negoff.bmp",
124 * negon_xpm = IMAGEDIR "negon.bmp",
125 * posoff_xpm = IMAGEDIR "posoff.bmp",
126 * poson_xpm = IMAGEDIR "poson.bmp",
127 * start_xpm = IMAGEDIR "start.bmp",
128 * stats_xpm = IMAGEDIR "stats.bmp",
129 * stats_leftpipe_xpm = IMAGEDIR "stats_leftpipe.bmp",
130 * stats_rightpipe_xpm = IMAGEDIR "stats_rightpipe.bmp",
131 * stats_toppipe_xpm = IMAGEDIR "stats_toppipe.bmp",
132 * title_xpm = IMAGEDIR "title.bmp",
133 * water_xpm = IMAGEDIR "water.bmp";
134
135 #endif
136
137
138 /* Globals: */
139
140 Display *display;
141 Window window;
142 GC whitegc, blackgc, pastegc;
143
144 Pixmap pix_title, pix_leftpipe;
145 Pixmap pix_stats, pix_stats_toppipe, pix_stats_leftpipe;
146 Pixmap pix_stats_rightpipe, pix_water;
147 Pixmap pix_brick1, pix_brick2, pix_brick3, pix_brick4, pix_brick5;
148 Pixmap pix_done, pix_start, pix_soundon, pix_soundoff, pix_conton, pix_contoff,
149 pix_negon, pix_negoff, pix_poson, pix_posoff;
150 Pixmap pix_pause, pix_launchon, pix_launchoff, pix_numbers;
151 Pixmap pix_ball, pix_paddle;
152
153 #ifdef USE_SDL
154 Pixmap pix_musicon, pix_musicoff;
155 #endif
156
157 int score, balls, level, paddle_x, paddle_target_x;
158 int ball_launched, ball_bx, ball_by;
159 int dir_x, dir_y, brake, slope;
160 int redraw_brick_x, redraw_brick_y;
161
162 char cur_board[6][10];
163 int num_bricks_left;
164
165
166 #ifdef USE_SDL
167
168 typedef struct breaking_brick_type {
169 int time;
170 char kind;
171 } breaking_brick_type;
172
173 breaking_brick_type breaking_bricks[6][10];
174
175
176
177 #define NUM_GAME_MUSICS 6
178
179 char * music_fnames[NUM_GAME_MUSICS] = {
180 MUSICDIR "yawny.mod",
181 MUSICDIR "Bootmusic_9.mod",
182 MUSICDIR "Dj_bobo_die.mod",
183 MUSICDIR "Pleasure_to_paso.mod",
184 MUSICDIR "invasion.mod",
185 MUSICDIR "Valley_of_chip_6.mod"
186 };
187
188 int use_sound;
189 Mix_Chunk * snd_wall, * snd_ceiling, * snd_metal, * snd_brick,
190 * snd_unbreakable, * snd_paddle, * snd_die;
191 Mix_Music * mus_title, * mus_game[NUM_GAME_MUSICS];
192
193 #endif
194
195
196
197 int sound, game_pending;
198
199 #ifdef USE_SDL
200 int music;
201 #endif
202
203 int slopes_x[7] = {
204 0,
205 392,
206 800,
207 1144,
208 1448,
209 1720,
210 1896
211 };
212
213 int slopes_y[7] = {
214 2048,
215 2008,
216 1888,
217 1696,
218 1448,
219 1112,
220 768
221 };
222
223 /* Valid symbols:
224 "-" - Regular brick
225 "=" - Shiny, two-hit brick
226 "/" - Gradient brick
227 "#" - Bevelled brick
228 ":" - Indestructable rivetted brick
229 */
230
231 #define NUM_LEVELS 20
232
233 char boards[NUM_LEVELS][6][10] = {
234 {
235 /* Level 1 */
236 " ",
237 "----------",
238 "----------",
239 "----------",
240 " ",
241 " "
242 },
243 {
244 /* Level 2 */
245 "----------",
246 "----------",
247 "----------",
248 "----------",
249 "==========",
250 "::------::"
251 },
252 {
253 /* Level 3 */
254 "----------",
255 "----------",
256 "---::::---",
257 "---::::---",
258 "----------",
259 "=========="
260 },
261 {
262 /* Level 4 */
263 "==========",
264 " :::::: ",
265 "----------",
266 " ::--:: ",
267 "----------",
268 " --::-- "
269 },
270 { /* Level 5 */
271 "=-/####/-=",
272 "-=-/##/-=-",
273 "/-=-//-=-/",
274 " /-=--=-/ ",
275 " /-==-/ ",
276 " /--/ "
277 },
278 { /* Level 6 */
279 "##########",
280 "==========",
281 "##########",
282 " ",
283 ":::: ::::",
284 ":: ::"
285 },
286 { /* Level 7 */
287 "#/#/#/#/#/",
288 "/#/#/#/#/#",
289 "#/#/#/#/#/",
290 "/#/#/#/#/#",
291 " ",
292 " "
293 },
294 { /* Level 8 */
295 " /####/ ",
296 " /##//##/ ",
297 " //####// ",
298 " /##//##/ ",
299 " /####/ ",
300 " "
301 },
302 { /* Level 9 */
303 "//////////",
304 " ////// ",
305 " ---- ",
306 "##: :##",
307 "#: :#",
308 ": :"
309 },
310 { /* Level 10 */
311 " ",
312 " // // // ",
313 "=-=-=-=-=-",
314 "-=-=-=-=-=",
315 " ",
316 "==--==--=="
317 },
318 { /* Level 11 */
319 ":: ::",
320 " ",
321 " :::::: ",
322 " ",
323 "= =",
324 "::: :: :::"
325 },
326 { /* Level 12 */
327 " ",
328 "//////////",
329 "####::####",
330 "==========",
331 " ",
332 " -- -- -- "
333 },
334 { /* Level 13 */
335 " #### ",
336 " ==## ",
337 " =## ",
338 " =## ",
339 " ==## ",
340 " #### "
341 },
342 { /* Level 14 */
343 "::::::::::",
344 "::======::",
345 ":========:",
346 ":=== ===:",
347 ":== ==:",
348 "::= == =::"
349 },
350 { /* Level 15 */
351 "/########/",
352 "##########",
353 "#= =#",
354 "#= =#",
355 "##======##",
356 "/########/"
357 },
358 { /* Level 16 */
359 " = = ",
360 " = = ",
361 ": ## :",
362 ": ## :",
363 " = = ",
364 " = = "
365 },
366 { /* Level 17 */
367 " == ",
368 " ==--== ",
369 "==--//--==",
370 "--//##//--",
371 "//## ##//",
372 "## ##"
373 },
374 { /* Level 18 */
375 " ",
376 " ==== ",
377 " ###### ",
378 " == ",
379 " = = ",
380 " = = "
381 },
382 { /* Level 19 */
383 ":########:",
384 ":########:",
385 "///:==:///",
386 "///:==:///",
387 ":--------:",
388 ":--------:"
389 },
390 { /* Level 20 */
391 "//////////",
392 "==========",
393 "##########",
394 " ",
395 " ",
396 ": :::::: :"
397 }
398 };
399
400
401 /* Local function prototypes: */
402
403 void setup(void);
404 void loadsettings(void);
405 int title(void);
406 void draw_titlescreen(void);
407 void game(void);
408 void draw_gamescreen(void);
409 #ifndef USE_SDL
410 GC CreateGC(Display *display, Drawable drawable, unsigned long forecolor,
411 unsigned long backcolor);
412 void LoadImage(char ** xpm, Pixmap * pix);
413 #else
414 Pixmap LoadImage(const char * file);
415 #endif
416 void DrawImage(Pixmap pix, Drawable dest, int x, int y, int w, int h);
417 void DrawNumbers(char * str, int x, int y);
418 #ifndef USE_SDL
419 void playsound(int pitch, int duration);
420 #else
421 void playsound(Mix_Chunk * snd);
422 #endif
423 void launch_ball(void);
424 void add_score(int val);
425 void draw_brick(int x, int y);
426 void reset_level(void);
427 int hit_brick(int x,int y);
428 #ifdef USE_SDL
429 Mix_Chunk * LoadSound(char * fname);
430 #endif
431
432
433 /* --- MAIN! --- */
434
main(int argc,char * argv[])435 int main(int argc, char * argv[])
436 {
437 int done;
438
439
440 setup();
441
442 loadsettings();
443
444 level = 1;
445 do
446 {
447 done = title();
448
449 if (!done)
450 game();
451 }
452 while (!done);
453
454 #ifdef USE_SDL
455 SDL_Quit();
456 #endif
457
458 return(0);
459 }
460
461
462 /* Title: */
463
title(void)464 int title(void)
465 {
466 int done, quit, want_level_chg, bx, by;
467 XEvent event;
468 KeySym key;
469 char str[24];
470 #ifdef USE_SDL
471 Uint32 last_tick, cur_tick;
472 #endif
473
474
475 draw_titlescreen();
476
477
478 /* Title loop: */
479
480 done = 0;
481 quit = 0;
482
483 #ifdef USE_SDL
484 last_tick = SDL_GetTicks();
485 #endif
486
487
488 do
489 {
490 want_level_chg = 0;
491
492 #ifndef USE_SDL
493 while (XPending(display))
494 {
495 XNextEvent(display, &event);
496 #else
497 while (SDL_PollEvent(&event) > 0)
498 {
499 #endif
500
501 if (event.type == ButtonPress)
502 {
503 bx = event.XBUTTON.x - SDL_X_OFF;
504 by = event.XBUTTON.y - SDL_Y_OFF;
505
506 if (bx >= 64 &&
507 bx <= 96 &&
508 by >= 170 &&
509 by <= 183)
510 {
511 /* Start! */
512
513 game_pending = 0;
514 done = 1;
515 }
516 else if (bx >= 64 &&
517 bx <= 96 &&
518 by >= 190 &&
519 by <= 203 &&
520 game_pending == 1)
521 {
522 /* Continue! */
523
524 done = 1;
525 }
526 else if (bx >= 14 &&
527 bx <= 46 &&
528 by >= 225 &&
529 by <= 238)
530 {
531 /* Done button! */
532
533 done = 1;
534 quit = 1;
535 }
536 else if (bx >= 126 &&
537 bx <= 144 &&
538 by >= 225 &&
539 by <= 238)
540 {
541 /* Sound control! */
542
543 sound = !sound;
544
545 if (sound == 1)
546 DrawImage(pix_soundon, window, 126, 225, 18, 13);
547 else
548 DrawImage(pix_soundoff, window, 126, 225, 18, 13);
549
550 #ifndef USE_SDL
551 XFlush(display);
552 #endif
553 }
554 #ifdef USE_SDL
555 else if (bx >= 100 &&
556 bx <= 118 &&
557 by >= 225 &&
558 by <= 238)
559 {
560 /* Music control! */
561
562 music = !music;
563
564 if (music == 1)
565 DrawImage(pix_musicon, window, 100, 225, 18, 13);
566 else
567 {
568 DrawImage(pix_musicoff, window, 100, 225, 18, 13);
569 Mix_HaltMusic();
570 }
571 }
572 #endif
573 else if (bx >= 60 &&
574 bx <= 76 &&
575 by >= 144 &&
576 by <= 157)
577 {
578 /* Negative button: */
579
580 want_level_chg = -1;
581 }
582 else if (bx >= 98 &&
583 bx <= 114 &&
584 by >= 144 &&
585 by <= 157)
586 {
587 /* Positive button: */
588
589 want_level_chg = 1;
590 }
591 }
592 else if (event.type == KeyPress)
593 {
594 #ifndef USE_SDL
595 key = XLookupKeysym((XKeyEvent *)&event, 0);
596 #else
597 key = event.key.keysym.sym;
598 #endif
599
600 if (key == XK_Left)
601 want_level_chg = -1;
602 else if (key == XK_Right)
603 want_level_chg = 1;
604 else if (key == XK_space)
605 done = 1;
606 else if (key == XK_Escape)
607 {
608 quit = 1;
609 done = 1;
610 }
611 }
612 #ifndef USE_SDL
613 else if (event.type == Expose)
614 {
615 draw_titlescreen();
616 }
617 #endif
618 }
619
620
621 if (want_level_chg == -1 && level > 1)
622 {
623 level--;
624
625 sprintf(str, "%.2d", level);
626 DrawNumbers(str, 79, 141);
627
628 if (level == 1)
629 DrawImage(pix_negoff, window, 60, 144, 16, 13);
630
631 if (level < NUM_LEVELS)
632 DrawImage(pix_poson, window, 98, 144, 16, 13);
633
634 game_pending = 0;
635 DrawImage(pix_contoff, window, 64, 190, 32, 13);
636
637 #ifdef USE_SDL
638 playsound(snd_wall);
639 #endif
640 }
641 else if (want_level_chg == 1 && level < NUM_LEVELS)
642 {
643 level++;
644
645 sprintf(str, "%.2d", level);
646 DrawNumbers(str, 79, 141);
647
648 if (level == NUM_LEVELS)
649 DrawImage(pix_posoff, window, 98, 144, 16, 13);
650
651 if (level > 1)
652 DrawImage(pix_negon, window, 60, 144, 16, 13);
653
654 game_pending = 0;
655 DrawImage(pix_contoff, window, 64, 190, 32, 13);
656
657 #ifdef USE_SDL
658 playsound(snd_paddle);
659 #endif
660 }
661
662
663 #ifdef USE_SDL
664 if (use_sound && music)
665 {
666 if (!Mix_PlayingMusic())
667 {
668 Mix_PlayMusic(mus_title, -1);
669 }
670 }
671 #endif
672
673
674 #ifdef USE_SDL
675 cur_tick = SDL_GetTicks();
676
677 if (cur_tick > last_tick + 100)
678 {
679 SDL_Flip(window);
680 last_tick = cur_tick;
681 }
682 #endif
683 }
684 while (done == 0);
685
686 #ifdef USE_SDL
687
688 if (use_sound)
689 {
690 Mix_HaltMusic();
691 }
692
693 if (quit)
694 {
695 SDL_FillRect(window, NULL, SDL_MapRGB(window->format, 0, 0, 128));
696 SDL_Flip(window);
697 playsound(snd_die);
698 SDL_Delay(1000);
699 }
700 #endif
701
702 return(quit);
703 }
704
705
706
707 /* Draw title screen: */
708
709 void draw_titlescreen(void)
710 {
711 int y;
712 char str[20];
713
714 /* (Title) */
715
716 #ifndef USE_SDL
717 XFillRectangle(display, window, blackgc, 0, 0, 160, 240);
718 #else
719 SDL_FillRect(window, NULL, blackgc);
720 #endif
721
722 DrawImage(pix_title, window, 0, 0, 160, 100);
723 for (y = 100; y < 240; y = y + 10)
724 {
725 DrawImage(pix_leftpipe, window, 0, y, 14, 10);
726 }
727
728
729 /* (Level buttons) */
730
731 if (level == 1)
732 DrawImage(pix_negoff, window, 60, 144, 16, 13);
733 else
734 DrawImage(pix_negon, window, 60, 144, 16, 13);
735
736 sprintf(str, "%.2d", level);
737 DrawNumbers(str, 79, 141);
738
739 if (level < NUM_LEVELS)
740 DrawImage(pix_poson, window, 98, 144, 16, 13);
741 else
742 DrawImage(pix_posoff, window, 98, 144, 16, 13);
743
744
745 /* (Done button) */
746
747 DrawImage(pix_done, window, 14, 225, 32, 13);
748
749
750 /* (Sound control button) */
751
752 if (sound == 1)
753 DrawImage(pix_soundon, window, 126, 225, 18, 13);
754 else
755 DrawImage(pix_soundoff, window, 126, 225, 18, 13);
756
757
758 #ifdef USE_SDL
759 /* (Music control button) */
760
761 if (music == 1)
762 DrawImage(pix_musicon, window, 100, 225, 18, 13);
763 else
764 DrawImage(pix_musicoff, window, 100, 225, 18, 13);
765 #endif
766
767
768 /* (Start button) */
769
770 DrawImage(pix_start, window, 64, 170, 32, 13);
771
772
773 /* (Continue button) */
774
775 if (game_pending == 1)
776 DrawImage(pix_conton, window, 64, 190, 32, 13);
777 else
778 DrawImage(pix_contoff, window, 64, 190, 32, 13);
779
780
781 #ifndef USE_SDL
782 XFlush(display);
783 #endif
784 }
785
786
787 /* GAME FUNCTION! */
788
789 void game(void)
790 {
791 XEvent event;
792 KeySym key;
793 int done, counter;
794 int x, y, i;
795 int ball_x, ball_y, mx, my, hit;
796 int left_down, right_down, bx, by;
797 char brick;
798 struct timeval now, then;
799 long time_padding;
800 #ifdef USE_SDL
801 SDL_Rect dest;
802 #endif
803
804
805 /* Set up game: */
806
807 if (!game_pending)
808 {
809 score = 0;
810 balls = 5;
811 paddle_x = 64;
812 paddle_target_x = 64;
813
814 for (y = 0; y < 6; y++)
815 {
816 for (x = 0; x < 10; x++)
817 {
818 cur_board[y][x] = ' ';
819 }
820 }
821
822 reset_level();
823
824 ball_launched = 0;
825 ball_bx = 4864;
826 ball_by = 7424;
827 brake = 8;
828 slope = 1;
829 dir_x = 0;
830 dir_y = 0;
831 redraw_brick_x = -1;
832 game_pending = 1;
833 }
834
835
836 /* Draw the game screen: */
837
838 draw_gamescreen();
839
840 done = 0;
841 left_down = 0;
842 right_down = 0;
843 counter = 0;
844
845 ball_x = ball_bx >> 6;
846 ball_y = ball_by >> 6;
847 do
848 {
849 gettimeofday(&then, NULL);
850 counter++;
851
852 /* Erase paddle: */
853
854 #ifndef USE_SDL
855 XFillRectangle(display, window, whitegc, paddle_x, 150, 32, 10);
856 #else
857 dest.x = paddle_x + SDL_X_OFF;
858 dest.y = 150 + SDL_Y_OFF;
859 dest.w = 32;
860 dest.h = 10;
861
862 SDL_FillRect(window, &dest, whitegc);
863 #endif
864
865
866 /* Erase ball: */
867
868 #ifndef USE_SDL
869 XFillRectangle(display, window, whitegc, ball_x, ball_y, 8, 8);
870 #else
871 dest.x = ball_x + SDL_X_OFF;
872 dest.y = ball_y + SDL_Y_OFF;
873 dest.w = 8;
874 dest.h = 8;
875
876 SDL_FillRect(window, &dest, whitegc);
877 #endif
878
879 if (redraw_brick_x >= 0)
880 {
881 draw_brick(redraw_brick_x, redraw_brick_y);
882 redraw_brick_x = -1;
883 }
884
885 /* Handle events: */
886
887 #ifndef USE_SDL
888 while (XPending(display))
889 {
890 XNextEvent(display, &event);
891 #else
892 while (SDL_PollEvent(&event) > 0)
893 {
894 #endif
895
896 if (event.type == ButtonPress)
897 {
898 bx = event.XBUTTON.x - SDL_X_OFF;
899 by = event.XBUTTON.y - SDL_Y_OFF;
900
901 if (bx >= 14 &&
902 bx <= 46 &&
903 by >= 225 &&
904 by <= 238)
905 {
906 /* Pause button! */
907
908 done = 1;
909 }
910 else if (bx >= 64 &&
911 bx <= 96 &&
912 by >= 225 &&
913 by <= 238)
914 {
915 /* Ball launcher button! */
916
917 if (ball_launched == 0)
918 launch_ball();
919 }
920 else if (bx >= 126 &&
921 bx <= 144 &&
922 by >= 225 &&
923 by <= 238)
924 {
925 /* Sound control! */
926
927 sound = !sound;
928
929 if (sound == 1)
930 DrawImage(pix_soundon, window, 126, 225, 18, 13);
931 else
932 DrawImage(pix_soundoff, window, 126, 225, 18, 13);
933
934 #ifndef USE_SDL
935 XFlush(display);
936 #endif
937 }
938 #ifdef USE_SDL
939 else if (bx >= 100 &&
940 bx <= 118 &&
941 by >= 225 &&
942 by <= 238)
943 {
944 /* Music control! */
945
946 music = !music;
947
948 if (music == 1)
949 DrawImage(pix_musicon, window, 100, 225, 18, 13);
950 else
951 {
952 DrawImage(pix_musicoff, window, 100, 225, 18, 13);
953 Mix_HaltMusic();
954 }
955 }
956 #endif
957 else if (by < 160)
958 {
959 /* Tap screen elsewhere - move paddle! */
960 paddle_target_x = bx - 16;
961
962 if (paddle_target_x < -16)
963 paddle_target_x = -16;
964 else if (paddle_target_x > 144)
965 paddle_target_x = 144;
966 }
967 }
968 else if (event.type == MotionNotify)
969 {
970 bx = event.XBUTTON.x - SDL_X_OFF;
971 by = event.XBUTTON.y - SDL_Y_OFF;
972
973 /* Move stylus - move paddle? */
974 paddle_target_x = bx - 16;
975
976 if (paddle_target_x < -16)
977 paddle_target_x = -16;
978 else if (paddle_target_x > 144)
979 paddle_target_x = 144;
980 }
981 else if (event.type == KeyPress)
982 {
983 #ifndef USE_SDL
984 /* Key press! */
985
986 key = XLookupKeysym((XKeyEvent *)&event, 0);
987 #else
988 key = event.key.keysym.sym;
989 #endif
990
991 if (key == XK_Left)
992 {
993 /* Left */
994
995 left_down = 1;
996 right_down = 0;
997 }
998 else if (key == XK_Right)
999 {
1000 /* Right */
1001
1002 left_down = 0;
1003 right_down = 1;
1004 }
1005 else if (key == XK_Page_Up || key == XK_Page_Down ||
1006 key == XK_space)
1007 {
1008 /* PageUp/PageDown */
1009
1010 if (ball_launched == 0)
1011 launch_ball();
1012 }
1013 else if (key == XK_Escape)
1014 {
1015 done = 1;
1016 }
1017 }
1018 else if (event.type == KeyRelease)
1019 {
1020 #ifndef USE_SDL
1021 /* Key release! */
1022
1023 key = XLookupKeysym((XKeyEvent *)&event, 0);
1024 #else
1025 key = event.key.keysym.sym;
1026 #endif
1027
1028 if (key == XK_Left)
1029 {
1030 left_down = 0;
1031 }
1032 else if (key == XK_Right)
1033 {
1034 right_down = 0;
1035 }
1036 }
1037 #ifndef USE_SDL
1038 else if (event.type == Expose)
1039 {
1040 draw_gamescreen();
1041 }
1042 #endif
1043 }
1044
1045
1046 /* Move paddle based on keypresses: */
1047
1048 if (left_down)
1049 {
1050 paddle_x = paddle_x - 4;
1051 if (paddle_x < -16)
1052 paddle_x = -16;
1053 paddle_target_x = paddle_x;
1054 }
1055 else if (right_down)
1056 {
1057 paddle_x = paddle_x + 4;
1058 if (paddle_x > 144)
1059 paddle_x = 144;
1060 paddle_target_x = paddle_x;
1061 }
1062
1063 if (paddle_target_x > paddle_x)
1064 {
1065 if (paddle_target_x > paddle_x + 4)
1066 paddle_x += 4;
1067 else
1068 paddle_x = paddle_target_x;
1069 }
1070 else if (paddle_target_x < paddle_x)
1071 {
1072 if (paddle_target_x < paddle_x - 4)
1073 paddle_x -= 4;
1074 else
1075 paddle_x = paddle_target_x;
1076 }
1077
1078 /* Control ball: */
1079
1080 if (ball_launched)
1081 {
1082 /* Move the ball: */
1083
1084 ball_bx += dir_x * (slopes_x[slope] / (brake + 8));
1085 ball_by += dir_y * (slopes_y[slope] / (brake + 8));
1086 ball_x = ball_bx >> 6;
1087 ball_y = ball_by >> 6;
1088
1089 /* Bounce off sides: */
1090
1091 if (ball_x < 0)
1092 {
1093 ball_x = 0;
1094 dir_x = 1;
1095
1096 #ifndef USE_SDL
1097 playsound(500, 10);
1098 #else
1099 playsound(snd_wall);
1100 #endif
1101 }
1102 else if (ball_x > 152)
1103 {
1104 ball_x = 152;
1105 dir_x = -1;
1106
1107 #ifndef USE_SDL
1108 playsound(500, 10);
1109 #else
1110 playsound(snd_wall);
1111 #endif
1112 }
1113
1114 /* Bounce off top of screen: */
1115
1116 if (ball_y < 0)
1117 {
1118 ball_y = 0;
1119 dir_y = 1;
1120
1121 /* Go faster! */
1122
1123 brake--;
1124 if (brake < 0)
1125 brake = 0;
1126
1127 #ifndef USE_SDL
1128 playsound(3000, 10);
1129 #else
1130 playsound(snd_ceiling);
1131 #endif
1132 }
1133
1134 /* Bounce off bricks: */
1135
1136 if (ball_y < 60)
1137 {
1138 x = (ball_x + 4) >> 4;
1139 y = (ball_y + 4) / 10;
1140 mx = (ball_x + 4) % 16;
1141 my = (ball_y + 4) % 10;
1142
1143 hit = 0;
1144 if (y < 6)
1145 {
1146 hit = hit_brick(x,y);
1147 if (!hit)
1148 {
1149 if (mx + 4 > 15 && x < 9)
1150 {
1151 x++;
1152 hit = hit_brick(x,y);
1153 if (!hit)
1154 x--;
1155 }
1156 else if (mx - 4 < 0 && x > 0)
1157 {
1158 x--;
1159 hit = hit_brick(x,y);
1160 if (!hit)
1161 x++;
1162 }
1163 }
1164 }
1165 if (!hit)
1166 {
1167 if (my + 4 > 9 && y < 5)
1168 {
1169 y++;
1170 hit = hit_brick(x,y);
1171 if (!hit)
1172 {
1173 if (mx + 4 > 15 && x < 9)
1174 {
1175 x++;
1176 hit = hit_brick(x,y);
1177 if (!hit)
1178 x--;
1179 }
1180 else if (mx - 4 < 0 && x > 0)
1181 {
1182 x--;
1183 hit = hit_brick(x,y);
1184 if (!hit)
1185 x++;
1186 }
1187 }
1188 }
1189 else if (my - 4 < 0 && y > 0)
1190 {
1191 y--;
1192 hit = hit_brick(x,y);
1193 if (!hit)
1194 {
1195 if (mx + 4 > 15 && x < 9)
1196 {
1197 x++;
1198 hit = hit_brick(x,y);
1199 }
1200 else if (mx - 4 < 0 && x > 0)
1201 {
1202 x--;
1203 hit = hit_brick(x,y);
1204 }
1205 }
1206 }
1207 }
1208
1209 if (hit)
1210 {
1211 ball_x = ball_bx >> 6;
1212 ball_y = ball_by >> 6;
1213
1214 brick = cur_board[y][x];
1215 if (brick == '=')
1216 {
1217 brick = '-';
1218 add_score(10);
1219
1220 #ifndef USE_SDL
1221 playsound(2000, 10);
1222 #else
1223 playsound(snd_metal);
1224 #endif
1225
1226 #ifdef USE_SDL
1227 breaking_bricks[y][x].time = 10;
1228 breaking_bricks[y][x].kind = cur_board[y][x];
1229 #endif
1230 }
1231 else if (brick == '-' || brick == '/' ||
1232 brick == '#')
1233 {
1234 add_score(5);
1235 brick = ' ';
1236
1237 num_bricks_left--;
1238
1239 #ifndef USE_SDL
1240 playsound(750, 10);
1241 #else
1242 playsound(snd_brick);
1243 #endif
1244
1245 #ifdef USE_SDL
1246 breaking_bricks[y][x].time = 10;
1247 breaking_bricks[y][x].kind = cur_board[y][x];
1248 #endif
1249 }
1250 else
1251 {
1252 #ifndef USE_SDL
1253 playsound(100, 10);
1254 #else
1255 playsound(snd_unbreakable);
1256 #endif
1257 }
1258
1259
1260 cur_board[y][x] = brick;
1261
1262
1263 /* Erase (or redraw) brick: */
1264
1265 draw_brick(x, y);
1266 }
1267 }
1268
1269
1270 /* Bounce off the paddle: */
1271
1272 if (ball_y >= 142 &&
1273 ball_x >= paddle_x - 8 &&
1274 ball_x <= paddle_x + 32)
1275 {
1276 dir_y = -1;
1277 counter = 0;
1278
1279 /* Angle (xm) depends on where it hit the paddle: */
1280
1281 if (ball_x <= paddle_x - 4)
1282 slope -= dir_x * 3;
1283 if (ball_x <= paddle_x + 2)
1284 slope -= dir_x * 2;
1285 else if (ball_x <= paddle_x + 8)
1286 slope -= dir_x;
1287 else if (ball_x <= paddle_x + 16)
1288 slope += 0;
1289 else if (ball_x <= paddle_x + 22)
1290 slope += dir_x;
1291 else if (ball_x <= paddle_x + 28)
1292 slope += dir_x * 2;
1293 else
1294 slope += dir_x * 3;
1295 if (slope < 0)
1296 {
1297 slope = -slope;
1298 dir_x = -dir_x;
1299 }
1300 if (slope > 6)
1301 slope = 6;
1302
1303 #ifndef USE_SDL
1304 playsound(1000, 10);
1305 #else
1306 playsound(snd_paddle);
1307 #endif
1308
1309 add_score(1);
1310 }
1311
1312 /* Fall off bottom of screen: */
1313
1314 if (ball_y > 150)
1315 {
1316 ball_launched = 0;
1317
1318 DrawImage(pix_launchon, window, 64, 225, 32, 13);
1319
1320 #ifndef USE_SDL
1321 playsound(125, 100);
1322 #else
1323 playsound(snd_die);
1324 #endif
1325
1326 balls--;
1327 draw_gamescreen();
1328
1329 /* Game over!? */
1330
1331 if (balls < 0)
1332 {
1333 game_pending = 0;
1334 done = 1;
1335
1336 for (i = 1000; i >= 100; i = i / 2)
1337 {
1338 #ifndef USE_SDL
1339 playsound(i, 200);
1340 #else
1341 playsound(snd_die);
1342 #endif
1343 usleep(200000);
1344 }
1345 }
1346 }
1347 }
1348
1349 /* Go to next level? */
1350
1351 if (num_bricks_left <= 0)
1352 {
1353 /* Increment level: */
1354
1355 level++;
1356
1357 if (level > NUM_LEVELS)
1358 level = 1;
1359
1360 ball_x = 76;
1361 ball_bx = 4864;
1362 ball_y = 116;
1363 ball_by = 7424;
1364 redraw_brick_x = -1;
1365 reset_level();
1366 draw_gamescreen();
1367 ball_launched = 0;
1368 DrawImage(pix_launchon, window, 64, 225, 32, 13);
1369
1370 #ifdef USE_SDL
1371 if (use_sound)
1372 {
1373 Mix_HaltMusic();
1374 }
1375 #endif
1376 }
1377
1378 /* figure out if the ball is stuck in an infinite loop */
1379 if (counter > 1000)
1380 {
1381 if (slope > 4)
1382 slope--;
1383 else
1384 slope++;
1385 }
1386
1387 /* Draw paddle: */
1388
1389 DrawImage(pix_paddle, window, paddle_x, 150, 32, 10);
1390
1391
1392 /* Draw ball: */
1393
1394 if (ball_launched)
1395 DrawImage(pix_ball, window, ball_x, ball_y, 8, 8);
1396
1397
1398
1399 /* Draw special effects: */
1400
1401 #ifdef USE_SDL
1402 for (y = 0; y < 6; y++)
1403 {
1404 for (x = 0; x < 10; x++)
1405 {
1406 if (breaking_bricks[y][x].time > 0)
1407 {
1408 SDL_Surface * tmp_surf;
1409 char c;
1410
1411
1412 breaking_bricks[y][x].time--;
1413
1414 dest.x = x * 16 + SDL_X_OFF;
1415 dest.y = y * 10 + SDL_Y_OFF;
1416 dest.w = 16;
1417 dest.h = 10;
1418
1419 if (breaking_bricks[y][x].time % 2)
1420 c = breaking_bricks[y][x].kind;
1421 else
1422 c = cur_board[y][x];
1423
1424 if (c == '-')
1425 tmp_surf = pix_brick1;
1426 else if (c == '=')
1427 tmp_surf = pix_brick2;
1428 else if (c == '#')
1429 tmp_surf = pix_brick3;
1430 else if (c == ':')
1431 tmp_surf = pix_brick4;
1432 else if (c == '/')
1433 tmp_surf = pix_brick5;
1434 else
1435 tmp_surf = NULL;
1436
1437 if (tmp_surf != NULL)
1438 SDL_BlitSurface(tmp_surf, NULL, window, &dest);
1439 else
1440 SDL_FillRect(window, &dest, whitegc);
1441 }
1442 }
1443 }
1444 #endif
1445
1446
1447 /* Delay... */
1448
1449 #ifndef USE_SDL
1450 XSync(display, 0);
1451 #else
1452 SDL_Flip(window);
1453 #endif
1454
1455 gettimeofday(&now, NULL);
1456
1457 time_padding = 10000 - ((now.tv_sec - then.tv_sec) * 1000000 +
1458 (now.tv_usec - then.tv_usec));
1459 if (time_padding > 0)
1460 {
1461 usleep(time_padding);
1462 }
1463
1464 #ifdef USE_SDL
1465 if (use_sound && music)
1466 {
1467 if (!Mix_PlayingMusic())
1468 {
1469 Mix_PlayMusic(mus_game[((level - 1) / 2) % NUM_GAME_MUSICS], -1);
1470 }
1471 }
1472 #endif
1473
1474 }
1475 while (!done);
1476
1477
1478 #ifdef USE_SDL
1479 if (use_sound)
1480 {
1481 Mix_HaltMusic();
1482 }
1483 #endif
1484 }
1485
1486
1487 /* Draw game screen: */
1488
1489 void draw_gamescreen(void)
1490 {
1491 char str[21];
1492 int x, y;
1493
1494
1495 /* Blank areas: */
1496
1497 #ifndef USE_SDL
1498 XFillRectangle(display, window, whitegc, 0, 0, 160, 160);
1499 XFillRectangle(display, window, blackgc, 0, 160, 160, 80);
1500 #else
1501 SDL_Rect dest;
1502
1503
1504 dest.x = SDL_X_OFF;
1505 dest.y = SDL_Y_OFF;
1506 dest.w = 160;
1507 dest.h = 160;
1508 SDL_FillRect(window, &dest, SDL_MapRGB(window->format, 255, 255, 255));
1509
1510 dest.x = SDL_X_OFF;
1511 dest.y = 160 + SDL_Y_OFF;
1512 dest.w = 160;
1513 dest.h = 80;
1514 SDL_FillRect(window, &dest, SDL_MapRGB(window->format, 0, 0, 0));
1515 #endif
1516
1517
1518 /* Draw water lapping: */
1519
1520 for (x = 0; x <= 160; x = x + 29)
1521 {
1522 DrawImage(pix_water, window, x, 160, 29, 12);
1523 }
1524
1525
1526 /* (Status info) */
1527
1528 DrawImage(pix_stats_toppipe, window, 0, 172, 160, 9);
1529 DrawImage(pix_stats_leftpipe, window, 0, 181, 11, 59);
1530 DrawImage(pix_stats_rightpipe, window, 149, 181, 11, 59);
1531 DrawImage(pix_stats, window, 12, 181, 52, 44);
1532
1533
1534 /* (Score) */
1535
1536 sprintf(str, "%.6d", score);
1537 DrawNumbers(str, 70, 181);
1538
1539
1540 /* (Balls) */
1541
1542 sprintf(str, "%.2d", balls);
1543 DrawNumbers(str, 70, 195);
1544
1545
1546 /* (Level) */
1547
1548 sprintf(str, "%.2d", level);
1549 DrawNumbers(str, 70, 209);
1550
1551
1552 /* (Pause button) */
1553
1554 DrawImage(pix_pause, window, 14, 225, 32, 13);
1555
1556
1557 /* (Launch button) */
1558
1559 if (ball_launched == 0)
1560 DrawImage(pix_launchon, window, 64, 225, 32, 13);
1561 else
1562 DrawImage(pix_launchoff, window, 64, 225, 32, 13);
1563
1564
1565 /* (Sound control button) */
1566
1567 if (sound == 1)
1568 DrawImage(pix_soundon, window, 126, 225, 18, 13);
1569 else
1570 DrawImage(pix_soundoff, window, 126, 225, 18, 13);
1571
1572
1573 #ifdef USE_SDL
1574 /* (Music control button) */
1575
1576 if (music == 1)
1577 DrawImage(pix_musicon, window, 100, 225, 18, 13);
1578 else
1579 DrawImage(pix_musicoff, window, 100, 225, 18, 13);
1580 #endif
1581
1582
1583 /* (Bricks) */
1584
1585 for (y = 0; y < 6; y++)
1586 {
1587 for (x = 0; x < 10; x++)
1588 {
1589 draw_brick(x, y);
1590 }
1591 }
1592 }
1593
1594
1595 /* Setup! */
1596
1597 void setup(void)
1598 {
1599 #ifndef USE_SDL
1600 Window rootwindow;
1601 int screen, black, white;
1602 XSetWindowAttributes attr;
1603 XWMHints wmhints;
1604 unsigned long attr_mask;
1605 char wname[64];
1606 #else
1607 int i;
1608 #endif
1609 struct timeval tp;
1610
1611
1612 /* Seed random number generator: */
1613
1614 gettimeofday(&tp, NULL);
1615 srand(tp.tv_sec + tp.tv_usec);
1616
1617
1618 #ifndef USE_SDL
1619 /* Connect to X server: */
1620
1621 display = XOpenDisplay(NULL);
1622 if (display == NULL)
1623 {
1624 fprintf(stderr, "Can't connect to display!\n");
1625 exit(1);
1626 }
1627
1628 screen = DefaultScreen(display);
1629 rootwindow = RootWindow(display, screen);
1630
1631
1632 /* Get primitive colors: */
1633
1634 black = BlackPixel(display, screen);
1635 white = WhitePixel(display, screen);
1636
1637
1638 /* Open window: */
1639
1640 attr.event_mask = (KeyPressMask | KeyReleaseMask | ButtonPressMask |
1641 ButtonReleaseMask | PointerMotionMask |
1642 ExposureMask | VisibilityChangeMask);
1643
1644 attr.border_pixel = black;
1645 attr.background_pixel = white;
1646 attr_mask = CWEventMask | CWBackPixel | CWBorderPixel;
1647
1648 window = XCreateWindow(display, rootwindow, 0, 0, 160, 240, 0,
1649 DefaultDepthOfScreen(DefaultScreenOfDisplay(display)),
1650 InputOutput, DefaultVisual(display, screen),
1651 attr_mask, &attr);
1652
1653
1654 /* Set input hints and window name (so we appear in the window lists).
1655 Need to do this because of a bug in VRSM. Not bad to do anyway, tho */
1656
1657 wmhints.input = True;
1658 wmhints.flags |= InputHint;
1659 XSetWMHints(display, window, &wmhints);
1660
1661 sprintf(wname, "BrickOut");
1662 XChangeProperty(display, window, XA_WM_NAME, XA_STRING, 8,
1663 PropModeReplace, wname, strlen(wname));
1664
1665
1666 /* Create primitive graphics contexts: */
1667
1668 whitegc = CreateGC(display, window, white, black);
1669 blackgc = CreateGC(display, window, black, black);
1670
1671 pastegc = CreateGC(display, window, white, black);
1672
1673 #else
1674
1675 if (SDL_Init(SDL_INIT_VIDEO) < 0)
1676 {
1677 fprintf(stderr, "Error: Can't init SDL video\n%s\n", SDL_GetError());
1678 exit(1);
1679 }
1680
1681 use_sound = 1;
1682
1683 if (SDL_Init(SDL_INIT_AUDIO) < 0)
1684 {
1685 fprintf(stderr, "Warning: Can't init SDL audio\n%s\n", SDL_GetError());
1686 use_sound = 0;
1687 }
1688
1689
1690 window = SDL_SetVideoMode(240, 320, 16, SDL_HWSURFACE);
1691
1692 if (window == NULL)
1693 {
1694 fprintf(stderr, "Error: Can't open window\n%s\n", SDL_GetError());
1695 exit(1);
1696 }
1697
1698 whitegc = SDL_MapRGB(window->format, 255, 255, 255);
1699 blackgc = SDL_MapRGB(window->format, 0, 0, 0);
1700
1701 SDL_WM_SetCaption("Brickout", "Brickout");
1702 #endif
1703
1704
1705 /* Create images: */
1706
1707 #ifndef USE_SDL
1708 /* (Title screen stuff) */
1709
1710 LoadImage(title_xpm, &pix_title);
1711 LoadImage(leftpipe_xpm, &pix_leftpipe);
1712
1713
1714 /* (Control buttons) */
1715
1716 LoadImage(start_xpm, &pix_start);
1717 LoadImage(done_xpm, &pix_done);
1718 LoadImage(pause_xpm, &pix_pause);
1719 LoadImage(launchon_xpm, &pix_launchon);
1720 LoadImage(launchoff_xpm, &pix_launchoff);
1721 LoadImage(conton_xpm, &pix_conton);
1722 LoadImage(contoff_xpm, &pix_contoff);
1723 LoadImage(soundon_xpm, &pix_soundon);
1724 LoadImage(soundoff_xpm, &pix_soundoff);
1725 LoadImage(negon_xpm, &pix_negon);
1726 LoadImage(negoff_xpm, &pix_negoff);
1727 LoadImage(poson_xpm, &pix_poson);
1728 LoadImage(posoff_xpm, &pix_posoff);
1729
1730
1731 /* (Ball and paddle) */
1732
1733 LoadImage(ball_xpm, &pix_ball);
1734 LoadImage(paddle_xpm, &pix_paddle);
1735
1736
1737 /* (Bricks) */
1738
1739 LoadImage(brick1_xpm, &pix_brick1);
1740 LoadImage(brick2_xpm, &pix_brick2);
1741 LoadImage(brick3_xpm, &pix_brick3);
1742 LoadImage(brick4_xpm, &pix_brick4);
1743 LoadImage(brick5_xpm, &pix_brick5);
1744
1745
1746 /* (Stats stuff) */
1747
1748 LoadImage(stats_xpm, &pix_stats);
1749 LoadImage(stats_toppipe_xpm, &pix_stats_toppipe);
1750 LoadImage(stats_leftpipe_xpm, &pix_stats_leftpipe);
1751 LoadImage(stats_rightpipe_xpm, &pix_stats_rightpipe);
1752 LoadImage(water_xpm, &pix_water);
1753 LoadImage(numbers_xpm, &pix_numbers);
1754
1755 #else
1756
1757 /* (Title screen stuff) */
1758
1759 pix_title = LoadImage(title_xpm);
1760 pix_leftpipe = LoadImage(leftpipe_xpm);
1761
1762
1763 /* (Control buttons) */
1764
1765 pix_start = LoadImage(start_xpm);
1766 pix_done = LoadImage(done_xpm);
1767 pix_pause = LoadImage(pause_xpm);
1768 pix_launchon = LoadImage(launchon_xpm);
1769 pix_launchoff = LoadImage(launchoff_xpm);
1770 pix_conton = LoadImage(conton_xpm);
1771 pix_contoff = LoadImage(contoff_xpm);
1772 pix_soundon = LoadImage(soundon_xpm);
1773 pix_soundoff = LoadImage(soundoff_xpm);
1774 pix_musicon = LoadImage(musicon_xpm);
1775 pix_musicoff = LoadImage(musicoff_xpm);
1776 pix_negon = LoadImage(negon_xpm);
1777 pix_negoff = LoadImage(negoff_xpm);
1778 pix_poson = LoadImage(poson_xpm);
1779 pix_posoff = LoadImage(posoff_xpm);
1780
1781
1782 /* (Ball and paddle) */
1783
1784 pix_ball = LoadImage(ball_xpm);
1785 pix_paddle = LoadImage(paddle_xpm);
1786
1787
1788 /* (Bricks) */
1789
1790 pix_brick1 = LoadImage(brick1_xpm);
1791 pix_brick2 = LoadImage(brick2_xpm);
1792 pix_brick3 = LoadImage(brick3_xpm);
1793 pix_brick4 = LoadImage(brick4_xpm);
1794 pix_brick5 = LoadImage(brick5_xpm);
1795
1796
1797 /* (Stats stuff) */
1798
1799 pix_stats = LoadImage(stats_xpm);
1800 pix_stats_toppipe = LoadImage(stats_toppipe_xpm);
1801 pix_stats_leftpipe = LoadImage(stats_leftpipe_xpm);
1802 pix_stats_rightpipe = LoadImage(stats_rightpipe_xpm);
1803 pix_water = LoadImage(water_xpm);
1804 pix_numbers = LoadImage(numbers_xpm);
1805
1806 #endif
1807
1808
1809 #ifdef USE_SDL
1810 if (Mix_OpenAudio(44100, AUDIO_S16, 2, 512) < 0)
1811 {
1812 fprintf(stderr, "Warning: Can't open audio at 44100 Hz / 16-bit\n%s\n",
1813 SDL_GetError());
1814
1815 use_sound = 0;
1816 }
1817
1818
1819 /* Load sounds: */
1820
1821 snd_wall = LoadSound(SOUNDDIR "wall.wav");
1822 snd_ceiling = LoadSound(SOUNDDIR "ceiling.wav");
1823 snd_metal = LoadSound(SOUNDDIR "metal.wav");
1824 snd_brick = LoadSound(SOUNDDIR "brick.wav");
1825 snd_unbreakable = LoadSound(SOUNDDIR "unbreakable.wav");
1826 snd_paddle = LoadSound(SOUNDDIR "paddle.wav");
1827 snd_die = LoadSound(SOUNDDIR "die.wav");
1828
1829
1830 /* Load music: */
1831
1832 if (use_sound)
1833 {
1834 mus_title = Mix_LoadMUS(MUSICDIR "/Church.mod");
1835 if (mus_title == NULL)
1836 {
1837 fprintf(stderr, "Warning: Can't load music: " MUSICDIR "/Chruch.mod\n"
1838 "%s\n",
1839 SDL_GetError());
1840
1841 use_sound = 0;
1842 }
1843 }
1844
1845
1846 for (i = 0; i < NUM_GAME_MUSICS && use_sound; i++)
1847 {
1848 mus_game[i] = Mix_LoadMUS(music_fnames[i]);
1849 if (mus_game[i] == NULL)
1850 {
1851 fprintf(stderr, "Warning: Can't load music: %s\n%s\n",
1852 music_fnames[i], SDL_GetError());
1853 use_sound = 0;
1854 }
1855 }
1856
1857 #endif
1858
1859
1860 /* Bring window up! */
1861
1862 #ifndef USE_SDL
1863 XMapWindow(display, window);
1864 XMapRaised(display, window);
1865 XSync(display, 0);
1866 #else
1867 SDL_Flip(window);
1868 #endif
1869 }
1870
1871
1872 /* Load settings from file: */
1873
1874 void loadsettings(void)
1875 {
1876 sound = 1;
1877 #ifdef USE_SDL
1878 music = 1;
1879 #endif
1880 game_pending = 0;
1881 }
1882
1883
1884
1885 /* Create a graphics context: */
1886
1887 #ifndef USE_SDL
1888 GC CreateGC(Display *display, Drawable drawable, unsigned long forecolor,
1889 unsigned long backcolor)
1890 {
1891 XGCValues xgcvalues;
1892 GC gc;
1893
1894 xgcvalues.foreground = forecolor;
1895 xgcvalues.background = backcolor;
1896 gc = XCreateGC(display,drawable,(GCForeground | GCBackground),
1897 &xgcvalues);
1898
1899 return(gc);
1900 }
1901 #endif
1902
1903
1904 /* Convert an image from XPM data to a pixmap: */
1905
1906 #ifndef USE_SDL
1907 void LoadImage(char ** xpm, Pixmap * pix)
1908 {
1909 XpmCreatePixmapFromData(display, window, xpm, pix, NULL, NULL);
1910 }
1911 #else
1912 Pixmap LoadImage(const char * file)
1913 {
1914 Pixmap pix;
1915 pix = SDL_LoadBMP(file);
1916
1917 if (pix == NULL)
1918 {
1919 fprintf(stderr, "Error: Can't load %s\n%s\n", file, SDL_GetError());
1920 exit(1);
1921 }
1922
1923 return pix;
1924 }
1925 #endif
1926
1927
1928 /* Paste a pixmap onto the screen: */
1929
1930 void DrawImage(Pixmap pix, Drawable dest, int x, int y, int w, int h)
1931 {
1932 #ifndef USE_SDL
1933 XSetClipOrigin(display, pastegc, x, y);
1934
1935 XCopyArea(display, pix, dest, pastegc, 0, 0, w, h, x, y);
1936 #else
1937 SDL_Rect dest_rect;
1938
1939 dest_rect.x = x + SDL_X_OFF;
1940 dest_rect.y = y + SDL_Y_OFF;
1941 dest_rect.w = w;
1942 dest_rect.h = h;
1943
1944 SDL_BlitSurface(pix, NULL, dest, &dest_rect);
1945 #endif
1946 }
1947
1948
1949 /* Draw numbers: */
1950
1951 void DrawNumbers(char * str, int x, int y)
1952 {
1953 int i;
1954 #ifdef USE_SDL
1955 SDL_Rect src, dest;
1956 #endif
1957
1958 for (i = 0; i < strlen(str); i++)
1959 {
1960 #ifndef USE_SDL
1961 XSetClipOrigin(display, pastegc, x, y);
1962 #else
1963 src.x = (str[i] - '0') * 8;
1964 src.y = 0;
1965 src.w = 8;
1966 src.h = 14;
1967
1968 dest.x = x + SDL_X_OFF;
1969 dest.y = y + SDL_Y_OFF;
1970 #endif
1971
1972 if (str[i] >= '0' && str[i] <= '9')
1973 {
1974 #ifndef USE_SDL
1975 XCopyArea(display, pix_numbers, window, pastegc,
1976 (str[i] - '0') * 8, 0, 8, 14, x, y);
1977 #else
1978 SDL_BlitSurface(pix_numbers, &src, window, &dest);
1979 #endif
1980 }
1981
1982 x = x + 8;
1983 }
1984 }
1985
1986
1987
1988 /* Play a sound! */
1989
1990 #ifndef USE_SDL
1991
1992 void playsound(int pitch, int duration)
1993 {
1994 XKeyboardControl vals;
1995
1996 if (sound)
1997 {
1998 vals.bell_pitch = pitch;
1999 vals.bell_duration = duration;
2000 vals.bell_percent = 100;
2001
2002 XChangeKeyboardControl(display,
2003 (KBBellPitch | KBBellDuration | KBBellPercent),
2004 &vals);
2005 XBell(display, 100);
2006 XFlush(display);
2007 }
2008 }
2009
2010 #else
2011
2012 void playsound(Mix_Chunk * snd)
2013 {
2014 if (use_sound && sound)
2015 {
2016 Mix_PlayChannel(-1, snd, 0);
2017 }
2018 }
2019
2020 #endif
2021
2022 /* Launch a ball! */
2023
2024 void launch_ball(void)
2025 {
2026 int ball_x;
2027 /* Launch the ball with a random direction/etc: */
2028
2029 ball_launched = 1;
2030 ball_x = (rand() % 60) - 30 + paddle_x;
2031 if (ball_x <= 10)
2032 ball_x = 10;
2033 if (ball_x >= 150)
2034 ball_x = 150;
2035 ball_bx = ball_x << 6;
2036 ball_by = 65 << 6;
2037 slope = (rand() % 5) + 1;
2038 brake = 8;
2039 dir_x = ((rand() % 2) * 2) - 1;
2040 dir_y = 1;
2041
2042 /* Disable Launch button: */
2043
2044 DrawImage(pix_launchoff, window, 64, 225, 32, 13);
2045 }
2046
2047
2048 /* Increment score, and redraw it on the screen: */
2049
2050 void add_score(int val)
2051 {
2052 char str[20];
2053
2054 score = score + val;
2055
2056 sprintf(str, "%.6d", score);
2057 DrawNumbers(str, 70, 181);
2058 }
2059
2060
2061 /* Draw a brick: */
2062
2063 void draw_brick(int x, int y)
2064 {
2065 char c;
2066 #ifdef USE_SDL
2067 SDL_Rect dest;
2068 #endif
2069
2070 c = cur_board[y][x];
2071
2072 if (c == '-')
2073 DrawImage(pix_brick1, window, x * 16, y * 10, 16, 10);
2074 else if (c == '=')
2075 DrawImage(pix_brick2, window, x * 16, y * 10, 16, 10);
2076 else if (c == '#')
2077 DrawImage(pix_brick3, window, x * 16, y * 10, 16, 10);
2078 else if (c == ':')
2079 DrawImage(pix_brick4, window, x * 16, y * 10, 16, 10);
2080 else if (c == '/')
2081 DrawImage(pix_brick5, window, x * 16, y * 10, 16, 10);
2082 else
2083 {
2084 #ifndef USE_SDL
2085 XFillRectangle(display, window, whitegc, x * 16, y * 10, 16, 10);
2086 #else
2087 dest.x = x * 16 + SDL_X_OFF;
2088 dest.y = y * 10 + SDL_Y_OFF;
2089 dest.w = 16;
2090 dest.h = 10;
2091
2092 SDL_FillRect(window, &dest, whitegc);
2093 #endif
2094 }
2095 }
2096
2097
2098 /* Initialize board: */
2099
2100 void reset_level(void)
2101 {
2102 int x, y;
2103
2104 num_bricks_left = 0;
2105
2106 for (y = 0; y < 6; y++)
2107 {
2108 for (x = 0; x < 10; x++)
2109 {
2110 #ifdef USE_SDL
2111 breaking_bricks[y][x].time = (rand() % 4) + 8;
2112 breaking_bricks[y][x].kind = cur_board[y][x];
2113 #endif
2114
2115 cur_board[y][x] = boards[level - 1][y][x];
2116
2117 if (cur_board[y][x] != ' ' &&
2118 cur_board[y][x] != ':')
2119 {
2120 num_bricks_left++;
2121 }
2122
2123 }
2124 }
2125 }
2126
2127 /* Check to see if we hit the given brick */
2128
2129 int hit_brick(int x,int y)
2130 {
2131 int dx, dy;
2132 int corner, forward_ball, forward_corner;
2133
2134 /* don't check anything if there is no brick here */
2135 if (cur_board[y][x] == ' ')
2136 return 0;
2137
2138 dx = ((ball_bx >> 6) + 4) - (x << 4);
2139 dy = ((ball_by >> 6) + 4) - (y * 10);
2140
2141 /* skip out if the ball is outside the sides */
2142 /* of the brick */
2143 if (dx < -4 || dx > 19)
2144 return 0;
2145 if (dy < -4 || dy > 13)
2146 return 0;
2147
2148 /* check for clean hit on top or bottom edge of brick */
2149 if (dx >= -1 && dx <= 16)
2150 {
2151 dir_y = -dir_y;
2152 if (dy < 5)
2153 ball_by -= ((dy + 4) << 6);
2154 else
2155 ball_by += ((14 - dy) << 6);
2156 return 1;
2157 }
2158
2159 /* check for vertical slope - must be a corner hit */
2160 if (slope == 0)
2161 {
2162 if (dx < -2)
2163 slope = 2;
2164 else
2165 slope = 1;
2166 dir_x = (dy >= 5) ? 1 : -1;
2167 dir_y = -dir_y;
2168 if (dy < 5)
2169 ball_by -= ((dy + 4) << 6);
2170 else
2171 ball_by += ((14 - dy) << 6);
2172 return 1;
2173 }
2174
2175 /* check for clean hit on side edge of brick */
2176 if (dy >= -1 && dy > 10)
2177 {
2178 dir_x = -dir_x;
2179 if (dx < 8)
2180 ball_bx -= ((dx + 4) << 6);
2181 else
2182 ball_bx += ((20 - dx) << 6);
2183 return 1;
2184 }
2185
2186 /* if the slope is close to 45 (#4) then */
2187 /* use a 6x6 square to approximate the */
2188 /* ball at the corners. */
2189 if (slope >= 3 && slope <= 5)
2190 {
2191 dx -= 1;
2192 dy -= 1;
2193 if (dx < -3 || dx > 18 ||
2194 dy < -3 || dy > 12)
2195 {
2196 /* mark this brick for redrawing as */
2197 /* the ball will probaby erase part */
2198 /* of it as it goes by (because the */
2199 /* ball is really a square pixmap */
2200 /* that just displays a round ball */
2201 redraw_brick_x = x;
2202 redraw_brick_y = y;
2203 return 0;
2204 }
2205 dx += 1;
2206 dy += 1;
2207 }
2208
2209 /* the ball hit a corner so figure that out now */
2210
2211 /* figure out which corner the ball hit */
2212 /* 0 1 */
2213 /* +------+ */
2214 /* | | */
2215 /* +------+ */
2216 /* 2 3 */
2217 corner = 0;
2218 if (dx >= 8)
2219 corner |= 1;
2220 if (dy >= 5)
2221 corner |= 2;
2222 forward_corner = (corner == 1 || corner == 2) ? 1 : 0;
2223 forward_ball = (dir_y != dir_x) ? 1 : 0;
2224
2225 /* first figure out if we hit the corner directly */
2226 /* or with a glancing blow */
2227 if (forward_corner ^ forward_ball)
2228 {
2229 /* for glancing blows, only toggle the dir_x */
2230 /* or dir_y that makes sense for the corner */
2231 if ((dir_x == 1 && dx < 8) ||
2232 (dir_x == -1 && dx >= 8))
2233 dir_x = -dir_x;
2234 else
2235 dir_y = -dir_y;
2236 }
2237 else
2238 {
2239 /* it was a direct hit on the corner */
2240 dir_x = -dir_x;
2241 dir_y = -dir_y;
2242 }
2243
2244 /* And adjust the ball so that it is not */
2245 /* overlapping the brick anymore */
2246 if ((dir_x == 1 && dx < 8) ||
2247 (dir_x == -1 && dx >= 8))
2248 {
2249 if (dy < 5)
2250 ball_by -= ((dy + 4) << 6);
2251 else
2252 ball_by += ((14 - dy) << 6);
2253 }
2254 else
2255 {
2256 if (dx < 8)
2257 ball_bx -= ((dx + 4) << 6);
2258 else
2259 ball_bx += ((20 - dx) << 6);
2260 }
2261
2262 return 1;
2263 }
2264
2265
2266 #ifdef USE_SDL
2267
2268 Mix_Chunk * LoadSound(char * fname)
2269 {
2270 Mix_Chunk * s;
2271
2272
2273 if (use_sound)
2274 {
2275 s = Mix_LoadWAV(fname);
2276
2277 if (s == NULL)
2278 {
2279 use_sound = 0;
2280
2281 fprintf(stderr, "Warning: Can't load sound: %s\n%s\n", fname,
2282 SDL_GetError());
2283 }
2284
2285 return s;
2286 }
2287 else
2288 return NULL;
2289 }
2290
2291 #endif
2292