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