rnd-20000806-1-src
[rocksndiamonds.git] / src / main.c
1 /***********************************************************
2 *  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
3 *----------------------------------------------------------*
4 *  (c) 1995-98 Artsoft Entertainment                       *
5 *              Holger Schemel                              *
6 *              Oststrasse 11a                              *
7 *              33604 Bielefeld                             *
8 *              phone: ++49 +521 290471                     *
9 *              email: aeglos@valinor.owl.de                *
10 *----------------------------------------------------------*
11 *  main.c                                                  *
12 ***********************************************************/
13
14 #include "main.h"
15 #include "init.h"
16 #include "game.h"
17 #include "events.h"
18 #include "sound.h"
19 #include "joystick.h"
20 #include "misc.h"
21
22 #ifdef MSDOS
23 #include <fcntl.h>
24 #endif
25
26 Display        *display;
27 Visual         *visual;
28 int             screen;
29 DrawWindow      window;
30 GC              gc, clip_gc[NUM_BITMAPS], tile_clip_gc;
31 Bitmap          pix[NUM_BITMAPS];
32 Bitmap          pix_masked[NUM_BITMAPS], tile_masked[NUM_TILES];
33 Pixmap          clipmask[NUM_BITMAPS], tile_clipmask[NUM_TILES];
34
35 #ifdef USE_XPM_LIBRARY
36 XpmAttributes   xpm_att[NUM_PICTURES];
37 #endif
38
39 DrawBuffer      drawto, drawto_field, backbuffer, fieldbuffer;
40 Colormap        cmap;
41
42 int             sound_pipe[2];
43 int             sound_device;
44 char           *sound_device_name = SOUND_DEVICE;
45 int             joystick_device = 0;
46 char           *joystick_device_name[MAX_PLAYERS] =
47 {
48   DEV_JOYSTICK_0,
49   DEV_JOYSTICK_1,
50   DEV_JOYSTICK_2,
51   DEV_JOYSTICK_3
52 };
53
54 char           *program_name = NULL;
55
56 int             game_status = MAINMENU;
57 boolean         level_editor_test_game = FALSE;
58 boolean         network_playing = FALSE;
59 int             button_status = MB_NOT_PRESSED;
60 boolean         motion_status = FALSE;
61 int             key_joystick_mapping = 0;
62 int             global_joystick_status = JOYSTICK_STATUS;
63 int             joystick_status = JOYSTICK_STATUS;
64 int             sound_status = SOUND_STATUS;
65 boolean         sound_loops_allowed = FALSE;
66
67 boolean         redraw[MAX_BUF_XSIZE][MAX_BUF_YSIZE];
68 int             redraw_x1 = 0, redraw_y1 = 0;
69 int             redraw_mask;
70 int             redraw_tiles;
71
72 short           Feld[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
73 short           Ur[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
74 short           MovPos[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
75 short           MovDir[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
76 short           MovDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
77 short           Store[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
78 short           Store2[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
79 short           StorePlayer[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
80 short           Frame[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
81 boolean         Stop[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
82 short           JustStopped[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
83 short           AmoebaNr[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
84 short           AmoebaCnt[MAX_NUM_AMOEBA], AmoebaCnt2[MAX_NUM_AMOEBA];
85 unsigned long   Elementeigenschaften1[MAX_ELEMENTS];
86 unsigned long   Elementeigenschaften2[MAX_ELEMENTS];
87
88 int             level_nr;
89 int             lev_fieldx,lev_fieldy, scroll_x,scroll_y;
90
91 int             FX = SX, FY = SY, ScrollStepSize;
92 int             ScreenMovDir = MV_NO_MOVING, ScreenMovPos = 0;
93 int             ScreenGfxPos = 0;
94 int             BorderElement = EL_BETON;
95 int             GameFrameDelay = GAME_FRAME_DELAY;
96 int             FfwdFrameDelay = FFWD_FRAME_DELAY;
97 int             BX1 = 0, BY1 = 0, BX2 = SCR_FIELDX-1, BY2 = SCR_FIELDY-1;
98 int             SBX_Left, SBX_Right;
99 int             SBY_Upper, SBY_Lower;
100 int             ZX,ZY, ExitX,ExitY;
101 int             AllPlayersGone;
102 int             FrameCounter, TimeFrames, TimePlayed, TimeLeft;
103
104 boolean         network_player_action_received = FALSE;
105
106 struct LevelDirInfo    *leveldir_first = NULL, *leveldir_current = NULL;
107 struct LevelInfo        level;
108 struct PlayerInfo       stored_player[MAX_PLAYERS], *local_player = NULL;
109 struct HiScore          highscore[MAX_SCORE_ENTRIES];
110 struct SoundInfo        Sound[NUM_SOUNDS];
111 struct TapeInfo         tape;
112 struct OptionInfo       options;
113 struct SetupInfo        setup;
114 struct GameInfo         game;
115 struct GlobalInfo       global;
116
117 /* data needed for playing sounds */
118 char *sound_name[NUM_SOUNDS] =
119 {
120   "alchemy",
121   "amoebe",
122   "antigrav",
123   "autsch",
124   "blurb",
125   "bong",
126   "buing",
127   "chase",
128   "czardasz",
129   "deng",
130   "fuel",
131   "gong",
132   "halloffame",
133   "holz",
134   "hui",
135   "kabumm",
136   "kink",
137   "klapper",
138   "kling",
139   "klopf",
140   "klumpf",
141   "knack",
142   "knurk",
143   "krach",
144   "lachen",
145   "laser",
146   "miep",
147   "network",
148   "njam",
149   "oeffnen",
150   "pling",
151   "pong",
152   "pusch",
153   "quiek",
154   "quirk",
155   "rhythmloop",
156   "roaaar",
157   "roehr",
158   "rumms",
159   "schlopp",
160   "schlurf",
161   "schrff",
162   "schwirr",
163   "sirr",
164   "slurp",
165   "sproing",
166   "twilight",
167   "tyger",
168   "voyager",
169   "warnton",
170   "whoosh",
171   "zisch",
172   "base",
173   "infotron",
174   "zonkdown",
175   "zonkpush",
176   "bug",
177   "boom",
178   "booom",
179   "exit",
180   "empty",
181   "gate"
182 };
183
184 /* background music */
185 int background_loop[] =
186 {
187   SND_ALCHEMY,
188   SND_CHASE,
189   SND_NETWORK,
190   SND_CZARDASZ,
191   SND_TYGER,
192   SND_VOYAGER,
193   SND_TWILIGHT
194 };
195 int num_bg_loops = sizeof(background_loop)/sizeof(int);
196
197 char *element_info[] =
198 {
199   "empty space",                                /* 0 */
200   "sand",
201   "normal wall",
202   "round wall",
203   "rock",
204   "key",
205   "emerald",
206   "closed exit",
207   "player",
208   "bug",
209   "spaceship",                                  /* 10 */
210   "yam yam",
211   "robot",
212   "steel wall",
213   "diamond",
214   "dead amoeba",
215   "empty quicksand",
216   "quicksand with rock",
217   "amoeba drop",
218   "bomb",
219   "magic wall",                                 /* 20 */
220   "speed ball",
221   "acid pool",
222   "dropping amoeba",
223   "normal amoeba",
224   "nut with emerald",
225   "life wall",
226   "biomaze",
227   "burning dynamite",
228   "unknown",
229   "magic wheel",                                /* 30 */
230   "running wire",
231   "red key",
232   "yellow key",
233   "green key",
234   "blue key",
235   "red door",
236   "yellow door",
237   "green door",
238   "blue door",
239   "gray door (opened by red key)",              /* 40 */
240   "gray door (opened by yellow key)",
241   "gray door (opened by green key)",
242   "gray door (opened by blue key)",
243   "dynamite",
244   "pac man",
245   "invisible normal wall",
246   "light bulb (dark)",
247   "ligh bulb (glowing)",
248   "wall with emerald",
249   "wall with diamond",                          /* 50 */
250   "amoeba with content",
251   "amoeba (BD style)",
252   "time orb (full)",
253   "time orb (empty)",
254   "growing wall",
255   "diamond (BD style)",
256   "yellow emerald",
257   "wall with BD style diamond",
258   "wall with yellow emerald",
259   "dark yam yam",                               /* 60 */
260   "magic wall (BD style)",
261   "invisible steel wall",
262   "-",
263   "increases number of bombs",
264   "increases explosion size",
265   "increases power of explosion",
266   "sokoban object",
267   "sokoban empty field",
268   "sokoban field with object",
269   "butterfly (starts moving right)",            /* 70 */
270   "butterfly (starts moving up)",
271   "butterfly (starts moving left)",
272   "butterfly (starts moving down)",
273   "firefly (starts moving right)",
274   "firefly (starts moving up)",
275   "firefly (starts moving left)",
276   "firefly (starts moving down)",
277   "butterfly",
278   "firefly",
279   "yellow player",                              /* 80 */
280   "red player",
281   "green player",
282   "blue player",
283   "bug (starts moving right)",
284   "bug (starts moving up)",
285   "bug (starts moving left)",
286   "bug (starts moving down)",
287   "spaceship (starts moving right)",
288   "spaceship (starts moving up)",
289   "spaceship (starts moving left)",             /* 90 */
290   "spaceship (starts moving down)",
291   "pac man (starts moving right)",
292   "pac man (starts moving up)",
293   "pac man (starts moving left)",
294   "pac man (starts moving down)",
295   "red emerald",
296   "violet emerald",
297   "wall with red emerald",
298   "wall with violet emerald",
299   "unknown",                                    /* 100 */
300   "unknown",
301   "unknown",
302   "unknown",
303   "unknown",
304   "normal wall (BD style)",
305   "rock (BD style)",
306   "open exit",
307   "unknown",
308   "amoeba",
309   "mole",                                       /* 110 */
310   "penguin",
311   "satellite",
312   "arrow left",
313   "arrow right",
314   "arrow up",
315   "arrow down",
316   "pig",
317   "fire breathing dragon",
318   "unknown",
319   "letter ' '",                                 /* 120 */
320   "letter '!'",
321   "letter '\"'",
322   "letter '#'",
323   "letter '$'",
324   "letter '%'",
325   "letter '&'",
326   "letter '''",
327   "letter '('",
328   "letter ')'",
329   "letter '*'",                                 /* 130 */
330   "letter '+'",
331   "letter ','",
332   "letter '-'",
333   "letter '.'",
334   "letter '/'",
335   "letter '0'",
336   "letter '1'",
337   "letter '2'",
338   "letter '3'",
339   "letter '4'",                                 /* 140 */
340   "letter '5'",
341   "letter '6'",
342   "letter '7'",
343   "letter '8'",
344   "letter '9'",
345   "letter ':'",
346   "letter ';'",
347   "letter '<'",
348   "letter '='",
349   "letter '>'",                                 /* 150 */
350   "letter '?'",
351   "letter '@'",
352   "letter 'A'",
353   "letter 'B'",
354   "letter 'C'",
355   "letter 'D'",
356   "letter 'E'",
357   "letter 'F'",
358   "letter 'G'",
359   "letter 'H'",                                 /* 160 */
360   "letter 'I'",
361   "letter 'J'",
362   "letter 'K'",
363   "letter 'L'",
364   "letter 'M'",
365   "letter 'N'",
366   "letter 'O'",
367   "letter 'P'",
368   "letter 'Q'",
369   "letter 'R'",                                 /* 170 */
370   "letter 'S'",
371   "letter 'T'",
372   "letter 'U'",
373   "letter 'V'",
374   "letter 'W'",
375   "letter 'X'",
376   "letter 'Y'",
377   "letter 'Z'",
378   "letter 'Ä'",
379   "letter 'Ö'",                                 /* 180 */
380   "letter 'Ãœ'",
381   "letter '^'",
382   "letter ''",
383   "letter ''",
384   "letter ''",
385   "letter ''",
386   "letter ''",
387   "letter ''",
388   "letter ''",
389   "letter ''",                                  /* 190 */
390   "letter ''",
391   "letter ''",
392   "letter ''",
393   "letter ''",
394   "letter ''",
395   "letter ''",
396   "letter ''",
397   "letter ''",
398   "letter ''",
399   "growing wall (horizontal)",                  /* 200 */
400   "growing wall (vertical)",
401   "growing wall (all directions)",
402   "unused",
403   "unused",
404   "unused",
405   "unused",
406   "unused",
407   "unused",
408   "unused",
409   "empty space",                                /* 210 */
410   "zonk",
411   "base",
412   "murphy",
413   "infotron",
414   "chip (single)",
415   "hardware",
416   "exit",
417   "orange disk",
418   "port (leading right)",
419   "port (leading down)",                        /* 220 */
420   "port (leading left)",
421   "port (leading up)",
422   "port (leading right)",
423   "port (leading down)",
424   "port (leading left)",
425   "port (leading up)",
426   "snik snak",
427   "yellow disk",
428   "terminal",
429   "red disk",                                   /* 230 */
430   "port (vertical)",
431   "port (horizontal)",
432   "port (all directions)",
433   "electron",
434   "buggy base",
435   "chip (left half)",
436   "chip (right half)",
437   "hardware",
438   "hardware",
439   "hardware",                                   /* 240 */
440   "hardware",
441   "hardware",
442   "hardware",
443   "hardware",
444   "hardware",
445   "hardware",
446   "hardware",
447   "chip (upper half)",
448   "chip (lower half)",
449   "unknown",                                    /* 250 */
450   "unknown",
451   "unknown",
452   "unknown",
453   "unknown",
454   "unknown",
455
456   /* 256 */
457
458   "pearl",                                      /* (256) */
459   "crystal",
460   "wall with pearl",
461   "wall with crystal",
462   "white door",                                 /* 260 */
463   "gray door (opened by white key)",
464   "white key",
465   "shield (passive)",
466   "extra time",
467   "switch gate (open)",
468   "switch gate (closed)",
469   "switch for switch gate",
470   "switch for switch gate",
471   "-",
472   "-",                                          /* 270 */
473   "red conveyor belt (left)",
474   "red conveyor belt (middle)",
475   "red conveyor belt (right)",
476   "switch for red conveyor belt (left)",
477   "switch for red conveyor belt (middle)",
478   "switch for red conveyor belt (right)",
479   "yellow conveyor belt (left)",
480   "yellow conveyor belt (middle)",
481   "yellow conveyor belt (right)",
482   "switch for yellow conveyor belt (left)",     /* 280 */
483   "switch for yellow conveyor belt (middle)",
484   "switch for yellow conveyor belt (right)",
485   "green conveyor belt (left)",
486   "green conveyor belt (middle)",
487   "green conveyor belt (right)",
488   "switch for green conveyor belt (left)",
489   "switch for green conveyor belt (middle)",
490   "switch for green conveyor belt (right)",
491   "blue conveyor belt (left)",
492   "blue conveyor belt (middle)",                /* 290 */
493   "blue conveyor belt (right)",
494   "switch for blue conveyor belt (left)",
495   "switch for blue conveyor belt (middle)",
496   "switch for blue conveyor belt (right)",
497   "land mine",
498   "mail envelope",
499   "light switch (off)",
500   "light switch (on)",
501   "sign (exclamation)",
502   "sign (radio activity)",                      /* 300 */
503   "sign (stop)",
504   "sign (wheel chair)",
505   "sign (parking)",
506   "sign (one way)",
507   "sign (heart)",
508   "sign (triangle)",
509   "sign (round)",
510   "sign (exit)",
511   "sign (yin yang)",
512   "sign (other)",                               /* 310 */
513   "mole (starts moving left)",
514   "mole (starts moving right)",
515   "mole (starts moving up)",
516   "mole (starts moving down)",
517   "steel wall (slanted)",
518   "invisible sand",
519   "dx unknown 15",
520   "dx unknown 42",
521   "-",
522   "-",                                          /* 320 */
523   "shield (active, kills enemies)",
524   "time gate (open)",
525   "time gate (closed)",
526   "switch for time gate",
527   "switch for time gate",
528   "balloon",
529   "send balloon to the left",
530   "send balloon to the right",
531   "send balloon up",
532   "send balloon down",                          /* 330 */
533   "send balloon in any direction",
534   "steel wall",
535   "steel wall",
536   "steel wall",
537   "steel wall",
538   "normal wall",
539   "normal wall",
540   "normal wall",
541   "normal wall",
542   "normal wall",                                /* 340 */
543   "normal wall",
544   "normal wall",
545   "normal wall",
546   "tube (all directions)",
547   "tube (vertical)",
548   "tube (horizontal)",
549   "tube (vertical & left)",
550   "tube (vertical & right)",
551   "tube (horizontal & up)",
552   "tube (horizontal & down)",                   /* 350 */
553   "tube (left & up)",
554   "tube (left & down)",
555   "tube (right & up)",
556   "tube (right & down)",
557   "spring",
558   "trap",
559   "stable bomb (DX style)",
560   "-"
561
562   /*
563   "-------------------------------",
564   */
565 };
566
567
568
569 /* +-----------------------------------------------------------------------+ */
570 /* | SDL TEST STUFF                                                        | */
571 /* +-----------------------------------------------------------------------+ */
572
573 #ifdef  USE_SDL_LIBRARY
574
575 SDL_Surface *sdl_screen, *sdl_image_tmp, *sdl_image, *sdl_image_masked;
576 SDL_Surface *sdl_image2_tmp, *sdl_image2, *sdl_image2_masked;
577
578 void TEST_SDL_BLIT_RECT(int x, int y)
579 {
580   SDL_Rect rect_src, rect_dst;
581
582   SDLCopyArea(pix_masked[PIX_HEROES], window,
583               8 * TILEX, 8 * TILEY, TILEX, TILEY, x, y);
584   return;
585
586   rect_src.x = 8 * TILEX;
587   rect_src.y = 8 * TILEY;
588   rect_src.w = TILEX;
589   rect_src.h = TILEY;
590
591   rect_dst.x = x;
592   rect_dst.y = y;
593   rect_dst.w = TILEX;
594   rect_dst.h = TILEY;
595
596   SDL_BlitSurface(sdl_image2_masked, &rect_src, sdl_screen, &rect_dst);
597   SDL_UpdateRect(sdl_screen, x, y, TILEX, TILEY);
598 }
599
600 void TEST_SDL_INIT_DISPLAY()
601 {
602   SDL_Rect rect_src, rect_dst;
603
604   if (SDL_Init(SDL_INIT_VIDEO) < 0)
605   {
606     fprintf(stderr, "SDL_Init() failed: %s\n", SDL_GetError());
607     exit(1);
608   }
609
610   /* automatically cleanup SDL stuff after exit() */
611   atexit(SDL_Quit);
612
613   if ((sdl_screen = SDL_SetVideoMode(WIN_XSIZE, WIN_YSIZE, 16, SDL_HWSURFACE))
614       == NULL)
615   {
616     fprintf(stderr, "SDL_SetVideoMode() failed: %s\n", SDL_GetError());
617     exit(1);
618   }
619
620   SDL_WM_SetCaption(WINDOW_TITLE_STRING, WINDOW_TITLE_STRING);
621
622   if ((sdl_image_tmp = IMG_Load("graphics/RocksScreen.pcx")) == NULL)
623   {
624     fprintf(stderr, "IMG_Load() failed: %s\n", SDL_GetError());
625     exit(1);
626   }
627
628   sdl_image = SDL_DisplayFormat(sdl_image_tmp);
629
630   SDL_SetColorKey(sdl_image_tmp, SDL_SRCCOLORKEY,
631                   SDL_MapRGB(sdl_image_tmp->format, 0x00, 0x00, 0x00));
632   sdl_image_masked = SDL_DisplayFormat(sdl_image_tmp);
633
634   SDL_FreeSurface(sdl_image_tmp);
635
636   if ((sdl_image2_tmp = IMG_Load("graphics/RocksHeroes.pcx")) == NULL)
637   {
638     fprintf(stderr, "IMG_Load() failed: %s\n", SDL_GetError());
639     exit(1);
640   }
641
642   sdl_image2 = SDL_DisplayFormat(sdl_image2_tmp);
643   SDL_FreeSurface(sdl_image2_tmp);
644
645   sdl_image2_masked = SDL_DisplayFormat(sdl_image2);
646   SDL_SetColorKey(sdl_image2_masked, SDL_SRCCOLORKEY,
647                   SDL_MapRGB(sdl_image2_masked->format, 0x00, 0x00, 0x00));
648
649   rect_src.x = 0;
650   rect_src.y = 0;
651   rect_src.w = sdl_image->w;
652   rect_src.h = sdl_image->h;
653
654   rect_dst.x = 0;
655   rect_dst.y = 0;
656   rect_dst.w = sdl_image->w;
657   rect_dst.h = sdl_image->h;
658                                            
659   SDL_BlitSurface(sdl_image, &rect_src, sdl_screen, &rect_dst);
660
661   /*
662   SDL_UpdateRect(sdl_screen, 0, 0, WIN_XSIZE, WIN_YSIZE);
663   */
664   /*
665   SDL_UpdateRect(sdl_screen, 0, 0, 0, 0);
666   */
667   SDL_Flip(sdl_screen);
668
669   /*
670   SDL_Delay(5000);
671   */
672 }
673
674 void TEST_SDL_EVENT_LOOP()
675 {
676   int quit_loop = 0;
677
678   SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
679
680   /*
681   while (!quit_loop && SDL_WaitEvent(&event) >=0)
682   */
683
684   while (!quit_loop)
685   {
686     SDL_Event event;
687
688     if (SDL_PollEvent(&event))
689     {
690       /* hier werden die Ereignisse behandelt */
691       switch(event.type)
692       {
693         case SDL_QUIT:
694         {
695           quit_loop = 1;
696           break;
697         }
698
699         case SDL_MOUSEBUTTONDOWN:
700         {
701           int x = event.button.x;
702           int y = event.button.y;
703
704           SDL_EventState(SDL_MOUSEMOTION, SDL_ENABLE);
705
706           TEST_SDL_BLIT_RECT(x, y);
707
708           printf("SDL_MOUSEBUTTONDOWN(%d, %d)\n", x, y);
709           break;
710         }
711
712         case SDL_MOUSEBUTTONUP:
713         {
714           int x = event.button.x;
715           int y = event.button.y;
716
717           SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
718
719           printf("SDL_MOUSEBUTTONUP(%d, %d)\n", x, y);
720           break;
721         }
722
723         case SDL_MOUSEMOTION:
724         {
725           int x = event.motion.x;
726           int y = event.motion.y;
727
728           TEST_SDL_BLIT_RECT(x, y);
729
730           printf("SDL_MOUSEMOTION(%d, %d)\n", x, y);
731           break;
732         }
733
734         default:
735           break;
736       }
737     }
738
739     if (!SDL_PollEvent(NULL))   /* delay only if no pending events */
740     {
741       printf("waiting...\n");
742       Delay(100);
743     }
744   }
745
746   SDL_FreeSurface(sdl_image);
747   SDL_Quit();
748 }
749
750 #define SCREEN_WIDTH    640
751 #define SCREEN_HEIGHT   480
752
753 void WatchJoysticks()
754 {
755         SDL_Surface *screen;
756         const char *name;
757         int i, done;
758         SDL_Event event;
759         int x, y, draw;
760         SDL_Rect axis_area[2];
761         int joystick_nr = 0;
762         SDL_Joystick *joystick = Get_SDL_Joystick(joystick_nr);
763
764         /* Set a video mode to display joystick axis position */
765         screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 16, 0);
766         if ( screen == NULL ) {
767                 fprintf(stderr, "Couldn't set video mode: %s\n",SDL_GetError());
768                 return;
769         }
770
771         /* Print info about the joysticks we are watching */
772         for (i=0; i<2; i++)
773         {
774           joystick = Get_SDL_Joystick(i);
775
776           name = SDL_JoystickName(i);
777           printf("Watching joystick %d: (%s)\n", i,
778                  name ? name : "Unknown Joystick");
779           printf("Joystick has %d axes, %d hats, %d balls, and %d buttons\n",
780                  SDL_JoystickNumAxes(joystick),
781                  SDL_JoystickNumHats(joystick),
782                  SDL_JoystickNumBalls(joystick),
783                  SDL_JoystickNumButtons(joystick));
784         }
785
786         /* Initialize drawing rectangles */
787         memset(axis_area, 0, (sizeof axis_area));
788         draw = 0;
789
790         /* Loop, getting joystick events! */
791         done = 0;
792         while ( ! done ) {
793                 while ( SDL_PollEvent(&event) ) {
794                         switch (event.type) {
795                             case SDL_JOYAXISMOTION:
796                               joystick_nr = event.jaxis.which;
797                                 printf("Joystick %d axis %d value: %d\n",
798                                        event.jaxis.which,
799                                        event.jaxis.axis,
800                                        event.jaxis.value);
801                                 break;
802                             case SDL_JOYHATMOTION:
803                               joystick_nr = event.jaxis.which;
804                                 printf("Joystick %d hat %d value:",
805                                        event.jhat.which,
806                                        event.jhat.hat);
807                                 if ( event.jhat.value == SDL_HAT_CENTERED )
808                                         printf(" centered");
809                                 if ( event.jhat.value & SDL_HAT_UP )
810                                         printf(" up");
811                                 if ( event.jhat.value & SDL_HAT_RIGHT )
812                                         printf(" right");
813                                 if ( event.jhat.value & SDL_HAT_DOWN )
814                                         printf(" down");
815                                 if ( event.jhat.value & SDL_HAT_LEFT )
816                                         printf(" left");
817                                 printf("\n");
818                                 break;
819                             case SDL_JOYBALLMOTION:
820                               joystick_nr = event.jaxis.which;
821                                 printf("Joystick %d ball %d delta: (%d,%d)\n",
822                                        event.jball.which,
823                                        event.jball.ball,
824                                        event.jball.xrel,
825                                        event.jball.yrel);
826                                 break;
827                             case SDL_JOYBUTTONDOWN:
828                               joystick_nr = event.jaxis.which;
829                                 printf("Joystick %d button %d down\n",
830                                        event.jbutton.which,
831                                        event.jbutton.button);
832                                 break;
833                             case SDL_JOYBUTTONUP:
834                               joystick_nr = event.jaxis.which;
835                                 printf("Joystick %d button %d up\n",
836                                        event.jbutton.which,
837                                        event.jbutton.button);
838                                 break;
839                             case SDL_KEYDOWN:
840                                 if ( event.key.keysym.sym != SDLK_ESCAPE ) {
841                                         break;
842                                 }
843                                 /* Fall through to signal quit */
844                             case SDL_QUIT:
845                                 done = 1;
846                                 break;
847                             default:
848                                 break;
849                         }
850                 }
851
852                 joystick = Get_SDL_Joystick(joystick_nr);               
853
854                 /* Update visual joystick state */
855                 for ( i=0; i<SDL_JoystickNumButtons(joystick); ++i ) {
856                         SDL_Rect area;
857
858                         area.x = i*34;
859                         area.y = SCREEN_HEIGHT-34;
860                         area.w = 32;
861                         area.h = 32;
862                         if (SDL_JoystickGetButton(joystick, i) == SDL_PRESSED) {
863                                 SDL_FillRect(screen, &area, 0xFFFF);
864                         } else {
865                                 SDL_FillRect(screen, &area, 0x0000);
866                         }
867                         SDL_UpdateRects(screen, 1, &area);
868                 }
869
870                 /* Erase previous axes */
871                 SDL_FillRect(screen, &axis_area[draw], 0x0000);
872
873                 /* Draw the X/Y axis */
874                 draw = !draw;
875                 x = (((int)SDL_JoystickGetAxis(joystick, 0))+32768);
876                 x *= SCREEN_WIDTH;
877                 x /= 65535;
878                 if ( x < 0 ) {
879                         x = 0;
880                 } else
881                 if ( x > (SCREEN_WIDTH-16) ) {
882                         x = SCREEN_WIDTH-16;
883                 }
884                 y = (((int)SDL_JoystickGetAxis(joystick, 1))+32768);
885                 y *= SCREEN_HEIGHT;
886                 y /= 65535;
887                 if ( y < 0 ) {
888                         y = 0;
889                 } else
890                 if ( y > (SCREEN_HEIGHT-16) ) {
891                         y = SCREEN_HEIGHT-16;
892                 }
893                 axis_area[draw].x = (Sint16)x;
894                 axis_area[draw].y = (Sint16)y;
895                 axis_area[draw].w = 16;
896                 axis_area[draw].h = 16;
897                 SDL_FillRect(screen, &axis_area[draw], 0xFFFF);
898
899                 SDL_UpdateRects(screen, 2, axis_area);
900         }
901 }
902
903 void TEST_SDL_JOYSTICK()
904 {
905   const char *name;
906   int i;
907
908   /* Initialize SDL (Note: video is required to start event loop) */
909   if ( SDL_Init(SDL_INIT_VIDEO|SDL_INIT_JOYSTICK) < 0 )
910   {
911     fprintf(stderr, "Couldn't initialize SDL: %s\n",SDL_GetError());
912     exit(1);
913   }
914
915   /* Print information about the joysticks */
916   printf("There are %d joysticks attached\n", SDL_NumJoysticks());
917   for ( i=0; i<SDL_NumJoysticks(); ++i )
918   {
919     name = SDL_JoystickName(i);
920     printf("Joystick %d: %s\n",i,name ? name : "Unknown Joystick");
921   }
922
923   for (i=0; i<2; i++)
924   {
925     if (!Open_SDL_Joystick(i))
926       printf("Couldn't open joystick %d: %s\n", i, SDL_GetError());
927   }
928
929   WatchJoysticks();
930
931   for (i=0; i<2; i++)
932     Close_SDL_Joystick(i);
933
934   SDL_QuitSubSystem(SDL_INIT_VIDEO|SDL_INIT_JOYSTICK);
935 }
936
937 #endif  /* USE_SDL_LIBRARY */
938
939 /* +-----------------------------------------------------------------------+ */
940 /* | SDL TEST STUFF                                                        | */
941 /* +-----------------------------------------------------------------------+ */
942
943
944
945 int main(int argc, char *argv[])
946 {
947   program_name = (strrchr(argv[0],'/') ? strrchr(argv[0],'/') + 1 : argv[0]);
948
949 #ifdef MSDOS
950   _fmode = O_BINARY;
951 #endif
952
953 #if 1
954   GetOptions(argv);
955   OpenAll(argc,argv);
956 #endif
957
958 #if 0
959 #ifdef USE_SDL_LIBRARY
960   /*
961   TEST_SDL_BLIT_RECT((WIN_XSIZE - TILEX)/2, (WIN_YSIZE - TILEY)/2);
962   TEST_SDL_EVENT_LOOP();
963   */
964   TEST_SDL_JOYSTICK();
965   exit(0);
966 #endif
967 #endif
968
969   EventLoop();
970   CloseAllAndExit(0);
971   exit(0);      /* to keep compilers happy */
972 }