1 /*
2   gemdropx.c
3 
4   Gem Drop for SDL (X-Window, MSWindows, MacOS, BeOS, etc.) and Qt/Embedded
5 
6   v.0.9
7 
8   based directly on GEMDROP.ACT, the original Atari 8-bit version of Gem Drop
9 
10   by Bill Kendrick
11   gemdropx@newbreedsoftware.com
12   http://www.newbreedsoftware.com/gemdropx/
13 
14   Atari version: August 17, 1997 - Sept. 24, 1997
15   X Window version: November 5, 1997 - November 21, 1997
16   X Window update: July 29, 1998 - April 4, 1999
17   SDL mixer fixes: October 31, 1999
18   100% SDL version: December 27, 1999
19   SDL fixes: December 29, 1999 - January 26, 2000
20   Sound tweaks: February 11, 2002
21   Qt/Embedded Support: February 11, 2002 - February 12, 2002
22 */
23 
24 
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <math.h>
29 #include <sys/types.h>
30 #include <sys/time.h>
31 #include <unistd.h>
32 
33 #ifndef EMBEDDED
34 #include <SDL.h>
35 #else
36 #include <qtimer.h>
37 #include <qpainter.h>
38 #include <qpe/qpeapplication.h>
39 #include <qwidget.h>
40 #include <qobject.h>
41 #endif
42 
43 #ifndef NOSOUND
44 #include <SDL_mixer.h>
45 #endif
46 
47 #ifndef EMBEDDED
48 #include "data/images/nothing.xbm"
49 #include "data/images/nothing-mask.xbm"
50 #include "data/images/left.xbm"
51 #include "data/images/left-mask.xbm"
52 #include "data/images/right.xbm"
53 #include "data/images/right-mask.xbm"
54 #include "data/images/action.xbm"
55 #include "data/images/action-mask.xbm"
56 #endif
57 
58 
59 /* Misc. value defines: */
60 
61 #define NO 0
62 #define YES 1
63 
64 
65 /* Game stuff: */
66 
67 #define FPS 20
68 #define HEIGHT 11
69 #define WIDTH 10
70 #define NUM_EXPLOSIONS 100
71 #define STICKWAIT 2
72 
73 
74 /* Explosion type: */
75 
76 typedef struct explosion_type {
77   int exist;     /* do I exist? */
78   int x, y;      /* position */
79   int anim;      /* animation frame counter */
80   int animrate;  /* pause for animation */
81 } explosion_type;
82 
83 
84 #ifdef EMBEDDED
85 typedef struct SDL_Rect { int x, y, w, h; } SDL_Rect;
86 typedef struct SDL_Surface { int w, h; QPixmap * image; } SDL_Surface;
87 #define Uint8 unsigned char
88 #define Uint32 unsigned long
89 #endif
90 
91 
92 /* Object specifications: */
93 
94 #define NUM_NORMAL_BLOCKS 4
95 #define NUM_ALL_BLOCKS 8
96 #define BOMB NUM_ALL_BLOCKS + 1
97 #define CLOCK NUM_ALL_BLOCKS + 2
98 #define WILDCARD NUM_ALL_BLOCKS + 3
99 #define NUM_SPECIALS 3
100 #define NUM_EXPLOSION_GFX 4
101 #define EXPLOSION_SLOW_VAL 1
102 #define HAPPY_GFX NUM_ALL_BLOCKS + NUM_SPECIALS + NUM_EXPLOSION_GFX + 1
103 #define SAD_GFX HAPPY_GFX + 1
104 #define WIN1_GFX SAD_GFX + 1
105 #define WIN2_GFX WIN1_GFX + 1
106 #define PATIENCE_GFX WIN2_GFX + 1
107 #define WARNING_GFX PATIENCE_GFX + 1
108 #define BRICK_GFX WARNING_GFX + 4
109 #define TITLE_GFX BRICK_GFX + 1
110 #define CREDITS_GFX TITLE_GFX + 1
111 #define LEVEL_GFX CREDITS_GFX + 1
112 #define LINES_GFX LEVEL_GFX + 1
113 #define NEED_GFX LINES_GFX + 1
114 #define NUMBERS_GFX NEED_GFX + 1
115 #define PAUSED_GFX NUMBERS_GFX + 1
116 #define SCORE_GFX PAUSED_GFX + 1
117 #define AUTHOR_GFX SCORE_GFX + 1
118 #define UHOH_GFX AUTHOR_GFX + 1
119 #define CONGRATULATIONS_GFX UHOH_GFX + 1
120 #define NUM_OBJECTS CONGRATULATIONS_GFX
121 
122 
123 /* Object (graphics) filenames: */
124 
125 char * object_filenames[NUM_OBJECTS] = {"block", "yellowgem",
126 					"diamond", "disc",
127 					"dot", "bluegem", "fuji", "triangle",
128 					"bomb", "stopwatch", "wildcard",
129 					"explode0", "explode1",
130 					"explode2", "explode3",
131 					"happy", "sad", "win1", "win2",
132 					"patience", "warning1", "warning2",
133 					"warning3", "warning4", "brick",
134 					"title", "credits", "level", "lines",
135 					"need", "numbers", "paused", "score",
136 					"author", "uhoh", "congratulations"};
137 
138 
139 /* Sounds: */
140 
141 enum {
142   SND_BEGIN,
143   SND_BOMB,
144   SND_CLOCK,
145   SND_GAMEOVER,
146   SND_GOT,
147   SND_LEVELSELECT,
148   SND_WILDCARD,
149   SND_WIN,
150   SND_GRAB,
151   SND_THROW,
152   SND_BUZZER,
153   SND_APPLAUSE,
154   NUM_SOUNDS
155 };
156 
157 /* Sound filenames: */
158 
159 char * sound_filenames[NUM_SOUNDS] = {
160   "begin", "bomb", "clock", "gameover", "got", "levelselect",
161   "wildcard", "win", "grab", "throw", "buzzer", "applause"
162 };
163 
164 enum {
165   MOD_TITLE,
166   MOD_GAME1,
167   MOD_GAME2,
168   MOD_GAME3,
169   NUM_MODS
170 };
171 
172 #define NUM_GAME_MODS 3
173 
174 char * music_filenames[NUM_MODS] = {
175   "hr_suds.xm", "22drops.mod", "citron.mod", "2force.xm"
176 };
177 
178 #ifndef NOSOUND
179 Mix_Chunk * samples[NUM_SOUNDS];
180 Mix_Music * songs[NUM_MODS];
181 #endif
182 
183 
184 #ifndef EMBEDDED
185 
186 /* Cursors: */
187 
188 enum {
189   CURSOR_NOTHING,
190   CURSOR_LEFT,
191   CURSOR_RIGHT,
192   CURSOR_ACTION,
193   NUM_CURSORS
194 };
195 
196 Uint8 * cursor_bitmap[NUM_CURSORS] = {
197   nothing_bits, left_bits, right_bits, action_bits
198 };
199 
200 Uint8 * cursor_bitmask[NUM_CURSORS] = {
201   nothing_mask_bits, left_mask_bits, right_mask_bits, action_mask_bits
202 };
203 
204 #endif
205 
206 
207 #ifdef EMBEDDED
208 #define SDLK_ESCAPE 27
209 #define SDLK_a 'a'
210 #define SDLK_k 'k'
211 #define SDLK_l 'l'
212 #define SDLK_p 'p'
213 #define SDLK_q 'q'
214 #define SDLK_z 'z'
215 #define SDLK_RETURN 10
216 #define SDLK_SPACE 32
217 #define SDLK_LAST 999
218 #define SDLK_RIGHT '<'
219 #define SDLK_LEFT '>'
220 #define SDLK_UP '^'
221 #define SDLK_DOWN 'v'
222 #endif
223 
224 
225 /* Globals: */
226 
227 explosion_type explosions[NUM_EXPLOSIONS];
228 int blocks[HEIGHT][WIDTH], killsx[100], killsy[100];
229 int scorevals[15];
230 int level, gameover, frozen, carrying, howmany, leveldone, _warning,
231   whichexplosion, lines, firstround, linesneeded, happy, score, playerx,
232   use_sound, use_joystick, max_level, clicks, no_music, game_playing;
233 
234 
235 int windowwidth, windowheight;
236 
237 
238 SDL_Surface * window;
239 SDL_Surface * object_pixmaps[NUM_OBJECTS];
240 
241 #ifndef EMBEDDED
242 SDL_Cursor * cursor[NUM_CURSORS];
243 SDL_Event event;
244 SDLKey key;
245 SDL_Joystick * js;
246 #else
247 
248 class MainWindow: public QWidget
249 {
250 //      Q_OBJECT
251         private:
252                 QPixmap* buffer;
253                 QPainter* bufpainter;
254                 QColor palette[2];
255 
256                 int (*timerhandler)();
257                 int (*keypresshandler)(int);
258                 int (*keyreleasehandler)(int);
259 
260         protected:
261                 void timerEvent(QTimerEvent*);
262                 void keyPressEvent(QKeyEvent*);
263                 void keyReleaseEvent(QKeyEvent*);
264 
265         public:
266                 MainWindow(const char* name);
267                 void setTimerhandler(int (*timerhandler)(void), int ms = 15);
268                 void setKeypresshandler(int (*keypresshandler)(int));
269                 void setKeyreleasehandler(int (*keyreleasehandler)(int));
270 
271                 void setBgColor(Q_UINT32 color);
272                 void setFgColor(Q_UINT32 color);
273 
274                 void plot(int x, int y);
275                 void flush();
276 
277                 void blit(QPixmap* image, int x, int y);
278 };
279 
MainWindow(const char * name)280 MainWindow::MainWindow(const char* name):
281         QWidget(0, name, WType_TopLevel)
282 {
283         // Setup the buffer
284         buffer = new QPixmap(240, 320);
285         bufpainter = new QPainter(buffer);
286 
287         // Initialize variables
288         setBgColor(0x000000);
289         setFgColor(0xffffff);
290 
291         // Initialize handlers
292         timerhandler = NULL;
293         keypresshandler = NULL;
294         keyreleasehandler = NULL;
295 
296         // Setup the window
297         resize(230, 280);
298         setCaption(name);
299         bufpainter->eraseRect(0, 0, 240, 320);
300 }
301 
setTimerhandler(int (* th)(void),int ms)302 void MainWindow::setTimerhandler(int (*th)(void), int ms)
303 {
304         timerhandler = th;                  // Install the timer handler
305         startTimer(ms);
306 }
307 
setKeypresshandler(int (* kph)(int))308 void MainWindow::setKeypresshandler(int (*kph)(int))
309 {
310         keypresshandler = kph;              // Install the keypress handler
311 }
312 
setKeyreleasehandler(int (* krh)(int))313 void MainWindow::setKeyreleasehandler(int (*krh)(int))
314 {
315         keyreleasehandler = krh;            // Install the keypress handler
316 }
317 
timerEvent(QTimerEvent *)318 void MainWindow::timerEvent(QTimerEvent*)
319 {
320         timerhandler();
321 }
322 
323 
keyPressEvent(QKeyEvent * e)324 void MainWindow::keyPressEvent(QKeyEvent* e)
325 {
326         if(!e->isAutoRepeat() && keypresshandler)
327         {
328                 keypresshandler(e->key());
329         }
330 }
331 
332 
keyReleaseEvent(QKeyEvent * e)333 void MainWindow::keyReleaseEvent(QKeyEvent* e)
334 {
335         if(!e->isAutoRepeat() && keyreleasehandler)
336         {
337                 keyreleasehandler(e->key());
338         }
339 }
340 
341 
setBgColor(Q_UINT32 color)342 void MainWindow::setBgColor(Q_UINT32 color)
343 {
344         palette[0] = QColor((color >> 16 & 0xff), (color >> 8) & 0xff, color & 0xff);
345         bufpainter->setBackgroundColor(palette[0]);
346 }
347 
348 
setFgColor(Q_UINT32 color)349 void MainWindow::setFgColor(Q_UINT32 color)
350 {
351         palette[1] = QColor((color >> 16 & 0xff), (color >> 8) & 0xff, color & 0xff);
352         bufpainter->setPen(palette[1]);
353 }
354 
355 
plot(int x,int y)356 void MainWindow::plot(int x, int y)
357 {
358         bufpainter->drawPoint(x, y);
359 }
360 
361 
flush()362 void MainWindow::flush()
363 {
364         QPainter p(this);
365         p.drawPixmap(0, 0, *buffer);
366 }
367 
368 
blit(QPixmap * image,int x,int y)369 void MainWindow::blit(QPixmap* image, int x, int y)
370 {
371         bufpainter->drawPixmap(x, y, *image);
372 }
373 
374 
375 
376 QPEApplication * qapp;
377 MainWindow * mw;
378 int key;
379 #endif
380 
381 
382 #ifdef EMBEDDED
SDL_BlitSurface(SDL_Surface * src,SDL_Rect * srcrect,SDL_Surface * dst,SDL_Rect * dstrect)383 int SDL_BlitSurface(SDL_Surface *src, SDL_Rect *srcrect,
384 		    SDL_Surface *dst, SDL_Rect *dstrect)
385 {
386   mw->blit(src->image, dstrect->x, dstrect->y);
387   return(0);
388 }
389 
SDL_UpdateRect(SDL_Surface * screen,int x,int y,int w,int h)390 int SDL_UpdateRect(SDL_Surface *screen, int x, int y, int w, int h)
391 {
392   printf("$$ SDL_UpdateRect()\n");
393   return(0);
394 }
395 
SDL_GetTicks(void)396 Uint32 SDL_GetTicks(void)
397 {
398   struct timeval tv;
399 
400   gettimeofday(&tv, NULL);
401   return (tv.tv_sec * 100000 + tv.tv_usec) / 1000;
402 }
403 
SDL_Delay(Uint32 ms)404 void SDL_Delay(Uint32 ms)
405 {
406   usleep(ms * 1000);
407 }
408 
SDL_LoadBMP(const char * file)409 SDL_Surface * SDL_LoadBMP(const char * file)
410 {
411   SDL_Surface * surf;
412 
413   surf = (SDL_Surface *) malloc(sizeof(SDL_Surface));
414 
415   surf->image = new QPixmap();
416   surf->image->load(file);
417   surf->w = (surf->image)->width();
418   surf->h = (surf->image)->height();
419   return(surf);
420 }
421 
SDL_GetError(void)422 char * SDL_GetError(void)
423 {
424   printf("$$ SDL_GetError()\n");
425   return ("???");
426 }
427 
SDL_Quit(void)428 void SDL_Quit(void)
429 {
430   exit(1);
431 }
432 #endif
433 
434 
my_FillRect(SDL_Surface * dst,SDL_Rect * dstrect,Uint8 r,Uint8 g,Uint8 b)435 int my_FillRect(SDL_Surface *dst, SDL_Rect *dstrect,
436 		Uint8 r, Uint8 g, Uint8 b)
437 {
438 #ifndef EMBEDDED
439   return (SDL_FillRect(dst, dstrect,
440 		       SDL_MapRGB(dst->format, r, g, b)));
441 #else
442   printf("$$ my_FillRect()\n");
443   return(0);
444 #endif
445 }
446 
447 
playsound(int which)448 void playsound(int which)
449 {
450 #ifndef NOSOUND
451   int i, found;
452 
453   if (use_sound)
454   {
455     found = -1;
456 
457     for (i = 0; i < MIX_CHANNELS; i++)
458       {
459         if (!Mix_Playing(i))
460 	  found = i;
461       }
462 
463     if (found == -1)
464       found = rand() % MIX_CHANNELS;
465 
466     Mix_PlayChannel(found, samples[which], 0);
467     /* Mix_Volume(found, 8); */
468   }
469 #endif
470 }
471 
472 
473 /* Beep: (was flash and beep on the Atari) */
474 
complain(void)475 void complain(void)
476 {
477   playsound(SND_BUZZER);
478 }
479 
480 
481 /* Clear the screen: */
482 
erasewindow(void)483 void erasewindow(void)
484 {
485   SDL_Rect dest;
486 
487   dest.x = 0;
488   dest.y = 0;
489   dest.w = windowwidth;
490   dest.h = windowheight;
491 
492   my_FillRect(window, &dest, 0x00, 0x00, 0x00);
493   SDL_UpdateRect(window, dest.x, dest.y, dest.w, dest.h);
494 }
495 
496 
497 /* Setup the application: */
498 
setup(int argc,char * argv[])499 void setup(int argc, char * argv[])
500 {
501   int i;
502   char file[128];
503 #ifndef EMBEDDED
504   int j;
505   Uint8 temp_bitmap[32], temp_bitmask[32];
506   Uint8 b;
507   SDL_Surface * image;
508 #endif
509   SDL_Rect dest;
510 
511 
512 #ifndef EMBEDDED
513   if (SDL_Init(SDL_INIT_VIDEO) < 0)
514     {
515       fprintf(stderr, "Couldn't initialize SDL video.\n%s\n",
516               SDL_GetError());
517       exit(1);
518     }
519 
520   use_joystick = 1;
521   if (SDL_Init(SDL_INIT_JOYSTICK) < 0)
522     {
523       fprintf(stderr, "Warning - Couldn't initialize SDL joystick.\n%s\n",
524 	      SDL_GetError());
525       use_joystick = 0;
526     }
527 
528 
529   /* Set key repeat: */
530 
531   SDL_EnableKeyRepeat(100, 30);
532 
533 
534   /* Open joystick: */
535 
536   if (use_joystick)
537     {
538       if (SDL_NumJoysticks() <= 0)
539 	{
540 	  fprintf(stderr, "Warning - No joysticks.\n");
541 	  use_joystick = 0;
542 	}
543     }
544 
545   if (use_joystick)
546     {
547       js = SDL_JoystickOpen(0);
548       if (js == NULL)
549 	{
550 	  fprintf(stderr, "Warning - Can't open joystick 1.\n%s\n",
551 		  SDL_GetError());
552 	  use_joystick = 0;
553 	}
554     }
555 
556 
557   /* Check for proper joystick config: */
558 
559   if (use_joystick)
560     {
561       if (SDL_JoystickNumAxes(js) < 1)
562 	{
563 	  fprintf(stderr, "Joystick doesn't have enough axes!\n");
564 	  use_joystick = 0;
565 	}
566     }
567 
568   if (use_joystick)
569     {
570       if (SDL_JoystickNumButtons(js) < 2)
571 	{
572 	  fprintf(stderr, "Joystick doesn't have enough buttons!\n");
573 	  use_joystick = 0;
574 	}
575     }
576 #else
577   qapp = new QPEApplication(argc, argv);
578   mw = new MainWindow("Gem Drop Z");
579 #endif
580 
581 
582   /* Set the size of the window: */
583 
584 #ifndef EMBEDDED
585   windowwidth = WIDTH * 48;
586   windowheight = (HEIGHT + 2) * 48;
587 #else
588   windowwidth = 240;
589   windowheight = 320;
590 #endif
591 
592 
593   /* Open window: */
594 
595 #ifndef EMBEDDED
596   window = SDL_SetVideoMode(windowwidth, windowheight, 16, SDL_HWSURFACE);
597   SDL_WM_SetCaption("Gem Drop X!", "Gem Drop X");
598 #else
599   printf("$$ setup() - open window\n");
600 #endif
601 
602 
603 #ifndef EMBEDDED
604   /* Make cursors: */
605 
606   for (i = 0; i < NUM_CURSORS; i++)
607     {
608       for (j = 0; j < 32; j++)
609 	{
610 	  b = cursor_bitmap[i][j];
611 
612 	  temp_bitmap[j] = (((b & 0x01) << 7) |
613 			    ((b & 0x02) << 5) |
614 			    ((b & 0x04) << 3) |
615 			    ((b & 0x08) << 1) |
616 			    ((b & 0x10) >> 1) |
617 			    ((b & 0x20) >> 3) |
618 			    ((b & 0x40) >> 5) |
619 			    ((b & 0x80) >> 7));
620 
621 	  b = cursor_bitmask[i][j];
622 
623 	  temp_bitmask[j] = (((b & 0x01) << 7) |
624 			     ((b & 0x02) << 5) |
625 			     ((b & 0x04) << 3) |
626 			     ((b & 0x08) << 1) |
627 			     ((b & 0x10) >> 1) |
628 			     ((b & 0x20) >> 3) |
629 			     ((b & 0x40) >> 5) |
630 			     ((b & 0x80) >> 7));
631 	}
632 
633       cursor[i] = SDL_CreateCursor(temp_bitmap, temp_bitmask,
634 				   16, 16, 8, 8);
635     }
636 #endif
637 
638 
639   /* Load the object graphics: */
640 
641   for (i = 0; i < NUM_OBJECTS; i++)
642     {
643       sprintf(file, "%s/images/%s.bmp", DATA_PREFIX, object_filenames[i]);
644 
645 #ifndef EMBEDDED
646       image = SDL_LoadBMP(file);
647 
648       if (image == NULL)
649 	{
650 	  fprintf(stderr, "%s: can't load: %s\n", file, SDL_GetError());
651 	  SDL_Quit();
652 	  exit(1);
653 	}
654 
655       object_pixmaps[i] = SDL_DisplayFormat(image);
656       SDL_FreeSurface(image);
657 #else
658       object_pixmaps[i] = SDL_LoadBMP(file);
659 
660       if (object_pixmaps[i] == NULL)
661 	{
662 	  fprintf(stderr, "%s: can't load: %s\n", file, SDL_GetError());
663 	  SDL_Quit();
664 	  exit(1);
665 	}
666 #endif
667 
668 
669 
670       if (i == PATIENCE_GFX)
671 	{
672 	  dest.x = (windowwidth - 96) / 2;
673 	  dest.y = (windowheight - 16) / 2;
674 	  dest.w = 96;
675 	  dest.h = 16;
676 
677 	  SDL_BlitSurface(object_pixmaps[PATIENCE_GFX - 1], NULL,
678 			  window, &dest);
679 	  SDL_UpdateRect(window, dest.x, dest.y, dest.w, dest.h);
680 	}
681     }
682 
683 
684   /* Initial level: */
685 
686   level = 1;
687 
688 
689   /* Reset explosions: */
690 
691   for (i = 0; i < NUM_EXPLOSIONS; i++)
692     {
693       explosions[i].exist = NO;
694     }
695 
696 
697   /* Init. score value table: */
698 
699   scorevals[0] = 0;
700   scorevals[1] = 0;
701   scorevals[2] = 0;
702   scorevals[3] = 10;
703   scorevals[4] = 20;
704   scorevals[5] = 50;
705   scorevals[6] = 100;
706   scorevals[7] = 150;
707   scorevals[8] = 200;
708   scorevals[9] = 250;
709   scorevals[10] = 300;
710   scorevals[11] = 500;
711   scorevals[12] = 1000;
712   scorevals[13] = 1000;
713   scorevals[14] = 5000;
714 
715 
716   /* Reset random number generator: */
717 
718   srand(SDL_GetTicks());
719 
720 
721   /* Setup sound: */
722 
723   use_sound = 1;
724 
725 #ifndef NOSOUND
726   if (use_sound)
727   {
728     if (SDL_Init(SDL_INIT_AUDIO) < 0)
729       {
730         fprintf(stderr, "Warning: Couldn't initialize SDL sound.\n%s\n",
731                 SDL_GetError());
732         use_sound = 0;
733       }
734   }
735 
736   if (use_sound)
737   {
738     if (Mix_OpenAudio(44100, AUDIO_S8, 2, 512) < 0)
739       {
740         fprintf(stderr,
741                 "Warning: Couldn't set 11025 Hz 8-bit stereo audio.\n%s\n",
742                 SDL_GetError());
743 	use_sound = 0;
744       }
745   }
746 
747 
748   if (use_sound)
749   {
750     /* Load sound files: */
751 
752     for (i = 0; i < NUM_SOUNDS; i++)
753       {
754         sprintf(file, "%s/sounds/%s.wav", DATA_PREFIX, sound_filenames[i]);
755         samples[i] = Mix_LoadWAV(file);
756         if (samples[i] == NULL)
757 	  {
758 	    fprintf(stderr, "Couldn't load %s: %s\n", file, SDL_GetError());
759 	    SDL_Quit();
760 	    exit(1);
761 	  }
762       }
763 
764 
765     /* Load music files: */
766 
767     if (no_music == 0)
768       {
769         for (i = 0; i < NUM_MODS; i++)
770 	  {
771 	    sprintf(file, "%s/sounds/%s", DATA_PREFIX, music_filenames[i]);
772 	    songs[i] = Mix_LoadMUS(file);
773 	    if (songs[i] == NULL)
774 	      {
775 	        fprintf(stderr, "Couldn't load %s: %s\n", file, SDL_GetError());
776 	        SDL_Quit();
777 	        exit(1);
778 	      }
779 	  }
780       }
781     }
782 #endif
783 }
784 
785 
786 /* Display a number using images: */
787 
shownumber(int num,int x,int y)788 void shownumber(int num, int x, int y)
789 {
790   int i;
791   char temp[15];
792   SDL_Rect src, dest;
793 
794   num = (num % 100000);
795 
796   sprintf(temp, "%d     ", num);
797 
798   for (i = 0; i < 5; i++)
799     {
800       dest.x = x + i * 16;
801       dest.y = y;
802       dest.w = 16;
803       dest.h = 16;
804 
805       if (temp[i] >= '0' && temp[i] <= '9')
806 	{
807 	  src.x = (temp[i] - '0') * 16;
808 	  src.y = 0;
809 	  src.w = 16;
810 	  src.h = 16;
811 
812 	  SDL_BlitSurface(object_pixmaps[NUMBERS_GFX - 1], &src,
813 			  window, &dest);
814 	}
815       else
816 	{
817 	  my_FillRect(window, &dest, 0x00, 0x00, 0x00);
818 	}
819 
820       SDL_UpdateRect(window, dest.x, dest.y, dest.w, dest.h);
821     }
822 }
823 
824 
825 /* Update the score in the window: */
826 
drawscore()827 void drawscore()
828 {
829   SDL_Rect dest;
830 
831   dest.x = 0;
832   dest.y = (HEIGHT + 2) * 48 - 16;
833   dest.w = 48;
834   dest.h  =16;
835 
836   SDL_BlitSurface(object_pixmaps[SCORE_GFX - 1], NULL,
837 		  window, &dest);
838   SDL_UpdateRect(window, dest.x, dest.y, dest.w, dest.h);
839 
840   shownumber(score, 48, (HEIGHT + 2) * 48 - 16);
841 }
842 
843 
844 /* Pick a random block: */
845 
randblock(void)846 int randblock(void)
847 {
848   int i;
849 
850 
851   /* Pick one of the main four pieces in level 1-14: */
852 
853   i = (rand() % NUM_NORMAL_BLOCKS) + 1;
854 
855 
856   /* Pick one of all eight pieces in levels 15-20: */
857 
858   if (level >= 15)
859      i = rand() % (NUM_ALL_BLOCKS + 1);
860 
861 
862   /* Maybe pick a non-gem object: */
863 
864   if ((rand() % 40) < 1)
865      i = (rand() % NUM_SPECIALS) + NUM_ALL_BLOCKS + 1;
866 
867   return(i);
868 }
869 
870 
871 /* Draw an object graphic somewhere in the window: */
872 
drawblockgraphic(int x,int y,int c)873 void drawblockgraphic(int x, int y, int c)
874 {
875   SDL_Rect dest;
876 
877   dest.x = x;
878   dest.y = y;
879   dest.w = 48;
880   dest.h = 48;
881 
882   if (c != 0)
883     {
884       SDL_BlitSurface(object_pixmaps[c - 1], NULL,
885 		      window, &dest);
886     }
887   else
888     {
889       my_FillRect(window, &dest, 0x00, 0x00, 0x00);
890     }
891 
892   SDL_UpdateRect(window, dest.x, dest.y, dest.w, dest.h);
893 }
894 
895 
896 /* Update the status icons at the bottom: */
897 
drawstatus()898 void drawstatus()
899 {
900   if (frozen != 0)
901     drawblockgraphic((WIDTH / 2) * 48, (HEIGHT + 1) * 48, CLOCK);
902   else
903     drawblockgraphic((WIDTH / 2) * 48, (HEIGHT + 1) * 48, 0);
904 
905   if (_warning != 0)
906     drawblockgraphic((WIDTH / 2) * 48 + 48, (HEIGHT + 1) * 48, WARNING_GFX +
907 		     (clicks % 4));
908   else
909     drawblockgraphic((WIDTH / 2) * 48 + 48, (HEIGHT + 1) * 48, 0);
910 }
911 
912 
913 /* Draw the player (it's two colors): */
914 
drawmangraphic(int x,int y,int c)915 void drawmangraphic(int x, int y, int c)
916 {
917   SDL_Rect dest;
918 
919   if (c != 0)
920     {
921       dest.x = x;
922       dest.y = y;
923       dest.w = 48;
924       dest.h = 48;
925 
926       SDL_BlitSurface(object_pixmaps[c - 1], NULL,
927 		      window, &dest);
928       SDL_UpdateRect(window, dest.x, dest.y, dest.w, dest.h);
929     }
930 }
931 
932 
933 /* Draw a block where it belongs: */
934 
drawblock(int x,int y)935 void drawblock(int x, int y)
936 {
937   int c;
938 
939 
940   /* Draw the block at (x, y): */
941 
942   c = blocks[y][x];
943 
944   drawblockgraphic(x * 48, y * 48, c);
945 }
946 
947 
948 /* Update the level number display: */
949 
updatelevel(void)950 void updatelevel(void)
951 {
952   SDL_Rect dest;
953 
954   dest.x = 0;
955   dest.y = (HEIGHT + 2) * 48 - 16 - 16;
956   dest.w = 48;
957   dest.h = 16;
958 
959   SDL_BlitSurface(object_pixmaps[LEVEL_GFX - 1], NULL,
960 		  window, &dest);
961   SDL_UpdateRect(window, dest.x, dest.y, dest.w, dest.h);
962 
963   shownumber(level, 48, (HEIGHT + 2) * 48 - 16 - 16);
964 }
965 
966 
967 /* Update the lines / needed lines displays: */
968 
updatelines(void)969 void updatelines(void)
970 {
971   SDL_Rect dest;
972 
973   dest.x = WIDTH * 48 - 48 - (16 * 5);
974   dest.y = (HEIGHT + 2) * 48 - 16 - 16;
975   dest.w = 48;
976   dest.h = 16;
977 
978   SDL_BlitSurface(object_pixmaps[LINES_GFX - 1], NULL,
979 		  window, &dest);
980 
981   SDL_UpdateRect(window, dest.x, dest.y, dest.w, dest.h);
982 
983   shownumber(lines, WIDTH * 48 - (16 * 5), (HEIGHT + 2) * 48 - 16 - 16);
984 
985 
986   dest.x = WIDTH * 48 - 48 - (16 * 5);
987   dest.y = (HEIGHT + 2) * 48 - 16;
988   dest.w = 48;
989   dest.h = 16;
990 
991   SDL_BlitSurface(object_pixmaps[NEED_GFX - 1], NULL,
992 		  window, &dest);
993 
994   SDL_UpdateRect(window, dest.x, dest.y, dest.w, dest.h);
995 
996   shownumber(linesneeded, WIDTH * 48 - (16 * 5), (HEIGHT + 2) * 48 - 16);
997 }
998 
999 
1000 /* Get a key... mouse is seen as key, too!
1001    Maybe handle expose events
1002    (the original source that this was ported from was obviously
1003    not written for an event-based system): */
1004 
getkey(int handle_expose)1005 void getkey(int handle_expose)
1006 {
1007   /* int x, y; */
1008 
1009 
1010 #ifndef EMBEDDED
1011   key = SDLK_LAST;
1012 
1013   while (SDL_PollEvent(&event))
1014     {
1015       if (event.type == SDL_KEYDOWN)
1016 	{
1017 	  /* Get the key's name: */
1018 
1019 	  key = event.key.keysym.sym;
1020 	}
1021       else if (event.type == SDL_MOUSEBUTTONDOWN)
1022 	{
1023 	  /* Mouse counts as keyboard: */
1024 
1025 	  if (event.button.y >= HEIGHT * 48)
1026 	    {
1027 	      /* Left or right of man at the bottom counts as left/right: */
1028 
1029 	      if (event.button.x < playerx * 48 + 16)
1030 		key = SDLK_LEFT;
1031 	      else if (event.button.x >= playerx * 48 + 31)
1032 		key = SDLK_RIGHT;
1033 	    }
1034 	  else
1035 	    {
1036 	      /* Left or right click above man count as grab/throw: */
1037 
1038 	      if (event.button.button == 1)
1039 		key = SDLK_DOWN;
1040 	      else
1041 		key = SDLK_UP;
1042 	    }
1043 	}
1044       else if (event.type == SDL_MOUSEMOTION)
1045 	{
1046 	  /* Handle cursor shape: */
1047 
1048 	  if (game_playing == 0)
1049 	    SDL_SetCursor(cursor[CURSOR_NOTHING]);
1050 	  else
1051 	    {
1052 	      if (event.motion.y >= HEIGHT * 48)
1053 		{
1054 		  /* Left/right arrows or nothing: */
1055 
1056 		  if (event.motion.x < playerx * 48 + 16)
1057 		    SDL_SetCursor(cursor[CURSOR_LEFT]);
1058 		  else if (event.motion.x >= playerx * 48 + 31)
1059 		    SDL_SetCursor(cursor[CURSOR_RIGHT]);
1060 		  else
1061 		    SDL_SetCursor(cursor[CURSOR_NOTHING]);
1062 		}
1063 	      else
1064 		SDL_SetCursor(cursor[CURSOR_ACTION]);
1065 	    }
1066 	}
1067     }
1068 #else
1069   printf("$$ getkey()\n");
1070 #endif
1071 }
1072 
1073 
1074 /* Wait until joystick buttons are released: */
1075 
1076 #ifndef EMBEDDED
1077 
eatjoybuttons(void)1078 void eatjoybuttons(void)
1079 {
1080   int i, any_down;
1081   SDL_Event event;
1082 
1083 
1084   if (use_joystick)
1085     {
1086       do
1087 	{
1088 	  any_down = 0;
1089 
1090 	  SDL_PollEvent(&event);
1091 
1092 	  for (i = 0; i < SDL_JoystickNumButtons(js); i++)
1093 	    {
1094 	      if (SDL_JoystickGetButton(js, i))
1095 		any_down = 1;
1096 	    }
1097 
1098 	  SDL_Delay(10);
1099 	}
1100       while (any_down);
1101     }
1102 }
1103 
1104 #endif
1105 
1106 
1107 /* Show the title... let them change the level: */
1108 
title(void)1109 int title(void)
1110 {
1111 #ifndef EMBEDDED
1112   int btn;
1113 #endif
1114   int quit, ok, title_width, title_height, height,
1115     author_width, author_height, author_x, author_y, author,
1116     author_xm, author_ym, sine_timer, i, credits_width, credits_height;
1117   SDL_Rect src, dest;
1118   Uint32 last_time;
1119 
1120 
1121   /* Find out size of bitmaps we're using in the title screen: */
1122 
1123   title_width = object_pixmaps[TITLE_GFX - 1] -> w;
1124   title_height = object_pixmaps[TITLE_GFX - 1] -> h;
1125 
1126   author_width = object_pixmaps[AUTHOR_GFX - 1] -> w;
1127   author_height = object_pixmaps[AUTHOR_GFX - 1] -> h;
1128 
1129   credits_width = object_pixmaps[CREDITS_GFX - 1] -> w;
1130   credits_height = object_pixmaps[CREDITS_GFX - 1] -> h;
1131 
1132   author_x = WIDTH * 48 - author_width;
1133   author_y = HEIGHT * 48 - author_height - (rand() % 10) - 30;
1134 
1135 
1136   /* Clear the screen: */
1137 
1138   erasewindow();
1139 
1140 
1141   /* Draw credits / title / version: */
1142 
1143   dest.x = (WIDTH * 48 - credits_width) / 2;
1144   dest.y = (HEIGHT * 48 - credits_height) / 2;
1145   dest.w = credits_width;
1146   dest.h = credits_height;
1147 
1148   SDL_BlitSurface(object_pixmaps[CREDITS_GFX - 1], NULL,
1149 		  window, &dest);
1150 
1151   SDL_UpdateRect(window, dest.x, dest.y, dest.w, dest.h);
1152 
1153 
1154   /* Draw the currently-selected level: */
1155 
1156   updatelevel();
1157 
1158 
1159   /* Init. animation variables: */
1160 
1161   author = 0;
1162   height = 0;
1163   do
1164     {
1165       author_xm = -(rand() % 3);
1166     }
1167   while (author_xm == 0);
1168   author_ym = (rand() % 6) - 3;
1169 
1170 
1171   /* We haven't quit and we haven't started a game: */
1172 
1173   quit = NO;
1174   ok = NO;
1175 
1176 
1177   /* Title animation loop: */
1178 
1179   sine_timer = 500 - title_height;
1180 
1181   do
1182     {
1183       last_time = SDL_GetTicks();
1184 
1185 
1186       /* Show more and more of the title: */
1187 
1188       height = height + 2;
1189       if (height > title_height)
1190 	height = title_height;
1191 
1192 
1193       /* Draw it: */
1194 
1195       sine_timer++;
1196 
1197       if (sine_timer < 500)
1198 	{
1199 	  dest.x = (WIDTH * 48 - title_width) / 2;
1200 	  dest.y = -title_height + height;
1201 	  dest.w = title_width;
1202 	  dest.h = title_height;
1203 
1204 	  SDL_BlitSurface(object_pixmaps[TITLE_GFX - 1], NULL,
1205 			  window, &dest);
1206 
1207 	  SDL_UpdateRect(window, dest.x, dest.y, dest.w, dest.h);
1208 	}
1209       else
1210 	{
1211 	  for (i = 0; i < title_height; i++)
1212 	    {
1213 	      src.x = 0;
1214 	      src.y = i;
1215 	      src.w = title_width;
1216 	      src.h = 1;
1217 
1218 	      dest.x = (int) ((WIDTH * 48 - title_width) / 2 +
1219 			sin(M_PI * ((i + sine_timer) * 5) / 180.0) * 5.0);
1220 	      dest.y = i;
1221 	      dest.w = title_width;
1222 	      dest.h = 1;
1223 
1224 	      SDL_BlitSurface(object_pixmaps[TITLE_GFX - 1], &src,
1225 			      window, &dest);
1226 
1227 	      SDL_UpdateRect(window, dest.x, dest.y, dest.w, dest.h);
1228 	    }
1229 	}
1230 
1231       /* Hmm!? */
1232 
1233       author = author + 1;
1234 
1235       if (author > 1000)
1236 	{
1237 	  dest.x = author_x;
1238 	  dest.y = author_y;
1239 	  dest.w = author_width;
1240 	  dest.h = author_height;
1241 
1242 	  my_FillRect(window, &dest, 0x00, 0x00, 0x00);
1243 
1244 	  SDL_UpdateRect(window, dest.x, dest.y, dest.w, dest.h);
1245 
1246 	  author_x = author_x + author_xm;
1247 	  if (author_x < 0)
1248 	    {
1249 	      author_x = 0;
1250 	      do
1251 		{
1252 		  author_xm = rand() % 3;
1253 		}
1254 	      while (author_xm == 0);
1255 	    }
1256 	  if (author_x > WIDTH * 48 - author_width)
1257 	    {
1258 	      author_x = WIDTH * 48 - author_width;
1259 	      do
1260 		{
1261 		  author_xm = -rand() % 3;
1262 		}
1263 	      while (author_xm == 0);
1264 	    }
1265 
1266 	  author_y = author_y + author_ym;
1267 	  if (author_y < windowheight / 2)
1268 	    {
1269 	      author_y = windowheight / 2;
1270 	    }
1271 	  if (author_y > HEIGHT * 48 - author_height)
1272 	    {
1273 	      author_y = HEIGHT * 48 - author_height;
1274 	      author_ym = -author_ym;
1275 	    }
1276 
1277 	  author_ym = author_ym + 1;
1278 	  if (author_ym > 10)
1279 	    author_ym = 10;
1280 
1281 	  if (author < 1500)
1282 	    {
1283 	      dest.x = author_x;
1284 	      dest.y = author_y;
1285 	      dest.w = author_width;
1286 	      dest.h = author_height;
1287 
1288 	      SDL_BlitSurface(object_pixmaps[AUTHOR_GFX - 1], NULL,
1289 			      window, &dest);
1290 
1291 	      SDL_UpdateRect(window, dest.x, dest.y, dest.w, dest.h);
1292 	    }
1293 	  else
1294 	    {
1295 	      author = 0;
1296 	    }
1297 	}
1298 
1299 
1300       /* Check for keypresses: */
1301 
1302       getkey(0);
1303 
1304       if (key == SDLK_ESCAPE ||
1305 	  key == SDLK_q)
1306 	{
1307 	  /* Escape to quit: */
1308 
1309 	  ok = YES;
1310 	  quit = YES;
1311 	}
1312       else if (key == SDLK_l)
1313 	{
1314 	  /* L for level select: */
1315 
1316 	  level = level + 1;
1317 	  if (level > max_level)
1318 	    level = 1;
1319 
1320 	  playsound(SND_LEVELSELECT);
1321 
1322 	  updatelevel();
1323 	}
1324       else if (key == SDLK_RETURN ||
1325 	       key == SDLK_SPACE)
1326 	{
1327 	  /* Return or Space to begin: */
1328 
1329 	  ok = YES;
1330 	}
1331       else if (key == SDLK_a)
1332 	{
1333 	  /* Hmm!? */
1334 
1335 	  if (author < 1000)
1336 	    author = 1000;
1337 	  else
1338 	    author = 1495;
1339 	}
1340 
1341 
1342       /* Any joystick buttons? */
1343 
1344 #ifndef EMBEDDED
1345       if (use_joystick)
1346 	{
1347 	  for (btn = 0; btn < SDL_JoystickNumButtons(js); btn++)
1348 	    {
1349 	      if (SDL_JoystickGetButton(js, btn))
1350 		ok = YES;
1351 	    }
1352 	}
1353 #endif
1354 
1355 
1356       /* Keep framerate exact: */
1357 
1358       if (SDL_GetTicks() < last_time + (1000 / FPS))
1359 	SDL_Delay(last_time + (1000 / FPS) - SDL_GetTicks());
1360 
1361 
1362       /* Play music: */
1363 #ifndef NOSOUND
1364       if (use_sound)
1365       {
1366         if (no_music == 0)
1367 	  {
1368 	    if (!Mix_PlayingMusic())
1369 	      Mix_PlayMusic(songs[MOD_TITLE], 0);
1370 	    /* Mix_VolumeMusic(8); */
1371 	  }
1372       }
1373 #endif
1374     }
1375   while (ok != YES);
1376 
1377 #ifndef EMBEDDED
1378   eatjoybuttons();
1379 #endif
1380 
1381   return(quit);
1382 }
1383 
1384 
1385 /* See if you're happy or sad...  Depends on if there are any blocks
1386    close to the bottom: */
1387 
checkhappy()1388 void checkhappy()
1389 {
1390   int x, y;
1391 
1392   happy = YES;
1393   for (y = HEIGHT - (HEIGHT / 3); y < HEIGHT; y++)
1394     {
1395       for (x = 0; x < WIDTH; x++)
1396 	{
1397 	  if (blocks[y][x] != 0)
1398 	    happy = NO;
1399 	}
1400     }
1401 }
1402 
1403 
1404 /* Init this level (randomly place blocks, etc.) */
1405 
initlevel(void)1406 void initlevel(void)
1407 {
1408   int x, y, yy;
1409 
1410 
1411   playsound(SND_BEGIN);
1412 
1413 
1414   /* Erase all blocks: */
1415 
1416   for (y = 0; y < HEIGHT; y++)
1417     for (x = 0; x < WIDTH; x++)
1418       blocks[y][x] = 0;
1419 
1420 
1421   /* How low should they go? */
1422 
1423   yy = level;
1424   if (level > 14)
1425     yy = yy - (HEIGHT - 2);
1426 
1427   if (yy > HEIGHT - 2)
1428     yy = HEIGHT - 2;
1429 
1430 
1431   /* Place random blocks: */
1432 
1433   for (y = 0; y <= yy; y++)
1434     for (x = 0; x < WIDTH; x++)
1435       blocks[y][x] = randblock();
1436 
1437 
1438   /* Draw all blocks: */
1439 
1440   for (y = 0; y < HEIGHT; y++)
1441     for (x = 0; x < WIDTH; x++)
1442       drawblock(x, y);
1443 
1444 
1445   /* Init level variables: */
1446 
1447   leveldone = NO;
1448 
1449   carrying = 0;
1450   howmany = 0;
1451   frozen = 0;
1452   _warning = NO;
1453   firstround = NO;
1454 
1455 
1456   /* Start out happy or not, depending on where the pieces are: */
1457 
1458   checkhappy();
1459 
1460 
1461   /* How many lines do you need / have? */
1462 
1463   lines = 0;
1464   linesneeded = (level * 3) + 2;
1465 
1466 
1467   /* Draw the rest of the game screen stuff: */
1468 
1469   drawscore();
1470   updatelines();
1471   drawstatus();
1472   updatelevel();
1473 }
1474 
1475 
1476 /* Erase player: */
1477 
eraseyou(int x)1478 void eraseyou(int x)
1479 {
1480   SDL_Rect dest;
1481 
1482   dest.x = x * 48 - 48;
1483   dest.y = HEIGHT * 48;
1484   dest.w = 48 * 3;
1485   dest.h = 48;
1486 
1487   my_FillRect(window, &dest, 0x00, 0x00, 0x00);
1488 
1489   SDL_UpdateRect(window, dest.x, dest.y, dest.w, dest.h);
1490 }
1491 
1492 
1493 /* Draw player and objects he's carrying: */
1494 
drawyou(int x)1495 void drawyou(int x)
1496 {
1497   int y;
1498 
1499 
1500   y = HEIGHT * 48;
1501 
1502   if (howmany < 3)
1503     {
1504       /* Happy?  Or sad? */
1505 
1506       if (happy == YES)
1507 	{
1508 	  drawmangraphic(x * 48, y, HAPPY_GFX);
1509 	}
1510       else
1511 	{
1512 	  drawmangraphic(x * 48, y, SAD_GFX);
1513 	}
1514     }
1515 
1516 
1517   if (carrying != 0)
1518     {
1519       drawblockgraphic(x * 48 + 48, y, carrying);
1520 
1521       if (howmany >= 2)
1522 	drawblockgraphic(x * 48 - 48, y, carrying);
1523 
1524       if (howmany >= 3)
1525 	drawblockgraphic(x * 48, y, carrying);
1526     }
1527 }
1528 
1529 
1530 /* Assign an explosion: */
1531 
explodeblock(int x,int y,int explosionwait)1532 void explodeblock(int x, int y, int explosionwait)
1533 {
1534   /* Pick an explosion entity to use: */
1535 
1536   whichexplosion = whichexplosion + 1;
1537 
1538   if (whichexplosion == NUM_EXPLOSIONS)
1539     whichexplosion = 0;
1540 
1541 
1542   /* Init. its values: */
1543 
1544   explosions[whichexplosion].exist = 1;
1545   explosions[whichexplosion].anim = -explosionwait;
1546   explosions[whichexplosion].animrate = 0;
1547   explosions[whichexplosion].x = x;
1548   explosions[whichexplosion].y = y;
1549 }
1550 
1551 
1552 /* See if two objects match: */
1553 
same(int a,int b)1554 int same(int a, int b)
1555 {
1556   int match;
1557 
1558 
1559   /* A match if it's the same, or the object (A) is a special object: */
1560 
1561   match = NO;
1562 
1563   if (a == b || a > NUM_ALL_BLOCKS || b > NUM_ALL_BLOCKS)
1564     match = YES;
1565 
1566   return(match);
1567 }
1568 
1569 
1570 /* Kill a block (may call itself recursively!) */
1571 
killblock(int x,int y,int killed)1572 int killblock(int x, int y, int killed)
1573 {
1574   int c, explosionwait;
1575 
1576 
1577   /* Values we use a lot later: */
1578 
1579   explosionwait = killed;
1580   c = blocks[y][x];
1581 
1582 
1583   if (c != 0)
1584     {
1585       /* Remove the block: */
1586 
1587       blocks[y][x] = 0;
1588 
1589 
1590       /* Put an explosion there: */
1591 
1592       explodeblock(x, y, explosionwait);
1593 
1594 
1595       if (c == BOMB)
1596 	{
1597 	  /* If it's a bomb, explode stuff next to it: */
1598 
1599           playsound(SND_BOMB);
1600 
1601 	  if (y > 0)
1602 	    {
1603 	      blocks[y - 1][x] = 0;
1604 	      explodeblock(x, y - 1, explosionwait);
1605 	    }
1606 
1607 	  if (y < HEIGHT - 1)
1608 	    {
1609 	      blocks[y + 1][x] = 0;
1610 	      explodeblock(x, y + 1, explosionwait);
1611 	    }
1612 
1613 	  if (x > 0)
1614 	    {
1615 	      blocks[y][x - 1] = 0;
1616 	      explodeblock(x - 1, y, explosionwait);
1617 	    }
1618 
1619 	  if (x < WIDTH - 1)
1620 	    {
1621 	      blocks[y][x + 1] = 0;
1622 	      explodeblock(x + 1, y, explosionwait);
1623 	    }
1624 	}
1625       else if (c == CLOCK)
1626 	{
1627 	  /* Hit a clock!  Freeze the game! */
1628 
1629 	  playsound(SND_CLOCK);
1630 
1631 	  frozen = 50;
1632 	}
1633       else if (c == WILDCARD)
1634 	{
1635 	  /* Hit a wildcard - play a noise... the rest comes natural: */
1636 
1637 	  playsound(SND_WILDCARD);
1638 	}
1639 
1640 
1641       /* Kill stuff next to you if they match! */
1642 
1643       if (y > 0)
1644 	{
1645 	  if (same(blocks[y - 1][x], c) == YES)
1646 	    killed = killblock(x, y - 1, killed + 1);
1647 	}
1648 
1649       if (y < HEIGHT - 1)
1650 	{
1651 	  if (same(blocks[y + 1][x], c) == YES)
1652 	    killed = killblock(x, y + 1, killed + 1);
1653 	}
1654 
1655       if (x > 0)
1656 	{
1657 	  if (same(blocks[y][x - 1], c) == YES)
1658 	    killed = killblock(x - 1, y, killed + 1);
1659 	}
1660 
1661       if (x < WIDTH - 1)
1662 	{
1663 	  if (same(blocks[y][x + 1], c) == YES)
1664 	    killed = killblock(x + 1, y, killed + 1);
1665 	}
1666     }
1667 
1668   if (killed > 14)
1669     killed = 14;
1670 
1671   return(killed);
1672 }
1673 
1674 
1675 /* Throw your gems: */
1676 
_throw(int x)1677 void _throw(int x)
1678 {
1679   int lasty, killed;
1680   int y, c, last, nextlast, ytop, ybot, ok, doit;
1681 
1682 
1683   if (carrying != 0)
1684     {
1685       last = 0;
1686       nextlast = 0;
1687       lasty = -1;
1688 
1689 
1690       /* Find the lowest point that they'll attach to: */
1691 
1692       for (y = 0; y < HEIGHT; y++)
1693 	{
1694 	  c = blocks[y][x];
1695 
1696 	  if (c != 0)
1697 	    {
1698 	      nextlast = last;
1699 	      last = c;
1700 	      lasty = y;
1701 	    }
1702 	}
1703 
1704 
1705       /* See if there's a match: */
1706 
1707       ok = NO;
1708 
1709       if (same(last, carrying) == YES)
1710 	{
1711 	  if (same(nextlast, carrying) == YES || howmany > 1)
1712 	    ok = YES;
1713 	}
1714 
1715       doit = YES;
1716 
1717       ybot = lasty + 1 + howmany - 1;
1718 
1719 
1720       /* Don't go past the bottom: */
1721 
1722       if (ybot > 10)
1723 	{
1724 	  doit = NO;
1725 	  ybot = 10;
1726 	  if (ok == YES || howmany > 2)
1727 	    doit = YES;
1728 	}
1729 
1730 
1731       /* These'll fit?  Put them on the screen: */
1732 
1733       if (doit == YES)
1734 	{
1735 	  for (y = lasty + 1; y <= ybot; y++)
1736 	    {
1737 	      blocks[y][x] = carrying;
1738 	      drawblock(x, y);
1739 	    }
1740 	}
1741 
1742 
1743       /* See if it's a match of 3 or more: */
1744 
1745       ok = NO;
1746 
1747       if (same(last, carrying) == YES)
1748 	{
1749 	  if (same(nextlast, carrying) == YES || howmany > 1)
1750 	    ok = YES;
1751 	}
1752 
1753       if (howmany > 2)
1754 	ok = YES;
1755 
1756 
1757       /* It IS! */
1758 
1759       if (ok == YES)
1760 	{
1761 	  ytop = 0;
1762 	  for (y = 0; y <= ybot; y++)
1763 	    {
1764 	      if (blocks[y][x] != carrying)
1765 		ytop = y + 1;
1766 	    }
1767 
1768 	  killed = killblock(x, ybot, 1);
1769 
1770 	  score = score + scorevals[killed];
1771 
1772 	  lines = lines + 1;
1773 
1774 	  drawscore();
1775 	  updatelines();
1776 	  playsound(SND_GOT);
1777 	}
1778 
1779       if (doit == YES)
1780 	{
1781 	  carrying = 0;
1782 	  howmany = 0;
1783 
1784 	  playsound(SND_THROW);
1785 	}
1786     }
1787   else
1788     {
1789       complain();
1790     }
1791 
1792 
1793   /* See if the level's done!? */
1794 
1795   if (lines >= linesneeded)
1796     leveldone = YES;
1797 }
1798 
1799 
1800 /* Grab some gems */
1801 
grab(int x)1802 void grab(int x)
1803 {
1804   int y, c, last, lasty, ok;
1805 
1806 
1807   /* Find the lowest gem on the column: */
1808 
1809   last = 0;
1810   lasty = 0;
1811 
1812   for (y = 0; y < HEIGHT; y++)
1813     {
1814       c = blocks[y][x];
1815       if (c != 0)
1816 	{
1817 	  last = c;
1818 	  lasty = y;
1819 	}
1820     }
1821 
1822 
1823   /* See if we got one: */
1824 
1825   if (last == 0 || last > NUM_ALL_BLOCKS)
1826     {
1827       /* Nope! */
1828 
1829       complain();
1830     }
1831   else
1832     {
1833       /* Yep!: */
1834 
1835       if (last != carrying && carrying != 0)
1836 	{
1837 	  /* Not the same as what we're carrying, though! */
1838 
1839 	  complain();
1840 	}
1841       else
1842 	{
1843 	  /* Grab it: */
1844 
1845 	  playsound(SND_GRAB);
1846 
1847 	  carrying = last;
1848 	  blocks[lasty][x] = 0;
1849 	  drawblock(x, lasty);
1850 	  howmany = howmany + 1;
1851 
1852 
1853 	  /* Grab any of the same type that are above it: */
1854 
1855 	  do
1856 	    {
1857 	      ok=0;
1858 	      lasty = lasty - 1;
1859 	      if (lasty >= 0)
1860 		{
1861 		  if (blocks[lasty][x] == last)
1862 		    {
1863 		      blocks[lasty][x] = 0;
1864 		      drawblock(x, lasty);
1865 		      ok = 1;
1866 		      howmany = howmany + 1;
1867 		    }
1868 		}
1869 	    }
1870 	  while (ok != 0);
1871 	}
1872     }
1873 }
1874 
1875 
1876 /* Add more gems at the top of the screen: */
1877 
addmore()1878 void addmore()
1879 {
1880   int x, y;
1881 
1882 
1883   /* See if the game's over: */
1884 
1885   for (x = 0; x < WIDTH; x++)
1886     {
1887       if (blocks[HEIGHT - 1][x] != 0)
1888 	gameover = YES;
1889     }
1890 
1891 
1892   if (gameover == NO)
1893     {
1894       /* Push the existing ones down: */
1895 
1896       for (y = HEIGHT - 1; y > 0; y--)
1897 	{
1898 	  for (x = 0; x < WIDTH; x++)
1899 	    {
1900 	      blocks[y][x] = blocks[y - 1][x];
1901 	      drawblock(x, y);
1902 	    }
1903 	}
1904 
1905 
1906       /* Add random ones to the top: */
1907 
1908       for (x = 0; x < WIDTH; x++)
1909 	{
1910 	  blocks[0][x] = randblock();
1911 	  drawblock(x, 0);
1912 	}
1913     }
1914 }
1915 
1916 
1917 /* Update the explosion animations: */
1918 
drawexplosions(void)1919 int drawexplosions(void)
1920 {
1921   int i, any;
1922 
1923 
1924   /* We'll say if there are any more or not: */
1925 
1926   any = 0;
1927 
1928 
1929   for (i = 0; i < NUM_EXPLOSIONS; i++)
1930     {
1931       if (explosions[i].exist == YES)
1932 	{
1933 	  /* (There are some!) */
1934 
1935 	  any = 1;
1936 
1937 
1938 	  /* There's an animation slow-down... */
1939 
1940 	  explosions[i].animrate++;
1941 
1942 	  if (explosions[i].animrate >= EXPLOSION_SLOW_VAL)
1943 	    {
1944 	      explosions[i].animrate = 0;
1945 	      explosions[i].anim++;
1946 
1947 	      if (explosions[i].anim >= NUM_EXPLOSION_GFX)
1948 		{
1949 		  /* It's gone!  Draw whatever was/is behind it: */
1950 
1951 		  explosions[i].exist = NO;
1952 		  drawblock(explosions[i].x, explosions[i].y);
1953 		}
1954 	      else if (explosions[i].anim >= 0)
1955 		{
1956 		  /* Draw the animation frame: */
1957 
1958 		  drawblockgraphic(explosions[i].x * 48, explosions[i].y * 48,
1959 				   NUM_ALL_BLOCKS + NUM_SPECIALS + 1 +
1960 				   explosions[i].anim);
1961 		}
1962 	    }
1963 	}
1964     }
1965 
1966   return(any);
1967 }
1968 
1969 
1970 /* End-of-level effect (major destruction, dude!) */
1971 
levelendfx(int yourx)1972 void levelendfx(int yourx)
1973 {
1974   int x, y, any, win;
1975   Uint32 last_time;
1976 
1977 
1978   /* Let all of old the explosions "fizzle out"... */
1979 
1980   do
1981     {
1982       last_time = SDL_GetTicks();
1983 
1984 
1985       /* Update explosions: */
1986 
1987       any = drawexplosions();
1988 
1989 
1990       /* Keep framerate exact: */
1991 
1992       if (SDL_GetTicks() < last_time + (1000 / FPS))
1993 	SDL_Delay(last_time + (1000 / FPS) - SDL_GetTicks());
1994     }
1995   while(any == 1);
1996 
1997 
1998   /* Toggle value for winning animation: */
1999 
2000   win = 0;
2001 
2002 
2003   /* Explode from the top to the bottom: */
2004 
2005   playsound(SND_WIN);
2006 
2007   for (y = 0; y < HEIGHT; y++)
2008     {
2009       last_time = SDL_GetTicks();
2010 
2011 
2012       /* Erase this row: */
2013 
2014       for (x = 0; x < WIDTH; x++)
2015 	{
2016 	  blocks[y][x] = 0;
2017 	  drawblock(x, y);
2018 	}
2019 
2020 
2021       /* Add some explosions: */
2022 
2023       for (x = 0; x < WIDTH; x++)
2024 	{
2025 	  if ((rand() % 10) < 6)
2026 	    explodeblock(x, y, -(rand() % 10));
2027 	}
2028 
2029 
2030       /* Animate the dude: */
2031 
2032       win = 1 - win;
2033       drawmangraphic(yourx * 48, HEIGHT * 48, WIN1_GFX + win);
2034 
2035 
2036       /* Update the explosions: */
2037 
2038       drawexplosions();
2039 
2040 
2041       /* Keep framerate exact: */
2042 
2043       if (SDL_GetTicks() < last_time + (1000 / FPS))
2044 	SDL_Delay(last_time + (1000 / FPS) - SDL_GetTicks());
2045     }
2046 
2047 
2048   /* Let all of the explosions "fizzle out"... */
2049 
2050   do
2051     {
2052       last_time = SDL_GetTicks();
2053 
2054 
2055       /* Update explosions: */
2056 
2057       any = drawexplosions();
2058 
2059 
2060       /* Draw man: */
2061 
2062       win = 1 - win;
2063       drawmangraphic(yourx * 48, HEIGHT * 48, WIN1_GFX + win);
2064 
2065 
2066       /* Keep framerate exact: */
2067 
2068       if (SDL_GetTicks() < last_time + (1000 / FPS))
2069 	SDL_Delay(last_time + (1000 / FPS) - SDL_GetTicks());
2070     }
2071   while(any == 1);
2072 }
2073 
2074 
2075 /* Level 15 effect */
2076 
level15fx()2077 void level15fx()
2078 {
2079   int x;
2080   Uint32 last_time;
2081   SDL_Rect dest;
2082 
2083 
2084   erasewindow();
2085 
2086   for (x = windowwidth; x >= -48; x = x - 8)
2087     {
2088       last_time = SDL_GetTicks();
2089 
2090 
2091       /* Draw player: */
2092 
2093       howmany = 2;
2094 
2095       dest.x = x;
2096       dest.y = windowheight / 2 - 16;
2097       dest.w = 56;
2098       dest.h = 64;
2099 
2100       my_FillRect(window, &dest, 0x00, 0x00, 0x00);
2101       SDL_UpdateRect(window, dest.x, dest.y, dest.w, dest.h);
2102 
2103       drawmangraphic(x, windowheight / 2 - 16, SAD_GFX);
2104 
2105       dest.x = x;
2106       dest.y = windowheight / 2 - 16 + 48;
2107       dest.w = 48;
2108       dest.h = 16;
2109 
2110       SDL_BlitSurface(object_pixmaps[UHOH_GFX - 1], NULL,
2111 		      window, &dest);
2112 
2113 
2114       /* Keep framerate exact: */
2115 
2116       if (SDL_GetTicks() < last_time + (1000 / FPS))
2117 	SDL_Delay(last_time + (1000 / FPS) - SDL_GetTicks());
2118     }
2119 
2120 }
2121 
2122 
2123 /* MAIN GAME FUNCTION!!!! */
2124 
play()2125 void play()
2126 {
2127   int oact, q, x, y, toggle, win;
2128 #ifndef EMBEDDED
2129   int jsx, ojsx, jsbutton0, jsbutton1, jsbutton23,
2130     ojsbutton0, ojsbutton1, ojsbutton23, jstimer;
2131 #endif
2132   Uint32 last_time;
2133   SDL_Rect dest;
2134 #ifndef NOSOUND
2135   int i;
2136 #endif
2137 
2138 
2139   /* Init the game variables: */
2140 
2141   initlevel();
2142   clicks = 0;
2143   playerx = 5;
2144   gameover = NO;
2145   win = NO;
2146   oact = 0 ;
2147   score = 0;
2148 
2149 
2150   /* Draw you! */
2151 
2152   drawyou(playerx);
2153 
2154 
2155 #ifndef EMBEDDED
2156   ojsx = 0;
2157   ojsbutton0 = 0;
2158   ojsbutton1 = 0;
2159   ojsbutton23 = 0;
2160   jstimer = 0;
2161 #endif
2162 
2163 
2164   /* MAIN GAME LOOP: */
2165 
2166   do
2167     {
2168       last_time = SDL_GetTicks();
2169 
2170 
2171       /* Get any keys: */
2172 
2173       getkey(1);
2174 
2175 #ifndef EMBEDDED
2176       if (use_joystick)
2177 	{
2178 	  jsx = SDL_JoystickGetAxis(js, 0);
2179 
2180 	  if (jsx < -16384 && (ojsx >= -16384 || jstimer == STICKWAIT - 1))
2181 	    key = SDLK_LEFT;
2182 	  else if (jsx > 16384 && (ojsx <= 16384 || jstimer == STICKWAIT - 1))
2183 	    key = SDLK_RIGHT;
2184 
2185 	  jsbutton0 = SDL_JoystickGetButton(js, 0);
2186 	  jsbutton1 = SDL_JoystickGetButton(js, 1);
2187 	  jsbutton23 = (SDL_JoystickGetButton(js, 2) +
2188 			SDL_JoystickGetButton(js, 3));
2189 
2190           if (jsbutton1 && ojsbutton1 == 0)
2191 	    key = SDLK_DOWN;
2192           else if (jsbutton0 && ojsbutton0 == 0)
2193 	    key = SDLK_UP;
2194           else if (jsbutton23 && ojsbutton23 == 0)
2195 	    key = SDLK_RETURN;
2196 
2197           if ((jsx < -16384 && ojsx < -16384) ||
2198 	      (jsx > 16384 && ojsx > 16384))
2199 	    {
2200 	      jstimer++;
2201 	      if (jstimer >= STICKWAIT)
2202 	        jstimer = 0;
2203 	    }
2204           else
2205 	    jstimer = 0;
2206 
2207 	  ojsx = jsx;
2208 	  ojsbutton0 = jsbutton0;
2209 	  ojsbutton1 = jsbutton1;
2210 	  ojsbutton23 = jsbutton23;
2211 	}
2212 #endif
2213 
2214       if (key != SDLK_LAST)
2215 	{
2216 	  if (key == SDLK_ESCAPE ||
2217 	      key == SDLK_q)
2218 	    {
2219 	      /* Escape or Q to quit: */
2220 
2221 	      gameover = YES;
2222 	    }
2223 	  else if (key == SDLK_RIGHT ||
2224 		   key == SDLK_l)
2225 	    {
2226 	      /* Right to move you right */
2227 
2228 	      eraseyou(playerx);
2229 	      playerx++;
2230 
2231 
2232 	      /* Wrap around: */
2233 
2234 	      if (playerx > WIDTH - 1)
2235 		playerx = 0;
2236 	    }
2237 	  else if (key == SDLK_LEFT ||
2238 		   key == SDLK_k)
2239 	    {
2240 	      /* Left to move you left: */
2241 
2242 	      eraseyou(playerx);
2243 	      playerx--;
2244 
2245 
2246 	      /* Wrap around: */
2247 
2248 	      if (playerx < 0)
2249 		playerx = WIDTH - 1;
2250 	    }
2251 	  else if (key == SDLK_UP ||
2252 		   key == SDLK_a)
2253 	    {
2254 	      /* Up to throw: */
2255 
2256 	      eraseyou(playerx);
2257 	      _throw(playerx);
2258 	    }
2259 	  else if (key == SDLK_DOWN ||
2260 		   key == SDLK_z)
2261 	    {
2262 	      /* Down to grab: */
2263 
2264 	      eraseyou(playerx);
2265 	      grab(playerx);
2266 	    }
2267 	  else if (key == SDLK_RETURN)
2268 	    {
2269 	      /* Return to get more gems NOW!: */
2270 
2271 	      firstround = YES;
2272 	      frozen = NO;
2273 	      clicks = 32767;
2274 	    }
2275 	  else if (key == SDLK_SPACE ||
2276 		   key == SDLK_p)
2277 	    {
2278 	      /* Space or P to pause... wait for keypress to continue: */
2279 
2280 	      eraseyou(playerx);
2281 
2282 	      toggle = 0;
2283 
2284 #ifndef NOSOUND
2285 	      if (use_sound)
2286 	      {
2287 	        for (i = 0; i < MIX_CHANNELS; i++)
2288 		  Mix_HaltChannel(i);
2289 
2290 	        if (no_music == 0)
2291 		  Mix_HaltMusic();
2292 	      }
2293 #endif
2294 
2295 	      do
2296 		{
2297 		  last_time = SDL_GetTicks();
2298 
2299 
2300 		  /* Pause for a frame: */
2301 
2302 		  getkey(1);
2303 
2304 
2305 		  /* Show the word "paused": */
2306 
2307 		  dest.x = (WIDTH * 48 - 48) / 2;
2308 		  dest.y = (HEIGHT + 1) * 48;
2309 		  dest.w = 48;
2310 		  dest.h = 16;
2311 
2312 		  SDL_BlitSurface(object_pixmaps[PAUSED_GFX - 1], NULL,
2313 				  window, &dest);
2314 		  SDL_UpdateRect(window, dest.x, dest.y, dest.w, dest.h);
2315 
2316 
2317 		  /* Keep framerate exact: */
2318 
2319 		  if (SDL_GetTicks() < last_time + (1000 / FPS))
2320 		    SDL_Delay(last_time + (1000 / FPS) - SDL_GetTicks());
2321 		}
2322 	      while (key == SDLK_LAST);
2323 
2324 	      dest.x = (WIDTH * 48 - 48) / 2;
2325 	      dest.y = (HEIGHT + 1) * 48;
2326 	      dest.w = 48;
2327 	      dest.h = 16;
2328 
2329 	      my_FillRect(window, &dest, 0x00, 0x00, 0x00);
2330 	      SDL_UpdateRect(window, dest.x, dest.y, dest.w, dest.h);
2331 	    }
2332 
2333 
2334 	  /* Draw you again, just in case: */
2335 
2336 	  drawyou(playerx);
2337 	}
2338 
2339 
2340       /* Draw explosions: */
2341 
2342       drawexplosions();
2343 
2344 
2345       /* Move stuff if need be: */
2346 
2347       if (frozen == 0)
2348 	{
2349 	  /* No clock... so keep counting til we move stuff down: */
2350 
2351 	  checkhappy();
2352 
2353 	  clicks = clicks + 1;
2354 
2355 
2356 	  /* The higher the level, the faster stuff comes: */
2357 
2358 	  if (level < 5)
2359 	    q = level * 60;
2360 	  else if (level < 14)
2361 	    q = level * 25;
2362 	  else if (level == 14)
2363 	    q = level * 24;
2364 	  else
2365 	    q = (level - 2) * 20;
2366 
2367 
2368 	  /* Warn them first... */
2369 
2370 	  if (clicks >= 370 - q && firstround == YES)
2371 	    {
2372 	      _warning = YES;
2373 	    }
2374 
2375 
2376 	  /* Drop stuff down: */
2377 
2378 	  if (clicks >= 400 - q)
2379 	    {
2380 	      if (firstround == YES)
2381 		{
2382 		  addmore();
2383 		  playsound(SND_BEGIN);
2384 		}
2385 
2386 	      clicks = 0;
2387 	      firstround = YES;
2388 
2389 	      _warning = NO;
2390 	    }
2391 	}
2392       else
2393 	{
2394 	  /* Count down the clock... */
2395 
2396 	  happy = YES;
2397 
2398 	  frozen = frozen - 1;
2399 	}
2400 
2401 
2402       drawstatus();
2403 
2404 
2405       /* See if the level's complete! */
2406 
2407       if (leveldone == YES)
2408 	{
2409 	  /* Do the end-of-level effect: */
2410 
2411 	  levelendfx(playerx);
2412 
2413 
2414 	  /* Increment the level: */
2415 
2416 	  level = level + 1;
2417 	  if (level > 20)
2418 	    {
2419 	      gameover = YES;
2420 	      win = YES;
2421 	    }
2422 
2423 	  if (level > max_level)
2424 	    max_level = level;
2425 
2426 
2427 	  /* Do the level 15 effect: */
2428 
2429 	  if (level == 15)
2430 	    level15fx();
2431 
2432 
2433 	  /* Reset the level! */
2434 
2435 	  initlevel();
2436 	  clicks = 0;
2437 	  updatelevel();
2438 	}
2439 
2440 
2441       /* Keep framerate exact: */
2442 
2443       if (SDL_GetTicks() < last_time + (1000 / FPS))
2444 	SDL_Delay(last_time + (1000 / FPS) - SDL_GetTicks());
2445 
2446 
2447       /* Play music: */
2448 #ifndef NOSOUND
2449       if (use_sound)
2450       {
2451         if (no_music == 0)
2452 	  {
2453 	    if (!Mix_PlayingMusic())
2454 	      Mix_PlayMusic(songs[MOD_GAME1 + (rand() % NUM_GAME_MODS)], 0);
2455 	    /* Mix_VolumeMusic(4); */
2456 	  }
2457       }
2458 #endif
2459     }
2460   while (gameover == NO);
2461 
2462 
2463 #ifndef NOSOUND
2464   if (use_sound)
2465   {
2466     if (no_music == 0)
2467       Mix_HaltMusic();
2468   }
2469 #endif
2470 
2471   if (win == NO)
2472     {
2473       /* End of game effect: */
2474 
2475       playsound(SND_GAMEOVER);
2476 
2477       happy = NO;
2478       drawyou(playerx);
2479 
2480 
2481       /* Dump bricks down at you!: */
2482 
2483       for (y = 0; y < HEIGHT; y++)
2484 	{
2485 	  last_time = SDL_GetTicks();
2486 
2487 	  for (x = 0; x < WIDTH; x++)
2488 	    {
2489 	      drawblockgraphic(x * 48, y * 48, BRICK_GFX);
2490 	    }
2491 
2492 
2493 	  /* Keep framerate exact: */
2494 
2495 	  if (SDL_GetTicks() < last_time + (1000 / FPS))
2496 	    SDL_Delay(last_time + (1000 / FPS) - SDL_GetTicks());
2497 	}
2498     }
2499   else
2500     {
2501       /* Win game effect: */
2502 
2503       playsound(SND_APPLAUSE);
2504 
2505       dest.x = windowwidth / 2 - 96;
2506       dest.y = windowheight / 2 - 32;
2507       dest.w = 192;
2508       dest.h = 64;
2509 
2510       SDL_BlitSurface(object_pixmaps[CONGRATULATIONS_GFX - 1], NULL,
2511 		      window, &dest);
2512 
2513       SDL_UpdateRect(window, dest.x, dest.y, dest.w, dest.h);
2514     }
2515 
2516   /* Wait for a keypress: */
2517 
2518   do
2519     {
2520       getkey(0);
2521     }
2522   while (key == SDLK_LAST);
2523 
2524 #ifndef EMBEDDED
2525   eatjoybuttons();
2526 #endif
2527 }
2528 
2529 
2530 /* Quit the application: */
2531 
quitapp()2532 void quitapp()
2533 {
2534 #ifndef EMBEDDED
2535   if (use_joystick)
2536     SDL_JoystickClose(js);
2537 
2538   SDL_Quit();
2539 #endif
2540 }
2541 
2542 
2543 /* Usage error, and quit: */
2544 
usage(int ret)2545 void usage(int ret)
2546 {
2547   fprintf(stderr, "Usage: gemdropx [--nomusic] | --version | --help | --usage\n\n");
2548   exit(ret);
2549 }
2550 
2551 
2552 /* MAIN FUNCTION */
2553 
main(int argc,char * argv[])2554 int main(int argc, char * argv[])
2555 {
2556   int quit;
2557   char datafile[1024];
2558   FILE * fi;
2559 #ifndef EMBEDDED
2560   SDL_version sdlver;
2561 #endif
2562 
2563 
2564   no_music = 0;
2565 
2566   if (argc == 2)
2567     {
2568       /* --version or --help?? */
2569 
2570       if (strcmp(argv[1], "--version") == 0)
2571 	{
2572 	  printf("\nGem Drop X 0.9\n\n");
2573 	  printf("February 11, 2002\n");
2574 	  printf("by Bill Kendrick\n");
2575 	  printf("New Breed Software, (c) 1997-2002\n\n");
2576 
2577 	  printf("Most graphics by Bernhard Trummer\n");
2578 	  printf("bernhard.trummer@gmx.net\n\n");
2579 
2580 	  printf("Visit our website: http://www.newbreedsoftware.com/\n\n");
2581 
2582 #ifndef EMBEDDED
2583 	  SDL_VERSION(&sdlver);
2584 	  printf("SDL version %d.%d.%d\n\n", sdlver.major,
2585 		 sdlver.minor, sdlver.patch);
2586 #else
2587 	  printf("Built for Qt/Embedded\n\n");
2588 #endif
2589 
2590 	  exit(0);
2591 	}
2592       else if (strcmp(argv[1], "--help") == 0)
2593 	{
2594 	  printf("GEM DROP X HELP\n");
2595 	  printf("How To Play:\n");
2596 	  printf("  Use the man to grab and throw gems.\n");
2597 	  printf("  Match 3+ in a column when you throw to get a line.\n");
2598 	  printf("  Get enough lines to beat the level.\n");
2599 	  printf("  Gems come down at you from the top.\n");
2600 	  printf("  If the screen fills, the game ends.\n\n");
2601 
2602 	  printf("Special Pieces:  (You can't grab them)\n");
2603 	  printf("  Activate them by including them in a match.\n");
2604 	  printf("  - Bombs explode.\n");
2605 	  printf("  - Clocks stop the gems from coming for a while.\n");
2606 	  printf("  - Wildcards (question-marks) make for more matches.\n\n");
2607 
2608 	  printf("Controls:\n");
2609 	  printf("  Left/Right - Move left/right\n");
2610 	  printf("  K/L        - Move left/right\n");
2611 	  printf("  Up/Down    - Throw/Grab\n");
2612 	  printf("  A/Z        - Throw/Grab\n");
2613 	  printf("  Return     - Get more gems immediately\n");
2614 	  printf("  Space / P  - Pause\n");
2615 	  printf("  S          - Toggle sound\n");
2616 	  printf("  Q/Escape   - Abort game\n\n");
2617 
2618 	  printf("Mouse:\n");
2619 	  printf("  Click Left/Right of Man - Move left/right\n");
2620 	  printf("  Left-click Above Man    - Grab\n");
2621 	  printf("  Right-click Above man   - Throw\n\n");
2622 
2623 	  printf("Joystick:\n");
2624 	  printf("  Left/Right - Move left/right\n");
2625 	  printf("  Button 1/2 - Throw/Grab\n");
2626 	  printf("  Button 3/4 - Get more gems immediately\n\n");
2627 
2628 	  exit(0);
2629 	}
2630       else if (strcmp(argv[1], "--nomusic") == 0)
2631 	{
2632 	  no_music = 1;
2633 	}
2634       else if (strcmp(argv[1], "--usage") == 0)
2635 	{
2636 	  usage(0);
2637 	}
2638       else
2639 	{
2640 	  usage(1);
2641 	}
2642     }
2643   else if (argc > 2)
2644     {
2645       /* Oops!  Usage! */
2646 
2647       usage(1);
2648     }
2649 
2650 
2651   /* Setup: */
2652 
2653   setup(argc, argv);
2654 
2655 
2656   /* Get max level: */
2657 
2658   sprintf(datafile, "%s/.gemdropx", getenv("HOME"));
2659 
2660   fi = fopen(datafile, "r");
2661   if (fi != NULL)
2662     {
2663       fscanf(fi, "%d", &max_level);
2664 
2665       if (max_level < 10 || max_level > 20)
2666 	{
2667 	  fprintf(stderr, "gemdropx: %s corrupt!\n", datafile);
2668 	  max_level = 10;
2669 	}
2670 
2671       fclose(fi);
2672     }
2673   else
2674     max_level = 10;
2675 
2676 
2677   /* Main loop: */
2678 
2679   do
2680     {
2681       game_playing = 0;
2682       quit = title();
2683 
2684 #ifndef NOSOUND
2685       if (use_sound)
2686 	{
2687 	  if (no_music == 0)
2688 	    Mix_HaltMusic();
2689 	}
2690 #endif
2691 
2692       if (quit == NO)
2693 	{
2694 	  game_playing = 1;
2695 	  play();
2696 	}
2697     }
2698   while (quit == NO);
2699 
2700 
2701   /* Save max. level: */
2702 
2703   fi = fopen(datafile, "w");
2704 
2705   if (fi != NULL)
2706     {
2707       fprintf(fi, "%d\n", max_level);
2708       fclose(fi);
2709     }
2710   else
2711     perror(datafile);
2712 
2713   quitapp();
2714 
2715   return(0);
2716 }
2717