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