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