rnd-19981022-2
[rocksndiamonds.git] / src / screens.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 *  screens.c                                               *
12 ***********************************************************/
13
14 #include "screens.h"
15 #include "events.h"
16 #include "sound.h"
17 #include "game.h"
18 #include "tools.h"
19 #include "editor.h"
20 #include "misc.h"
21 #include "files.h"
22 #include "buttons.h"
23 #include "tape.h"
24 #include "joystick.h"
25 #include "cartoons.h"
26 #include "network.h"
27
28 #ifdef MSDOS
29 extern unsigned char get_ascii(KeySym);
30 #endif
31
32 void DrawHeadline()
33 {
34   int x1 = SX+(SXSIZE - strlen(GAMETITLE_STRING) * FONT1_XSIZE) / 2;
35   int y1 = SY+8;
36   int x2 = SX+(SXSIZE - strlen(COPYRIGHT_STRING) * FONT2_XSIZE) / 2;
37   int y2 = SY+46;
38
39   DrawText(x1,y1, GAMETITLE_STRING, FS_BIG, FC_YELLOW);
40   DrawText(x2,y2, COPYRIGHT_STRING, FS_SMALL, FC_RED);
41 }
42
43 void DrawMainMenu()
44 {
45   int i;
46
47   FadeSounds();
48   GetPlayerConfig();
49   LoadLevel(level_nr);
50
51   ClearWindow();
52   DrawHeadline();
53   DrawText(SX + 32,    SY + 2*32, "Name:", FS_BIG, FC_GREEN);
54   DrawText(SX + 6*32,  SY + 2*32, local_player->alias_name, FS_BIG, FC_RED);
55   DrawText(SX + 32,    SY + 3*32, "Level:", FS_BIG, FC_GREEN);
56   DrawText(SX + 11*32, SY + 3*32, int2str(level_nr,3), FS_BIG,
57            (level_nr<leveldir[leveldir_nr].levels ? FC_RED : FC_YELLOW));
58   DrawText(SX + 32,    SY + 4*32, "Hall Of Fame", FS_BIG, FC_GREEN);
59   DrawText(SX + 32,    SY + 5*32, "Level Creator", FS_BIG, FC_GREEN);
60   DrawText(SY + 32,    SY + 6*32, "Info Screen", FS_BIG, FC_GREEN);
61   DrawText(SX + 32,    SY + 7*32, "Start Game", FS_BIG, FC_GREEN);
62   DrawText(SX + 32,    SY + 8*32, "Setup", FS_BIG, FC_GREEN);
63   DrawText(SX + 32,    SY + 9*32, "Quit", FS_BIG, FC_GREEN);
64
65   DrawMicroLevel(MICROLEV_XPOS,MICROLEV_YPOS);
66
67   for(i=2;i<10;i++)
68     DrawGraphic(0,i,GFX_KUGEL_BLAU);
69   DrawGraphic(10,3,GFX_PFEIL_L);
70   DrawGraphic(14,3,GFX_PFEIL_R);
71
72   DrawText(SX+40+16,SY+326,"A Game by Artsoft Entertainment",FS_SMALL,FC_BLUE);
73   DrawText(SX+40+16,SY+344,"Graphics: Deluxe Paint IV Amiga",
74            FS_SMALL,FC_BLUE);
75   DrawText(SX+60+16,SY+362,"Sounds: AudioMaster IV Amiga",
76            FS_SMALL,FC_BLUE);
77
78   FadeToFront();
79   InitAnimation();
80   HandleMainMenu(0,0,0,0,MB_MENU_INITIALIZE);
81
82   TapeStop();
83   if (TAPE_IS_EMPTY(tape))
84     LoadLevelTape(level_nr);
85   DrawCompleteVideoDisplay();
86
87   OpenDoor(DOOR_CLOSE_1 | DOOR_OPEN_2);
88
89   ClearEventQueue();
90   XAutoRepeatOn(display);
91 }
92
93 void HandleMainMenu(int mx, int my, int dx, int dy, int button)
94 {
95   static int choice = 3;
96   static int redraw = TRUE;
97   int x = (mx+32-SX)/32, y = (my+32-SY)/32;
98
99   if (redraw || button == MB_MENU_INITIALIZE)
100   {
101     DrawGraphic(0,choice-1,GFX_KUGEL_ROT);
102     redraw = FALSE;
103   }
104
105   if (button == MB_MENU_INITIALIZE)
106     return;
107
108   if (dx || dy)
109   {
110     if (dx && choice==4)
111     {
112       x = (dx<0 ? 11 : 15);
113       y = 4;
114     }
115     else if (dy)
116     {
117       x = 1;
118       y = choice+dy;
119     }
120     else
121       x = y = 0;
122
123     if (y<3)
124       y = 3;
125     else if (y>10)
126       y = 10;
127   }
128
129   if (!mx && !my && !dx && !dy)
130   {
131     x = 1;
132     y = choice;
133   }
134
135   if (y==4 && ((x==11 && level_nr>0) ||
136                (x==15 && level_nr<leveldir[leveldir_nr].levels-1)) &&
137       button)
138   {
139     static long level_delay = 0;
140     int step = (button==1 ? 1 : button==2 ? 5 : 10);
141     int new_level_nr, old_level_nr = level_nr;
142
143     new_level_nr = level_nr + (x==11 ? -step : +step);
144     if (new_level_nr<0)
145       new_level_nr = 0;
146     if (new_level_nr>leveldir[leveldir_nr].levels-1)
147       new_level_nr = leveldir[leveldir_nr].levels-1;
148
149     if (old_level_nr==new_level_nr || !DelayReached(&level_delay,150))
150       goto out;
151
152     level_nr = new_level_nr;
153
154     if (level_nr > local_player->handicap)
155       level_nr = local_player->handicap;
156
157     DrawTextExt(drawto,gc,SX+11*32,SY+3*32,
158                 int2str(level_nr,3), FS_BIG,FC_RED);
159     DrawTextExt(window,gc,SX+11*32,SY+3*32,
160                 int2str(level_nr,3), FS_BIG,FC_RED);
161
162     LoadLevel(level_nr);
163     DrawMicroLevel(MICROLEV_XPOS,MICROLEV_YPOS);
164
165     TapeErase();
166     LoadLevelTape(level_nr);
167     DrawCompleteVideoDisplay();
168
169     /* needed because DrawMicroLevel() takes some time */
170     BackToFront();
171     XSync(display,FALSE);
172     DelayReached(&level_delay,0);       /* reset delay counter */
173   }
174   else if (x==1 && y>=3 && y<=10)
175   {
176     if (button)
177     {
178       if (y!=choice)
179       {
180         DrawGraphic(0,y-1,GFX_KUGEL_ROT);
181         DrawGraphic(0,choice-1,GFX_KUGEL_BLAU);
182       }
183       choice = y;
184     }
185     else
186     {
187       if (y==3)
188       {
189         game_status = TYPENAME;
190         HandleTypeName(strlen(local_player->alias_name),0);
191       }
192       else if (y==4)
193       {
194         if (num_leveldirs)
195         {
196           game_status = CHOOSELEVEL;
197           SavePlayerInfo(PLAYER_LEVEL);
198           DrawChooseLevel();
199         }
200       }
201       else if (y==5)
202       {
203         game_status = HALLOFFAME;
204         DrawHallOfFame(-1);
205       }
206       else if (y==6)
207       {
208         game_status = LEVELED;
209         if (leveldir[leveldir_nr].readonly)
210           Request("This level is read only !",REQ_CONFIRM);
211         DrawLevelEd();
212       }
213       else if (y==7)
214       {
215         game_status = HELPSCREEN;
216         DrawHelpScreen();
217       }
218       else if (y==8)
219       {
220         if (setup.autorecord_on)
221           TapeStartRecording();
222
223         if (options.network)
224           SendToServer_StartPlaying();
225         else
226         {
227           game_status = PLAYING;
228           InitGame();
229         }
230       }
231       else if (y==9)
232       {
233         game_status = SETUP;
234         DrawSetupScreen();
235       }
236       else if (y==10)
237       {
238         SavePlayerInfo(PLAYER_LEVEL);
239         if (Request("Do you really want to quit ?", REQ_ASK | REQ_STAY_CLOSED))
240           game_status = EXITGAME;
241       }
242
243       if (!button)
244         redraw = TRUE;
245     }
246   }
247   BackToFront();
248
249   out:
250
251   if (game_status==MAINMENU)
252     DoAnimation();
253 }
254
255 #define MAX_HELPSCREEN_ELS      10
256 #define HA_NEXT                 -999
257 #define HA_END                  -1000
258
259 static long helpscreen_state;
260 static int helpscreen_step[MAX_HELPSCREEN_ELS];
261 static int helpscreen_frame[MAX_HELPSCREEN_ELS];
262 static int helpscreen_delay[MAX_HELPSCREEN_ELS];
263 static int helpscreen_action[] =
264 {
265   GFX_SPIELER1_DOWN,4,2,
266   GFX_SPIELER1_UP,4,2,
267   GFX_SPIELER1_LEFT,4,2,
268   GFX_SPIELER1_RIGHT,4,2,
269   GFX_SPIELER1_PUSH_LEFT,4,2,
270   GFX_SPIELER1_PUSH_RIGHT,4,2,                                  HA_NEXT,
271   GFX_ERDREICH,1,100,                                           HA_NEXT,
272   GFX_LEERRAUM,1,100,                                           HA_NEXT,
273   GFX_MORAST_LEER,1,100,                                        HA_NEXT,
274   GFX_BETON,1,100,                                              HA_NEXT,
275   GFX_MAUERWERK,1,100,                                          HA_NEXT,
276   GFX_MAUER_R1,3,4, GFX_MAUERWERK,1,20, GFX_LEERRAUM,1,10,
277   GFX_MAUER_L1,3,4, GFX_MAUERWERK,1,20, GFX_LEERRAUM,1,10,      HA_NEXT,
278   GFX_UNSICHTBAR,1,100,                                         HA_NEXT,
279   GFX_FELSBODEN,1,100,                                          HA_NEXT,
280   GFX_CHAR_A,30,4, GFX_CHAR_AUSRUF,32,4,                        HA_NEXT,
281   GFX_EDELSTEIN,2,5,                                            HA_NEXT,
282   GFX_DIAMANT,2,5,                                              HA_NEXT,
283   GFX_EDELSTEIN_BD,2,5,                                         HA_NEXT,
284   GFX_EDELSTEIN_GELB,2,5, GFX_EDELSTEIN_ROT,2,5,
285   GFX_EDELSTEIN_LILA,2,5,                                       HA_NEXT,
286   GFX_FELSBROCKEN,4,5,                                          HA_NEXT,
287   GFX_BOMBE,1,50, GFX_EXPLOSION,8,1, GFX_LEERRAUM,1,10,         HA_NEXT,
288   GFX_KOKOSNUSS,1,50, GFX_CRACKINGNUT,3,1, GFX_EDELSTEIN,1,10,  HA_NEXT,
289   GFX_ERZ_EDEL,1,50, GFX_EXPLOSION,8,1, GFX_EDELSTEIN,1,10,     HA_NEXT,
290   GFX_ERZ_DIAM,1,50, GFX_EXPLOSION,8,1, GFX_DIAMANT,1,10,       HA_NEXT,
291   GFX_ERZ_EDEL_BD,1,50, GFX_EXPLOSION,8,1,GFX_EDELSTEIN_BD,1,10,HA_NEXT,
292   GFX_ERZ_EDEL_GELB,1,50, GFX_EXPLOSION,8,1,
293   GFX_EDELSTEIN_GELB,1,10, GFX_ERZ_EDEL_ROT,1,50,
294   GFX_EXPLOSION,8,1, GFX_EDELSTEIN_ROT,1,10,
295   GFX_ERZ_EDEL_LILA,1,50, GFX_EXPLOSION,8,1,
296   GFX_EDELSTEIN_LILA,1,10,                                      HA_NEXT,
297   GFX_GEBLUBBER,4,4,                                            HA_NEXT,
298   GFX_SCHLUESSEL1,4,25,                                         HA_NEXT,
299   GFX_PFORTE1,4,25,                                             HA_NEXT,
300   GFX_PFORTE1X,4,25,                                            HA_NEXT,
301   GFX_DYNAMIT_AUS,1,100,                                        HA_NEXT,
302   GFX_DYNAMIT,7,6, GFX_EXPLOSION,8,1, GFX_LEERRAUM,1,10,        HA_NEXT,
303   GFX_DYNABOMB+0,4,3, GFX_DYNABOMB+3,1,3, GFX_DYNABOMB+2,1,3,
304   GFX_DYNABOMB+1,1,3, GFX_DYNABOMB+0,1,3, GFX_EXPLOSION,8,1,
305   GFX_LEERRAUM,1,10,                                            HA_NEXT,
306   GFX_DYNABOMB_NR,1,100,                                        HA_NEXT,
307   GFX_DYNABOMB_SZ,1,100,                                        HA_NEXT,
308   GFX_FLIEGER+4,1,3, GFX_FLIEGER+0,1,3, GFX_FLIEGER+4,1,3,
309   GFX_FLIEGER+5,1,3, GFX_FLIEGER+1,1,3, GFX_FLIEGER+5,1,3,
310   GFX_FLIEGER+6,1,3, GFX_FLIEGER+2,1,3, GFX_FLIEGER+6,1,3,
311   GFX_FLIEGER+7,1,3, GFX_FLIEGER+3,1,3, GFX_FLIEGER+7,1,3,      HA_NEXT,
312   GFX_KAEFER+4,1,1, GFX_KAEFER+0,1,1, GFX_KAEFER+4,1,1,
313   GFX_KAEFER+5,1,1, GFX_KAEFER+1,1,1, GFX_KAEFER+5,1,1,
314   GFX_KAEFER+6,1,1, GFX_KAEFER+2,1,1, GFX_KAEFER+6,1,1,
315   GFX_KAEFER+7,1,1, GFX_KAEFER+3,1,1, GFX_KAEFER+7,1,1,         HA_NEXT,
316   GFX_BUTTERFLY,2,2,                                            HA_NEXT,
317   GFX_FIREFLY,2,2,                                              HA_NEXT,
318   GFX_PACMAN+0,1,3, GFX_PACMAN+4,1,2, GFX_PACMAN+0,1,3,
319   GFX_PACMAN+1,1,3, GFX_PACMAN+5,1,2, GFX_PACMAN+1,1,3,
320   GFX_PACMAN+2,1,3, GFX_PACMAN+6,1,2, GFX_PACMAN+2,1,3,
321   GFX_PACMAN+3,1,3, GFX_PACMAN+7,1,2, GFX_PACMAN+3,1,3,         HA_NEXT,
322   GFX_MAMPFER+0,4,1, GFX_MAMPFER+3,1,1, GFX_MAMPFER+2,1,1,
323   GFX_MAMPFER+1,1,1, GFX_MAMPFER+0,1,1,                         HA_NEXT,
324   GFX_MAMPFER2+0,4,1, GFX_MAMPFER2+3,1,1, GFX_MAMPFER2+2,1,1,
325   GFX_MAMPFER2+1,1,1, GFX_MAMPFER2+0,1,1,                       HA_NEXT,
326   GFX_ROBOT+0,4,1, GFX_ROBOT+3,1,1, GFX_ROBOT+2,1,1,
327   GFX_ROBOT+1,1,1, GFX_ROBOT+0,1,1,                             HA_NEXT,
328   GFX_MAULWURF_DOWN,4,2,
329   GFX_MAULWURF_UP,4,2,
330   GFX_MAULWURF_LEFT,4,2,
331   GFX_MAULWURF_RIGHT,4,2,                                       HA_NEXT,
332   GFX_PINGUIN_DOWN,4,2,
333   GFX_PINGUIN_UP,4,2,
334   GFX_PINGUIN_LEFT,4,2,
335   GFX_PINGUIN_RIGHT,4,2,                                        HA_NEXT,
336   GFX_SCHWEIN_DOWN,4,2,
337   GFX_SCHWEIN_UP,4,2,
338   GFX_SCHWEIN_LEFT,4,2,
339   GFX_SCHWEIN_RIGHT,4,2,                                        HA_NEXT,
340   GFX_DRACHE_DOWN,4,2,
341   GFX_DRACHE_UP,4,2,
342   GFX_DRACHE_LEFT,4,2,
343   GFX_DRACHE_RIGHT,4,2,                                         HA_NEXT,
344   GFX_SONDE_START,8,1,                                          HA_NEXT,
345   GFX_ABLENK,4,1,                                               HA_NEXT,
346   GFX_BIRNE_AUS,1,25, GFX_BIRNE_EIN,1,25,                       HA_NEXT,
347   GFX_ZEIT_VOLL,1,25, GFX_ZEIT_LEER,1,25,                       HA_NEXT,
348   GFX_TROPFEN,1,25, GFX_AMOEBING,4,1, GFX_AMOEBE_LEBT,1,10,     HA_NEXT,
349   GFX_AMOEBE_TOT+2,2,50, GFX_AMOEBE_TOT,2,50,                   HA_NEXT,
350   GFX_AMOEBE_LEBT,4,40,                                         HA_NEXT,
351   GFX_AMOEBE_LEBT,1,10, GFX_AMOEBING,4,2,                       HA_NEXT,
352   GFX_AMOEBE_LEBT,1,25, GFX_AMOEBE_TOT,1,25, GFX_EXPLOSION,8,1,
353   GFX_DIAMANT,1,10,                                             HA_NEXT,
354   GFX_LIFE,1,100,                                               HA_NEXT,
355   GFX_LIFE_ASYNC,1,100,                                         HA_NEXT,
356   GFX_SIEB_LEER,4,2,                                            HA_NEXT,
357   GFX_SIEB2_LEER,4,2,                                           HA_NEXT,
358   GFX_AUSGANG_ZU,1,100, GFX_AUSGANG_ACT,4,2,
359   GFX_AUSGANG_AUF+0,4,2, GFX_AUSGANG_AUF+3,1,2,
360   GFX_AUSGANG_AUF+2,1,2, GFX_AUSGANG_AUF+1,1,2,                 HA_NEXT,
361   GFX_AUSGANG_AUF+0,4,2, GFX_AUSGANG_AUF+3,1,2,
362   GFX_AUSGANG_AUF+2,1,2, GFX_AUSGANG_AUF+1,1,2,                 HA_NEXT,
363   HA_END
364 };
365 static char *helpscreen_eltext[][2] =
366 {
367  {"THE HERO:",                          "(Is _this_ guy good old Rockford?)"},
368  {"Normal sand:",                       "You can dig through it"},
369  {"Empty field:",                       "You can walk through it"},
370  {"Quicksand: You cannot pass it,",     "but rocks can fall though it"},
371  {"Massive Wall:",                      "Nothing can go through it"},
372  {"Normal Wall: You can't go through",  "it, but you can bomb it away"},
373  {"Growing Wall: Grows to the left or", "right if there is an empty field"},
374  {"Invisible Wall: Behaves like normal","wall, but is invisible"},
375  {"Old Wall: Like normal wall, but",    "some things can fall down from it"},
376  {"Letter Wall: Looks like a letter,",  "behaves like a normal wall"},
377  {"Emerald: You must collect enough of","them to finish a level"},
378  {"Diamond: Counts as 3 emeralds, but", "can be destroyed by rocks"},
379  {"Diamond (BD style): Counts like one","emerald and behaves a bit different"},
380  {"Colorful Gems:",                     "Seem to behave like Emeralds"},
381  {"Rock: Smashes several things;",      "Can be moved by the player"},
382  {"Bomb: You can move it, but be",      "careful when dropping it"},
383  {"Nut: Throw a rock on it to open it;","Each nut contains an emerald"},
384  {"Wall with an emerald inside:",       "Bomb the wall away to get it"},
385  {"Wall with a diamond inside:",        "Bomb the wall away to get it"},
386  {"Wall with BD style diamond inside:", "Bomb the wall away to get it"},
387  {"Wall with colorful gem inside:",     "Bomb the wall away to get it"},
388  {"Acid: Things that fall in are gone", "forever (including our hero)"},
389  {"Key: Opens the door that has the",   "same color (red/yellow/green/blue)"},
390  {"Door: Can be opened by the key",     "with the same color"},
391  {"Door: You have to find out the",     "right color of the key for it"},
392  {"Dynamite: Collect it and use it to", "destroy walls or kill enemies"},
393  {"Dynamite: This one explodes after",  "a few seconds"},
394  {"Dyna Bomb: Explodes in 4 directions","with variable explosion size"},
395  {"Dyna Bomb: Increases the number of", "dyna bombs available at a time"},
396  {"Dyna Bomb: Increases the size of",   "explosion of dyna bombs"},
397  {"Spaceship: Moves at the left side",  "of walls; don't touch it!"},
398  {"Bug: Moves at the right side",       "of walls; don't touch it!"},
399  {"Butterfly: Moves at the right side", "of walls; don't touch it!"},
400  {"Firefly: Moves at the left side",    "of walls; don't touch it!"},
401  {"Pacman: Eats the amoeba and you,",   "if you're not careful"},
402  {"Cruncher: Eats diamonds and you,",   "if you're not careful"},
403  {"Cruncher (BD style):",               "Eats almost everything"},
404  {"Robot: Tries to kill the player",    ""},
405  {"The mole: You must guide him savely","to the exit; he will follow you"},
406  {"The penguin: Guide him to the exit,","but keep him away from monsters!"},
407  {"The Pig: Harmless, but eats all",    "gems it can get"},
408  {"The Dragon: Breathes fire,",         "especially to some monsters"},
409  {"Sonde: Follows you everywhere;",     "harmless, but may block your way"},
410  {"Magic Wheel: Touch it to get rid of","the robots for some seconds"},
411  {"Light Bulb: All of them must be",    "switched on to finish a level"},
412  {"Extra Time Orb: Adds some seconds",  "to the time available for the level"},
413  {"Amoeba Drop: Grows to an amoeba on", "the ground - don't touch it"},
414  {"Dead Amoeba: Does not grow, but",    "can still kill bugs and spaceships"},
415  {"Normal Amoeba: Grows through empty", "fields, sand and quicksand"},
416  {"Dropping Amoeba: This one makes",    "drops that grow to a new amoeba"},
417  {"Living Amoeba (BD style): Contains", "other element, when surrounded"},
418  {"Game Of Life: Behaves like the well","known 'Game Of Life' (2333 style)"},
419  {"Biomaze: A bit like the 'Game Of",   "Life', but builds crazy mazes"},
420  {"Magic Wall: Changes rocks, emeralds","and diamonds when they pass it"},
421  {"Magic Wall (BD style):",             "Changes rocks and BD style diamonds"},
422  {"Exit door: Opens if you have enough","emeralds to finish the level"},
423  {"Open exit door: Enter here to leave","the level and exit the actual game"},
424 };
425 static int num_helpscreen_els = sizeof(helpscreen_eltext)/(2*sizeof(char *));
426
427 static char *helpscreen_music[][3] =
428 {
429   { "Alchemy",                  "Ian Boddy",            "Drive" },
430   { "The Chase",                "Propaganda",           "A Secret Wish" },
431   { "Network 23",               "Tangerine Dream",      "Exit" },
432   { "Czardasz",                 "Robert Pieculewicz",   "Czardasz" },
433   { "21st Century Common Man",  "Tangerine Dream",      "Tyger" },
434   { "Voyager",                  "The Alan Parsons Project","Pyramid" },
435   { "Twilight Painter",         "Tangerine Dream",      "Heartbreakers" }
436 };
437 static int helpscreen_musicpos;
438
439 void DrawHelpScreenElAction(int start)
440 {
441   int i = 0, j = 0;
442   int frame, graphic;
443   int xstart = SX+16, ystart = SY+64+2*32, ystep = TILEY+4;
444
445   while(helpscreen_action[j] != HA_END)
446   {
447     if (i>=start+MAX_HELPSCREEN_ELS || i>=num_helpscreen_els)
448       break;
449     else if (i<start || helpscreen_delay[i-start])
450     {
451       if (i>=start && helpscreen_delay[i-start])
452         helpscreen_delay[i-start]--;
453
454       while(helpscreen_action[j] != HA_NEXT)
455         j++;
456       j++;
457       i++;
458       continue;
459     }
460
461     j += 3*helpscreen_step[i-start];
462     graphic = helpscreen_action[j++];
463
464     if (helpscreen_frame[i-start])
465     {
466       frame = helpscreen_action[j++] - helpscreen_frame[i-start];
467       helpscreen_frame[i-start]--;
468     }
469     else
470     {
471       frame = 0;
472       helpscreen_frame[i-start] = helpscreen_action[j++]-1;
473     }
474
475     helpscreen_delay[i-start] = helpscreen_action[j++] - 1;
476
477     if (helpscreen_action[j] == HA_NEXT)
478     {
479       if (!helpscreen_frame[i-start])
480         helpscreen_step[i-start] = 0;
481     }
482     else
483     {
484       if (!helpscreen_frame[i-start])
485         helpscreen_step[i-start]++;
486       while(helpscreen_action[j] != HA_NEXT)
487         j++;
488     }
489     j++;
490
491     DrawGraphicExt(drawto, gc, xstart, ystart+(i-start)*ystep, graphic+frame);
492     i++;
493   }
494
495   for(i=2;i<16;i++)
496   {
497     MarkTileDirty(0,i);
498     MarkTileDirty(1,i);
499   }
500 }
501
502 void DrawHelpScreenElText(int start)
503 {
504   int i;
505   int xstart = SX+56, ystart = SY+65+2*32, ystep = TILEY+4;
506   char text[FULL_SXSIZE/FONT2_XSIZE+10];
507
508   ClearWindow();
509   DrawHeadline();
510
511   sprintf(text,"The game elements:");
512   DrawText(SX+(SXSIZE-strlen(text)*FONT2_XSIZE)/2,SY+100,
513            text,FS_SMALL,FC_GREEN);
514
515   for(i=start;i<start+MAX_HELPSCREEN_ELS && i<num_helpscreen_els;i++)
516   {
517     DrawText(xstart,ystart+(i-start)*ystep+(*helpscreen_eltext[i][1] ? 0 : 8),
518              helpscreen_eltext[i][0],FS_SMALL,FC_YELLOW);
519     DrawText(xstart,ystart+(i-start)*ystep+16,
520              helpscreen_eltext[i][1],FS_SMALL,FC_YELLOW);
521   }
522
523   sprintf(text,"Press any key or button for next page");
524   DrawText(SX+(SXSIZE-strlen(text)*FONT2_XSIZE)/2,SY+SYSIZE-20,
525            text,FS_SMALL,FC_BLUE);
526 }
527
528 void DrawHelpScreenMusicText(int num)
529 {
530   int ystart = 150, ystep = 30;
531   char text[FULL_SXSIZE/FONT2_XSIZE+10];
532
533   FadeSounds();
534   ClearWindow();
535   DrawHeadline();
536
537   sprintf(text,"The game background music loops:");
538   DrawText(SX+(SXSIZE-strlen(text)*FONT2_XSIZE)/2,SY+100,
539            text,FS_SMALL,FC_GREEN);
540
541   sprintf(text,"Excerpt from");
542   DrawText(SX+(SXSIZE-strlen(text)*FONT2_XSIZE)/2,SY+ystart+0*ystep,
543            text,FS_SMALL,FC_YELLOW);
544   sprintf(text,"%c%s%c",'\"',helpscreen_music[num][0],'\"');
545   DrawText(SX+(SXSIZE-strlen(text)*FONT2_XSIZE)/2,SY+ystart+1*ystep,
546            text,FS_SMALL,FC_RED);
547   sprintf(text,"by");
548   DrawText(SX+(SXSIZE-strlen(text)*FONT2_XSIZE)/2,SY+ystart+2*ystep,
549            text,FS_SMALL,FC_YELLOW);
550   sprintf(text,"%s",helpscreen_music[num][1]);
551   DrawText(SX+(SXSIZE-strlen(text)*FONT2_XSIZE)/2,SY+ystart+3*ystep,
552            text,FS_SMALL,FC_RED);
553   sprintf(text,"from the album");
554   DrawText(SX+(SXSIZE-strlen(text)*FONT2_XSIZE)/2,SY+ystart+4*ystep,
555            text,FS_SMALL,FC_YELLOW);
556   sprintf(text,"%c%s%c",'\"',helpscreen_music[num][2],'\"');
557   DrawText(SX+(SXSIZE-strlen(text)*FONT2_XSIZE)/2,SY+ystart+5*ystep,
558            text,FS_SMALL,FC_RED);
559
560   sprintf(text,"Press any key or button for next page");
561   DrawText(SX+(SXSIZE-strlen(text)*FONT2_XSIZE)/2,SY+SYSIZE-20,
562            text,FS_SMALL,FC_BLUE);
563
564   PlaySoundLoop(background_loop[num]);
565 }
566
567 void DrawHelpScreenCreditsText()
568 {
569   int ystart = 150, ystep = 30;
570   char text[FULL_SXSIZE/FONT2_XSIZE+10];
571
572   FadeSounds();
573   ClearWindow();
574   DrawHeadline();
575
576   sprintf(text,"Program information:");
577   DrawText(SX+(SXSIZE-strlen(text)*FONT2_XSIZE)/2,SY+100,
578            text,FS_SMALL,FC_GREEN);
579
580   sprintf(text,"This game is Freeware!");
581   DrawText(SX+(SXSIZE-strlen(text)*FONT2_XSIZE)/2,SY+ystart+0*ystep,
582            text,FS_SMALL,FC_YELLOW);
583   sprintf(text,"If you like it, send e-mail to:");
584   DrawText(SX+(SXSIZE-strlen(text)*FONT2_XSIZE)/2,SY+ystart+1*ystep,
585            text,FS_SMALL,FC_YELLOW);
586   sprintf(text,"aeglos@valinor.owl.de");
587   DrawText(SX+(SXSIZE-strlen(text)*FONT2_XSIZE)/2,SY+ystart+2*ystep,
588            text,FS_SMALL,FC_RED);
589   sprintf(text,"or SnailMail to:");
590   DrawText(SX+(SXSIZE-strlen(text)*FONT2_XSIZE)/2,SY+ystart+3*ystep,
591            text,FS_SMALL,FC_YELLOW);
592   sprintf(text,"Holger Schemel");
593   DrawText(SX+(SXSIZE-strlen(text)*FONT2_XSIZE)/2,SY+ystart+4*ystep,
594            text,FS_SMALL,FC_RED);
595   sprintf(text,"Sennehof 28");
596   DrawText(SX+(SXSIZE-strlen(text)*FONT2_XSIZE)/2,SY+ystart+4*ystep+20,
597            text,FS_SMALL,FC_RED);
598   sprintf(text,"33659 Bielefeld");
599   DrawText(SX+(SXSIZE-strlen(text)*FONT2_XSIZE)/2,SY+ystart+4*ystep+40,
600            text,FS_SMALL,FC_RED);
601   sprintf(text,"Germany");
602   DrawText(SX+(SXSIZE-strlen(text)*FONT2_XSIZE)/2,SY+ystart+4*ystep+60,
603            text,FS_SMALL,FC_RED);
604
605   sprintf(text,"If you have created new levels,");
606   DrawText(SX+(SXSIZE-strlen(text)*FONT2_XSIZE)/2,SY+ystart+7*ystep,
607            text,FS_SMALL,FC_YELLOW);
608   sprintf(text,"send them to me to include them!");
609   DrawText(SX+(SXSIZE-strlen(text)*FONT2_XSIZE)/2,SY+ystart+8*ystep,
610            text,FS_SMALL,FC_YELLOW);
611   sprintf(text,":-)");
612   DrawText(SX+(SXSIZE-strlen(text)*FONT2_XSIZE)/2,SY+ystart+9*ystep,
613            text,FS_SMALL,FC_YELLOW);
614
615   sprintf(text,"Press any key or button for main menu");
616   DrawText(SX+(SXSIZE-strlen(text)*FONT2_XSIZE)/2,SY+SYSIZE-20,
617            text,FS_SMALL,FC_BLUE);
618 }
619
620 void DrawHelpScreen()
621 {
622   int i;
623
624   CloseDoor(DOOR_CLOSE_2);
625
626   for(i=0;i<MAX_HELPSCREEN_ELS;i++)
627     helpscreen_step[i] = helpscreen_frame[i] = helpscreen_delay[i] = 0;
628   helpscreen_musicpos = 0;
629   helpscreen_state = 0;
630   DrawHelpScreenElText(0);
631   DrawHelpScreenElAction(0);
632
633   FadeToFront();
634   InitAnimation();
635   PlaySoundLoop(SND_RHYTHMLOOP);
636 }
637
638 void HandleHelpScreen(int button)
639 {
640   static long hs_delay = 0;
641   int num_helpscreen_els_pages =
642     (num_helpscreen_els + MAX_HELPSCREEN_ELS-1) / MAX_HELPSCREEN_ELS;
643   int button_released = !button;
644   int i;
645
646   if (button_released)
647   {
648     if (helpscreen_state<num_helpscreen_els_pages-1)
649     {
650       for(i=0;i<MAX_HELPSCREEN_ELS;i++)
651         helpscreen_step[i] = helpscreen_frame[i] = helpscreen_delay[i] = 0;
652       helpscreen_state++;
653       DrawHelpScreenElText(helpscreen_state*MAX_HELPSCREEN_ELS);
654       DrawHelpScreenElAction(helpscreen_state*MAX_HELPSCREEN_ELS);
655     }
656     else if (helpscreen_state<num_helpscreen_els_pages+num_bg_loops-1)
657     {
658       helpscreen_state++;
659       DrawHelpScreenMusicText(helpscreen_state-num_helpscreen_els_pages);
660     }
661     else if (helpscreen_state==num_helpscreen_els_pages+num_bg_loops-1)
662     {
663       helpscreen_state++;
664       DrawHelpScreenCreditsText();
665     }
666     else
667     {
668       FadeSounds();
669       DrawMainMenu();
670       game_status = MAINMENU;
671     }
672   }
673   else
674   {
675     if (DelayReached(&hs_delay,GAME_FRAME_DELAY * 2))
676     {
677       if (helpscreen_state<num_helpscreen_els_pages)
678         DrawHelpScreenElAction(helpscreen_state*MAX_HELPSCREEN_ELS);
679     }
680     DoAnimation();
681   }
682
683   BackToFront();
684 }
685
686 void CheckCheat()
687 {
688   int old_handicap = local_player->handicap;
689
690 #if 0
691   if (!strcmp(local_player->alias_name,"Artsoft"))
692 #endif
693     local_player->handicap = leveldir[leveldir_nr].levels-1;
694
695   if (local_player->handicap != old_handicap)
696   {
697     SavePlayerInfo(PLAYER_LEVEL);
698     level_nr = local_player->handicap;
699   }
700 }
701
702 void HandleTypeName(int newxpos, KeySym key)
703 {
704   static int xpos = 0, ypos = 2;
705   unsigned char ascii;
706
707   if (newxpos)
708   {
709     xpos = newxpos;
710     DrawText(SX+6*32, SY+ypos*32, local_player->alias_name, FS_BIG, FC_YELLOW);
711     DrawGraphic(xpos+6,ypos,GFX_KUGEL_ROT);
712     return;
713   }
714
715 #ifndef MSDOS
716   if ((key>=XK_A && key<=XK_Z) || (key>=XK_a && key<=XK_z && 
717       xpos<MAX_NAMELEN-1))
718   {
719     if (key>=XK_A && key<=XK_Z)
720       ascii = 'A'+(char)(key-XK_A);
721     if (key>=XK_a && key<=XK_z)
722       ascii = 'a'+(char)(key-XK_a);
723 #else
724   if((ascii = get_ascii(key)) && xpos<MAX_NAMELEN-1)
725   {
726 #endif
727     local_player->alias_name[xpos] = ascii;
728     local_player->alias_name[xpos+1] = 0;
729     xpos++;
730     DrawTextExt(drawto,gc,SX+6*32,SY+ypos*32,
731                 local_player->alias_name,FS_BIG,FC_YELLOW);
732     DrawTextExt(window,gc,SX+6*32,SY+ypos*32,
733                 local_player->alias_name,FS_BIG,FC_YELLOW);
734     DrawGraphic(xpos+6,ypos,GFX_KUGEL_ROT);
735   }
736   else if ((key==XK_Delete || key==XK_BackSpace) && xpos>0)
737   {
738     xpos--;
739     local_player->alias_name[xpos] = 0;
740     DrawGraphic(xpos+6,ypos,GFX_KUGEL_ROT);
741     DrawGraphic(xpos+7,ypos,GFX_LEERRAUM);
742   }
743   else if (key==XK_Return && xpos>0)
744   {
745     DrawText(SX+6*32,SY+ypos*32,local_player->alias_name,FS_BIG,FC_RED);
746     DrawGraphic(xpos+6,ypos,GFX_LEERRAUM);
747     SavePlayerInfo(PLAYER_SETUP);
748     CheckCheat();
749
750     game_status = MAINMENU;
751 /*
752     DrawMainMenu();
753 */
754
755   }
756   BackToFront();
757 }
758
759 void DrawChooseLevel()
760 {
761   int i;
762
763   CloseDoor(DOOR_CLOSE_2);
764
765   ClearWindow();
766   DrawText(SX,SY,"Level Directories",FS_BIG,FC_GREEN);
767   for(i=0;i<num_leveldirs;i++)
768   {
769     DrawText(SX+32,SY+(i+2)*32,leveldir[i].name,FS_BIG,FC_YELLOW);
770     DrawGraphic(0,i+2,GFX_KUGEL_BLAU);
771   }
772
773   FadeToFront();
774   InitAnimation();
775   HandleChooseLevel(0,0,0,0,MB_MENU_INITIALIZE);
776 }
777
778 void HandleChooseLevel(int mx, int my, int dx, int dy, int button)
779 {
780   static int choice = 3;
781   static int redraw = TRUE;
782   int x = (mx+32-SX)/32, y = (my+32-SY)/32;
783
784   if (button == MB_MENU_INITIALIZE)
785   {
786     redraw = TRUE;
787     choice = leveldir_nr + 3;
788   }
789
790   if (redraw)
791   {
792     DrawGraphic(0,choice-1,GFX_KUGEL_ROT);
793     redraw = FALSE;
794   }
795
796   if (button == MB_MENU_INITIALIZE)
797     return;
798
799   if (dx || dy)
800   {
801     if (dy)
802     {
803       x = 1;
804       y = choice+dy;
805     }
806     else
807       x = y = 0;
808
809     if (y<3)
810       y = 3;
811     else if (y>num_leveldirs+2)
812       y = num_leveldirs+2;
813   }
814
815   if (!mx && !my && !dx && !dy)
816   {
817     x = 1;
818     y = choice;
819   }
820
821   if (x==1 && y>=3 && y<=num_leveldirs+2)
822   {
823     if (button)
824     {
825       if (y!=choice)
826       {
827         DrawGraphic(0,y-1,GFX_KUGEL_ROT);
828         DrawGraphic(0,choice-1,GFX_KUGEL_BLAU);
829       }
830       choice = y;
831     }
832     else
833     {
834       local_player->leveldir_nr = leveldir_nr = y-3;
835       LoadPlayerInfo(PLAYER_LEVEL);
836       SavePlayerInfo(PLAYER_SETUP);
837       CheckCheat();
838
839       TapeErase();
840       LoadLevelTape(level_nr);
841
842       game_status = MAINMENU;
843       DrawMainMenu();
844       redraw = TRUE;
845     }
846   }
847   BackToFront();
848
849   if (game_status==CHOOSELEVEL)
850     DoAnimation();
851 }
852
853 void DrawHallOfFame(int pos)
854 {
855   int y;
856   char txt[40];
857
858   CloseDoor(DOOR_CLOSE_2);
859
860   if (pos<0) 
861     LoadScore(level_nr);
862   ClearWindow();
863   DrawText(SX+64,SY+10,"Hall Of Fame",FS_BIG,FC_YELLOW);
864   sprintf(txt,"HighScores of Level %d",level_nr);
865   DrawText(SX+256-strlen(txt)*7,SY+48,txt,FS_SMALL,FC_RED);
866   for(y=0;y<MAX_SCORE_ENTRIES;y++)
867   {
868     DrawText(SX,SY+64+y*32,".................",FS_BIG,
869              (y==pos ? FC_RED : FC_GREEN));
870     DrawText(SX,SY+64+y*32,highscore[y].Name,FS_BIG,
871              (y==pos ? FC_RED : FC_GREEN));
872     DrawText(SX+12*32,SY+64+y*32,
873              int2str(highscore[y].Score,5),FS_BIG,
874              (y==pos ? FC_RED : FC_GREEN));
875   }
876
877   FadeToFront();
878   InitAnimation();
879   PlaySound(SND_HALLOFFAME);
880 }
881
882 void HandleHallOfFame(int button)
883 {
884   int button_released = !button;
885
886   if (button_released)
887   {
888     FadeSound(SND_HALLOFFAME);
889     game_status = MAINMENU;
890     DrawMainMenu();
891     BackToFront();
892   }
893   else
894     DoAnimation();
895 }
896
897 void DrawSetupScreen()
898 {
899   int i;
900   static struct setup
901   {
902     unsigned int bit;
903     char *text, *mode[2];
904     int color[2];
905   } setup[] =
906   {
907     {SETUP_SOUND,       "Sound:",       {"on", "off"},  {FC_YELLOW,FC_BLUE}},
908     {SETUP_SOUND_LOOPS, " Sound Loops:",{"on", "off"},  {FC_YELLOW,FC_BLUE}},
909     {SETUP_SOUND_MUSIC, " Game Music:", {"on", "off"},  {FC_YELLOW,FC_BLUE}},
910     {SETUP_TOONS,       "Toons:",       {"on", "off"},  {FC_YELLOW,FC_BLUE}},
911     {SETUP_DIRECT_DRAW, "Buffered gfx:",{"off","on" },  {FC_BLUE,FC_YELLOW}},
912     {SETUP_SCROLL_DELAY,"Scroll Delay:",{"on", "off"},  {FC_YELLOW,FC_BLUE}},
913     {SETUP_SOFT_SCROLL, "Soft Scroll.:",{"on", "off"},  {FC_YELLOW,FC_BLUE}},
914     {SETUP_FADING,      "Fading:",      {"on", "off"},  {FC_YELLOW,FC_BLUE}},
915     {SETUP_QUICK_DOORS, "Quick Doors:", {"on", "off"},  {FC_YELLOW,FC_BLUE}},
916     {SETUP_AUTO_RECORD, "Auto-Record:", {"on", "off"},  {FC_YELLOW,FC_BLUE}},
917     {0,                 "Input Devices",{"",   ""},     {0,0}},
918     {0,                 "",             {"",   ""},     {0,0}},
919     {0,                 "",             {"",   ""},     {0,0}},
920     {0,                 "Exit",         {"",   ""},     {0,0}},
921     {0,                 "Save and exit",{"",   ""},     {0,0}}
922   };
923
924   CloseDoor(DOOR_CLOSE_2);
925   ClearWindow();
926   DrawText(SX+16, SY+16, "SETUP",FS_BIG,FC_YELLOW);
927
928   for(i=SETUP_SCREEN_POS_START;i<=SETUP_SCREEN_POS_END;i++)
929   {
930     int base = i - SETUP_SCREEN_POS_START;
931
932     if (!(i >= SETUP_SCREEN_POS_EMPTY1 && i <= SETUP_SCREEN_POS_EMPTY2))
933     {
934       DrawGraphic(0,i,GFX_KUGEL_BLAU);
935       DrawText(SX+32,SY+i*32, setup[base].text, FS_BIG,FC_GREEN);
936     }
937
938     if (i < SETUP_SCREEN_POS_EMPTY1)
939     {
940       int setting_bit = setup[base].bit;
941       int setting_pos = ((local_player->setup & setting_bit) != 0 ? 0 : 1);
942       DrawText(SX+14*32, SY+i*32,setup[base].mode[setting_pos],
943                FS_BIG,setup[base].color[setting_pos]);
944     }
945   }
946
947   FadeToFront();
948   InitAnimation();
949   HandleSetupScreen(0,0,0,0,MB_MENU_INITIALIZE);
950 }
951
952 void HandleSetupScreen(int mx, int my, int dx, int dy, int button)
953 {
954   static int choice = 3;
955   static int redraw = TRUE;
956   int x = (mx+32-SX)/32, y = (my+32-SY)/32;
957   int pos_start  = SETUP_SCREEN_POS_START  + 1;
958   int pos_empty1 = SETUP_SCREEN_POS_EMPTY1 + 1;
959   int pos_empty2 = SETUP_SCREEN_POS_EMPTY2 + 1;
960   int pos_end    = SETUP_SCREEN_POS_END    + 1;
961
962   if (button == MB_MENU_INITIALIZE)
963     redraw = TRUE;
964
965   if (redraw)
966   {
967     DrawGraphic(0,choice-1,GFX_KUGEL_ROT);
968     redraw = FALSE;
969   }
970
971   if (button == MB_MENU_INITIALIZE)
972     return;
973
974   if (dx || dy)
975   {
976     if (dy)
977     {
978       x = 1;
979       y = choice+dy;
980     }
981     else
982       x = y = 0;
983
984     if (y >= pos_empty1 && y <= pos_empty2)
985       y = (dy > 0 ? pos_empty2 + 1 : pos_empty1 - 1);
986
987     if (y < pos_start)
988       y = pos_start;
989     else if (y > pos_end)
990       y = pos_end;
991   }
992
993   if (!mx && !my && !dx && !dy)
994   {
995     x = 1;
996     y = choice;
997   }
998
999   if (x==1 && y >= pos_start && y <= pos_end &&
1000       !(y >= pos_empty1 && y <= pos_empty2))
1001   {
1002     if (button)
1003     {
1004       if (y!=choice)
1005       {
1006         DrawGraphic(0,y-1,GFX_KUGEL_ROT);
1007         DrawGraphic(0,choice-1,GFX_KUGEL_BLAU);
1008       }
1009       choice = y;
1010     }
1011     else
1012     {
1013       int yy = y-1;
1014
1015       if (y==3 && sound_status==SOUND_AVAILABLE)
1016       {
1017         if (SETUP_SOUND_ON(local_player->setup))
1018         {
1019           DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE);
1020           DrawText(SX+14*32, SY+(yy+1)*32,"off",FS_BIG,FC_BLUE);
1021           DrawText(SX+14*32, SY+(yy+2)*32,"off",FS_BIG,FC_BLUE);
1022           local_player->setup &= ~SETUP_SOUND_LOOPS;
1023           local_player->setup &= ~SETUP_SOUND_MUSIC;
1024         }
1025         else
1026           DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW);
1027         local_player->setup ^= SETUP_SOUND;
1028       }
1029       else if (y==4 && sound_loops_allowed)
1030       {
1031         if (SETUP_SOUND_LOOPS_ON(local_player->setup))
1032           DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE);
1033         else
1034         {
1035           DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW);
1036           DrawText(SX+14*32, SY+(yy-1)*32,"on ",FS_BIG,FC_YELLOW);
1037           local_player->setup |= SETUP_SOUND;
1038         }
1039         local_player->setup ^= SETUP_SOUND_LOOPS;
1040       }
1041       else if (y==5 && sound_loops_allowed)
1042       {
1043         if (SETUP_SOUND_MUSIC_ON(local_player->setup))
1044           DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE);
1045         else
1046         {
1047           DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW);
1048           DrawText(SX+14*32, SY+(yy-2)*32,"on ",FS_BIG,FC_YELLOW);
1049           local_player->setup |= SETUP_SOUND;
1050         }
1051         local_player->setup ^= SETUP_SOUND_MUSIC;
1052       }
1053       else if (y==6)
1054       {
1055         if (SETUP_TOONS_ON(local_player->setup))
1056           DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE);
1057         else
1058           DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW);
1059         local_player->setup ^= SETUP_TOONS;
1060       }
1061       else if (y==7)
1062       {
1063         if (!SETUP_DIRECT_DRAW_ON(local_player->setup))
1064           DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE);
1065         else
1066           DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW);
1067         local_player->setup ^= SETUP_DIRECT_DRAW;
1068       }
1069       else if (y==8)
1070       {
1071         if (SETUP_SCROLL_DELAY_ON(local_player->setup))
1072           DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE);
1073         else
1074           DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW);
1075         local_player->setup ^= SETUP_SCROLL_DELAY;
1076       }
1077       else if (y==9)
1078       {
1079         if (SETUP_SOFT_SCROLL_ON(local_player->setup))
1080           DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE);
1081         else
1082           DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW);
1083         local_player->setup ^= SETUP_SOFT_SCROLL;
1084       }
1085       else if (y==10)
1086       {
1087         if (SETUP_FADING_ON(local_player->setup))
1088           DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE);
1089         else
1090           DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW);
1091         local_player->setup ^= SETUP_FADING;
1092       }
1093       else if (y==11)
1094       {
1095         if (SETUP_QUICK_DOORS_ON(local_player->setup))
1096           DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE);
1097         else
1098           DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW);
1099         local_player->setup ^= SETUP_QUICK_DOORS;
1100       }
1101       else if (y==12)
1102       {
1103         if (SETUP_AUTO_RECORD_ON(local_player->setup))
1104           DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE);
1105         else
1106           DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW);
1107         local_player->setup ^= SETUP_AUTO_RECORD;
1108       }
1109       else if (y==13)
1110       {
1111         game_status = SETUPINPUT;
1112         DrawSetupInputScreen();
1113         redraw = TRUE;
1114       }
1115       else if (y==pos_end-1 || y==pos_end)
1116       {
1117         if (y==pos_end)
1118         {
1119           SavePlayerInfo(PLAYER_SETUP);
1120           SaveJoystickData();
1121         }
1122
1123         game_status = MAINMENU;
1124         DrawMainMenu();
1125         redraw = TRUE;
1126       }
1127     }
1128   }
1129   BackToFront();
1130
1131   if (game_status==SETUP)
1132     DoAnimation();
1133 }
1134
1135 void DrawSetupInputScreen()
1136 {
1137   ClearWindow();
1138   DrawText(SX+16, SY+16, "SETUP INPUT", FS_BIG, FC_YELLOW);
1139
1140   DrawGraphic(0, 2, GFX_KUGEL_BLAU);
1141   DrawGraphic(0, 3, GFX_KUGEL_BLAU);
1142   DrawGraphic(0, 4, GFX_KUGEL_BLAU);
1143   DrawGraphic(0, 15, GFX_KUGEL_BLAU);
1144   DrawGraphic(10, 2, GFX_PFEIL_L);
1145   DrawGraphic(12, 2, GFX_PFEIL_R);
1146
1147   DrawText(SX+32, SY+2*32, "Player:", FS_BIG, FC_GREEN);
1148   DrawText(SX+32, SY+3*32, "Device:", FS_BIG, FC_GREEN);
1149   DrawText(SX+32, SY+15*32, "Exit", FS_BIG, FC_GREEN);
1150
1151   FadeToFront();
1152   InitAnimation();
1153   HandleSetupInputScreen(0,0,0,0,MB_MENU_INITIALIZE);
1154 }
1155
1156 static void drawPlayerSetupInputInfo(int player_nr)
1157 {
1158   int i;
1159   static struct SetupKeyboardInfo custom_key;
1160   static KeySym *key[] =
1161   {
1162     &custom_key.left,
1163     &custom_key.right,
1164     &custom_key.up,
1165     &custom_key.down,
1166     &custom_key.snap,
1167     &custom_key.bomb
1168   };
1169   static char *joy_text[] =
1170   {
1171     "Joystick Left",
1172     "Joystick Right",
1173     "Joystick Up",
1174     "Joystick Down",
1175     "Button 1",
1176     "Button 2",
1177   };
1178
1179   custom_key = setup.key_input[player_nr];
1180
1181   DrawText(SX+11*32, SY+2*32, int2str(player_nr + 1, 1), FS_BIG, FC_RED);
1182   DrawGraphic(8, 2, GFX_SPIELER1 + player_nr);
1183
1184   if (setup.joy_input[player_nr].use_joystick)
1185   {
1186     DrawText(SX+8*32, SY+3*32,
1187              (setup.joy_input[player_nr].joystick_nr == 0 ?
1188               "Joystick1" : "Joystick2"),
1189              FS_BIG, FC_YELLOW);
1190     DrawText(SX+32, SY+4*32, "Calibrate", FS_BIG, FC_GREEN);
1191   }
1192   else
1193   {
1194     DrawText(SX+8*32, SY+3*32, "Keyboard ", FS_BIG, FC_YELLOW);
1195     DrawText(SX+32, SY+4*32, "Customize", FS_BIG, FC_GREEN);
1196   }
1197
1198   DrawText(SX+32, SY+5*32, "Actual Settings:", FS_BIG, FC_GREEN);
1199   DrawGraphic(1, 6, GFX_PFEIL_L);
1200   DrawGraphic(1, 7, GFX_PFEIL_R);
1201   DrawGraphic(1, 8, GFX_PFEIL_O);
1202   DrawGraphic(1, 9, GFX_PFEIL_U);
1203   DrawText(SX+2*32, SY+6*32, ":", FS_BIG, FC_BLUE);
1204   DrawText(SX+2*32, SY+7*32, ":", FS_BIG, FC_BLUE);
1205   DrawText(SX+2*32, SY+8*32, ":", FS_BIG, FC_BLUE);
1206   DrawText(SX+2*32, SY+9*32, ":", FS_BIG, FC_BLUE);
1207   DrawText(SX+32, SY+10*32, "Snap Field:", FS_BIG, FC_BLUE);
1208   DrawText(SX+32, SY+12*32, "Place Bomb:", FS_BIG, FC_BLUE);
1209
1210   for (i=0; i<6; i++)
1211   {
1212     int ypos = 6 + i + (i > 3 ? i-3 : 0);
1213
1214     DrawText(SX + 3*32, SY + ypos*32,
1215              "              ", FS_BIG, FC_YELLOW);
1216     DrawText(SX + 3*32, SY + ypos*32,
1217              (setup.joy_input[player_nr].use_joystick ?
1218               joy_text[i] :
1219               getKeySymName(*key[i])),
1220              FS_BIG, FC_YELLOW);
1221   }
1222 }
1223
1224 void HandleSetupInputScreen(int mx, int my, int dx, int dy, int button)
1225 {
1226   static int choice = 3;
1227   static int player_nr = 0;
1228   static int redraw = TRUE;
1229   int x = (mx+32-SX)/32, y = (my+32-SY)/32;
1230   int pos_start  = SETUPINPUT_SCREEN_POS_START  + 1;
1231   int pos_empty1 = SETUPINPUT_SCREEN_POS_EMPTY1 + 1;
1232   int pos_empty2 = SETUPINPUT_SCREEN_POS_EMPTY2 + 1;
1233   int pos_end    = SETUPINPUT_SCREEN_POS_END    + 1;
1234
1235   if (button == MB_MENU_INITIALIZE)
1236   {
1237     drawPlayerSetupInputInfo(player_nr);
1238     redraw = TRUE;
1239   }
1240
1241   if (redraw)
1242   {
1243     DrawGraphic(0,choice-1,GFX_KUGEL_ROT);
1244     redraw = FALSE;
1245   }
1246
1247   if (button == MB_MENU_INITIALIZE)
1248     return;
1249
1250   if (dx || dy)
1251   {
1252     if (dx && choice == 3)
1253     {
1254       x = (dx < 0 ? 11 : 13);
1255       y = 3;
1256     }
1257     else if (dx && choice == 4)
1258     {
1259       button = MB_MENU_CHOICE;
1260       x = 1;
1261       y = 4;
1262     }
1263     else if (dy)
1264     {
1265       x = 1;
1266       y = choice + dy;
1267     }
1268     else
1269       x = y = 0;
1270
1271     if (y >= pos_empty1 && y <= pos_empty2)
1272       y = (dy > 0 ? pos_empty2 + 1 : pos_empty1 - 1);
1273
1274     if (y < pos_start)
1275       y = pos_start;
1276     else if (y > pos_end)
1277       y = pos_end;
1278   }
1279
1280   if (!mx && !my && !dx && !dy)
1281   {
1282     x = 1;
1283     y = choice;
1284   }
1285
1286   if (y == 3 && ((x == 1 && !button) || ((x == 11 || x == 13) && button)))
1287   {
1288     static long delay = 0;
1289
1290     if (!DelayReached(&delay,150))
1291       goto out;
1292
1293     player_nr = (player_nr + (x == 11 ? -1 : +1) + MAX_PLAYERS) % MAX_PLAYERS;
1294
1295     drawPlayerSetupInputInfo(player_nr);
1296   }
1297   else if (x==1 && y >= pos_start && y <= pos_end &&
1298            !(y >= pos_empty1 && y <= pos_empty2))
1299   {
1300     if (button)
1301     {
1302       if (y != choice)
1303       {
1304         DrawGraphic(0, y-1, GFX_KUGEL_ROT);
1305         DrawGraphic(0, choice-1, GFX_KUGEL_BLAU);
1306       }
1307       choice = y;
1308     }
1309     else
1310     {
1311       if (y == 4)
1312       {
1313         int one_joystick_nr       = (dx >= 0 ? 0 : 1);
1314         int the_other_joystick_nr = (dx >= 0 ? 1 : 0);
1315
1316         if (setup.joy_input[player_nr].use_joystick)
1317         {
1318           if (setup.joy_input[player_nr].joystick_nr == one_joystick_nr)
1319             setup.joy_input[player_nr].joystick_nr = the_other_joystick_nr;
1320           else
1321             setup.joy_input[player_nr].use_joystick = FALSE;
1322         }
1323         else
1324         {
1325           setup.joy_input[player_nr].use_joystick = TRUE;
1326           setup.joy_input[player_nr].joystick_nr = one_joystick_nr;
1327         }
1328
1329         drawPlayerSetupInputInfo(player_nr);
1330       }
1331       else if (y == 5)
1332       {
1333         if (setup.joy_input[player_nr].use_joystick)
1334           CalibrateJoystick(setup.joy_input[player_nr].joystick_nr);
1335         else
1336           CustomizeKeyboard(player_nr);
1337
1338         redraw = TRUE;
1339       }
1340       else if (y == pos_end)
1341       {
1342         game_status = SETUP;
1343         DrawSetupScreen();
1344         redraw = TRUE;
1345       }
1346     }
1347   }
1348   BackToFront();
1349
1350   out:
1351
1352   if (game_status == SETUPINPUT)
1353     DoAnimation();
1354 }
1355
1356 void CustomizeKeyboard(int player_nr)
1357 {
1358   int i;
1359   int step_nr;
1360   boolean finished = FALSE;
1361   static struct SetupKeyboardInfo custom_key;
1362   static struct
1363   {
1364     KeySym *keysym;
1365     char *text;
1366   } customize_step[] =
1367   {
1368     { &custom_key.left,  "Move Left"  },
1369     { &custom_key.right, "Move Right" },
1370     { &custom_key.up,    "Move Up"    },
1371     { &custom_key.down,  "Move Down"  },
1372     { &custom_key.snap,  "Snap Field" },
1373     { &custom_key.bomb,  "Place Bomb" }
1374   };
1375
1376   /* read existing key bindings from player setup */
1377   custom_key = setup.key_input[player_nr];
1378
1379   ClearWindow();
1380   DrawText(SX + 16, SY + 16, "Keyboard Input", FS_BIG, FC_YELLOW);
1381
1382   BackToFront();
1383   InitAnimation();
1384
1385   step_nr = 0;
1386   DrawText(SX, SY + (2+2*step_nr)*32,
1387            customize_step[step_nr].text, FS_BIG, FC_RED);
1388   DrawText(SX, SY + (2+2*step_nr+1)*32,
1389            "Key:", FS_BIG, FC_RED);
1390   DrawText(SX + 4*32, SY + (2+2*step_nr+1)*32,
1391            getKeySymName(*customize_step[step_nr].keysym), FS_BIG, FC_BLUE);
1392
1393   while(!finished)
1394   {
1395     if (XPending(display))      /* got event from X server */
1396     {
1397       XEvent event;
1398
1399       XNextEvent(display, &event);
1400
1401       switch(event.type)
1402       {
1403         case KeyPress:
1404           {
1405             KeySym key = XLookupKeysym((XKeyEvent *)&event,
1406                                        ((XKeyEvent *)&event)->state);
1407
1408             if (key == XK_Escape || (key == XK_Return && step_nr == 6))
1409             {
1410               finished = TRUE;
1411               break;
1412             }
1413
1414             /* press 'Enter' to keep the existing key binding */
1415             if (key == XK_Return || step_nr == 6)
1416               key = *customize_step[step_nr].keysym;
1417
1418             /* check if key already used */
1419             for (i=0; i<step_nr; i++)
1420               if (*customize_step[i].keysym == key)
1421                 break;
1422             if (i < step_nr)
1423               break;
1424
1425             /* got new key binding */
1426             *customize_step[step_nr].keysym = key;
1427             DrawText(SX + 4*32, SY + (2+2*step_nr+1)*32,
1428                      "             ", FS_BIG, FC_YELLOW);
1429             DrawText(SX + 4*32, SY + (2+2*step_nr+1)*32,
1430                      getKeySymName(key), FS_BIG, FC_YELLOW);
1431             step_nr++;
1432
1433             /* un-highlight last query */
1434             DrawText(SX, SY+(2+2*(step_nr-1))*32,
1435                      customize_step[step_nr-1].text, FS_BIG, FC_GREEN);
1436             DrawText(SX, SY+(2+2*(step_nr-1)+1)*32,
1437                      "Key:", FS_BIG, FC_GREEN);
1438
1439             /* press 'Enter' to leave */
1440             if (step_nr == 6)
1441             {
1442               DrawText(SX + 16, SY + 15*32+16,
1443                        "Press Enter", FS_BIG, FC_YELLOW);
1444               break;
1445             }
1446
1447             /* query next key binding */
1448             DrawText(SX, SY+(2+2*step_nr)*32,
1449                      customize_step[step_nr].text, FS_BIG, FC_RED);
1450             DrawText(SX, SY+(2+2*step_nr+1)*32,
1451                      "Key:", FS_BIG, FC_RED);
1452             DrawText(SX + 4*32, SY+(2+2*step_nr+1)*32,
1453                      getKeySymName(*customize_step[step_nr].keysym),
1454                      FS_BIG, FC_BLUE);
1455           }
1456           break;
1457
1458         case KeyRelease:
1459           key_joystick_mapping = 0;
1460           break;
1461
1462         default:
1463           HandleOtherEvents(&event);
1464           break;
1465       }
1466     }
1467
1468     BackToFront();
1469     DoAnimation();
1470
1471     /* don't eat all CPU time */
1472     Delay(10);
1473   }
1474
1475   /* write new key bindings back to player setup */
1476   setup.key_input[player_nr] = custom_key;
1477
1478   StopAnimation();
1479   DrawSetupInputScreen();
1480 }
1481
1482 void CalibrateJoystick(int joystick_nr)
1483 {
1484 #ifdef __FreeBSD__
1485   struct joystick joy_ctrl;
1486 #else
1487   struct joystick_control
1488   {
1489     int buttons;
1490     int x;
1491     int y;
1492   } joy_ctrl;
1493 #endif
1494
1495 #ifdef MSDOS
1496   char joy_nr[4];
1497 #endif
1498
1499   int new_joystick_xleft = 128, new_joystick_xright = 128;
1500   int new_joystick_yupper = 128, new_joystick_ylower = 128;
1501   int new_joystick_xmiddle, new_joystick_ymiddle;
1502   int x, y, last_x, last_y, xpos = 8, ypos = 3;
1503   boolean check[3][3];
1504   int check_remaining = 3 * 3;
1505   int joy;
1506   int result = -1;
1507
1508   if (joystick_status == JOYSTICK_OFF)
1509     return;
1510
1511   ClearWindow();
1512   DrawText(SX,      SY +  6*32, " ROTATE JOYSTICK ",FS_BIG,FC_YELLOW);
1513   DrawText(SX,      SY +  7*32, "IN ALL DIRECTIONS",FS_BIG,FC_YELLOW);
1514   DrawText(SX + 16, SY +  9*32, "  IF ALL BALLS  ",FS_BIG,FC_YELLOW);
1515   DrawText(SX,      SY + 10*32, "   ARE YELLOW,   ",FS_BIG,FC_YELLOW);
1516   DrawText(SX,      SY + 11*32, "  PRESS BUTTON!  ",FS_BIG,FC_YELLOW);
1517
1518   for(y=0; y<3; y++)
1519   {
1520     for(x=0; x<3; x++)
1521     {
1522       check[x][y] = FALSE;
1523       DrawGraphic(xpos + x - 1, ypos + y - 1, GFX_KUGEL_BLAU);
1524     }
1525   }
1526
1527   joy = Joystick();
1528   last_x = (joy & JOY_LEFT ? -1 : joy & JOY_RIGHT ? +1 : 0);
1529   last_y = (joy & JOY_UP   ? -1 : joy & JOY_DOWN  ? +1 : 0);
1530   DrawGraphic(xpos + last_x, ypos + last_y, GFX_KUGEL_ROT);
1531
1532   BackToFront();
1533
1534 #ifdef __FreeBSD__
1535   joy_ctrl.b1 = joy_ctrl.b2 = 0;
1536 #else
1537   joy_ctrl.buttons = 0;
1538 #endif
1539
1540   while(Joystick() & JOY_BUTTON);
1541
1542   InitAnimation();
1543
1544   while(result < 0)
1545   {
1546     if (XPending(display))      /* got event from X server */
1547     {
1548       XEvent event;
1549
1550       XNextEvent(display, &event);
1551
1552       switch(event.type)
1553       {
1554         case KeyPress:
1555           switch(XLookupKeysym((XKeyEvent *)&event,
1556                                ((XKeyEvent *)&event)->state))
1557           {
1558             case XK_Return:
1559               if (check_remaining == 0)
1560                 result = 1;
1561               break;
1562
1563             case XK_Escape:
1564               result = 0;
1565               break;
1566
1567             default:
1568               break;
1569           }
1570           break;
1571
1572         case KeyRelease:
1573           key_joystick_mapping = 0;
1574           break;
1575
1576         default:
1577           HandleOtherEvents(&event);
1578           break;
1579       }
1580     }
1581
1582     if (read(joystick_device, &joy_ctrl, sizeof(joy_ctrl)) != sizeof(joy_ctrl))
1583     {
1584       joystick_status = JOYSTICK_OFF;
1585       goto error_out;
1586     }
1587
1588     new_joystick_xleft  = MIN(new_joystick_xleft,  joy_ctrl.x);
1589     new_joystick_xright = MAX(new_joystick_xright, joy_ctrl.x);
1590     new_joystick_yupper = MIN(new_joystick_yupper, joy_ctrl.y);
1591     new_joystick_ylower = MAX(new_joystick_ylower, joy_ctrl.y);
1592
1593     new_joystick_xmiddle =
1594       new_joystick_xleft + (new_joystick_xright - new_joystick_xleft) / 2;
1595     new_joystick_ymiddle =
1596       new_joystick_yupper + (new_joystick_ylower - new_joystick_yupper) / 2;
1597
1598     joystick[joystick_nr].xleft = new_joystick_xleft;
1599     joystick[joystick_nr].yupper = new_joystick_yupper;
1600     joystick[joystick_nr].xright = new_joystick_xright;
1601     joystick[joystick_nr].ylower = new_joystick_ylower;
1602     joystick[joystick_nr].xmiddle = new_joystick_xmiddle;
1603     joystick[joystick_nr].ymiddle = new_joystick_ymiddle;
1604
1605     CheckJoystickData();
1606
1607     joy = Joystick();
1608
1609     if (joy & JOY_BUTTON && check_remaining == 0)
1610       result = 1;
1611
1612     x = (joy & JOY_LEFT ? -1 : joy & JOY_RIGHT ? +1 : 0);
1613     y = (joy & JOY_UP   ? -1 : joy & JOY_DOWN  ? +1 : 0);
1614
1615     if (x != last_x || y != last_y)
1616     {
1617       DrawGraphic(xpos + last_x, ypos + last_y, GFX_KUGEL_GELB);
1618       DrawGraphic(xpos + x,      ypos + y,      GFX_KUGEL_ROT);
1619
1620       last_x = x;
1621       last_y = y;
1622
1623       if (check_remaining > 0 && !check[x+1][y+1])
1624       {
1625         check[x+1][y+1] = TRUE;
1626         check_remaining--;
1627       }
1628
1629 #if 0
1630       printf("LEFT / MIDDLE / RIGHT == %d / %d / %d\n",
1631              joystick[joystick_nr].xleft,
1632              joystick[joystick_nr].xmiddle,
1633              joystick[joystick_nr].xright);
1634       printf("UP / MIDDLE / DOWN == %d / %d / %d\n",
1635              joystick[joystick_nr].yupper,
1636              joystick[joystick_nr].ymiddle,
1637              joystick[joystick_nr].ylower);
1638 #endif
1639     }
1640
1641     BackToFront();
1642     DoAnimation();
1643
1644     /* don't eat all CPU time */
1645     Delay(10);
1646   }
1647
1648   StopAnimation();
1649
1650   DrawSetupInputScreen();
1651   while(Joystick() & JOY_BUTTON);
1652   return;
1653
1654   error_out:
1655
1656   ClearWindow();
1657   DrawText(SX+16, SY+16, "NO JOYSTICK",FS_BIG,FC_YELLOW);
1658   DrawText(SX+16, SY+48, " AVAILABLE ",FS_BIG,FC_YELLOW);
1659   BackToFront();
1660   Delay(3000);
1661   DrawSetupInputScreen();
1662 }
1663
1664 void CalibrateJoystick_OLD()
1665 {
1666 #ifdef __FreeBSD__
1667   struct joystick joy_ctrl;
1668 #else
1669   struct joystick_control
1670   {
1671     int buttons;
1672     int x;
1673     int y;
1674   } joy_ctrl;
1675 #endif
1676
1677 #ifdef MSDOS
1678   char joy_nr[4];
1679 #endif
1680
1681   int joystick_nr = setup.joy_input[0].joystick_nr;
1682   int new_joystick_xleft, new_joystick_xright, new_joystick_xmiddle;
1683   int new_joystick_yupper, new_joystick_ylower, new_joystick_ymiddle;
1684
1685   if (joystick_status == JOYSTICK_OFF)
1686     goto error_out;
1687
1688 #ifndef MSDOS
1689   ClearWindow();
1690   DrawText(SX+16, SY+7*32, "MOVE JOYSTICK TO",FS_BIG,FC_YELLOW);
1691   DrawText(SX+16, SY+8*32, " THE UPPER LEFT ",FS_BIG,FC_YELLOW);
1692   DrawText(SX+16, SY+9*32, "AND PRESS BUTTON",FS_BIG,FC_YELLOW);
1693   BackToFront();
1694
1695 #ifdef __FreeBSD__
1696   joy_ctrl.b1 = joy_ctrl.b2 = 0;
1697 #else
1698   joy_ctrl.buttons = 0;
1699 #endif
1700   while(Joystick() & JOY_BUTTON);
1701 #ifdef __FreeBSD__
1702   while(!(joy_ctrl.b1 || joy_ctrl.b2))
1703 #else
1704   while(!joy_ctrl.buttons)
1705 #endif
1706   {
1707     if (read(joystick_device, &joy_ctrl, sizeof(joy_ctrl)) != sizeof(joy_ctrl))
1708     {
1709       joystick_status=JOYSTICK_OFF;
1710       goto error_out;
1711     }
1712     Delay(10);
1713   }
1714
1715   new_joystick_xleft = joy_ctrl.x;
1716   new_joystick_yupper = joy_ctrl.y;
1717
1718   ClearWindow();
1719   DrawText(SX+16, SY+7*32, "MOVE JOYSTICK TO",FS_BIG,FC_YELLOW);
1720   DrawText(SX+32, SY+8*32, "THE LOWER RIGHT",FS_BIG,FC_YELLOW);
1721   DrawText(SX+16, SY+9*32, "AND PRESS BUTTON",FS_BIG,FC_YELLOW);
1722   BackToFront();
1723
1724 #ifdef __FreeBSD__
1725   joy_ctrl.b1 = joy_ctrl.b2 = 0;
1726 #else
1727   joy_ctrl.buttons = 0;
1728 #endif
1729   while(Joystick() & JOY_BUTTON);
1730 #ifdef __FreeBSD__
1731   while(!(joy_ctrl.b1 || joy_ctrl.b2))
1732 #else
1733   while(!joy_ctrl.buttons)
1734 #endif
1735   {
1736     if (read(joystick_device, &joy_ctrl, sizeof(joy_ctrl)) != sizeof(joy_ctrl))
1737     {
1738       joystick_status=JOYSTICK_OFF;
1739       goto error_out;
1740     }
1741     Delay(10);
1742   }
1743
1744   new_joystick_xright = joy_ctrl.x;
1745   new_joystick_ylower = joy_ctrl.y;
1746
1747   ClearWindow();
1748   DrawText(SX+32, SY+16+7*32, "CENTER JOYSTICK",FS_BIG,FC_YELLOW);
1749   DrawText(SX+16, SY+16+8*32, "AND PRESS BUTTON",FS_BIG,FC_YELLOW);
1750   BackToFront();
1751
1752 #ifdef __FreeBSD__
1753   joy_ctrl.b1 = joy_ctrl.b2 = 0;
1754 #else
1755   joy_ctrl.buttons = 0;
1756 #endif
1757   while(Joystick() & JOY_BUTTON);
1758 #ifdef __FreeBSD__
1759   while(!(joy_ctrl.b1 || joy_ctrl.b2))
1760 #else
1761   while(!joy_ctrl.buttons)
1762 #endif
1763   {
1764     if (read(joystick_device, &joy_ctrl, sizeof(joy_ctrl)) != sizeof(joy_ctrl))
1765     {
1766       joystick_status=JOYSTICK_OFF;
1767       goto error_out;
1768     }
1769     Delay(10);
1770   }
1771
1772   new_joystick_xmiddle = joy_ctrl.x;
1773   new_joystick_ymiddle = joy_ctrl.y;
1774
1775   joystick[joystick_nr].xleft = new_joystick_xleft;
1776   joystick[joystick_nr].yupper = new_joystick_yupper;
1777   joystick[joystick_nr].xright = new_joystick_xright;
1778   joystick[joystick_nr].ylower = new_joystick_ylower;
1779   joystick[joystick_nr].xmiddle = new_joystick_xmiddle;
1780   joystick[joystick_nr].ymiddle = new_joystick_ymiddle;
1781
1782   CheckJoystickData();
1783
1784   DrawSetupScreen();
1785   while(Joystick() & JOY_BUTTON);
1786   return;
1787
1788 #endif
1789   error_out:
1790
1791 #ifdef MSDOS
1792   joy_nr[0] = '#';
1793   joy_nr[1] = SETUP_2ND_JOYSTICK_ON(local_player->setup)+49;
1794   joy_nr[2] = '\0';
1795
1796   remove_joystick();
1797   ClearWindow();
1798   DrawText(SX+32, SY+7*32, "CENTER JOYSTICK",FS_BIG,FC_YELLOW);
1799   DrawText(SX+16+7*32, SY+8*32, joy_nr, FS_BIG,FC_YELLOW);
1800   DrawText(SX+32, SY+9*32, "AND PRESS A KEY",FS_BIG,FC_YELLOW);
1801   BackToFront();
1802
1803   for(clear_keybuf();!keypressed(););
1804   install_joystick(JOY_TYPE_2PADS);
1805
1806   ClearWindow();
1807   DrawText(SX+16, SY+7*32, "MOVE JOYSTICK TO",FS_BIG,FC_YELLOW);
1808   DrawText(SX+16, SY+8*32, " THE UPPER LEFT ",FS_BIG,FC_YELLOW);
1809   DrawText(SX+32, SY+9*32, "AND PRESS A KEY",FS_BIG,FC_YELLOW);
1810   BackToFront();
1811
1812   for(clear_keybuf();!keypressed(););
1813   calibrate_joystick(SETUP_2ND_JOYSTICK_ON(local_player->setup));
1814
1815   ClearWindow();
1816   DrawText(SX+16, SY+7*32, "MOVE JOYSTICK TO",FS_BIG,FC_YELLOW);
1817   DrawText(SX+32, SY+8*32, "THE LOWER RIGHT",FS_BIG,FC_YELLOW);
1818   DrawText(SX+32, SY+9*32, "AND PRESS A KEY",FS_BIG,FC_YELLOW);
1819   BackToFront();
1820
1821   for(clear_keybuf();!keypressed(););
1822   calibrate_joystick(SETUP_2ND_JOYSTICK_ON(local_player->setup));
1823
1824   DrawSetupScreen();
1825   return;
1826 #endif
1827
1828   ClearWindow();
1829   DrawText(SX+16, SY+16, "NO JOYSTICK",FS_BIG,FC_YELLOW);
1830   DrawText(SX+16, SY+48, " AVAILABLE ",FS_BIG,FC_YELLOW);
1831   BackToFront();
1832   Delay(3000);
1833   DrawSetupScreen();
1834 }
1835
1836 void HandleGameActions(byte player_action)
1837 {
1838   if (game_status != PLAYING)
1839     return;
1840
1841   if (local_player->LevelSolved)
1842     GameWon();
1843
1844   if (AllPlayersGone && !TAPE_IS_STOPPED(tape))
1845     TapeStop();
1846
1847   GameActions(player_action);
1848
1849   BackToFront();
1850 }
1851
1852 void HandleVideoButtons(int mx, int my, int button)
1853 {
1854   if (game_status != MAINMENU && game_status != PLAYING)
1855     return;
1856
1857   switch(CheckVideoButtons(mx,my,button))
1858   {
1859     case BUTTON_VIDEO_EJECT:
1860       TapeStop();
1861       if (TAPE_IS_EMPTY(tape))
1862       {
1863         LoadLevelTape(level_nr);
1864         if (TAPE_IS_EMPTY(tape))
1865           Request("No tape for this level !",REQ_CONFIRM);
1866       }
1867       else
1868       {
1869         if (tape.changed)
1870           SaveLevelTape(tape.level_nr);
1871         TapeErase();
1872       }
1873       DrawCompleteVideoDisplay();
1874       break;
1875
1876     case BUTTON_VIDEO_STOP:
1877       TapeStop();
1878       break;
1879
1880     case BUTTON_VIDEO_PAUSE:
1881       TapeTogglePause();
1882       break;
1883
1884     case BUTTON_VIDEO_REC:
1885       if (TAPE_IS_STOPPED(tape))
1886       {
1887         TapeStartRecording();
1888
1889         if (options.network)
1890           SendToServer_StartPlaying();
1891         else
1892         {
1893           game_status = PLAYING;
1894           InitGame();
1895         }
1896       }
1897       else if (tape.pausing)
1898       {
1899         if (tape.playing)       /* PLAYING -> PAUSING -> RECORDING */
1900         {
1901           tape.pos[tape.counter].delay = tape.delay_played;
1902           tape.playing = FALSE;
1903           tape.recording = TRUE;
1904           tape.changed = TRUE;
1905
1906           DrawVideoDisplay(VIDEO_STATE_PLAY_OFF | VIDEO_STATE_REC_ON,0);
1907         }
1908         else
1909           TapeTogglePause();
1910       }
1911       break;
1912
1913     case BUTTON_VIDEO_PLAY:
1914       if (TAPE_IS_EMPTY(tape))
1915         break;
1916
1917       if (TAPE_IS_STOPPED(tape))
1918       {
1919         TapeStartPlaying();
1920
1921         game_status = PLAYING;
1922         InitGame();
1923       }
1924       else if (tape.playing)
1925       {
1926         if (tape.pausing)                       /* PAUSE -> PLAY */
1927           TapeTogglePause();
1928         else if (!tape.fast_forward)            /* PLAY -> FAST FORWARD PLAY */
1929         {
1930           tape.fast_forward = TRUE;
1931           DrawVideoDisplay(VIDEO_STATE_FFWD_ON, 0);
1932         }
1933         else if (!tape.pause_before_death)      /* FFWD PLAY -> + AUTO PAUSE */
1934         {
1935           tape.pause_before_death = TRUE;
1936           DrawVideoDisplay(VIDEO_STATE_PAUSE_ON, VIDEO_DISPLAY_LABEL_ONLY);
1937         }
1938         else                                    /* -> NORMAL PLAY */
1939         {
1940           tape.fast_forward = FALSE;
1941           tape.pause_before_death = FALSE;
1942           DrawVideoDisplay(VIDEO_STATE_FFWD_OFF | VIDEO_STATE_PAUSE_OFF, 0);
1943         }
1944       }
1945       break;
1946
1947     default:
1948       break;
1949   }
1950
1951   BackToFront();
1952 }
1953
1954 void HandleSoundButtons(int mx, int my, int button)
1955 {
1956   if (game_status != PLAYING)
1957     return;
1958
1959   switch(CheckSoundButtons(mx,my,button))
1960   {
1961     case BUTTON_SOUND_MUSIC:
1962       if (setup.sound_music_on)
1963       { 
1964         setup.sound_music_on = FALSE;
1965         local_player->setup &= ~SETUP_SOUND_MUSIC;
1966         FadeSound(background_loop[level_nr % num_bg_loops]);
1967         DrawSoundDisplay(BUTTON_SOUND_MUSIC_OFF);
1968       }
1969       else if (sound_loops_allowed)
1970       { 
1971         setup.sound_on = setup.sound_music_on = TRUE;
1972         local_player->setup |= (SETUP_SOUND | SETUP_SOUND_MUSIC);
1973         PlaySoundLoop(background_loop[level_nr % num_bg_loops]);
1974         DrawSoundDisplay(BUTTON_SOUND_MUSIC_ON);
1975       }
1976       else
1977         DrawSoundDisplay(BUTTON_SOUND_MUSIC_OFF);
1978       break;
1979
1980     case BUTTON_SOUND_LOOPS:
1981       if (setup.sound_loops_on)
1982       { 
1983         setup.sound_loops_on = FALSE;
1984         local_player->setup &= ~SETUP_SOUND_LOOPS;
1985         DrawSoundDisplay(BUTTON_SOUND_LOOPS_OFF);
1986       }
1987       else if (sound_loops_allowed)
1988       { 
1989         setup.sound_on = setup.sound_loops_on = TRUE;
1990         local_player->setup |= (SETUP_SOUND | SETUP_SOUND_LOOPS);
1991         DrawSoundDisplay(BUTTON_SOUND_LOOPS_ON);
1992       }
1993       else
1994         DrawSoundDisplay(BUTTON_SOUND_LOOPS_OFF);
1995       break;
1996
1997     case BUTTON_SOUND_SIMPLE:
1998       if (setup.sound_simple_on)
1999       { 
2000         setup.sound_simple_on = FALSE;
2001         local_player->setup &= ~SETUP_SOUND;
2002         DrawSoundDisplay(BUTTON_SOUND_SIMPLE_OFF);
2003       }
2004       else if (sound_status==SOUND_AVAILABLE)
2005       { 
2006         setup.sound_on = setup.sound_simple_on = TRUE;
2007         local_player->setup |= SETUP_SOUND;
2008         DrawSoundDisplay(BUTTON_SOUND_SIMPLE_ON);
2009       }
2010       else
2011         DrawSoundDisplay(BUTTON_SOUND_SIMPLE_OFF);
2012       break;
2013
2014     default:
2015       break;
2016   }
2017
2018   BackToFront();
2019 }
2020
2021 void HandleGameButtons(int mx, int my, int button)
2022 {
2023   if (game_status != PLAYING)
2024     return;
2025
2026   switch(CheckGameButtons(mx,my,button))
2027   {
2028     case BUTTON_GAME_STOP:
2029       if (AllPlayersGone)
2030       {
2031         CloseDoor(DOOR_CLOSE_1);
2032         game_status = MAINMENU;
2033         DrawMainMenu();
2034         break;
2035       }
2036
2037       if (Request("Do you really want to quit the game ?",
2038                   REQ_ASK | REQ_STAY_CLOSED))
2039       { 
2040         if (options.network)
2041           SendToServer_StopPlaying();
2042         else
2043         {
2044           game_status = MAINMENU;
2045           DrawMainMenu();
2046         }
2047       }
2048       else
2049         OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2050       break;
2051
2052     case BUTTON_GAME_PAUSE:
2053       if (options.network)
2054       {
2055         if (tape.pausing)
2056           SendToServer_ContinuePlaying();
2057         else
2058           SendToServer_PausePlaying();
2059       }
2060       else
2061         TapeTogglePause();
2062
2063       /*
2064       if (tape.pausing)
2065       {
2066         if (options.network)
2067           SendToServer_ContinuePlaying();
2068         else
2069         {
2070           tape.pausing = FALSE;
2071           DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0);
2072         }
2073       }
2074       else
2075       {
2076         if (options.network)
2077           SendToServer_PausePlaying();
2078         else
2079         {
2080           tape.pausing = TRUE;
2081           DrawVideoDisplay(VIDEO_STATE_PAUSE_ON,0);
2082         }
2083       }
2084       */
2085
2086       break;
2087
2088     case BUTTON_GAME_PLAY:
2089       if (tape.pausing)
2090       {
2091         if (options.network)
2092           SendToServer_ContinuePlaying();
2093         else
2094         {
2095           tape.pausing = FALSE;
2096           DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0);
2097         }
2098       }
2099       break;
2100
2101     default:
2102       break;
2103   }
2104
2105   BackToFront();
2106 }