rnd-19981024-1
[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 struct
1161   {
1162     KeySym *keysym;
1163     char *text;
1164   } custom[] =
1165   {
1166     { &custom_key.left,  "Joystick Left"  },
1167     { &custom_key.right, "Joystick Right" },
1168     { &custom_key.up,    "Joystick Up"    },
1169     { &custom_key.down,  "Joystick Down"  },
1170     { &custom_key.snap,  "Button 1"       },
1171     { &custom_key.bomb,  "Button 2"       }
1172   };
1173
1174   custom_key = setup.input[player_nr].key;
1175
1176   DrawText(SX+11*32, SY+2*32, int2str(player_nr + 1, 1), FS_BIG, FC_RED);
1177   DrawGraphic(8, 2, GFX_SPIELER1 + player_nr);
1178
1179   if (setup.input[player_nr].use_joystick)
1180   {
1181     DrawText(SX+8*32, SY+3*32,
1182              (setup.input[player_nr].joystick_nr == 0 ?
1183               "Joystick1" : "Joystick2"),
1184              FS_BIG, FC_YELLOW);
1185     DrawText(SX+32, SY+4*32, "Calibrate", FS_BIG, FC_GREEN);
1186   }
1187   else
1188   {
1189     DrawText(SX+8*32, SY+3*32, "Keyboard ", FS_BIG, FC_YELLOW);
1190     DrawText(SX+32, SY+4*32, "Customize", FS_BIG, FC_GREEN);
1191   }
1192
1193   DrawText(SX+32, SY+5*32, "Actual Settings:", FS_BIG, FC_GREEN);
1194   DrawGraphic(1, 6, GFX_PFEIL_L);
1195   DrawGraphic(1, 7, GFX_PFEIL_R);
1196   DrawGraphic(1, 8, GFX_PFEIL_O);
1197   DrawGraphic(1, 9, GFX_PFEIL_U);
1198   DrawText(SX+2*32, SY+6*32, ":", FS_BIG, FC_BLUE);
1199   DrawText(SX+2*32, SY+7*32, ":", FS_BIG, FC_BLUE);
1200   DrawText(SX+2*32, SY+8*32, ":", FS_BIG, FC_BLUE);
1201   DrawText(SX+2*32, SY+9*32, ":", FS_BIG, FC_BLUE);
1202   DrawText(SX+32, SY+10*32, "Snap Field:", FS_BIG, FC_BLUE);
1203   DrawText(SX+32, SY+12*32, "Place Bomb:", FS_BIG, FC_BLUE);
1204
1205   for (i=0; i<6; i++)
1206   {
1207     int ypos = 6 + i + (i > 3 ? i-3 : 0);
1208
1209     DrawText(SX + 3*32, SY + ypos*32,
1210              "              ", FS_BIG, FC_YELLOW);
1211     DrawText(SX + 3*32, SY + ypos*32,
1212              (setup.input[player_nr].use_joystick ?
1213               custom[i].text :
1214               getKeySymName(*custom[i].keysym)),
1215              FS_BIG, FC_YELLOW);
1216   }
1217 }
1218
1219 void HandleSetupInputScreen(int mx, int my, int dx, int dy, int button)
1220 {
1221   static int choice = 3;
1222   static int player_nr = 0;
1223   static int redraw = TRUE;
1224   int x = (mx+32-SX)/32, y = (my+32-SY)/32;
1225   int pos_start  = SETUPINPUT_SCREEN_POS_START  + 1;
1226   int pos_empty1 = SETUPINPUT_SCREEN_POS_EMPTY1 + 1;
1227   int pos_empty2 = SETUPINPUT_SCREEN_POS_EMPTY2 + 1;
1228   int pos_end    = SETUPINPUT_SCREEN_POS_END    + 1;
1229
1230   if (button == MB_MENU_INITIALIZE)
1231   {
1232     drawPlayerSetupInputInfo(player_nr);
1233     redraw = TRUE;
1234   }
1235
1236   if (redraw)
1237   {
1238     DrawGraphic(0,choice-1,GFX_KUGEL_ROT);
1239     redraw = FALSE;
1240   }
1241
1242   if (button == MB_MENU_INITIALIZE)
1243     return;
1244
1245   if (dx || dy)
1246   {
1247     if (dx && choice == 3)
1248     {
1249       x = (dx < 0 ? 11 : 13);
1250       y = 3;
1251     }
1252     else if (dx && choice == 4)
1253     {
1254       button = MB_MENU_CHOICE;
1255       x = 1;
1256       y = 4;
1257     }
1258     else if (dy)
1259     {
1260       x = 1;
1261       y = choice + dy;
1262     }
1263     else
1264       x = y = 0;
1265
1266     if (y >= pos_empty1 && y <= pos_empty2)
1267       y = (dy > 0 ? pos_empty2 + 1 : pos_empty1 - 1);
1268
1269     if (y < pos_start)
1270       y = pos_start;
1271     else if (y > pos_end)
1272       y = pos_end;
1273   }
1274
1275   if (!mx && !my && !dx && !dy)
1276   {
1277     x = 1;
1278     y = choice;
1279   }
1280
1281   if (y == 3 && ((x == 1 && !button) || ((x == 11 || x == 13) && button)))
1282   {
1283     static long delay = 0;
1284
1285     if (!DelayReached(&delay,150))
1286       goto out;
1287
1288     player_nr = (player_nr + (x == 11 ? -1 : +1) + MAX_PLAYERS) % MAX_PLAYERS;
1289
1290     drawPlayerSetupInputInfo(player_nr);
1291   }
1292   else if (x==1 && y >= pos_start && y <= pos_end &&
1293            !(y >= pos_empty1 && y <= pos_empty2))
1294   {
1295     if (button)
1296     {
1297       if (y != choice)
1298       {
1299         DrawGraphic(0, y-1, GFX_KUGEL_ROT);
1300         DrawGraphic(0, choice-1, GFX_KUGEL_BLAU);
1301       }
1302       choice = y;
1303     }
1304     else
1305     {
1306       if (y == 4)
1307       {
1308         int one_joystick_nr       = (dx >= 0 ? 0 : 1);
1309         int the_other_joystick_nr = (dx >= 0 ? 1 : 0);
1310
1311         if (setup.input[player_nr].use_joystick)
1312         {
1313           if (setup.input[player_nr].joystick_nr == one_joystick_nr)
1314             setup.input[player_nr].joystick_nr = the_other_joystick_nr;
1315           else
1316             setup.input[player_nr].use_joystick = FALSE;
1317         }
1318         else
1319         {
1320           setup.input[player_nr].use_joystick = TRUE;
1321           setup.input[player_nr].joystick_nr = one_joystick_nr;
1322         }
1323
1324         drawPlayerSetupInputInfo(player_nr);
1325       }
1326       else if (y == 5)
1327       {
1328         if (setup.input[player_nr].use_joystick)
1329           CalibrateJoystick(setup.input[player_nr].joystick_nr);
1330         else
1331           CustomizeKeyboard(player_nr);
1332
1333         redraw = TRUE;
1334       }
1335       else if (y == pos_end)
1336       {
1337         game_status = SETUP;
1338         DrawSetupScreen();
1339         redraw = TRUE;
1340       }
1341     }
1342   }
1343   BackToFront();
1344
1345   out:
1346
1347   if (game_status == SETUPINPUT)
1348     DoAnimation();
1349 }
1350
1351 void CustomizeKeyboard(int player_nr)
1352 {
1353   int i;
1354   int step_nr;
1355   boolean finished = FALSE;
1356   static struct SetupKeyboardInfo custom_key;
1357   static struct
1358   {
1359     KeySym *keysym;
1360     char *text;
1361   } customize_step[] =
1362   {
1363     { &custom_key.left,  "Move Left"  },
1364     { &custom_key.right, "Move Right" },
1365     { &custom_key.up,    "Move Up"    },
1366     { &custom_key.down,  "Move Down"  },
1367     { &custom_key.snap,  "Snap Field" },
1368     { &custom_key.bomb,  "Place Bomb" }
1369   };
1370
1371   /* read existing key bindings from player setup */
1372   custom_key = setup.input[player_nr].key;
1373
1374   ClearWindow();
1375   DrawText(SX + 16, SY + 16, "Keyboard Input", FS_BIG, FC_YELLOW);
1376
1377   BackToFront();
1378   InitAnimation();
1379
1380   step_nr = 0;
1381   DrawText(SX, SY + (2+2*step_nr)*32,
1382            customize_step[step_nr].text, FS_BIG, FC_RED);
1383   DrawText(SX, SY + (2+2*step_nr+1)*32,
1384            "Key:", FS_BIG, FC_RED);
1385   DrawText(SX + 4*32, SY + (2+2*step_nr+1)*32,
1386            getKeySymName(*customize_step[step_nr].keysym), FS_BIG, FC_BLUE);
1387
1388   while(!finished)
1389   {
1390     if (XPending(display))      /* got event from X server */
1391     {
1392       XEvent event;
1393
1394       XNextEvent(display, &event);
1395
1396       switch(event.type)
1397       {
1398         case KeyPress:
1399           {
1400             KeySym key = XLookupKeysym((XKeyEvent *)&event,
1401                                        ((XKeyEvent *)&event)->state);
1402
1403             if (key == XK_Escape || (key == XK_Return && step_nr == 6))
1404             {
1405               finished = TRUE;
1406               break;
1407             }
1408
1409             /* press 'Enter' to keep the existing key binding */
1410             if (key == XK_Return || step_nr == 6)
1411               key = *customize_step[step_nr].keysym;
1412
1413             /* check if key already used */
1414             for (i=0; i<step_nr; i++)
1415               if (*customize_step[i].keysym == key)
1416                 break;
1417             if (i < step_nr)
1418               break;
1419
1420             /* got new key binding */
1421             *customize_step[step_nr].keysym = key;
1422             DrawText(SX + 4*32, SY + (2+2*step_nr+1)*32,
1423                      "             ", FS_BIG, FC_YELLOW);
1424             DrawText(SX + 4*32, SY + (2+2*step_nr+1)*32,
1425                      getKeySymName(key), FS_BIG, FC_YELLOW);
1426             step_nr++;
1427
1428             /* un-highlight last query */
1429             DrawText(SX, SY+(2+2*(step_nr-1))*32,
1430                      customize_step[step_nr-1].text, FS_BIG, FC_GREEN);
1431             DrawText(SX, SY+(2+2*(step_nr-1)+1)*32,
1432                      "Key:", FS_BIG, FC_GREEN);
1433
1434             /* press 'Enter' to leave */
1435             if (step_nr == 6)
1436             {
1437               DrawText(SX + 16, SY + 15*32+16,
1438                        "Press Enter", FS_BIG, FC_YELLOW);
1439               break;
1440             }
1441
1442             /* query next key binding */
1443             DrawText(SX, SY+(2+2*step_nr)*32,
1444                      customize_step[step_nr].text, FS_BIG, FC_RED);
1445             DrawText(SX, SY+(2+2*step_nr+1)*32,
1446                      "Key:", FS_BIG, FC_RED);
1447             DrawText(SX + 4*32, SY+(2+2*step_nr+1)*32,
1448                      getKeySymName(*customize_step[step_nr].keysym),
1449                      FS_BIG, FC_BLUE);
1450           }
1451           break;
1452
1453         case KeyRelease:
1454           key_joystick_mapping = 0;
1455           break;
1456
1457         default:
1458           HandleOtherEvents(&event);
1459           break;
1460       }
1461     }
1462
1463     BackToFront();
1464     DoAnimation();
1465
1466     /* don't eat all CPU time */
1467     Delay(10);
1468   }
1469
1470   /* write new key bindings back to player setup */
1471   setup.input[player_nr].key = custom_key;
1472
1473   StopAnimation();
1474   DrawSetupInputScreen();
1475 }
1476
1477 void CalibrateJoystick(int joystick_nr)
1478 {
1479 #ifdef __FreeBSD__
1480   struct joystick joy_ctrl;
1481 #else
1482   struct joystick_control
1483   {
1484     int buttons;
1485     int x;
1486     int y;
1487   } joy_ctrl;
1488 #endif
1489
1490 #ifdef MSDOS
1491   char joy_nr[4];
1492 #endif
1493
1494   int new_joystick_xleft = 128, new_joystick_xright = 128;
1495   int new_joystick_yupper = 128, new_joystick_ylower = 128;
1496   int new_joystick_xmiddle, new_joystick_ymiddle;
1497   int x, y, last_x, last_y, xpos = 8, ypos = 3;
1498   boolean check[3][3];
1499   int check_remaining = 3 * 3;
1500   int joy;
1501   int result = -1;
1502
1503   if (joystick_status == JOYSTICK_OFF)
1504     return;
1505
1506   ClearWindow();
1507   DrawText(SX,      SY +  6*32, " ROTATE JOYSTICK ",FS_BIG,FC_YELLOW);
1508   DrawText(SX,      SY +  7*32, "IN ALL DIRECTIONS",FS_BIG,FC_YELLOW);
1509   DrawText(SX + 16, SY +  9*32, "  IF ALL BALLS  ",FS_BIG,FC_YELLOW);
1510   DrawText(SX,      SY + 10*32, "   ARE YELLOW,   ",FS_BIG,FC_YELLOW);
1511   DrawText(SX,      SY + 11*32, "  PRESS BUTTON!  ",FS_BIG,FC_YELLOW);
1512
1513   for(y=0; y<3; y++)
1514   {
1515     for(x=0; x<3; x++)
1516     {
1517       check[x][y] = FALSE;
1518       DrawGraphic(xpos + x - 1, ypos + y - 1, GFX_KUGEL_BLAU);
1519     }
1520   }
1521
1522   joy = Joystick();
1523   last_x = (joy & JOY_LEFT ? -1 : joy & JOY_RIGHT ? +1 : 0);
1524   last_y = (joy & JOY_UP   ? -1 : joy & JOY_DOWN  ? +1 : 0);
1525   DrawGraphic(xpos + last_x, ypos + last_y, GFX_KUGEL_ROT);
1526
1527   BackToFront();
1528
1529 #ifdef __FreeBSD__
1530   joy_ctrl.b1 = joy_ctrl.b2 = 0;
1531 #else
1532   joy_ctrl.buttons = 0;
1533 #endif
1534
1535   while(Joystick() & JOY_BUTTON);
1536
1537   InitAnimation();
1538
1539   while(result < 0)
1540   {
1541     if (XPending(display))      /* got event from X server */
1542     {
1543       XEvent event;
1544
1545       XNextEvent(display, &event);
1546
1547       switch(event.type)
1548       {
1549         case KeyPress:
1550           switch(XLookupKeysym((XKeyEvent *)&event,
1551                                ((XKeyEvent *)&event)->state))
1552           {
1553             case XK_Return:
1554               if (check_remaining == 0)
1555                 result = 1;
1556               break;
1557
1558             case XK_Escape:
1559               result = 0;
1560               break;
1561
1562             default:
1563               break;
1564           }
1565           break;
1566
1567         case KeyRelease:
1568           key_joystick_mapping = 0;
1569           break;
1570
1571         default:
1572           HandleOtherEvents(&event);
1573           break;
1574       }
1575     }
1576
1577     if (read(joystick_device, &joy_ctrl, sizeof(joy_ctrl)) != sizeof(joy_ctrl))
1578     {
1579       joystick_status = JOYSTICK_OFF;
1580       goto error_out;
1581     }
1582
1583     new_joystick_xleft  = MIN(new_joystick_xleft,  joy_ctrl.x);
1584     new_joystick_xright = MAX(new_joystick_xright, joy_ctrl.x);
1585     new_joystick_yupper = MIN(new_joystick_yupper, joy_ctrl.y);
1586     new_joystick_ylower = MAX(new_joystick_ylower, joy_ctrl.y);
1587
1588     new_joystick_xmiddle =
1589       new_joystick_xleft + (new_joystick_xright - new_joystick_xleft) / 2;
1590     new_joystick_ymiddle =
1591       new_joystick_yupper + (new_joystick_ylower - new_joystick_yupper) / 2;
1592
1593     joystick[joystick_nr].xleft = new_joystick_xleft;
1594     joystick[joystick_nr].yupper = new_joystick_yupper;
1595     joystick[joystick_nr].xright = new_joystick_xright;
1596     joystick[joystick_nr].ylower = new_joystick_ylower;
1597     joystick[joystick_nr].xmiddle = new_joystick_xmiddle;
1598     joystick[joystick_nr].ymiddle = new_joystick_ymiddle;
1599
1600     CheckJoystickData();
1601
1602     joy = Joystick();
1603
1604     if (joy & JOY_BUTTON && check_remaining == 0)
1605       result = 1;
1606
1607     x = (joy & JOY_LEFT ? -1 : joy & JOY_RIGHT ? +1 : 0);
1608     y = (joy & JOY_UP   ? -1 : joy & JOY_DOWN  ? +1 : 0);
1609
1610     if (x != last_x || y != last_y)
1611     {
1612       DrawGraphic(xpos + last_x, ypos + last_y, GFX_KUGEL_GELB);
1613       DrawGraphic(xpos + x,      ypos + y,      GFX_KUGEL_ROT);
1614
1615       last_x = x;
1616       last_y = y;
1617
1618       if (check_remaining > 0 && !check[x+1][y+1])
1619       {
1620         check[x+1][y+1] = TRUE;
1621         check_remaining--;
1622       }
1623
1624 #if 0
1625       printf("LEFT / MIDDLE / RIGHT == %d / %d / %d\n",
1626              joystick[joystick_nr].xleft,
1627              joystick[joystick_nr].xmiddle,
1628              joystick[joystick_nr].xright);
1629       printf("UP / MIDDLE / DOWN == %d / %d / %d\n",
1630              joystick[joystick_nr].yupper,
1631              joystick[joystick_nr].ymiddle,
1632              joystick[joystick_nr].ylower);
1633 #endif
1634     }
1635
1636     BackToFront();
1637     DoAnimation();
1638
1639     /* don't eat all CPU time */
1640     Delay(10);
1641   }
1642
1643   StopAnimation();
1644
1645   DrawSetupInputScreen();
1646   while(Joystick() & JOY_BUTTON);
1647   return;
1648
1649   error_out:
1650
1651   ClearWindow();
1652   DrawText(SX+16, SY+16, "NO JOYSTICK",FS_BIG,FC_YELLOW);
1653   DrawText(SX+16, SY+48, " AVAILABLE ",FS_BIG,FC_YELLOW);
1654   BackToFront();
1655   Delay(3000);
1656   DrawSetupInputScreen();
1657 }
1658
1659 void CalibrateJoystick_OLD()
1660 {
1661 #ifdef __FreeBSD__
1662   struct joystick joy_ctrl;
1663 #else
1664   struct joystick_control
1665   {
1666     int buttons;
1667     int x;
1668     int y;
1669   } joy_ctrl;
1670 #endif
1671
1672 #ifdef MSDOS
1673   char joy_nr[4];
1674 #endif
1675
1676   int joystick_nr = setup.input[0].joystick_nr;
1677   int new_joystick_xleft, new_joystick_xright, new_joystick_xmiddle;
1678   int new_joystick_yupper, new_joystick_ylower, new_joystick_ymiddle;
1679
1680   if (joystick_status == JOYSTICK_OFF)
1681     goto error_out;
1682
1683 #ifndef MSDOS
1684   ClearWindow();
1685   DrawText(SX+16, SY+7*32, "MOVE JOYSTICK TO",FS_BIG,FC_YELLOW);
1686   DrawText(SX+16, SY+8*32, " THE UPPER LEFT ",FS_BIG,FC_YELLOW);
1687   DrawText(SX+16, SY+9*32, "AND PRESS BUTTON",FS_BIG,FC_YELLOW);
1688   BackToFront();
1689
1690 #ifdef __FreeBSD__
1691   joy_ctrl.b1 = joy_ctrl.b2 = 0;
1692 #else
1693   joy_ctrl.buttons = 0;
1694 #endif
1695   while(Joystick() & JOY_BUTTON);
1696 #ifdef __FreeBSD__
1697   while(!(joy_ctrl.b1 || joy_ctrl.b2))
1698 #else
1699   while(!joy_ctrl.buttons)
1700 #endif
1701   {
1702     if (read(joystick_device, &joy_ctrl, sizeof(joy_ctrl)) != sizeof(joy_ctrl))
1703     {
1704       joystick_status=JOYSTICK_OFF;
1705       goto error_out;
1706     }
1707     Delay(10);
1708   }
1709
1710   new_joystick_xleft = joy_ctrl.x;
1711   new_joystick_yupper = joy_ctrl.y;
1712
1713   ClearWindow();
1714   DrawText(SX+16, SY+7*32, "MOVE JOYSTICK TO",FS_BIG,FC_YELLOW);
1715   DrawText(SX+32, SY+8*32, "THE LOWER RIGHT",FS_BIG,FC_YELLOW);
1716   DrawText(SX+16, SY+9*32, "AND PRESS BUTTON",FS_BIG,FC_YELLOW);
1717   BackToFront();
1718
1719 #ifdef __FreeBSD__
1720   joy_ctrl.b1 = joy_ctrl.b2 = 0;
1721 #else
1722   joy_ctrl.buttons = 0;
1723 #endif
1724   while(Joystick() & JOY_BUTTON);
1725 #ifdef __FreeBSD__
1726   while(!(joy_ctrl.b1 || joy_ctrl.b2))
1727 #else
1728   while(!joy_ctrl.buttons)
1729 #endif
1730   {
1731     if (read(joystick_device, &joy_ctrl, sizeof(joy_ctrl)) != sizeof(joy_ctrl))
1732     {
1733       joystick_status=JOYSTICK_OFF;
1734       goto error_out;
1735     }
1736     Delay(10);
1737   }
1738
1739   new_joystick_xright = joy_ctrl.x;
1740   new_joystick_ylower = joy_ctrl.y;
1741
1742   ClearWindow();
1743   DrawText(SX+32, SY+16+7*32, "CENTER JOYSTICK",FS_BIG,FC_YELLOW);
1744   DrawText(SX+16, SY+16+8*32, "AND PRESS BUTTON",FS_BIG,FC_YELLOW);
1745   BackToFront();
1746
1747 #ifdef __FreeBSD__
1748   joy_ctrl.b1 = joy_ctrl.b2 = 0;
1749 #else
1750   joy_ctrl.buttons = 0;
1751 #endif
1752   while(Joystick() & JOY_BUTTON);
1753 #ifdef __FreeBSD__
1754   while(!(joy_ctrl.b1 || joy_ctrl.b2))
1755 #else
1756   while(!joy_ctrl.buttons)
1757 #endif
1758   {
1759     if (read(joystick_device, &joy_ctrl, sizeof(joy_ctrl)) != sizeof(joy_ctrl))
1760     {
1761       joystick_status=JOYSTICK_OFF;
1762       goto error_out;
1763     }
1764     Delay(10);
1765   }
1766
1767   new_joystick_xmiddle = joy_ctrl.x;
1768   new_joystick_ymiddle = joy_ctrl.y;
1769
1770   joystick[joystick_nr].xleft = new_joystick_xleft;
1771   joystick[joystick_nr].yupper = new_joystick_yupper;
1772   joystick[joystick_nr].xright = new_joystick_xright;
1773   joystick[joystick_nr].ylower = new_joystick_ylower;
1774   joystick[joystick_nr].xmiddle = new_joystick_xmiddle;
1775   joystick[joystick_nr].ymiddle = new_joystick_ymiddle;
1776
1777   CheckJoystickData();
1778
1779   DrawSetupScreen();
1780   while(Joystick() & JOY_BUTTON);
1781   return;
1782
1783 #endif
1784   error_out:
1785
1786 #ifdef MSDOS
1787   joy_nr[0] = '#';
1788   joy_nr[1] = SETUP_2ND_JOYSTICK_ON(local_player->setup)+49;
1789   joy_nr[2] = '\0';
1790
1791   remove_joystick();
1792   ClearWindow();
1793   DrawText(SX+32, SY+7*32, "CENTER JOYSTICK",FS_BIG,FC_YELLOW);
1794   DrawText(SX+16+7*32, SY+8*32, joy_nr, FS_BIG,FC_YELLOW);
1795   DrawText(SX+32, SY+9*32, "AND PRESS A KEY",FS_BIG,FC_YELLOW);
1796   BackToFront();
1797
1798   for(clear_keybuf();!keypressed(););
1799   install_joystick(JOY_TYPE_2PADS);
1800
1801   ClearWindow();
1802   DrawText(SX+16, SY+7*32, "MOVE JOYSTICK TO",FS_BIG,FC_YELLOW);
1803   DrawText(SX+16, SY+8*32, " THE UPPER LEFT ",FS_BIG,FC_YELLOW);
1804   DrawText(SX+32, SY+9*32, "AND PRESS A KEY",FS_BIG,FC_YELLOW);
1805   BackToFront();
1806
1807   for(clear_keybuf();!keypressed(););
1808   calibrate_joystick(SETUP_2ND_JOYSTICK_ON(local_player->setup));
1809
1810   ClearWindow();
1811   DrawText(SX+16, SY+7*32, "MOVE JOYSTICK TO",FS_BIG,FC_YELLOW);
1812   DrawText(SX+32, SY+8*32, "THE LOWER RIGHT",FS_BIG,FC_YELLOW);
1813   DrawText(SX+32, SY+9*32, "AND PRESS A KEY",FS_BIG,FC_YELLOW);
1814   BackToFront();
1815
1816   for(clear_keybuf();!keypressed(););
1817   calibrate_joystick(SETUP_2ND_JOYSTICK_ON(local_player->setup));
1818
1819   DrawSetupScreen();
1820   return;
1821 #endif
1822
1823   ClearWindow();
1824   DrawText(SX+16, SY+16, "NO JOYSTICK",FS_BIG,FC_YELLOW);
1825   DrawText(SX+16, SY+48, " AVAILABLE ",FS_BIG,FC_YELLOW);
1826   BackToFront();
1827   Delay(3000);
1828   DrawSetupScreen();
1829 }
1830
1831 void HandleGameActions()
1832 {
1833   if (game_status != PLAYING)
1834     return;
1835
1836   if (local_player->LevelSolved)
1837     GameWon();
1838
1839   if (AllPlayersGone && !TAPE_IS_STOPPED(tape))
1840     TapeStop();
1841
1842   GameActions();
1843
1844   BackToFront();
1845 }
1846
1847 void HandleVideoButtons(int mx, int my, int button)
1848 {
1849   if (game_status != MAINMENU && game_status != PLAYING)
1850     return;
1851
1852   switch(CheckVideoButtons(mx,my,button))
1853   {
1854     case BUTTON_VIDEO_EJECT:
1855       TapeStop();
1856       if (TAPE_IS_EMPTY(tape))
1857       {
1858         LoadLevelTape(level_nr);
1859         if (TAPE_IS_EMPTY(tape))
1860           Request("No tape for this level !",REQ_CONFIRM);
1861       }
1862       else
1863       {
1864         if (tape.changed)
1865           SaveLevelTape(tape.level_nr);
1866         TapeErase();
1867       }
1868       DrawCompleteVideoDisplay();
1869       break;
1870
1871     case BUTTON_VIDEO_STOP:
1872       TapeStop();
1873       break;
1874
1875     case BUTTON_VIDEO_PAUSE:
1876       TapeTogglePause();
1877       break;
1878
1879     case BUTTON_VIDEO_REC:
1880       if (TAPE_IS_STOPPED(tape))
1881       {
1882         TapeStartRecording();
1883
1884         if (options.network)
1885           SendToServer_StartPlaying();
1886         else
1887         {
1888           game_status = PLAYING;
1889           InitGame();
1890         }
1891       }
1892       else if (tape.pausing)
1893       {
1894         if (tape.playing)       /* PLAYING -> PAUSING -> RECORDING */
1895         {
1896           tape.pos[tape.counter].delay = tape.delay_played;
1897           tape.playing = FALSE;
1898           tape.recording = TRUE;
1899           tape.changed = TRUE;
1900
1901           DrawVideoDisplay(VIDEO_STATE_PLAY_OFF | VIDEO_STATE_REC_ON,0);
1902         }
1903         else
1904           TapeTogglePause();
1905       }
1906       break;
1907
1908     case BUTTON_VIDEO_PLAY:
1909       if (TAPE_IS_EMPTY(tape))
1910         break;
1911
1912       if (TAPE_IS_STOPPED(tape))
1913       {
1914         TapeStartPlaying();
1915
1916         game_status = PLAYING;
1917         InitGame();
1918       }
1919       else if (tape.playing)
1920       {
1921         if (tape.pausing)                       /* PAUSE -> PLAY */
1922           TapeTogglePause();
1923         else if (!tape.fast_forward)            /* PLAY -> FAST FORWARD PLAY */
1924         {
1925           tape.fast_forward = TRUE;
1926           DrawVideoDisplay(VIDEO_STATE_FFWD_ON, 0);
1927         }
1928         else if (!tape.pause_before_death)      /* FFWD PLAY -> + AUTO PAUSE */
1929         {
1930           tape.pause_before_death = TRUE;
1931           DrawVideoDisplay(VIDEO_STATE_PAUSE_ON, VIDEO_DISPLAY_LABEL_ONLY);
1932         }
1933         else                                    /* -> NORMAL PLAY */
1934         {
1935           tape.fast_forward = FALSE;
1936           tape.pause_before_death = FALSE;
1937           DrawVideoDisplay(VIDEO_STATE_FFWD_OFF | VIDEO_STATE_PAUSE_OFF, 0);
1938         }
1939       }
1940       break;
1941
1942     default:
1943       break;
1944   }
1945
1946   BackToFront();
1947 }
1948
1949 void HandleSoundButtons(int mx, int my, int button)
1950 {
1951   if (game_status != PLAYING)
1952     return;
1953
1954   switch(CheckSoundButtons(mx,my,button))
1955   {
1956     case BUTTON_SOUND_MUSIC:
1957       if (setup.sound_music_on)
1958       { 
1959         setup.sound_music_on = FALSE;
1960         local_player->setup &= ~SETUP_SOUND_MUSIC;
1961         FadeSound(background_loop[level_nr % num_bg_loops]);
1962         DrawSoundDisplay(BUTTON_SOUND_MUSIC_OFF);
1963       }
1964       else if (sound_loops_allowed)
1965       { 
1966         setup.sound_on = setup.sound_music_on = TRUE;
1967         local_player->setup |= (SETUP_SOUND | SETUP_SOUND_MUSIC);
1968         PlaySoundLoop(background_loop[level_nr % num_bg_loops]);
1969         DrawSoundDisplay(BUTTON_SOUND_MUSIC_ON);
1970       }
1971       else
1972         DrawSoundDisplay(BUTTON_SOUND_MUSIC_OFF);
1973       break;
1974
1975     case BUTTON_SOUND_LOOPS:
1976       if (setup.sound_loops_on)
1977       { 
1978         setup.sound_loops_on = FALSE;
1979         local_player->setup &= ~SETUP_SOUND_LOOPS;
1980         DrawSoundDisplay(BUTTON_SOUND_LOOPS_OFF);
1981       }
1982       else if (sound_loops_allowed)
1983       { 
1984         setup.sound_on = setup.sound_loops_on = TRUE;
1985         local_player->setup |= (SETUP_SOUND | SETUP_SOUND_LOOPS);
1986         DrawSoundDisplay(BUTTON_SOUND_LOOPS_ON);
1987       }
1988       else
1989         DrawSoundDisplay(BUTTON_SOUND_LOOPS_OFF);
1990       break;
1991
1992     case BUTTON_SOUND_SIMPLE:
1993       if (setup.sound_simple_on)
1994       { 
1995         setup.sound_simple_on = FALSE;
1996         local_player->setup &= ~SETUP_SOUND;
1997         DrawSoundDisplay(BUTTON_SOUND_SIMPLE_OFF);
1998       }
1999       else if (sound_status==SOUND_AVAILABLE)
2000       { 
2001         setup.sound_on = setup.sound_simple_on = TRUE;
2002         local_player->setup |= SETUP_SOUND;
2003         DrawSoundDisplay(BUTTON_SOUND_SIMPLE_ON);
2004       }
2005       else
2006         DrawSoundDisplay(BUTTON_SOUND_SIMPLE_OFF);
2007       break;
2008
2009     default:
2010       break;
2011   }
2012
2013   BackToFront();
2014 }
2015
2016 void HandleGameButtons(int mx, int my, int button)
2017 {
2018   if (game_status != PLAYING)
2019     return;
2020
2021   switch(CheckGameButtons(mx,my,button))
2022   {
2023     case BUTTON_GAME_STOP:
2024       if (AllPlayersGone)
2025       {
2026         CloseDoor(DOOR_CLOSE_1);
2027         game_status = MAINMENU;
2028         DrawMainMenu();
2029         break;
2030       }
2031
2032       if (Request("Do you really want to quit the game ?",
2033                   REQ_ASK | REQ_STAY_CLOSED))
2034       { 
2035         if (options.network)
2036           SendToServer_StopPlaying();
2037         else
2038         {
2039           game_status = MAINMENU;
2040           DrawMainMenu();
2041         }
2042       }
2043       else
2044         OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2045       break;
2046
2047     case BUTTON_GAME_PAUSE:
2048       if (options.network)
2049       {
2050         if (tape.pausing)
2051           SendToServer_ContinuePlaying();
2052         else
2053           SendToServer_PausePlaying();
2054       }
2055       else
2056         TapeTogglePause();
2057
2058       /*
2059       if (tape.pausing)
2060       {
2061         if (options.network)
2062           SendToServer_ContinuePlaying();
2063         else
2064         {
2065           tape.pausing = FALSE;
2066           DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0);
2067         }
2068       }
2069       else
2070       {
2071         if (options.network)
2072           SendToServer_PausePlaying();
2073         else
2074         {
2075           tape.pausing = TRUE;
2076           DrawVideoDisplay(VIDEO_STATE_PAUSE_ON,0);
2077         }
2078       }
2079       */
2080
2081       break;
2082
2083     case BUTTON_GAME_PLAY:
2084       if (tape.pausing)
2085       {
2086         if (options.network)
2087           SendToServer_ContinuePlaying();
2088         else
2089         {
2090           tape.pausing = FALSE;
2091           DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0);
2092         }
2093       }
2094       break;
2095
2096     default:
2097       break;
2098   }
2099
2100   BackToFront();
2101 }