fa1175c0d59b56e24d2dfcd5ecf0bad9f8232473
[rocksndiamonds.git] / src / game.c
1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
3 *----------------------------------------------------------*
4 * (c) 1995-2001 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * game.c                                                   *
12 ***********************************************************/
13
14 #include "libgame/libgame.h"
15
16 #include "game.h"
17 #include "tools.h"
18 #include "screens.h"
19 #include "init.h"
20 #include "files.h"
21 #include "tape.h"
22 #include "network.h"
23
24 /* this switch controls how rocks move horizontally */
25 #define OLD_GAME_BEHAVIOUR      FALSE
26
27 /* EXPERIMENTAL STUFF */
28 #define USE_NEW_AMOEBA_CODE     FALSE
29
30 /* for DigField() */
31 #define DF_NO_PUSH              0
32 #define DF_DIG                  1
33 #define DF_SNAP                 2
34
35 /* for MoveFigure() */
36 #define MF_NO_ACTION            0
37 #define MF_MOVING               1
38 #define MF_ACTION               2
39
40 /* for ScrollFigure() */
41 #define SCROLL_INIT             0
42 #define SCROLL_GO_ON            1
43
44 /* for Explode() */
45 #define EX_PHASE_START          0
46 #define EX_NO_EXPLOSION         0
47 #define EX_NORMAL               1
48 #define EX_CENTER               2
49 #define EX_BORDER               3
50
51 /* special positions in the game control window (relative to control window) */
52 #define XX_LEVEL                37
53 #define YY_LEVEL                20
54 #define XX_EMERALDS             29
55 #define YY_EMERALDS             54
56 #define XX_DYNAMITE             29
57 #define YY_DYNAMITE             89
58 #define XX_KEYS                 18
59 #define YY_KEYS                 123
60 #define XX_SCORE                15
61 #define YY_SCORE                159
62 #define XX_TIME                 29
63 #define YY_TIME                 194
64
65 /* special positions in the game control window (relative to main window) */
66 #define DX_LEVEL                (DX + XX_LEVEL)
67 #define DY_LEVEL                (DY + YY_LEVEL)
68 #define DX_EMERALDS             (DX + XX_EMERALDS)
69 #define DY_EMERALDS             (DY + YY_EMERALDS)
70 #define DX_DYNAMITE             (DX + XX_DYNAMITE)
71 #define DY_DYNAMITE             (DY + YY_DYNAMITE)
72 #define DX_KEYS                 (DX + XX_KEYS)
73 #define DY_KEYS                 (DY + YY_KEYS)
74 #define DX_SCORE                (DX + XX_SCORE)
75 #define DY_SCORE                (DY + YY_SCORE)
76 #define DX_TIME                 (DX + XX_TIME)
77 #define DY_TIME                 (DY + YY_TIME)
78
79 #define IS_LOOP_SOUND(s)        ((s)==SND_KLAPPER || (s)==SND_ROEHR ||  \
80                                  (s)==SND_NJAM || (s)==SND_MIEP)
81 #define IS_MUSIC_SOUND(s)       ((s)==SND_ALCHEMY || (s)==SND_CHASE || \
82                                  (s)==SND_NETWORK || (s)==SND_CZARDASZ || \
83                                  (s)==SND_TYGER || (s)==SND_VOYAGER || \
84                                  (s)==SND_TWILIGHT)
85
86 /* values for player movement speed (which is in fact a delay value) */
87 #define MOVE_DELAY_NORMAL_SPEED 8
88 #define MOVE_DELAY_HIGH_SPEED   4
89
90 #define DOUBLE_MOVE_DELAY(x)    (x = (x <= MOVE_DELAY_HIGH_SPEED ? x * 2 : x))
91 #define HALVE_MOVE_DELAY(x)     (x = (x >= MOVE_DELAY_HIGH_SPEED ? x / 2 : x))
92 #define DOUBLE_PLAYER_SPEED(p)  (HALVE_MOVE_DELAY((p)->move_delay_value))
93 #define HALVE_PLAYER_SPEED(p)   (DOUBLE_MOVE_DELAY((p)->move_delay_value))
94
95 /* game button identifiers */
96 #define GAME_CTRL_ID_STOP               0
97 #define GAME_CTRL_ID_PAUSE              1
98 #define GAME_CTRL_ID_PLAY               2
99 #define SOUND_CTRL_ID_MUSIC             3
100 #define SOUND_CTRL_ID_LOOPS             4
101 #define SOUND_CTRL_ID_SIMPLE            5
102
103 #define NUM_GAME_BUTTONS                6
104
105 /* forward declaration for internal use */
106 static void CloseAllOpenTimegates(void);
107 static void CheckGravityMovement(struct PlayerInfo *);
108 static void KillHeroUnlessProtected(int, int);
109
110 static void MapGameButtons();
111 static void HandleGameButtons(struct GadgetInfo *);
112
113 static struct GadgetInfo *game_gadget[NUM_GAME_BUTTONS];
114
115
116
117 #ifdef DEBUG
118 #if 0
119 static unsigned int getStateCheckSum(int counter)
120 {
121   int x, y;
122   unsigned int mult = 1;
123   unsigned int checksum = 0;
124   /*
125   static short lastFeld[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
126   */
127   static boolean first_game = TRUE;
128
129   for (y=0; y<lev_fieldy; y++) for(x=0; x<lev_fieldx; x++)
130   {
131     /*
132     if (counter == 3)
133     {
134       if (first_game)
135         lastFeld[x][y] = Feld[x][y];
136       else if (lastFeld[x][y] != Feld[x][y])
137         printf("DIFF: [%d][%d]: lastFeld == %d != %d == Feld\n",
138                x, y, lastFeld[x][y], Feld[x][y]);
139     }
140     */
141
142     checksum += mult++ * Ur[x][y];
143     checksum += mult++ * Feld[x][y];
144
145     /*
146     checksum += mult++ * MovPos[x][y];
147     checksum += mult++ * MovDir[x][y];
148     checksum += mult++ * MovDelay[x][y];
149     checksum += mult++ * Store[x][y];
150     checksum += mult++ * Store2[x][y];
151     checksum += mult++ * StorePlayer[x][y];
152     checksum += mult++ * Frame[x][y];
153     checksum += mult++ * AmoebaNr[x][y];
154     checksum += mult++ * JustStopped[x][y];
155     checksum += mult++ * Stop[x][y];
156     */
157   }
158
159   if (counter == 3 && first_game)
160     first_game = FALSE;
161
162   return checksum;
163 }
164 #endif
165 #endif
166
167
168
169
170 void GetPlayerConfig()
171 {
172   if (!audio.sound_available)
173     setup.sound = FALSE;
174
175   if (!audio.loops_available)
176     setup.sound_loops = FALSE;
177
178   if (!audio.music_available)
179     setup.sound_music = FALSE;
180
181   if (!video.fullscreen_available)
182     setup.fullscreen = FALSE;
183
184   setup.sound_simple = setup.sound;
185
186   SetAudioMode(setup.sound);
187   InitJoysticks();
188 }
189
190 static int getBeltNrFromElement(int element)
191 {
192   return (element < EL_BELT2_LEFT ? 0 :
193           element < EL_BELT3_LEFT ? 1 :
194           element < EL_BELT4_LEFT ? 2 : 3);
195 }
196
197 static int getBeltNrFromSwitchElement(int element)
198 {
199   return (element < EL_BELT2_SWITCH_LEFT ? 0 :
200           element < EL_BELT3_SWITCH_LEFT ? 1 :
201           element < EL_BELT4_SWITCH_LEFT ? 2 : 3);
202 }
203
204 static int getBeltDirNrFromSwitchElement(int element)
205 {
206   static int belt_base_element[4] =
207   {
208     EL_BELT1_SWITCH_LEFT,
209     EL_BELT2_SWITCH_LEFT,
210     EL_BELT3_SWITCH_LEFT,
211     EL_BELT4_SWITCH_LEFT
212   };
213
214   int belt_nr = getBeltNrFromSwitchElement(element);
215   int belt_dir_nr = element - belt_base_element[belt_nr];
216
217   return (belt_dir_nr % 3);
218 }
219
220 static int getBeltDirFromSwitchElement(int element)
221 {
222   static int belt_move_dir[3] =
223   {
224     MV_LEFT,
225     MV_NO_MOVING,
226     MV_RIGHT
227   };
228
229   int belt_dir_nr = getBeltDirNrFromSwitchElement(element);
230
231   return belt_move_dir[belt_dir_nr];
232 }
233
234 static void InitField(int x, int y, boolean init_game)
235 {
236   switch (Feld[x][y])
237   {
238     case EL_SP_MURPHY:
239       if (init_game)
240       {
241         if (stored_player[0].present)
242         {
243           Feld[x][y] = EL_SP_MURPHY_CLONE;
244           break;
245         }
246       }
247       /* no break! */
248     case EL_SPIELFIGUR:
249       if (init_game)
250         Feld[x][y] = EL_SPIELER1;
251       /* no break! */
252     case EL_SPIELER1:
253     case EL_SPIELER2:
254     case EL_SPIELER3:
255     case EL_SPIELER4:
256       if (init_game)
257       {
258         struct PlayerInfo *player = &stored_player[Feld[x][y] - EL_SPIELER1];
259         int jx = player->jx, jy = player->jy;
260
261         player->present = TRUE;
262
263         if (!options.network || player->connected)
264         {
265           player->active = TRUE;
266
267           /* remove potentially duplicate players */
268           if (StorePlayer[jx][jy] == Feld[x][y])
269             StorePlayer[jx][jy] = 0;
270
271           StorePlayer[x][y] = Feld[x][y];
272
273           if (options.debug)
274           {
275             printf("Player %d activated.\n", player->element_nr);
276             printf("[Local player is %d and currently %s.]\n",
277                    local_player->element_nr,
278                    local_player->active ? "active" : "not active");
279           }
280         }
281
282         Feld[x][y] = EL_LEERRAUM;
283         player->jx = player->last_jx = x;
284         player->jy = player->last_jy = y;
285       }
286       break;
287
288     case EL_BADEWANNE:
289       if (x < lev_fieldx-1 && Feld[x+1][y] == EL_SALZSAEURE)
290         Feld[x][y] = EL_BADEWANNE1;
291       else if (x > 0 && Feld[x-1][y] == EL_SALZSAEURE)
292         Feld[x][y] = EL_BADEWANNE2;
293       else if (y > 0 && Feld[x][y-1] == EL_BADEWANNE1)
294         Feld[x][y] = EL_BADEWANNE3;
295       else if (y > 0 && Feld[x][y-1] == EL_SALZSAEURE)
296         Feld[x][y] = EL_BADEWANNE4;
297       else if (y > 0 && Feld[x][y-1] == EL_BADEWANNE2)
298         Feld[x][y] = EL_BADEWANNE5;
299       break;
300
301     case EL_KAEFER_RIGHT:
302     case EL_KAEFER_UP:
303     case EL_KAEFER_LEFT:
304     case EL_KAEFER_DOWN:
305     case EL_KAEFER:
306     case EL_FLIEGER_RIGHT:
307     case EL_FLIEGER_UP:
308     case EL_FLIEGER_LEFT:
309     case EL_FLIEGER_DOWN:
310     case EL_FLIEGER:
311     case EL_BUTTERFLY_RIGHT:
312     case EL_BUTTERFLY_UP:
313     case EL_BUTTERFLY_LEFT:
314     case EL_BUTTERFLY_DOWN:
315     case EL_BUTTERFLY:
316     case EL_FIREFLY_RIGHT:
317     case EL_FIREFLY_UP:
318     case EL_FIREFLY_LEFT:
319     case EL_FIREFLY_DOWN:
320     case EL_FIREFLY:
321     case EL_PACMAN_RIGHT:
322     case EL_PACMAN_UP:
323     case EL_PACMAN_LEFT:
324     case EL_PACMAN_DOWN:
325     case EL_MAMPFER:
326     case EL_MAMPFER2:
327     case EL_ROBOT:
328     case EL_PACMAN:
329     case EL_SP_SNIKSNAK:
330     case EL_SP_ELECTRON:
331     case EL_MOLE_LEFT:
332     case EL_MOLE_RIGHT:
333     case EL_MOLE_UP:
334     case EL_MOLE_DOWN:
335     case EL_MOLE:
336       InitMovDir(x, y);
337       break;
338
339     case EL_AMOEBE_VOLL:
340     case EL_AMOEBE_BD:
341       InitAmoebaNr(x, y);
342       break;
343
344     case EL_TROPFEN:
345       if (y == lev_fieldy - 1)
346       {
347         Feld[x][y] = EL_AMOEBING;
348         Store[x][y] = EL_AMOEBE_NASS;
349       }
350       break;
351
352     case EL_DYNAMITE_ACTIVE:
353       MovDelay[x][y] = 96;
354       break;
355
356     case EL_BIRNE_AUS:
357       local_player->lights_still_needed++;
358       break;
359
360     case EL_SOKOBAN_FELD_LEER:
361       local_player->sokobanfields_still_needed++;
362       break;
363
364     case EL_PINGUIN:
365       local_player->friends_still_needed++;
366       break;
367
368     case EL_SCHWEIN:
369     case EL_DRACHE:
370       MovDir[x][y] = 1 << RND(4);
371       break;
372
373     case EL_SP_EMPTY:
374       Feld[x][y] = EL_LEERRAUM;
375       break;
376
377     case EL_EM_KEY_1_FILE:
378       Feld[x][y] = EL_EM_KEY_1;
379       break;
380     case EL_EM_KEY_2_FILE:
381       Feld[x][y] = EL_EM_KEY_2;
382       break;
383     case EL_EM_KEY_3_FILE:
384       Feld[x][y] = EL_EM_KEY_3;
385       break;
386     case EL_EM_KEY_4_FILE:
387       Feld[x][y] = EL_EM_KEY_4;
388       break;
389
390     case EL_BELT1_SWITCH_LEFT:
391     case EL_BELT1_SWITCH_MIDDLE:
392     case EL_BELT1_SWITCH_RIGHT:
393     case EL_BELT2_SWITCH_LEFT:
394     case EL_BELT2_SWITCH_MIDDLE:
395     case EL_BELT2_SWITCH_RIGHT:
396     case EL_BELT3_SWITCH_LEFT:
397     case EL_BELT3_SWITCH_MIDDLE:
398     case EL_BELT3_SWITCH_RIGHT:
399     case EL_BELT4_SWITCH_LEFT:
400     case EL_BELT4_SWITCH_MIDDLE:
401     case EL_BELT4_SWITCH_RIGHT:
402       if (init_game)
403       {
404         int belt_nr = getBeltNrFromSwitchElement(Feld[x][y]);
405         int belt_dir = getBeltDirFromSwitchElement(Feld[x][y]);
406         int belt_dir_nr = getBeltDirNrFromSwitchElement(Feld[x][y]);
407
408         if (game.belt_dir_nr[belt_nr] == 3)     /* initial value */
409         {
410           game.belt_dir[belt_nr] = belt_dir;
411           game.belt_dir_nr[belt_nr] = belt_dir_nr;
412         }
413         else    /* more than one switch -- set it like the first switch */
414         {
415           Feld[x][y] = Feld[x][y] - belt_dir_nr + game.belt_dir_nr[belt_nr];
416         }
417       }
418       break;
419
420     case EL_SWITCHGATE_SWITCH_2:        /* always start with same switch pos */
421       if (init_game)
422         Feld[x][y] = EL_SWITCHGATE_SWITCH_1;
423       break;
424
425     case EL_LIGHT_SWITCH_ON:
426       if (init_game)
427         game.light_time_left = level.time_light * FRAMES_PER_SECOND;
428       break;
429
430     default:
431       break;
432   }
433 }
434
435 void DrawGameDoorValues()
436 {
437   DrawText(DX + XX_EMERALDS, DY + YY_EMERALDS,
438            int2str(local_player->gems_still_needed, 3), FS_SMALL, FC_YELLOW);
439   DrawText(DX + XX_DYNAMITE, DY + YY_DYNAMITE,
440            int2str(local_player->dynamite, 3), FS_SMALL, FC_YELLOW);
441   DrawText(DX + XX_SCORE, DY + YY_SCORE,
442            int2str(local_player->score, 5), FS_SMALL, FC_YELLOW);
443   DrawText(DX + XX_TIME, DY + YY_TIME,
444            int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
445 }
446
447 void InitGame()
448 {
449   int i, j, x, y;
450   boolean emulate_bd = TRUE;    /* unless non-BOULDERDASH elements found */
451   boolean emulate_sb = TRUE;    /* unless non-SOKOBAN     elements found */
452   boolean emulate_sp = TRUE;    /* unless non-SUPAPLEX    elements found */
453
454 #if DEBUG
455 #if USE_NEW_AMOEBA_CODE
456   printf("Using new amoeba code.\n");
457 #else
458   printf("Using old amoeba code.\n");
459 #endif
460 #endif
461
462   /* don't play tapes over network */
463   network_playing = (options.network && !tape.playing);
464
465   for (i=0; i<MAX_PLAYERS; i++)
466   {
467     struct PlayerInfo *player = &stored_player[i];
468
469     player->index_nr = i;
470     player->element_nr = EL_SPIELER1 + i;
471
472     player->present = FALSE;
473     player->active = FALSE;
474
475     player->action = 0;
476     player->effective_action = 0;
477     player->programmed_action = 0;
478
479     player->score = 0;
480     player->gems_still_needed = level.gems_needed;
481     player->sokobanfields_still_needed = 0;
482     player->lights_still_needed = 0;
483     player->friends_still_needed = 0;
484
485     for (j=0; j<4; j++)
486       player->key[j] = FALSE;
487
488     player->dynamite = 0;
489     player->dynabomb_count = 0;
490     player->dynabomb_size = 1;
491     player->dynabombs_left = 0;
492     player->dynabomb_xl = FALSE;
493
494     player->MovDir = MV_NO_MOVING;
495     player->MovPos = 0;
496     player->Pushing = FALSE;
497     player->Switching = FALSE;
498     player->GfxPos = 0;
499     player->Frame = 0;
500
501     player->actual_frame_counter = 0;
502
503     player->frame_reset_delay = 0;
504
505     player->last_move_dir = MV_NO_MOVING;
506     player->is_moving = FALSE;
507
508     player->move_delay = -1;    /* no initial move delay */
509     player->move_delay_value =
510       (level.double_speed ? MOVE_DELAY_HIGH_SPEED : MOVE_DELAY_NORMAL_SPEED);
511
512     player->push_delay = 0;
513     player->push_delay_value = 5;
514
515     player->snapped = FALSE;
516
517     player->last_jx = player->last_jy = 0;
518     player->jx = player->jy = 0;
519
520     player->shield_passive_time_left = 0;
521     player->shield_active_time_left = 0;
522
523     DigField(player, 0, 0, 0, 0, DF_NO_PUSH);
524     SnapField(player, 0, 0);
525
526     player->LevelSolved = FALSE;
527     player->GameOver = FALSE;
528   }
529
530   network_player_action_received = FALSE;
531
532 #if defined(PLATFORM_UNIX)
533   /* initial null action */
534   if (network_playing)
535     SendToServer_MovePlayer(MV_NO_MOVING);
536 #endif
537
538   ZX = ZY = -1;
539
540   FrameCounter = 0;
541   TimeFrames = 0;
542   TimePlayed = 0;
543   TimeLeft = level.time;
544
545   ScreenMovDir = MV_NO_MOVING;
546   ScreenMovPos = 0;
547   ScreenGfxPos = 0;
548
549   ScrollStepSize = 0;   /* will be correctly initialized by ScrollScreen() */
550
551   AllPlayersGone = FALSE;
552
553   game.yam_content_nr = 0;
554   game.magic_wall_active = FALSE;
555   game.magic_wall_time_left = 0;
556   game.light_time_left = 0;
557   game.timegate_time_left = 0;
558   game.switchgate_pos = 0;
559   game.balloon_dir = MV_NO_MOVING;
560   game.explosions_delayed = TRUE;
561
562   for (i=0; i<4; i++)
563   {
564     game.belt_dir[i] = MV_NO_MOVING;
565     game.belt_dir_nr[i] = 3;            /* not moving, next moving left */
566   }
567
568   for (i=0; i<MAX_NUM_AMOEBA; i++)
569     AmoebaCnt[i] = AmoebaCnt2[i] = 0;
570
571   for (x=0; x<lev_fieldx; x++)
572   {
573     for (y=0; y<lev_fieldy; y++)
574     {
575       Feld[x][y] = Ur[x][y];
576       MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
577       Store[x][y] = Store2[x][y] = StorePlayer[x][y] = 0;
578       Frame[x][y] = 0;
579       AmoebaNr[x][y] = 0;
580       JustStopped[x][y] = 0;
581       Stop[x][y] = FALSE;
582       ExplodeField[x][y] = EX_NO_EXPLOSION;
583     }
584   }
585
586   for(y=0; y<lev_fieldy; y++)
587   {
588     for(x=0; x<lev_fieldx; x++)
589     {
590       if (emulate_bd && !IS_BD_ELEMENT(Feld[x][y]))
591         emulate_bd = FALSE;
592       if (emulate_sb && !IS_SB_ELEMENT(Feld[x][y]))
593         emulate_sb = FALSE;
594       if (emulate_sp && !IS_SP_ELEMENT(Feld[x][y]))
595         emulate_sp = FALSE;
596
597       InitField(x, y, TRUE);
598     }
599   }
600
601   /* correct non-moving belts to start moving left */
602   for (i=0; i<4; i++)
603     if (game.belt_dir[i] == MV_NO_MOVING)
604       game.belt_dir_nr[i] = 3;          /* not moving, next moving left */
605
606   /* check if any connected player was not found in playfield */
607   for (i=0; i<MAX_PLAYERS; i++)
608   {
609     struct PlayerInfo *player = &stored_player[i];
610
611     if (player->connected && !player->present)
612     {
613       for (j=0; j<MAX_PLAYERS; j++)
614       {
615         struct PlayerInfo *some_player = &stored_player[j];
616         int jx = some_player->jx, jy = some_player->jy;
617
618         /* assign first free player found that is present in the playfield */
619         if (some_player->present && !some_player->connected)
620         {
621           player->present = TRUE;
622           player->active = TRUE;
623           some_player->present = FALSE;
624
625           StorePlayer[jx][jy] = player->element_nr;
626           player->jx = player->last_jx = jx;
627           player->jy = player->last_jy = jy;
628
629           break;
630         }
631       }
632     }
633   }
634
635   if (tape.playing)
636   {
637     /* when playing a tape, eliminate all players who do not participate */
638
639     for (i=0; i<MAX_PLAYERS; i++)
640     {
641       if (stored_player[i].active && !tape.player_participates[i])
642       {
643         struct PlayerInfo *player = &stored_player[i];
644         int jx = player->jx, jy = player->jy;
645
646         player->active = FALSE;
647         StorePlayer[jx][jy] = 0;
648         Feld[jx][jy] = EL_LEERRAUM;
649       }
650     }
651   }
652   else if (!options.network && !setup.team_mode)        /* && !tape.playing */
653   {
654     /* when in single player mode, eliminate all but the first active player */
655
656     for (i=0; i<MAX_PLAYERS; i++)
657     {
658       if (stored_player[i].active)
659       {
660         for (j=i+1; j<MAX_PLAYERS; j++)
661         {
662           if (stored_player[j].active)
663           {
664             struct PlayerInfo *player = &stored_player[j];
665             int jx = player->jx, jy = player->jy;
666
667             player->active = FALSE;
668             StorePlayer[jx][jy] = 0;
669             Feld[jx][jy] = EL_LEERRAUM;
670           }
671         }
672       }
673     }
674   }
675
676   /* when recording the game, store which players take part in the game */
677   if (tape.recording)
678   {
679     for (i=0; i<MAX_PLAYERS; i++)
680       if (stored_player[i].active)
681         tape.player_participates[i] = TRUE;
682   }
683
684   if (options.debug)
685   {
686     for (i=0; i<MAX_PLAYERS; i++)
687     {
688       struct PlayerInfo *player = &stored_player[i];
689
690       printf("Player %d: present == %d, connected == %d, active == %d.\n",
691              i+1,
692              player->present,
693              player->connected,
694              player->active);
695       if (local_player == player)
696         printf("Player  %d is local player.\n", i+1);
697     }
698   }
699
700   game.version = (tape.playing ? tape.game_version : level.game_version);
701   game.emulation = (emulate_bd ? EMU_BOULDERDASH :
702                     emulate_sb ? EMU_SOKOBAN :
703                     emulate_sp ? EMU_SUPAPLEX : EMU_NONE);
704
705   /* dynamically adjust element properties according to game engine version */
706   {
707     static int ep_em_slippery_wall[] =
708     {
709       EL_BETON,
710       EL_MAUERWERK,
711       EL_MAUER_LEBT,
712       EL_MAUER_X,
713       EL_MAUER_Y,
714       EL_MAUER_XY
715     };
716 #if 1
717     static int ep_em_slippery_wall_num = SIZEOF_ARRAY_INT(ep_em_slippery_wall);
718 #else
719     static int ep_em_slippery_wall_num =
720       sizeof(ep_em_slippery_wall) / sizeof(int);
721 #endif
722
723     /*
724     printf("level %d: game.version == %06d\n", level_nr, level.game_version);
725     printf("         file_version == %06d\n", level.file_version);
726     */
727
728     for (i=0; i<ep_em_slippery_wall_num; i++)
729     {
730 #if 1
731       if (level.em_slippery_gems)       /* special EM style gems behaviour */
732 #else
733       if (game.version >= GAME_VERSION_2_0)
734 #endif
735         Elementeigenschaften2[ep_em_slippery_wall[i]] |=
736           EP_BIT_EM_SLIPPERY_WALL;
737       else
738         Elementeigenschaften2[ep_em_slippery_wall[i]] &=
739           ~EP_BIT_EM_SLIPPERY_WALL;
740     }
741   }
742
743   if (BorderElement == EL_LEERRAUM)
744   {
745     SBX_Left = 0;
746     SBX_Right = lev_fieldx - SCR_FIELDX;
747     SBY_Upper = 0;
748     SBY_Lower = lev_fieldy - SCR_FIELDY;
749   }
750   else
751   {
752     SBX_Left = -1;
753     SBX_Right = lev_fieldx - SCR_FIELDX + 1;
754     SBY_Upper = -1;
755     SBY_Lower = lev_fieldy - SCR_FIELDY + 1;
756   }
757
758   if (lev_fieldx + (SBX_Left == -1 ? 2 : 0) <= SCR_FIELDX)
759     SBX_Left = SBX_Right = -1 * (SCR_FIELDX - lev_fieldx) / 2;
760
761   if (lev_fieldy + (SBY_Upper == -1 ? 2 : 0) <= SCR_FIELDY)
762     SBY_Upper = SBY_Lower = -1 * (SCR_FIELDY - lev_fieldy) / 2;
763
764   scroll_x = SBX_Left;
765   scroll_y = SBY_Upper;
766   if (local_player->jx >= SBX_Left + MIDPOSX)
767     scroll_x = (local_player->jx <= SBX_Right + MIDPOSX ?
768                 local_player->jx - MIDPOSX :
769                 SBX_Right);
770   if (local_player->jy >= SBY_Upper + MIDPOSY)
771     scroll_y = (local_player->jy <= SBY_Lower + MIDPOSY ?
772                 local_player->jy - MIDPOSY :
773                 SBY_Lower);
774
775   CloseDoor(DOOR_CLOSE_1);
776
777   DrawLevel();
778   DrawAllPlayers();
779   FadeToFront();
780
781   /* after drawing the level, correct some elements */
782   if (game.timegate_time_left == 0)
783     CloseAllOpenTimegates();
784
785   if (setup.soft_scrolling)
786     BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
787
788   redraw_mask |= REDRAW_FROM_BACKBUFFER;
789
790   /* copy default game door content to main double buffer */
791   BlitBitmap(pix[PIX_DOOR], drawto,
792              DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY);
793
794   if (level_nr < 100)
795     DrawText(DX + XX_LEVEL, DY + YY_LEVEL,
796              int2str(level_nr, 2), FS_SMALL, FC_YELLOW);
797   else
798   {
799     DrawTextExt(drawto, DX + XX_EMERALDS, DY + YY_EMERALDS,
800                 int2str(level_nr, 3), FS_SMALL, FC_SPECIAL3);
801     BlitBitmap(drawto, drawto,
802                DX + XX_EMERALDS, DY + YY_EMERALDS + 1,
803                FONT5_XSIZE * 3, FONT5_YSIZE - 1,
804                DX + XX_LEVEL - 1, DY + YY_LEVEL + 1);
805   }
806
807 #if 1
808   DrawGameDoorValues();
809 #else
810   DrawText(DX + XX_EMERALDS, DY + YY_EMERALDS,
811            int2str(local_player->gems_still_needed, 3), FS_SMALL, FC_YELLOW);
812   DrawText(DX + XX_DYNAMITE, DY + YY_DYNAMITE,
813            int2str(local_player->dynamite, 3), FS_SMALL, FC_YELLOW);
814   DrawText(DX + XX_SCORE, DY + YY_SCORE,
815            int2str(local_player->score, 5), FS_SMALL, FC_YELLOW);
816   DrawText(DX + XX_TIME, DY + YY_TIME,
817            int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
818 #endif
819
820   UnmapGameButtons();
821   UnmapTapeButtons();
822   game_gadget[SOUND_CTRL_ID_MUSIC]->checked = setup.sound_music;
823   game_gadget[SOUND_CTRL_ID_LOOPS]->checked = setup.sound_loops;
824   game_gadget[SOUND_CTRL_ID_SIMPLE]->checked = setup.sound_simple;
825   MapGameButtons();
826   MapTapeButtons();
827
828   /* copy actual game door content to door double buffer for OpenDoor() */
829   BlitBitmap(drawto, pix[PIX_DB_DOOR],
830              DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
831
832   OpenDoor(DOOR_OPEN_ALL);
833
834   if (setup.sound_music && num_bg_loops)
835     PlayMusic(level_nr % num_bg_loops);
836
837   KeyboardAutoRepeatOff();
838
839   if (options.debug)
840   {
841     for (i=0; i<4; i++)
842       printf("Player %d %sactive.\n",
843              i + 1, (stored_player[i].active ? "" : "not "));
844   }
845 }
846
847 void InitMovDir(int x, int y)
848 {
849   int i, element = Feld[x][y];
850   static int xy[4][2] =
851   {
852     {  0, +1 },
853     { +1,  0 },
854     {  0, -1 },
855     { -1,  0 }
856   };
857   static int direction[3][4] =
858   {
859     { MV_RIGHT, MV_UP,   MV_LEFT,  MV_DOWN },
860     { MV_LEFT,  MV_DOWN, MV_RIGHT, MV_UP },
861     { MV_LEFT,  MV_RIGHT, MV_UP, MV_DOWN }
862   };
863
864   switch(element)
865   {
866     case EL_KAEFER_RIGHT:
867     case EL_KAEFER_UP:
868     case EL_KAEFER_LEFT:
869     case EL_KAEFER_DOWN:
870       Feld[x][y] = EL_KAEFER;
871       MovDir[x][y] = direction[0][element - EL_KAEFER_RIGHT];
872       break;
873
874     case EL_FLIEGER_RIGHT:
875     case EL_FLIEGER_UP:
876     case EL_FLIEGER_LEFT:
877     case EL_FLIEGER_DOWN:
878       Feld[x][y] = EL_FLIEGER;
879       MovDir[x][y] = direction[0][element - EL_FLIEGER_RIGHT];
880       break;
881
882     case EL_BUTTERFLY_RIGHT:
883     case EL_BUTTERFLY_UP:
884     case EL_BUTTERFLY_LEFT:
885     case EL_BUTTERFLY_DOWN:
886       Feld[x][y] = EL_BUTTERFLY;
887       MovDir[x][y] = direction[0][element - EL_BUTTERFLY_RIGHT];
888       break;
889
890     case EL_FIREFLY_RIGHT:
891     case EL_FIREFLY_UP:
892     case EL_FIREFLY_LEFT:
893     case EL_FIREFLY_DOWN:
894       Feld[x][y] = EL_FIREFLY;
895       MovDir[x][y] = direction[0][element - EL_FIREFLY_RIGHT];
896       break;
897
898     case EL_PACMAN_RIGHT:
899     case EL_PACMAN_UP:
900     case EL_PACMAN_LEFT:
901     case EL_PACMAN_DOWN:
902       Feld[x][y] = EL_PACMAN;
903       MovDir[x][y] = direction[0][element - EL_PACMAN_RIGHT];
904       break;
905
906     case EL_SP_SNIKSNAK:
907       MovDir[x][y] = MV_UP;
908       break;
909
910     case EL_SP_ELECTRON:
911       MovDir[x][y] = MV_LEFT;
912       break;
913
914     case EL_MOLE_LEFT:
915     case EL_MOLE_RIGHT:
916     case EL_MOLE_UP:
917     case EL_MOLE_DOWN:
918       Feld[x][y] = EL_MOLE;
919       MovDir[x][y] = direction[2][element - EL_MOLE_LEFT];
920       break;
921
922     default:
923       MovDir[x][y] = 1 << RND(4);
924       if (element != EL_KAEFER &&
925           element != EL_FLIEGER &&
926           element != EL_BUTTERFLY &&
927           element != EL_FIREFLY)
928         break;
929
930       for (i=0; i<4; i++)
931       {
932         int x1 = x + xy[i][0];
933         int y1 = y + xy[i][1];
934
935         if (!IN_LEV_FIELD(x1, y1) || !IS_FREE(x1, y1))
936         {
937           if (element == EL_KAEFER || element == EL_BUTTERFLY)
938           {
939             MovDir[x][y] = direction[0][i];
940             break;
941           }
942           else if (element == EL_FLIEGER || element == EL_FIREFLY ||
943                    element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
944           {
945             MovDir[x][y] = direction[1][i];
946             break;
947           }
948         }
949       }
950       break;
951   }
952 }
953
954 void InitAmoebaNr(int x, int y)
955 {
956   int i;
957   int group_nr = AmoebeNachbarNr(x, y);
958
959   if (group_nr == 0)
960   {
961     for (i=1; i<MAX_NUM_AMOEBA; i++)
962     {
963       if (AmoebaCnt[i] == 0)
964       {
965         group_nr = i;
966         break;
967       }
968     }
969   }
970
971   AmoebaNr[x][y] = group_nr;
972   AmoebaCnt[group_nr]++;
973   AmoebaCnt2[group_nr]++;
974 }
975
976 void GameWon()
977 {
978   int hi_pos;
979   boolean raise_level = FALSE;
980
981   if (local_player->MovPos)
982     return;
983
984   local_player->LevelSolved = FALSE;
985
986   if (TimeLeft)
987   {
988     if (!tape.playing && setup.sound_loops)
989       PlaySoundExt(SND_SIRR, PSND_MAX_VOLUME, PSND_MAX_RIGHT, PSND_LOOP);
990
991     while(TimeLeft > 0)
992     {
993       if (!tape.playing && !setup.sound_loops)
994         PlaySoundStereo(SND_SIRR, PSND_MAX_RIGHT);
995       if (TimeLeft > 0 && !(TimeLeft % 10))
996         RaiseScore(level.score[SC_ZEITBONUS]);
997       if (TimeLeft > 100 && !(TimeLeft % 10))
998         TimeLeft -= 10;
999       else
1000         TimeLeft--;
1001       DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
1002       BackToFront();
1003
1004       if (!tape.playing)
1005         Delay(10);
1006     }
1007
1008     if (!tape.playing && setup.sound_loops)
1009       StopSound(SND_SIRR);
1010   }
1011   else if (level.time == 0)             /* level without time limit */
1012   {
1013     if (!tape.playing && setup.sound_loops)
1014       PlaySoundExt(SND_SIRR, PSND_MAX_VOLUME, PSND_MAX_RIGHT, PSND_LOOP);
1015
1016     while(TimePlayed < 999)
1017     {
1018       if (!tape.playing && !setup.sound_loops)
1019         PlaySoundStereo(SND_SIRR, PSND_MAX_RIGHT);
1020       if (TimePlayed < 999 && !(TimePlayed % 10))
1021         RaiseScore(level.score[SC_ZEITBONUS]);
1022       if (TimePlayed < 900 && !(TimePlayed % 10))
1023         TimePlayed += 10;
1024       else
1025         TimePlayed++;
1026       DrawText(DX_TIME, DY_TIME, int2str(TimePlayed, 3), FS_SMALL, FC_YELLOW);
1027       BackToFront();
1028
1029       if (!tape.playing)
1030         Delay(10);
1031     }
1032
1033     if (!tape.playing && setup.sound_loops)
1034       StopSound(SND_SIRR);
1035   }
1036
1037 #if 0
1038   FadeSounds();
1039 #endif
1040
1041   /* Hero disappears */
1042   DrawLevelField(ExitX, ExitY);
1043   BackToFront();
1044
1045   if (tape.playing)
1046     return;
1047
1048   CloseDoor(DOOR_CLOSE_1);
1049
1050   if (tape.recording)
1051   {
1052     TapeStop();
1053     SaveTape(tape.level_nr);            /* Ask to save tape */
1054   }
1055
1056   if (level_nr == leveldir_current->handicap_level)
1057   {
1058     leveldir_current->handicap_level++;
1059     SaveLevelSetup_SeriesInfo();
1060   }
1061
1062   if (level_editor_test_game)
1063     local_player->score = -1;   /* no highscore when playing from editor */
1064   else if (level_nr < leveldir_current->last_level)
1065     raise_level = TRUE;         /* advance to next level */
1066
1067   if ((hi_pos = NewHiScore()) >= 0) 
1068   {
1069     game_status = HALLOFFAME;
1070     DrawHallOfFame(hi_pos);
1071     if (raise_level)
1072     {
1073       level_nr++;
1074       TapeErase();
1075     }
1076   }
1077   else
1078   {
1079     game_status = MAINMENU;
1080     if (raise_level)
1081     {
1082       level_nr++;
1083       TapeErase();
1084     }
1085     DrawMainMenu();
1086   }
1087
1088   BackToFront();
1089 }
1090
1091 int NewHiScore()
1092 {
1093   int k, l;
1094   int position = -1;
1095
1096   LoadScore(level_nr);
1097
1098   if (strcmp(setup.player_name, EMPTY_PLAYER_NAME) == 0 ||
1099       local_player->score < highscore[MAX_SCORE_ENTRIES - 1].Score) 
1100     return -1;
1101
1102   for (k=0; k<MAX_SCORE_ENTRIES; k++) 
1103   {
1104     if (local_player->score > highscore[k].Score)
1105     {
1106       /* player has made it to the hall of fame */
1107
1108       if (k < MAX_SCORE_ENTRIES - 1)
1109       {
1110         int m = MAX_SCORE_ENTRIES - 1;
1111
1112 #ifdef ONE_PER_NAME
1113         for (l=k; l<MAX_SCORE_ENTRIES; l++)
1114           if (!strcmp(setup.player_name, highscore[l].Name))
1115             m = l;
1116         if (m == k)     /* player's new highscore overwrites his old one */
1117           goto put_into_list;
1118 #endif
1119
1120         for (l=m; l>k; l--)
1121         {
1122           strcpy(highscore[l].Name, highscore[l - 1].Name);
1123           highscore[l].Score = highscore[l - 1].Score;
1124         }
1125       }
1126
1127 #ifdef ONE_PER_NAME
1128       put_into_list:
1129 #endif
1130       strncpy(highscore[k].Name, setup.player_name, MAX_PLAYER_NAME_LEN);
1131       highscore[k].Name[MAX_PLAYER_NAME_LEN] = '\0';
1132       highscore[k].Score = local_player->score; 
1133       position = k;
1134       break;
1135     }
1136
1137 #ifdef ONE_PER_NAME
1138     else if (!strncmp(setup.player_name, highscore[k].Name,
1139                       MAX_PLAYER_NAME_LEN))
1140       break;    /* player already there with a higher score */
1141 #endif
1142
1143   }
1144
1145   if (position >= 0) 
1146     SaveScore(level_nr);
1147
1148   return position;
1149 }
1150
1151 void InitMovingField(int x, int y, int direction)
1152 {
1153   int newx = x + (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
1154   int newy = y + (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
1155
1156   MovDir[x][y] = direction;
1157   MovDir[newx][newy] = direction;
1158   if (Feld[newx][newy] == EL_LEERRAUM)
1159     Feld[newx][newy] = EL_BLOCKED;
1160 }
1161
1162 void Moving2Blocked(int x, int y, int *goes_to_x, int *goes_to_y)
1163 {
1164   int direction = MovDir[x][y];
1165   int newx = x + (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
1166   int newy = y + (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
1167
1168   *goes_to_x = newx;
1169   *goes_to_y = newy;
1170 }
1171
1172 void Blocked2Moving(int x, int y, int *comes_from_x, int *comes_from_y)
1173 {
1174   int oldx = x, oldy = y;
1175   int direction = MovDir[x][y];
1176
1177   if (direction == MV_LEFT)
1178     oldx++;
1179   else if (direction == MV_RIGHT)
1180     oldx--;
1181   else if (direction == MV_UP)
1182     oldy++;
1183   else if (direction == MV_DOWN)
1184     oldy--;
1185
1186   *comes_from_x = oldx;
1187   *comes_from_y = oldy;
1188 }
1189
1190 int MovingOrBlocked2Element(int x, int y)
1191 {
1192   int element = Feld[x][y];
1193
1194   if (element == EL_BLOCKED)
1195   {
1196     int oldx, oldy;
1197
1198     Blocked2Moving(x, y, &oldx, &oldy);
1199     return Feld[oldx][oldy];
1200   }
1201   else
1202     return element;
1203 }
1204
1205 static int MovingOrBlocked2ElementIfNotLeaving(int x, int y)
1206 {
1207   /* like MovingOrBlocked2Element(), but if element is moving
1208      and (x,y) is the field the moving element is just leaving,
1209      return EL_BLOCKED instead of the element value */
1210   int element = Feld[x][y];
1211
1212   if (IS_MOVING(x, y))
1213   {
1214     if (element == EL_BLOCKED)
1215     {
1216       int oldx, oldy;
1217
1218       Blocked2Moving(x, y, &oldx, &oldy);
1219       return Feld[oldx][oldy];
1220     }
1221     else
1222       return EL_BLOCKED;
1223   }
1224   else
1225     return element;
1226 }
1227
1228 static void RemoveField(int x, int y)
1229 {
1230   Feld[x][y] = EL_LEERRAUM;
1231   MovPos[x][y] = 0;
1232   MovDir[x][y] = 0;
1233   MovDelay[x][y] = 0;
1234 }
1235
1236 void RemoveMovingField(int x, int y)
1237 {
1238   int oldx = x, oldy = y, newx = x, newy = y;
1239
1240   if (Feld[x][y] != EL_BLOCKED && !IS_MOVING(x, y))
1241     return;
1242
1243   if (IS_MOVING(x, y))
1244   {
1245     Moving2Blocked(x, y, &newx, &newy);
1246     if (Feld[newx][newy] != EL_BLOCKED)
1247       return;
1248   }
1249   else if (Feld[x][y] == EL_BLOCKED)
1250   {
1251     Blocked2Moving(x, y, &oldx, &oldy);
1252     if (!IS_MOVING(oldx, oldy))
1253       return;
1254   }
1255
1256   if (Feld[x][y] == EL_BLOCKED &&
1257       (Feld[oldx][oldy] == EL_QUICKSAND_EMPTYING ||
1258        Feld[oldx][oldy] == EL_MAGIC_WALL_EMPTYING ||
1259        Feld[oldx][oldy] == EL_MAGIC_WALL_BD_EMPTYING ||
1260        Feld[oldx][oldy] == EL_AMOEBA_DRIPPING))
1261     Feld[oldx][oldy] = get_next_element(Feld[oldx][oldy]);
1262   else
1263     Feld[oldx][oldy] = EL_LEERRAUM;
1264
1265   Store[oldx][oldy] = Store2[oldx][oldy] = 0;
1266
1267   Feld[newx][newy] = EL_LEERRAUM;
1268   MovPos[oldx][oldy] = MovDir[oldx][oldy] = MovDelay[oldx][oldy] = 0;
1269   MovPos[newx][newy] = MovDir[newx][newy] = MovDelay[newx][newy] = 0;
1270
1271   DrawLevelField(oldx, oldy);
1272   DrawLevelField(newx, newy);
1273 }
1274
1275 void DrawDynamite(int x, int y)
1276 {
1277   int sx = SCREENX(x), sy = SCREENY(y);
1278   int graphic = el2gfx(Feld[x][y]);
1279   int phase;
1280
1281   if (!IN_SCR_FIELD(sx, sy) || IS_PLAYER(x, y))
1282     return;
1283
1284   if (Store[x][y])
1285     DrawGraphic(sx, sy, el2gfx(Store[x][y]));
1286
1287   if (Feld[x][y] == EL_DYNAMITE_ACTIVE)
1288   {
1289     if ((phase = (96 - MovDelay[x][y]) / 12) > 6)
1290       phase = 6;
1291   }
1292   else
1293   {
1294     if ((phase = ((96 - MovDelay[x][y]) / 6) % 8) > 3)
1295       phase = 7 - phase;
1296   }
1297
1298   if (game.emulation == EMU_SUPAPLEX)
1299     DrawGraphic(sx, sy, GFX_SP_DISK_RED);
1300   else if (Store[x][y])
1301     DrawGraphicThruMask(sx, sy, graphic + phase);
1302   else
1303     DrawGraphic(sx, sy, graphic + phase);
1304 }
1305
1306 void CheckDynamite(int x, int y)
1307 {
1308   if (MovDelay[x][y])           /* dynamite is still waiting to explode */
1309   {
1310     MovDelay[x][y]--;
1311     if (MovDelay[x][y])
1312     {
1313       if (!(MovDelay[x][y] % 12))
1314         PlaySoundLevel(x, y, SND_ZISCH);
1315
1316       if (IS_ACTIVE_BOMB(Feld[x][y]))
1317       {
1318         int delay = (Feld[x][y] == EL_DYNAMITE_ACTIVE ? 12 : 6);
1319
1320         if (!(MovDelay[x][y] % delay))
1321           DrawDynamite(x, y);
1322       }
1323
1324       return;
1325     }
1326   }
1327
1328   StopSound(SND_ZISCH);
1329   Bang(x, y);
1330 }
1331
1332 void Explode(int ex, int ey, int phase, int mode)
1333 {
1334   int x, y;
1335   int num_phase = 9, delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
1336   int last_phase = num_phase * delay;
1337   int half_phase = (num_phase / 2) * delay;
1338   int first_phase_after_start = EX_PHASE_START + 1;
1339
1340   if (game.explosions_delayed)
1341   {
1342     ExplodeField[ex][ey] = mode;
1343     return;
1344   }
1345
1346   if (phase == EX_PHASE_START)          /* initialize 'Store[][]' field */
1347   {
1348     int center_element = Feld[ex][ey];
1349
1350     if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey))
1351     {
1352       /* put moving element to center field (and let it explode there) */
1353       center_element = MovingOrBlocked2Element(ex, ey);
1354       RemoveMovingField(ex, ey);
1355       Feld[ex][ey] = center_element;
1356     }
1357
1358     for (y=ey-1; y<=ey+1; y++) for(x=ex-1; x<=ex+1; x++)
1359     {
1360       int element;
1361
1362       if (!IN_LEV_FIELD(x, y) ||
1363           ((mode != EX_NORMAL || center_element == EL_AMOEBA2DIAM) &&
1364            (x != ex || y != ey)))
1365         continue;
1366
1367       element = Feld[x][y];
1368
1369       if (IS_MOVING(x, y) || IS_BLOCKED(x, y))
1370       {
1371         element = MovingOrBlocked2Element(x, y);
1372         RemoveMovingField(x, y);
1373       }
1374
1375       if (IS_MASSIVE(element) || element == EL_BURNING)
1376         continue;
1377
1378       if (IS_PLAYER(x, y) && SHIELD_ON(PLAYERINFO(x, y)))
1379       {
1380         if (IS_ACTIVE_BOMB(element))
1381         {
1382           /* re-activate things under the bomb like gate or penguin */
1383           Feld[x][y] = (Store[x][y] ? Store[x][y] : EL_LEERRAUM);
1384           Store[x][y] = 0;
1385         }
1386
1387         continue;
1388       }
1389
1390       if (element == EL_EXPLODING)
1391         element = Store2[x][y];
1392
1393       if (IS_PLAYER(ex, ey) && !PLAYER_PROTECTED(ex, ey))
1394       {
1395         switch(StorePlayer[ex][ey])
1396         {
1397           case EL_SPIELER2:
1398             Store[x][y] = EL_EDELSTEIN_ROT;
1399             break;
1400           case EL_SPIELER3:
1401             Store[x][y] = EL_EDELSTEIN;
1402             break;
1403           case EL_SPIELER4:
1404             Store[x][y] = EL_EDELSTEIN_LILA;
1405             break;
1406           case EL_SPIELER1:
1407           default:
1408             Store[x][y] = EL_EDELSTEIN_GELB;
1409             break;
1410         }
1411
1412         if (game.emulation == EMU_SUPAPLEX)
1413           Store[x][y] = EL_LEERRAUM;
1414       }
1415       else if (center_element == EL_MOLE)
1416         Store[x][y] = EL_EDELSTEIN_ROT;
1417       else if (center_element == EL_PINGUIN)
1418         Store[x][y] = EL_EDELSTEIN_LILA;
1419       else if (center_element == EL_KAEFER)
1420         Store[x][y] = ((x == ex && y == ey) ? EL_DIAMANT : EL_EDELSTEIN);
1421       else if (center_element == EL_BUTTERFLY)
1422         Store[x][y] = EL_EDELSTEIN_BD;
1423       else if (center_element == EL_SP_ELECTRON)
1424         Store[x][y] = EL_SP_INFOTRON;
1425       else if (center_element == EL_MAMPFER)
1426         Store[x][y] = level.yam_content[game.yam_content_nr][x-ex+1][y-ey+1];
1427       else if (center_element == EL_AMOEBA2DIAM)
1428         Store[x][y] = level.amoeba_content;
1429       else if (element == EL_ERZ_EDEL)
1430         Store[x][y] = EL_EDELSTEIN;
1431       else if (element == EL_ERZ_DIAM)
1432         Store[x][y] = EL_DIAMANT;
1433       else if (element == EL_ERZ_EDEL_BD)
1434         Store[x][y] = EL_EDELSTEIN_BD;
1435       else if (element == EL_ERZ_EDEL_GELB)
1436         Store[x][y] = EL_EDELSTEIN_GELB;
1437       else if (element == EL_ERZ_EDEL_ROT)
1438         Store[x][y] = EL_EDELSTEIN_ROT;
1439       else if (element == EL_ERZ_EDEL_LILA)
1440         Store[x][y] = EL_EDELSTEIN_LILA;
1441       else if (element == EL_WALL_PEARL)
1442         Store[x][y] = EL_PEARL;
1443       else if (element == EL_WALL_CRYSTAL)
1444         Store[x][y] = EL_CRYSTAL;
1445       else if (!IS_PFORTE(Store[x][y]))
1446         Store[x][y] = EL_LEERRAUM;
1447
1448       if (x != ex || y != ey ||
1449           center_element == EL_AMOEBA2DIAM || mode == EX_BORDER)
1450         Store2[x][y] = element;
1451
1452       if (AmoebaNr[x][y] &&
1453           (element == EL_AMOEBE_VOLL ||
1454            element == EL_AMOEBE_BD ||
1455            element == EL_AMOEBING))
1456       {
1457         AmoebaCnt[AmoebaNr[x][y]]--;
1458         AmoebaCnt2[AmoebaNr[x][y]]--;
1459       }
1460
1461       Feld[x][y] = EL_EXPLODING;
1462       MovDir[x][y] = MovPos[x][y] = 0;
1463       AmoebaNr[x][y] = 0;
1464       Frame[x][y] = 1;
1465       Stop[x][y] = TRUE;
1466     }
1467
1468     if (center_element == EL_MAMPFER)
1469       game.yam_content_nr = (game.yam_content_nr + 1) % level.num_yam_contents;
1470
1471     return;
1472   }
1473
1474   if (Stop[ex][ey])
1475     return;
1476
1477   x = ex;
1478   y = ey;
1479
1480   Frame[x][y] = (phase < last_phase ? phase + 1 : 0);
1481
1482   if (phase == first_phase_after_start)
1483   {
1484     int element = Store2[x][y];
1485
1486     if (element == EL_BLACK_ORB)
1487     {
1488       Feld[x][y] = Store2[x][y];
1489       Store2[x][y] = 0;
1490       Bang(x, y);
1491     }
1492   }
1493   else if (phase == half_phase)
1494   {
1495     int element = Store2[x][y];
1496
1497     if (IS_PLAYER(x, y))
1498       KillHeroUnlessProtected(x, y);
1499     else if (IS_EXPLOSIVE(element))
1500     {
1501       Feld[x][y] = Store2[x][y];
1502       Store2[x][y] = 0;
1503       Bang(x, y);
1504     }
1505     else if (element == EL_AMOEBA2DIAM)
1506       AmoebeUmwandeln(x, y);
1507   }
1508
1509   if (phase == last_phase)
1510   {
1511     int element;
1512
1513     element = Feld[x][y] = Store[x][y];
1514     Store[x][y] = Store2[x][y] = 0;
1515     MovDir[x][y] = MovPos[x][y] = MovDelay[x][y] = 0;
1516     InitField(x, y, FALSE);
1517     if (CAN_MOVE(element) || COULD_MOVE(element))
1518       InitMovDir(x, y);
1519     DrawLevelField(x, y);
1520
1521     if (IS_PLAYER(x, y) && !PLAYERINFO(x,y)->present)
1522       StorePlayer[x][y] = 0;
1523   }
1524   else if (!(phase % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1525   {
1526     int graphic = GFX_EXPLOSION;
1527
1528     if (game.emulation == EMU_SUPAPLEX)
1529       graphic = (Store[x][y] == EL_SP_INFOTRON ?
1530                  GFX_SP_EXPLODE_INFOTRON :
1531                  GFX_SP_EXPLODE_EMPTY);
1532
1533     if (phase == delay)
1534       ErdreichAnbroeckeln(SCREENX(x), SCREENY(y));
1535
1536     graphic += (phase / delay - 1);
1537
1538     if (IS_PFORTE(Store[x][y]))
1539     {
1540       DrawLevelElement(x, y, Store[x][y]);
1541       DrawGraphicThruMask(SCREENX(x), SCREENY(y), graphic);
1542     }
1543     else
1544       DrawGraphic(SCREENX(x), SCREENY(y), graphic);
1545   }
1546 }
1547
1548 void DynaExplode(int ex, int ey)
1549 {
1550   int i, j;
1551   int dynabomb_size = 1;
1552   boolean dynabomb_xl = FALSE;
1553   struct PlayerInfo *player;
1554   static int xy[4][2] =
1555   {
1556     { 0, -1 },
1557     { -1, 0 },
1558     { +1, 0 },
1559     { 0, +1 }
1560   };
1561
1562   if (IS_ACTIVE_BOMB(Feld[ex][ey]))
1563   {
1564     player = &stored_player[Feld[ex][ey] - EL_DYNABOMB_ACTIVE_1];
1565     dynabomb_size = player->dynabomb_size;
1566     dynabomb_xl = player->dynabomb_xl;
1567     player->dynabombs_left++;
1568   }
1569
1570   Explode(ex, ey, EX_PHASE_START, EX_CENTER);
1571
1572   for (i=0; i<4; i++)
1573   {
1574     for (j=1; j<=dynabomb_size; j++)
1575     {
1576       int x = ex + j * xy[i % 4][0];
1577       int y = ey + j * xy[i % 4][1];
1578       int element;
1579
1580       if (!IN_LEV_FIELD(x, y) || IS_MASSIVE(Feld[x][y]))
1581         break;
1582
1583       element = Feld[x][y];
1584
1585       /* do not restart explosions of fields with active bombs */
1586       if (element == EL_EXPLODING && IS_ACTIVE_BOMB(Store2[x][y]))
1587         continue;
1588
1589       Explode(x, y, EX_PHASE_START, EX_BORDER);
1590
1591       if (element != EL_LEERRAUM &&
1592           element != EL_ERDREICH &&
1593           element != EL_EXPLODING &&
1594           !dynabomb_xl)
1595         break;
1596     }
1597   }
1598 }
1599
1600 void Bang(int x, int y)
1601 {
1602   int element = Feld[x][y];
1603
1604   if (game.emulation == EMU_SUPAPLEX)
1605     PlaySoundLevel(x, y, SND_SP_BOOOM);
1606   else
1607     PlaySoundLevel(x, y, SND_ROAAAR);
1608
1609 #if 0
1610   if (IS_PLAYER(x, y))  /* remove objects that might cause smaller explosion */
1611     element = EL_LEERRAUM;
1612 #endif
1613
1614   switch(element)
1615   {
1616     case EL_KAEFER:
1617     case EL_FLIEGER:
1618     case EL_BUTTERFLY:
1619     case EL_FIREFLY:
1620     case EL_MAMPFER:
1621     case EL_MAMPFER2:
1622     case EL_ROBOT:
1623     case EL_PACMAN:
1624     case EL_MOLE:
1625       RaiseScoreElement(element);
1626       Explode(x, y, EX_PHASE_START, EX_NORMAL);
1627       break;
1628     case EL_DYNABOMB_ACTIVE_1:
1629     case EL_DYNABOMB_ACTIVE_2:
1630     case EL_DYNABOMB_ACTIVE_3:
1631     case EL_DYNABOMB_ACTIVE_4:
1632     case EL_DYNABOMB_NR:
1633     case EL_DYNABOMB_SZ:
1634     case EL_DYNABOMB_XL:
1635       DynaExplode(x, y);
1636       break;
1637     case EL_PINGUIN:
1638     case EL_BIRNE_AUS:
1639     case EL_BIRNE_EIN:
1640       if (IS_PLAYER(x, y))
1641         Explode(x, y, EX_PHASE_START, EX_NORMAL);
1642       else
1643         Explode(x, y, EX_PHASE_START, EX_CENTER);
1644       break;
1645     default:
1646       Explode(x, y, EX_PHASE_START, EX_NORMAL);
1647       break;
1648   }
1649 }
1650
1651 void Blurb(int x, int y)
1652 {
1653   int element = Feld[x][y];
1654
1655   if (element != EL_BLURB_LEFT && element != EL_BLURB_RIGHT)    /* start */
1656   {
1657     PlaySoundLevel(x, y, SND_BLURB);
1658     if (IN_LEV_FIELD(x-1, y) && IS_FREE(x-1, y) &&
1659         (!IN_LEV_FIELD(x-1, y-1) ||
1660          !CAN_FALL(MovingOrBlocked2Element(x-1, y-1))))
1661     {
1662       Feld[x-1][y] = EL_BLURB_LEFT;
1663     }
1664     if (IN_LEV_FIELD(x+1, y) && IS_FREE(x+1, y) &&
1665         (!IN_LEV_FIELD(x+1, y-1) ||
1666          !CAN_FALL(MovingOrBlocked2Element(x+1, y-1))))
1667     {
1668       Feld[x+1][y] = EL_BLURB_RIGHT;
1669     }
1670   }
1671   else                                                          /* go on */
1672   {
1673     int graphic = (element==EL_BLURB_LEFT ? GFX_BLURB_LEFT : GFX_BLURB_RIGHT);
1674
1675     if (!MovDelay[x][y])        /* initialize animation counter */
1676       MovDelay[x][y] = 9;
1677
1678     if (MovDelay[x][y])         /* continue animation */
1679     {
1680       MovDelay[x][y]--;
1681       if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1682         DrawGraphic(SCREENX(x), SCREENY(y), graphic+4-MovDelay[x][y]/2);
1683
1684       if (!MovDelay[x][y])
1685       {
1686         Feld[x][y] = EL_LEERRAUM;
1687         DrawLevelField(x, y);
1688       }
1689     }
1690   }
1691 }
1692
1693 static void ToggleBeltSwitch(int x, int y)
1694 {
1695   static int belt_base_element[4] =
1696   {
1697     EL_BELT1_SWITCH_LEFT,
1698     EL_BELT2_SWITCH_LEFT,
1699     EL_BELT3_SWITCH_LEFT,
1700     EL_BELT4_SWITCH_LEFT
1701   };
1702   static int belt_move_dir[4] =
1703   {
1704     MV_LEFT,
1705     MV_NO_MOVING,
1706     MV_RIGHT,
1707     MV_NO_MOVING,
1708   };
1709
1710   int element = Feld[x][y];
1711   int belt_nr = getBeltNrFromSwitchElement(element);
1712   int belt_dir_nr = (game.belt_dir_nr[belt_nr] + 1) % 4;
1713   int belt_dir = belt_move_dir[belt_dir_nr];
1714   int xx, yy;
1715
1716   if (!IS_BELT_SWITCH(element))
1717     return;
1718
1719   game.belt_dir_nr[belt_nr] = belt_dir_nr;
1720   game.belt_dir[belt_nr] = belt_dir;
1721
1722   if (belt_dir_nr == 3)
1723     belt_dir_nr = 1;
1724
1725   for (yy=0; yy<lev_fieldy; yy++)
1726   {
1727     for (xx=0; xx<lev_fieldx; xx++)
1728     {
1729       int element = Feld[xx][yy];
1730
1731       if (IS_BELT_SWITCH(element))
1732       {
1733         int e_belt_nr = getBeltNrFromSwitchElement(element);
1734
1735         if (e_belt_nr == belt_nr)
1736         {
1737           Feld[xx][yy] = belt_base_element[belt_nr] + belt_dir_nr;
1738           DrawLevelField(xx, yy);
1739         }
1740       }
1741       else if (belt_dir == MV_NO_MOVING && IS_BELT(element))
1742       {
1743         int e_belt_nr = getBeltNrFromElement(element);
1744
1745         if (e_belt_nr == belt_nr)
1746           DrawLevelField(xx, yy);    /* set belt to parking position */
1747       }
1748     }
1749   }
1750 }
1751
1752 static void ToggleSwitchgateSwitch(int x, int y)
1753 {
1754   int xx, yy;
1755
1756   game.switchgate_pos = !game.switchgate_pos;
1757
1758   for (yy=0; yy<lev_fieldy; yy++)
1759   {
1760     for (xx=0; xx<lev_fieldx; xx++)
1761     {
1762       int element = Feld[xx][yy];
1763
1764       if (element == EL_SWITCHGATE_SWITCH_1 ||
1765           element == EL_SWITCHGATE_SWITCH_2)
1766       {
1767         Feld[xx][yy] = EL_SWITCHGATE_SWITCH_1 + game.switchgate_pos;
1768         DrawLevelField(xx, yy);
1769       }
1770       else if (element == EL_SWITCHGATE_OPEN ||
1771                element == EL_SWITCHGATE_OPENING)
1772       {
1773         Feld[xx][yy] = EL_SWITCHGATE_CLOSING;
1774         PlaySoundLevel(xx, yy, SND_OEFFNEN);
1775       }
1776       else if (element == EL_SWITCHGATE_CLOSED ||
1777                element == EL_SWITCHGATE_CLOSING)
1778       {
1779         Feld[xx][yy] = EL_SWITCHGATE_OPENING;
1780         PlaySoundLevel(xx, yy, SND_OEFFNEN);
1781       }
1782     }
1783   }
1784 }
1785
1786 static void RedrawAllLightSwitchesAndInvisibleElements()
1787 {
1788   int x, y;
1789
1790   for (y=0; y<lev_fieldy; y++)
1791   {
1792     for (x=0; x<lev_fieldx; x++)
1793     {
1794       int element = Feld[x][y];
1795
1796       if (element == EL_LIGHT_SWITCH_OFF &&
1797           game.light_time_left > 0)
1798       {
1799         Feld[x][y] = EL_LIGHT_SWITCH_ON;
1800         DrawLevelField(x, y);
1801       }
1802       else if (element == EL_LIGHT_SWITCH_ON &&
1803                game.light_time_left == 0)
1804       {
1805         Feld[x][y] = EL_LIGHT_SWITCH_OFF;
1806         DrawLevelField(x, y);
1807       }
1808
1809       if (element == EL_INVISIBLE_STEEL ||
1810           element == EL_UNSICHTBAR ||
1811           element == EL_SAND_INVISIBLE)
1812         DrawLevelField(x, y);
1813     }
1814   }
1815 }
1816
1817 static void ToggleLightSwitch(int x, int y)
1818 {
1819   int element = Feld[x][y];
1820
1821   game.light_time_left =
1822     (element == EL_LIGHT_SWITCH_OFF ?
1823      level.time_light * FRAMES_PER_SECOND : 0);
1824
1825   RedrawAllLightSwitchesAndInvisibleElements();
1826 }
1827
1828 static void ActivateTimegateSwitch(int x, int y)
1829 {
1830   int xx, yy;
1831
1832   game.timegate_time_left = level.time_timegate * FRAMES_PER_SECOND;
1833
1834   for (yy=0; yy<lev_fieldy; yy++)
1835   {
1836     for (xx=0; xx<lev_fieldx; xx++)
1837     {
1838       int element = Feld[xx][yy];
1839
1840       if (element == EL_TIMEGATE_CLOSED ||
1841           element == EL_TIMEGATE_CLOSING)
1842       {
1843         Feld[xx][yy] = EL_TIMEGATE_OPENING;
1844         PlaySoundLevel(xx, yy, SND_OEFFNEN);
1845       }
1846
1847       /*
1848       else if (element == EL_TIMEGATE_SWITCH_ON)
1849       {
1850         Feld[xx][yy] = EL_TIMEGATE_SWITCH_OFF;
1851         DrawLevelField(xx, yy);
1852       }
1853       */
1854
1855     }
1856   }
1857
1858   Feld[x][y] = EL_TIMEGATE_SWITCH_ON;
1859 }
1860
1861 void Impact(int x, int y)
1862 {
1863   boolean lastline = (y == lev_fieldy-1);
1864   boolean object_hit = FALSE;
1865   int element = Feld[x][y];
1866   int smashed = 0;
1867
1868   if (!lastline)        /* check if element below was hit */
1869   {
1870     if (Feld[x][y+1] == EL_PLAYER_IS_LEAVING)
1871       return;
1872
1873     object_hit = (!IS_FREE(x, y+1) && (!IS_MOVING(x, y+1) ||
1874                                       MovDir[x][y+1]!=MV_DOWN ||
1875                                       MovPos[x][y+1]<=TILEY/2));
1876     if (object_hit)
1877       smashed = MovingOrBlocked2Element(x, y+1);
1878   }
1879
1880   if (!lastline && smashed == EL_SALZSAEURE)    /* element falls into acid */
1881   {
1882     Blurb(x, y);
1883     return;
1884   }
1885
1886   if ((element == EL_BOMBE ||
1887        element == EL_SP_DISK_ORANGE ||
1888        element == EL_DX_SUPABOMB) &&
1889       (lastline || object_hit)) /* element is bomb */
1890   {
1891     Bang(x, y);
1892     return;
1893   }
1894   else if (element == EL_PEARL)
1895   {
1896     Feld[x][y] = EL_PEARL_BREAKING;
1897     PlaySoundLevel(x, y, SND_KNACK);
1898     return;
1899   }
1900
1901   if (element == EL_TROPFEN && (lastline || object_hit))        /* acid drop */
1902   {
1903     if (object_hit && IS_PLAYER(x, y+1))
1904       KillHeroUnlessProtected(x, y+1);
1905     else if (object_hit && smashed == EL_PINGUIN)
1906       Bang(x, y+1);
1907     else
1908     {
1909       Feld[x][y] = EL_AMOEBING;
1910       Store[x][y] = EL_AMOEBE_NASS;
1911     }
1912     return;
1913   }
1914
1915   if (!lastline && object_hit)          /* check which object was hit */
1916   {
1917     if (CAN_CHANGE(element) && 
1918         (smashed == EL_MAGIC_WALL_OFF || smashed == EL_MAGIC_WALL_BD_OFF))
1919     {
1920       int x, y;
1921       int activated_magic_wall =
1922         (smashed == EL_MAGIC_WALL_OFF ? EL_MAGIC_WALL_EMPTY :
1923          EL_MAGIC_WALL_BD_EMPTY);
1924
1925       /* activate magic wall / mill */
1926
1927       for (y=0; y<lev_fieldy; y++)
1928         for (x=0; x<lev_fieldx; x++)
1929           if (Feld[x][y] == smashed)
1930             Feld[x][y] = activated_magic_wall;
1931
1932       game.magic_wall_time_left = level.time_magic_wall * FRAMES_PER_SECOND;
1933       game.magic_wall_active = TRUE;
1934     }
1935
1936     if (IS_PLAYER(x, y+1))
1937     {
1938       KillHeroUnlessProtected(x, y+1);
1939       return;
1940     }
1941     else if (smashed == EL_PINGUIN)
1942     {
1943       Bang(x, y+1);
1944       return;
1945     }
1946     else if (element == EL_EDELSTEIN_BD)
1947     {
1948       if (IS_ENEMY(smashed) && IS_BD_ELEMENT(smashed))
1949       {
1950         Bang(x, y+1);
1951         return;
1952       }
1953     }
1954     else if ((element == EL_SP_INFOTRON || element == EL_SP_ZONK) &&
1955              (smashed == EL_SP_SNIKSNAK || smashed == EL_SP_ELECTRON ||
1956               smashed == EL_SP_DISK_ORANGE))
1957     {
1958       Bang(x, y+1);
1959       return;
1960     }
1961     else if (element == EL_FELSBROCKEN ||
1962              element == EL_SP_ZONK ||
1963              element == EL_BD_ROCK)
1964     {
1965       if (IS_ENEMY(smashed) ||
1966           smashed == EL_BOMBE || smashed == EL_SP_DISK_ORANGE ||
1967           smashed == EL_DX_SUPABOMB ||
1968           smashed == EL_SONDE || smashed == EL_SCHWEIN ||
1969           smashed == EL_DRACHE || smashed == EL_MOLE)
1970       {
1971         Bang(x, y+1);
1972         return;
1973       }
1974       else if (!IS_MOVING(x, y+1))
1975       {
1976         if (smashed == EL_BIRNE_AUS || smashed == EL_BIRNE_EIN)
1977         {
1978           Bang(x, y+1);
1979           return;
1980         }
1981         else if (smashed == EL_KOKOSNUSS)
1982         {
1983           Feld[x][y+1] = EL_CRACKINGNUT;
1984           PlaySoundLevel(x, y, SND_KNACK);
1985           RaiseScoreElement(EL_KOKOSNUSS);
1986           return;
1987         }
1988         else if (smashed == EL_PEARL)
1989         {
1990           Feld[x][y+1] = EL_PEARL_BREAKING;
1991           PlaySoundLevel(x, y, SND_KNACK);
1992           return;
1993         }
1994         else if (smashed == EL_DIAMANT)
1995         {
1996           Feld[x][y+1] = EL_LEERRAUM;
1997           PlaySoundLevel(x, y, SND_QUIRK);
1998           return;
1999         }
2000         else if (IS_BELT_SWITCH(smashed))
2001         {
2002           ToggleBeltSwitch(x, y+1);
2003         }
2004         else if (smashed == EL_SWITCHGATE_SWITCH_1 ||
2005                  smashed == EL_SWITCHGATE_SWITCH_2)
2006         {
2007           ToggleSwitchgateSwitch(x, y+1);
2008         }
2009         else if (smashed == EL_LIGHT_SWITCH_OFF ||
2010                  smashed == EL_LIGHT_SWITCH_ON)
2011         {
2012           ToggleLightSwitch(x, y+1);
2013         }
2014       }
2015     }
2016   }
2017
2018   /* play sound of magic wall / mill */
2019   if (!lastline &&
2020       (Feld[x][y+1] == EL_MAGIC_WALL_EMPTY ||
2021        Feld[x][y+1] == EL_MAGIC_WALL_BD_EMPTY))
2022   {
2023     PlaySoundLevel(x, y, SND_QUIRK);
2024     return;
2025   }
2026
2027   /* play sound of object that hits the ground */
2028   if (lastline || object_hit)
2029   {
2030     int sound;
2031
2032     switch(element)
2033     {
2034       case EL_EDELSTEIN:
2035       case EL_EDELSTEIN_BD:
2036       case EL_EDELSTEIN_GELB:
2037       case EL_EDELSTEIN_ROT:
2038       case EL_EDELSTEIN_LILA:
2039       case EL_DIAMANT:
2040       case EL_SP_INFOTRON:
2041         sound = SND_PLING;
2042         break;
2043       case EL_KOKOSNUSS:
2044         sound = SND_KLUMPF;
2045         break;
2046       case EL_FELSBROCKEN:
2047       case EL_BD_ROCK:
2048         sound = SND_KLOPF;
2049         break;
2050       case EL_SP_ZONK:
2051         sound = SND_SP_ZONKDOWN;
2052         break;
2053       case EL_SCHLUESSEL:
2054       case EL_SCHLUESSEL1:
2055       case EL_SCHLUESSEL2:
2056       case EL_SCHLUESSEL3:
2057       case EL_SCHLUESSEL4:
2058       case EL_EM_KEY_1:
2059       case EL_EM_KEY_2:
2060       case EL_EM_KEY_3:
2061       case EL_EM_KEY_4:
2062         sound = SND_KINK;
2063         break;
2064       case EL_ZEIT_VOLL:
2065       case EL_ZEIT_LEER:
2066         sound = SND_DENG;
2067         break;
2068       default:
2069         sound = -1;
2070         break;
2071     }
2072
2073     if (sound >= 0)
2074       PlaySoundLevel(x, y, sound);
2075   }
2076 }
2077
2078 void TurnRound(int x, int y)
2079 {
2080   static struct
2081   {
2082     int x, y;
2083   } move_xy[] =
2084   {
2085     { 0, 0 },
2086     {-1, 0 },
2087     {+1, 0 },
2088     { 0, 0 },
2089     { 0, -1 },
2090     { 0, 0 }, { 0, 0 }, { 0, 0 },
2091     { 0, +1 }
2092   };
2093   static struct
2094   {
2095     int left, right, back;
2096   } turn[] =
2097   {
2098     { 0,        0,              0 },
2099     { MV_DOWN,  MV_UP,          MV_RIGHT },
2100     { MV_UP,    MV_DOWN,        MV_LEFT },
2101     { 0,        0,              0 },
2102     { MV_LEFT,  MV_RIGHT,       MV_DOWN },
2103     { 0,0,0 },  { 0,0,0 },      { 0,0,0 },
2104     { MV_RIGHT, MV_LEFT,        MV_UP }
2105   };
2106
2107   int element = Feld[x][y];
2108   int old_move_dir = MovDir[x][y];
2109   int left_dir = turn[old_move_dir].left;
2110   int right_dir = turn[old_move_dir].right;
2111   int back_dir = turn[old_move_dir].back;
2112
2113   int left_dx = move_xy[left_dir].x, left_dy = move_xy[left_dir].y;
2114   int right_dx = move_xy[right_dir].x, right_dy = move_xy[right_dir].y;
2115   int move_dx = move_xy[old_move_dir].x, move_dy = move_xy[old_move_dir].y;
2116   int back_dx = move_xy[back_dir].x, back_dy = move_xy[back_dir].y;
2117
2118   int left_x = x+left_dx, left_y = y+left_dy;
2119   int right_x = x+right_dx, right_y = y+right_dy;
2120   int move_x = x+move_dx, move_y = y+move_dy;
2121
2122   if (element == EL_KAEFER || element == EL_BUTTERFLY)
2123   {
2124     TestIfBadThingTouchesOtherBadThing(x, y);
2125
2126     if (IN_LEV_FIELD(right_x, right_y) &&
2127         IS_FREE(right_x, right_y))
2128       MovDir[x][y] = right_dir;
2129     else if (!IN_LEV_FIELD(move_x, move_y) ||
2130              !IS_FREE(move_x, move_y))
2131       MovDir[x][y] = left_dir;
2132
2133     if (element == EL_KAEFER && MovDir[x][y] != old_move_dir)
2134       MovDelay[x][y] = 9;
2135     else if (element == EL_BUTTERFLY)   /* && MovDir[x][y] == left_dir) */
2136       MovDelay[x][y] = 1;
2137   }
2138   else if (element == EL_FLIEGER || element == EL_FIREFLY ||
2139            element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
2140   {
2141     TestIfBadThingTouchesOtherBadThing(x, y);
2142
2143     if (IN_LEV_FIELD(left_x, left_y) &&
2144         IS_FREE(left_x, left_y))
2145       MovDir[x][y] = left_dir;
2146     else if (!IN_LEV_FIELD(move_x, move_y) ||
2147              !IS_FREE(move_x, move_y))
2148       MovDir[x][y] = right_dir;
2149
2150     if ((element == EL_FLIEGER ||
2151          element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
2152         && MovDir[x][y] != old_move_dir)
2153       MovDelay[x][y] = 9;
2154     else if (element == EL_FIREFLY)     /* && MovDir[x][y] == right_dir) */
2155       MovDelay[x][y] = 1;
2156   }
2157   else if (element == EL_MAMPFER)
2158   {
2159     boolean can_turn_left = FALSE, can_turn_right = FALSE;
2160
2161     if (IN_LEV_FIELD(left_x, left_y) &&
2162         (IS_FREE_OR_PLAYER(left_x, left_y) ||
2163          Feld[left_x][left_y] == EL_DIAMANT))
2164       can_turn_left = TRUE;
2165     if (IN_LEV_FIELD(right_x, right_y) &&
2166         (IS_FREE_OR_PLAYER(right_x, right_y) ||
2167          Feld[right_x][right_y] == EL_DIAMANT))
2168       can_turn_right = TRUE;
2169
2170     if (can_turn_left && can_turn_right)
2171       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
2172     else if (can_turn_left)
2173       MovDir[x][y] = (RND(2) ? left_dir : back_dir);
2174     else if (can_turn_right)
2175       MovDir[x][y] = (RND(2) ? right_dir : back_dir);
2176     else
2177       MovDir[x][y] = back_dir;
2178
2179     MovDelay[x][y] = 16+16*RND(3);
2180   }
2181   else if (element == EL_MAMPFER2)
2182   {
2183     boolean can_turn_left = FALSE, can_turn_right = FALSE;
2184
2185     if (IN_LEV_FIELD(left_x, left_y) &&
2186         (IS_FREE_OR_PLAYER(left_x, left_y) ||
2187          IS_MAMPF2(Feld[left_x][left_y])))
2188       can_turn_left = TRUE;
2189     if (IN_LEV_FIELD(right_x, right_y) &&
2190         (IS_FREE_OR_PLAYER(right_x, right_y) ||
2191          IS_MAMPF2(Feld[right_x][right_y])))
2192       can_turn_right = TRUE;
2193
2194     if (can_turn_left && can_turn_right)
2195       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
2196     else if (can_turn_left)
2197       MovDir[x][y] = (RND(2) ? left_dir : back_dir);
2198     else if (can_turn_right)
2199       MovDir[x][y] = (RND(2) ? right_dir : back_dir);
2200     else
2201       MovDir[x][y] = back_dir;
2202
2203     MovDelay[x][y] = 16+16*RND(3);
2204   }
2205   else if (element == EL_PACMAN)
2206   {
2207     boolean can_turn_left = FALSE, can_turn_right = FALSE;
2208
2209     if (IN_LEV_FIELD(left_x, left_y) &&
2210         (IS_FREE_OR_PLAYER(left_x, left_y) ||
2211          IS_AMOEBOID(Feld[left_x][left_y])))
2212       can_turn_left = TRUE;
2213     if (IN_LEV_FIELD(right_x, right_y) &&
2214         (IS_FREE_OR_PLAYER(right_x, right_y) ||
2215          IS_AMOEBOID(Feld[right_x][right_y])))
2216       can_turn_right = TRUE;
2217
2218     if (can_turn_left && can_turn_right)
2219       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
2220     else if (can_turn_left)
2221       MovDir[x][y] = (RND(2) ? left_dir : back_dir);
2222     else if (can_turn_right)
2223       MovDir[x][y] = (RND(2) ? right_dir : back_dir);
2224     else
2225       MovDir[x][y] = back_dir;
2226
2227     MovDelay[x][y] = 6+RND(40);
2228   }
2229   else if (element == EL_SCHWEIN)
2230   {
2231     boolean can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE;
2232     boolean should_turn_left = FALSE, should_turn_right = FALSE;
2233     boolean should_move_on = FALSE;
2234     int rnd_value = 24;
2235     int rnd = RND(rnd_value);
2236
2237     if (IN_LEV_FIELD(left_x, left_y) &&
2238         (IS_FREE(left_x, left_y) || IS_GEM(Feld[left_x][left_y])))
2239       can_turn_left = TRUE;
2240     if (IN_LEV_FIELD(right_x, right_y) &&
2241         (IS_FREE(right_x, right_y) || IS_GEM(Feld[right_x][right_y])))
2242       can_turn_right = TRUE;
2243     if (IN_LEV_FIELD(move_x, move_y) &&
2244         (IS_FREE(move_x, move_y) || IS_GEM(Feld[move_x][move_y])))
2245       can_move_on = TRUE;
2246
2247     if (can_turn_left &&
2248         (!can_move_on ||
2249          (IN_LEV_FIELD(x+back_dx+left_dx, y+back_dy+left_dy) &&
2250           !IS_FREE(x+back_dx+left_dx, y+back_dy+left_dy))))
2251       should_turn_left = TRUE;
2252     if (can_turn_right &&
2253         (!can_move_on ||
2254          (IN_LEV_FIELD(x+back_dx+right_dx, y+back_dy+right_dy) &&
2255           !IS_FREE(x+back_dx+right_dx, y+back_dy+right_dy))))
2256       should_turn_right = TRUE;
2257     if (can_move_on &&
2258         (!can_turn_left || !can_turn_right ||
2259          (IN_LEV_FIELD(x+move_dx+left_dx, y+move_dy+left_dy) &&
2260           !IS_FREE(x+move_dx+left_dx, y+move_dy+left_dy)) ||
2261          (IN_LEV_FIELD(x+move_dx+right_dx, y+move_dy+right_dy) &&
2262           !IS_FREE(x+move_dx+right_dx, y+move_dy+right_dy))))
2263       should_move_on = TRUE;
2264
2265     if (should_turn_left || should_turn_right || should_move_on)
2266     {
2267       if (should_turn_left && should_turn_right && should_move_on)
2268         MovDir[x][y] = (rnd < rnd_value/3 ? left_dir :
2269                         rnd < 2*rnd_value/3 ? right_dir :
2270                         old_move_dir);
2271       else if (should_turn_left && should_turn_right)
2272         MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
2273       else if (should_turn_left && should_move_on)
2274         MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : old_move_dir);
2275       else if (should_turn_right && should_move_on)
2276         MovDir[x][y] = (rnd < rnd_value/2 ? right_dir : old_move_dir);
2277       else if (should_turn_left)
2278         MovDir[x][y] = left_dir;
2279       else if (should_turn_right)
2280         MovDir[x][y] = right_dir;
2281       else if (should_move_on)
2282         MovDir[x][y] = old_move_dir;
2283     }
2284     else if (can_move_on && rnd > rnd_value/8)
2285       MovDir[x][y] = old_move_dir;
2286     else if (can_turn_left && can_turn_right)
2287       MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
2288     else if (can_turn_left && rnd > rnd_value/8)
2289       MovDir[x][y] = left_dir;
2290     else if (can_turn_right && rnd > rnd_value/8)
2291       MovDir[x][y] = right_dir;
2292     else
2293       MovDir[x][y] = back_dir;
2294
2295     if (!IS_FREE(x+move_xy[MovDir[x][y]].x, y+move_xy[MovDir[x][y]].y) &&
2296         !IS_GEM(Feld[x+move_xy[MovDir[x][y]].x][y+move_xy[MovDir[x][y]].y]))
2297       MovDir[x][y] = old_move_dir;
2298
2299     MovDelay[x][y] = 0;
2300   }
2301   else if (element == EL_DRACHE)
2302   {
2303     boolean can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE;
2304     int rnd_value = 24;
2305     int rnd = RND(rnd_value);
2306
2307     if (IN_LEV_FIELD(left_x, left_y) && IS_FREE(left_x, left_y))
2308       can_turn_left = TRUE;
2309     if (IN_LEV_FIELD(right_x, right_y) && IS_FREE(right_x, right_y))
2310       can_turn_right = TRUE;
2311     if (IN_LEV_FIELD(move_x, move_y) && IS_FREE(move_x, move_y))
2312       can_move_on = TRUE;
2313
2314     if (can_move_on && rnd > rnd_value/8)
2315       MovDir[x][y] = old_move_dir;
2316     else if (can_turn_left && can_turn_right)
2317       MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
2318     else if (can_turn_left && rnd > rnd_value/8)
2319       MovDir[x][y] = left_dir;
2320     else if (can_turn_right && rnd > rnd_value/8)
2321       MovDir[x][y] = right_dir;
2322     else
2323       MovDir[x][y] = back_dir;
2324
2325     if (!IS_FREE(x+move_xy[MovDir[x][y]].x, y+move_xy[MovDir[x][y]].y))
2326       MovDir[x][y] = old_move_dir;
2327
2328     MovDelay[x][y] = 0;
2329   }
2330   else if (element == EL_MOLE)
2331   {
2332     boolean can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE;
2333
2334     if (IN_LEV_FIELD(move_x, move_y) &&
2335         (IS_FREE(move_x, move_y) || IS_AMOEBOID(Feld[move_x][move_y]) ||
2336          Feld[move_x][move_y] == EL_DEAMOEBING))
2337       can_move_on = TRUE;
2338
2339     if (!can_move_on)
2340     {
2341       if (IN_LEV_FIELD(left_x, left_y) &&
2342           (IS_FREE(left_x, left_y) || IS_AMOEBOID(Feld[left_x][left_y])))
2343         can_turn_left = TRUE;
2344       if (IN_LEV_FIELD(right_x, right_y) &&
2345           (IS_FREE(right_x, right_y) || IS_AMOEBOID(Feld[right_x][right_y])))
2346         can_turn_right = TRUE;
2347
2348       if (can_turn_left && can_turn_right)
2349         MovDir[x][y] = (RND(2) ? left_dir : right_dir);
2350       else if (can_turn_left)
2351         MovDir[x][y] = left_dir;
2352       else
2353         MovDir[x][y] = right_dir;
2354     }
2355
2356     if (MovDir[x][y] != old_move_dir)
2357       MovDelay[x][y] = 9;
2358   }
2359   else if (element == EL_BALLOON)
2360   {
2361     MovDir[x][y] = game.balloon_dir;
2362     MovDelay[x][y] = 0;
2363   }
2364   else if (element == EL_SPRING_MOVING)
2365   {
2366     if (!IN_LEV_FIELD(move_x, move_y) || !IS_FREE(move_x, move_y) ||
2367         (IN_LEV_FIELD(x, y+1) && IS_FREE(x, y+1)))
2368     {
2369       Feld[x][y] = EL_SPRING;
2370       MovDir[x][y] = MV_NO_MOVING;
2371     }
2372     MovDelay[x][y] = 0;
2373   }
2374   else if (element == EL_ROBOT || element == EL_SONDE || element == EL_PINGUIN)
2375   {
2376     int attr_x = -1, attr_y = -1;
2377
2378     if (AllPlayersGone)
2379     {
2380       attr_x = ExitX;
2381       attr_y = ExitY;
2382     }
2383     else
2384     {
2385       int i;
2386
2387       for (i=0; i<MAX_PLAYERS; i++)
2388       {
2389         struct PlayerInfo *player = &stored_player[i];
2390         int jx = player->jx, jy = player->jy;
2391
2392         if (!player->active)
2393           continue;
2394
2395         if (attr_x == -1 || ABS(jx-x)+ABS(jy-y) < ABS(attr_x-x)+ABS(attr_y-y))
2396         {
2397           attr_x = jx;
2398           attr_y = jy;
2399         }
2400       }
2401     }
2402
2403     if (element == EL_ROBOT && ZX>=0 && ZY>=0)
2404     {
2405       attr_x = ZX;
2406       attr_y = ZY;
2407     }
2408
2409     if (element == EL_PINGUIN)
2410     {
2411       int i;
2412       static int xy[4][2] =
2413       {
2414         { 0, -1 },
2415         { -1, 0 },
2416         { +1, 0 },
2417         { 0, +1 }
2418       };
2419
2420       for (i=0; i<4; i++)
2421       {
2422         int ex = x + xy[i%4][0];
2423         int ey = y + xy[i%4][1];
2424
2425         if (IN_LEV_FIELD(ex, ey) && Feld[ex][ey] == EL_AUSGANG_AUF)
2426         {
2427           attr_x = ex;
2428           attr_y = ey;
2429           break;
2430         }
2431       }
2432     }
2433
2434     MovDir[x][y] = MV_NO_MOVING;
2435     if (attr_x<x)
2436       MovDir[x][y] |= (AllPlayersGone ? MV_RIGHT : MV_LEFT);
2437     else if (attr_x>x)
2438       MovDir[x][y] |= (AllPlayersGone ? MV_LEFT : MV_RIGHT);
2439     if (attr_y<y)
2440       MovDir[x][y] |= (AllPlayersGone ? MV_DOWN : MV_UP);
2441     else if (attr_y>y)
2442       MovDir[x][y] |= (AllPlayersGone ? MV_UP : MV_DOWN);
2443
2444     if (element == EL_ROBOT)
2445     {
2446       int newx, newy;
2447
2448       if ((MovDir[x][y]&(MV_LEFT|MV_RIGHT)) && (MovDir[x][y]&(MV_UP|MV_DOWN)))
2449         MovDir[x][y] &= (RND(2) ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
2450       Moving2Blocked(x, y, &newx, &newy);
2451
2452       if (IN_LEV_FIELD(newx, newy) && IS_FREE_OR_PLAYER(newx, newy))
2453         MovDelay[x][y] = 8+8*!RND(3);
2454       else
2455         MovDelay[x][y] = 16;
2456     }
2457     else
2458     {
2459       int newx, newy;
2460
2461       MovDelay[x][y] = 1;
2462
2463       if ((MovDir[x][y]&(MV_LEFT|MV_RIGHT)) && (MovDir[x][y]&(MV_UP|MV_DOWN)))
2464       {
2465         boolean first_horiz = RND(2);
2466         int new_move_dir = MovDir[x][y];
2467
2468         MovDir[x][y] =
2469           new_move_dir & (first_horiz ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
2470         Moving2Blocked(x, y, &newx, &newy);
2471
2472         if (IN_LEV_FIELD(newx, newy) &&
2473             (IS_FREE(newx, newy) ||
2474              Feld[newx][newy] == EL_SALZSAEURE ||
2475              (element == EL_PINGUIN &&
2476               (Feld[newx][newy] == EL_AUSGANG_AUF ||
2477                IS_MAMPF3(Feld[newx][newy])))))
2478           return;
2479
2480         MovDir[x][y] =
2481           new_move_dir & (!first_horiz ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
2482         Moving2Blocked(x, y, &newx, &newy);
2483
2484         if (IN_LEV_FIELD(newx, newy) &&
2485             (IS_FREE(newx, newy) ||
2486              Feld[newx][newy] == EL_SALZSAEURE ||
2487              (element == EL_PINGUIN &&
2488               (Feld[newx][newy] == EL_AUSGANG_AUF ||
2489                IS_MAMPF3(Feld[newx][newy])))))
2490           return;
2491
2492         MovDir[x][y] = old_move_dir;
2493         return;
2494       }
2495     }
2496   }
2497 }
2498
2499 static boolean JustBeingPushed(int x, int y)
2500 {
2501   int i;
2502
2503   for (i=0; i<MAX_PLAYERS; i++)
2504   {
2505     struct PlayerInfo *player = &stored_player[i];
2506
2507     if (player->active && player->Pushing && player->MovPos)
2508     {
2509       int next_jx = player->jx + (player->jx - player->last_jx);
2510       int next_jy = player->jy + (player->jy - player->last_jy);
2511
2512       if (x == next_jx && y == next_jy)
2513         return TRUE;
2514     }
2515   }
2516
2517   return FALSE;
2518 }
2519
2520 void StartMoving(int x, int y)
2521 {
2522   int element = Feld[x][y];
2523
2524   if (Stop[x][y])
2525     return;
2526
2527   if (CAN_FALL(element) && y<lev_fieldy-1)
2528   {
2529     if ((x>0 && IS_PLAYER(x-1, y)) || (x<lev_fieldx-1 && IS_PLAYER(x+1, y)))
2530       if (JustBeingPushed(x, y))
2531         return;
2532
2533     if (element == EL_MORAST_VOLL)
2534     {
2535       if (IS_FREE(x, y+1))
2536       {
2537         InitMovingField(x, y, MV_DOWN);
2538         Feld[x][y] = EL_QUICKSAND_EMPTYING;
2539         Store[x][y] = EL_FELSBROCKEN;
2540       }
2541       else if (Feld[x][y+1] == EL_MORAST_LEER)
2542       {
2543         if (!MovDelay[x][y])
2544           MovDelay[x][y] = TILEY + 1;
2545
2546         if (MovDelay[x][y])
2547         {
2548           MovDelay[x][y]--;
2549           if (MovDelay[x][y])
2550             return;
2551         }
2552
2553         Feld[x][y] = EL_MORAST_LEER;
2554         Feld[x][y+1] = EL_MORAST_VOLL;
2555         Store[x][y+1] = Store[x][y];
2556         Store[x][y] = 0;
2557       }
2558     }
2559     else if ((element == EL_FELSBROCKEN || element == EL_BD_ROCK) &&
2560              Feld[x][y+1] == EL_MORAST_LEER)
2561     {
2562       InitMovingField(x, y, MV_DOWN);
2563       Feld[x][y] = EL_QUICKSAND_FILLING;
2564       Store[x][y] = element;
2565     }
2566     else if (element == EL_MAGIC_WALL_FULL)
2567     {
2568       if (IS_FREE(x, y+1))
2569       {
2570         InitMovingField(x, y, MV_DOWN);
2571         Feld[x][y] = EL_MAGIC_WALL_EMPTYING;
2572         Store[x][y] = EL_CHANGED(Store[x][y]);
2573       }
2574       else if (Feld[x][y+1] == EL_MAGIC_WALL_EMPTY)
2575       {
2576         if (!MovDelay[x][y])
2577           MovDelay[x][y] = TILEY/4 + 1;
2578
2579         if (MovDelay[x][y])
2580         {
2581           MovDelay[x][y]--;
2582           if (MovDelay[x][y])
2583             return;
2584         }
2585
2586         Feld[x][y] = EL_MAGIC_WALL_EMPTY;
2587         Feld[x][y+1] = EL_MAGIC_WALL_FULL;
2588         Store[x][y+1] = EL_CHANGED(Store[x][y]);
2589         Store[x][y] = 0;
2590       }
2591     }
2592     else if (element == EL_MAGIC_WALL_BD_FULL)
2593     {
2594       if (IS_FREE(x, y+1))
2595       {
2596         InitMovingField(x, y, MV_DOWN);
2597         Feld[x][y] = EL_MAGIC_WALL_BD_EMPTYING;
2598         Store[x][y] = EL_CHANGED2(Store[x][y]);
2599       }
2600       else if (Feld[x][y+1] == EL_MAGIC_WALL_BD_EMPTY)
2601       {
2602         if (!MovDelay[x][y])
2603           MovDelay[x][y] = TILEY/4 + 1;
2604
2605         if (MovDelay[x][y])
2606         {
2607           MovDelay[x][y]--;
2608           if (MovDelay[x][y])
2609             return;
2610         }
2611
2612         Feld[x][y] = EL_MAGIC_WALL_BD_EMPTY;
2613         Feld[x][y+1] = EL_MAGIC_WALL_BD_FULL;
2614         Store[x][y+1] = EL_CHANGED2(Store[x][y]);
2615         Store[x][y] = 0;
2616       }
2617     }
2618     else if (CAN_CHANGE(element) &&
2619              (Feld[x][y+1] == EL_MAGIC_WALL_EMPTY ||
2620               Feld[x][y+1] == EL_MAGIC_WALL_BD_EMPTY))
2621     {
2622       InitMovingField(x, y, MV_DOWN);
2623       Feld[x][y] =
2624         (Feld[x][y+1] == EL_MAGIC_WALL_EMPTY ? EL_MAGIC_WALL_FILLING :
2625          EL_MAGIC_WALL_BD_FILLING);
2626       Store[x][y] = element;
2627     }
2628     else if (CAN_SMASH(element) && Feld[x][y+1] == EL_SALZSAEURE)
2629     {
2630       Blurb(x, y);
2631       InitMovingField(x, y, MV_DOWN);
2632       Store[x][y] = EL_SALZSAEURE;
2633     }
2634     else if (CAN_SMASH(element) && Feld[x][y+1] == EL_BLOCKED &&
2635              JustStopped[x][y])
2636     {
2637       Impact(x, y);
2638     }
2639     else if (IS_FREE(x, y+1))
2640     {
2641       InitMovingField(x, y, MV_DOWN);
2642     }
2643     else if (element == EL_TROPFEN)
2644     {
2645       Feld[x][y] = EL_AMOEBING;
2646       Store[x][y] = EL_AMOEBE_NASS;
2647     }
2648     /* Store[x][y+1] must be zero, because:
2649        (EL_MORAST_VOLL -> EL_FELSBROCKEN): Store[x][y+1] == EL_MORAST_LEER
2650     */
2651 #if 0
2652 #if OLD_GAME_BEHAVIOUR
2653     else if (IS_SLIPPERY(Feld[x][y+1]) && !Store[x][y+1])
2654 #else
2655     else if (IS_SLIPPERY(Feld[x][y+1]) && !Store[x][y+1] &&
2656              !IS_FALLING(x, y+1) && !JustStopped[x][y+1] &&
2657              element != EL_DX_SUPABOMB)
2658 #endif
2659 #else
2660     else if ((IS_SLIPPERY(Feld[x][y+1]) ||
2661               (IS_EM_SLIPPERY_WALL(Feld[x][y+1]) && IS_GEM(element))) &&
2662              !IS_FALLING(x, y+1) && !JustStopped[x][y+1] &&
2663              element != EL_DX_SUPABOMB && element != EL_SP_DISK_ORANGE)
2664 #endif
2665     {
2666       boolean left  = (x>0 && IS_FREE(x-1, y) &&
2667                        (IS_FREE(x-1, y+1) || Feld[x-1][y+1] == EL_SALZSAEURE));
2668       boolean right = (x<lev_fieldx-1 && IS_FREE(x+1, y) &&
2669                        (IS_FREE(x+1, y+1) || Feld[x+1][y+1] == EL_SALZSAEURE));
2670
2671       if (left || right)
2672       {
2673         if (left && right &&
2674             (game.emulation != EMU_BOULDERDASH &&
2675              element != EL_BD_ROCK && element != EL_EDELSTEIN_BD))
2676           left = !(right = RND(2));
2677
2678         InitMovingField(x, y, left ? MV_LEFT : MV_RIGHT);
2679       }
2680     }
2681     else if (IS_BELT(Feld[x][y+1]))
2682     {
2683       boolean left_is_free  = (x>0 && IS_FREE(x-1, y));
2684       boolean right_is_free = (x<lev_fieldx-1 && IS_FREE(x+1, y));
2685       int belt_nr = getBeltNrFromElement(Feld[x][y+1]);
2686       int belt_dir = game.belt_dir[belt_nr];
2687
2688       if ((belt_dir == MV_LEFT  && left_is_free) ||
2689           (belt_dir == MV_RIGHT && right_is_free))
2690         InitMovingField(x, y, belt_dir);
2691     }
2692   }
2693   else if (CAN_MOVE(element))
2694   {
2695     int newx, newy;
2696
2697     if ((element == EL_SONDE || element == EL_BALLOON ||
2698          element == EL_SPRING_MOVING)
2699         && JustBeingPushed(x, y))
2700       return;
2701
2702     if (!MovDelay[x][y])        /* start new movement phase */
2703     {
2704       /* all objects that can change their move direction after each step */
2705       /* (MAMPFER, MAMPFER2 and PACMAN go straight until they hit a wall  */
2706
2707       if (element!=EL_MAMPFER && element!=EL_MAMPFER2 && element!=EL_PACMAN)
2708       {
2709         TurnRound(x, y);
2710         if (MovDelay[x][y] && (element == EL_KAEFER ||
2711                                element == EL_FLIEGER ||
2712                                element == EL_SP_SNIKSNAK ||
2713                                element == EL_SP_ELECTRON ||
2714                                element == EL_MOLE))
2715           DrawLevelField(x, y);
2716       }
2717     }
2718
2719     if (MovDelay[x][y])         /* wait some time before next movement */
2720     {
2721       MovDelay[x][y]--;
2722
2723       if (element == EL_ROBOT ||
2724           element == EL_MAMPFER || element == EL_MAMPFER2)
2725       {
2726         int phase = MovDelay[x][y] % 8;
2727
2728         if (phase>3)
2729           phase = 7-phase;
2730
2731         if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2732           DrawGraphic(SCREENX(x), SCREENY(y), el2gfx(element)+phase);
2733
2734         if ((element == EL_MAMPFER || element == EL_MAMPFER2)
2735             && MovDelay[x][y]%4 == 3)
2736           PlaySoundLevel(x, y, SND_NJAM);
2737       }
2738       else if (element == EL_SP_ELECTRON)
2739         DrawGraphicAnimation(x, y, GFX2_SP_ELECTRON, 8, 2, ANIM_NORMAL);
2740       else if (element == EL_DRACHE)
2741       {
2742         int i;
2743         int dir = MovDir[x][y];
2744         int dx = (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2745         int dy = (dir == MV_UP   ? -1 : dir == MV_DOWN  ? +1 : 0);
2746         int graphic = (dir == MV_LEFT   ? GFX_FLAMMEN_LEFT :
2747                        dir == MV_RIGHT  ? GFX_FLAMMEN_RIGHT :
2748                        dir == MV_UP     ? GFX_FLAMMEN_UP :
2749                        dir == MV_DOWN   ? GFX_FLAMMEN_DOWN : GFX_LEERRAUM);
2750         int phase = FrameCounter % 2;
2751
2752         for (i=1; i<=3; i++)
2753         {
2754           int xx = x + i*dx, yy = y + i*dy;
2755           int sx = SCREENX(xx), sy = SCREENY(yy);
2756
2757           if (!IN_LEV_FIELD(xx, yy) ||
2758               IS_SOLID(Feld[xx][yy]) || Feld[xx][yy] == EL_EXPLODING)
2759             break;
2760
2761           if (MovDelay[x][y])
2762           {
2763             int flamed = MovingOrBlocked2Element(xx, yy);
2764
2765             if (IS_ENEMY(flamed) || IS_EXPLOSIVE(flamed))
2766               Bang(xx, yy);
2767             else
2768               RemoveMovingField(xx, yy);
2769
2770             Feld[xx][yy] = EL_BURNING;
2771             if (IN_SCR_FIELD(sx, sy))
2772               DrawGraphic(sx, sy, graphic + phase*3 + i-1);
2773           }
2774           else
2775           {
2776             if (Feld[xx][yy] == EL_BURNING)
2777               Feld[xx][yy] = EL_LEERRAUM;
2778             DrawLevelField(xx, yy);
2779           }
2780         }
2781       }
2782
2783       if (MovDelay[x][y])
2784         return;
2785     }
2786
2787     if (element == EL_KAEFER || element == EL_BUTTERFLY)
2788     {
2789       PlaySoundLevel(x, y, SND_KLAPPER);
2790     }
2791     else if (element == EL_FLIEGER || element == EL_FIREFLY)
2792     {
2793       PlaySoundLevel(x, y, SND_ROEHR);
2794     }
2795
2796     /* now make next step */
2797
2798     Moving2Blocked(x, y, &newx, &newy); /* get next screen position */
2799
2800     if (IS_ENEMY(element) && IS_PLAYER(newx, newy) &&
2801         !PLAYER_PROTECTED(newx, newy))
2802     {
2803
2804 #if 1
2805       TestIfBadThingRunsIntoHero(x, y, MovDir[x][y]);
2806       return;
2807 #else
2808       /* enemy got the player */
2809       MovDir[x][y] = 0;
2810       KillHero(PLAYERINFO(newx, newy));
2811       return;
2812 #endif
2813
2814     }
2815     else if ((element == EL_PINGUIN || element == EL_ROBOT ||
2816               element == EL_SONDE || element == EL_BALLOON) &&
2817              IN_LEV_FIELD(newx, newy) &&
2818              MovDir[x][y] == MV_DOWN && Feld[newx][newy] == EL_SALZSAEURE)
2819     {
2820       Blurb(x, y);
2821       Store[x][y] = EL_SALZSAEURE;
2822     }
2823     else if (element == EL_PINGUIN && IN_LEV_FIELD(newx, newy))
2824     {
2825       if (Feld[newx][newy] == EL_AUSGANG_AUF)
2826       {
2827         Feld[x][y] = EL_LEERRAUM;
2828         DrawLevelField(x, y);
2829
2830         PlaySoundLevel(newx, newy, SND_BUING);
2831         if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2832           DrawGraphicThruMask(SCREENX(newx), SCREENY(newy), el2gfx(element));
2833
2834         local_player->friends_still_needed--;
2835         if (!local_player->friends_still_needed &&
2836             !local_player->GameOver && AllPlayersGone)
2837           local_player->LevelSolved = local_player->GameOver = TRUE;
2838
2839         return;
2840       }
2841       else if (IS_MAMPF3(Feld[newx][newy]))
2842       {
2843         if (DigField(local_player, newx, newy, 0, 0, DF_DIG) == MF_MOVING)
2844           DrawLevelField(newx, newy);
2845         else
2846           MovDir[x][y] = MV_NO_MOVING;
2847       }
2848       else if (!IS_FREE(newx, newy))
2849       {
2850         if (IS_PLAYER(x, y))
2851           DrawPlayerField(x, y);
2852         else
2853           DrawLevelField(x, y);
2854         return;
2855       }
2856     }
2857     else if (element == EL_SCHWEIN && IN_LEV_FIELD(newx, newy))
2858     {
2859       if (IS_GEM(Feld[newx][newy]))
2860       {
2861         if (IS_MOVING(newx, newy))
2862           RemoveMovingField(newx, newy);
2863         else
2864         {
2865           Feld[newx][newy] = EL_LEERRAUM;
2866           DrawLevelField(newx, newy);
2867         }
2868       }
2869       else if (!IS_FREE(newx, newy))
2870       {
2871         if (IS_PLAYER(x, y))
2872           DrawPlayerField(x, y);
2873         else
2874           DrawLevelField(x, y);
2875         return;
2876       }
2877     }
2878     else if (element == EL_DRACHE && IN_LEV_FIELD(newx, newy))
2879     {
2880       if (!IS_FREE(newx, newy))
2881       {
2882         if (IS_PLAYER(x, y))
2883           DrawPlayerField(x, y);
2884         else
2885           DrawLevelField(x, y);
2886         return;
2887       }
2888       else
2889       {
2890         boolean wanna_flame = !RND(10);
2891         int dx = newx - x, dy = newy - y;
2892         int newx1 = newx+1*dx, newy1 = newy+1*dy;
2893         int newx2 = newx+2*dx, newy2 = newy+2*dy;
2894         int element1 = (IN_LEV_FIELD(newx1, newy1) ?
2895                         MovingOrBlocked2Element(newx1, newy1) : EL_BETON);
2896         int element2 = (IN_LEV_FIELD(newx2, newy2) ?
2897                         MovingOrBlocked2Element(newx2, newy2) : EL_BETON);
2898
2899         if ((wanna_flame || IS_ENEMY(element1) || IS_ENEMY(element2)) &&
2900             element1 != EL_DRACHE && element2 != EL_DRACHE &&
2901             element1 != EL_BURNING && element2 != EL_BURNING)
2902         {
2903           if (IS_PLAYER(x, y))
2904             DrawPlayerField(x, y);
2905           else
2906             DrawLevelField(x, y);
2907
2908           MovDelay[x][y] = 50;
2909           Feld[newx][newy] = EL_BURNING;
2910           if (IN_LEV_FIELD(newx1, newy1) && Feld[newx1][newy1] == EL_LEERRAUM)
2911             Feld[newx1][newy1] = EL_BURNING;
2912           if (IN_LEV_FIELD(newx2, newy2) && Feld[newx2][newy2] == EL_LEERRAUM)
2913             Feld[newx2][newy2] = EL_BURNING;
2914           return;
2915         }
2916       }
2917     }
2918     else if (element == EL_MAMPFER && IN_LEV_FIELD(newx, newy) &&
2919              Feld[newx][newy] == EL_DIAMANT)
2920     {
2921       if (IS_MOVING(newx, newy))
2922         RemoveMovingField(newx, newy);
2923       else
2924       {
2925         Feld[newx][newy] = EL_LEERRAUM;
2926         DrawLevelField(newx, newy);
2927       }
2928     }
2929     else if (element == EL_MAMPFER2 && IN_LEV_FIELD(newx, newy) &&
2930              IS_MAMPF2(Feld[newx][newy]))
2931     {
2932       if (AmoebaNr[newx][newy])
2933       {
2934         AmoebaCnt2[AmoebaNr[newx][newy]]--;
2935         if (Feld[newx][newy] == EL_AMOEBE_VOLL ||
2936             Feld[newx][newy] == EL_AMOEBE_BD)
2937           AmoebaCnt[AmoebaNr[newx][newy]]--;
2938       }
2939
2940       if (IS_MOVING(newx, newy))
2941         RemoveMovingField(newx, newy);
2942       else
2943       {
2944         Feld[newx][newy] = EL_LEERRAUM;
2945         DrawLevelField(newx, newy);
2946       }
2947     }
2948     else if ((element == EL_PACMAN || element == EL_MOLE)
2949              && IN_LEV_FIELD(newx, newy) && IS_AMOEBOID(Feld[newx][newy]))
2950     {
2951       if (AmoebaNr[newx][newy])
2952       {
2953         AmoebaCnt2[AmoebaNr[newx][newy]]--;
2954         if (Feld[newx][newy] == EL_AMOEBE_VOLL ||
2955             Feld[newx][newy] == EL_AMOEBE_BD)
2956           AmoebaCnt[AmoebaNr[newx][newy]]--;
2957       }
2958
2959       if (element == EL_MOLE)
2960       {
2961         Feld[newx][newy] = EL_DEAMOEBING;
2962         MovDelay[newx][newy] = 0;       /* start amoeba shrinking delay */
2963         return;                         /* wait for shrinking amoeba */
2964       }
2965       else      /* element == EL_PACMAN */
2966       {
2967         Feld[newx][newy] = EL_LEERRAUM;
2968         DrawLevelField(newx, newy);
2969       }
2970     }
2971     else if (element == EL_MOLE && IN_LEV_FIELD(newx, newy) &&
2972              (Feld[newx][newy] == EL_DEAMOEBING ||
2973               (Feld[newx][newy] == EL_LEERRAUM && Stop[newx][newy])))
2974     {
2975       /* wait for shrinking amoeba to completely disappear */
2976       return;
2977     }
2978     else if (!IN_LEV_FIELD(newx, newy) || !IS_FREE(newx, newy))
2979     {
2980       /* object was running against a wall */
2981
2982       TurnRound(x, y);
2983
2984       if (element == EL_KAEFER || element == EL_FLIEGER ||
2985           element == EL_SP_SNIKSNAK || element == EL_MOLE)
2986         DrawLevelField(x, y);
2987       else if (element == EL_BUTTERFLY || element == EL_FIREFLY)
2988         DrawGraphicAnimation(x, y, el2gfx(element), 2, 4, ANIM_NORMAL);
2989       else if (element == EL_SONDE)
2990         DrawGraphicAnimation(x, y, GFX_SONDE_START, 8, 2, ANIM_NORMAL);
2991       else if (element == EL_SP_ELECTRON)
2992         DrawGraphicAnimation(x, y, GFX2_SP_ELECTRON, 8, 2, ANIM_NORMAL);
2993
2994       if (DONT_TOUCH(element))
2995         TestIfBadThingTouchesHero(x, y);
2996
2997       return;
2998     }
2999
3000     if (element == EL_ROBOT && IN_SCR_FIELD(x, y))
3001       PlaySoundLevel(x, y, SND_SCHLURF);
3002
3003     InitMovingField(x, y, MovDir[x][y]);
3004   }
3005
3006   if (MovDir[x][y])
3007     ContinueMoving(x, y);
3008 }
3009
3010 void ContinueMoving(int x, int y)
3011 {
3012   int element = Feld[x][y];
3013   int direction = MovDir[x][y];
3014   int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
3015   int dy = (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
3016   int horiz_move = (dx!=0);
3017   int newx = x + dx, newy = y + dy;
3018   int step = (horiz_move ? dx : dy) * TILEX / 8;
3019
3020   if (element == EL_TROPFEN || element == EL_AMOEBA_DRIPPING)
3021     step /= 2;
3022   else if (element == EL_QUICKSAND_FILLING ||
3023            element == EL_QUICKSAND_EMPTYING)
3024     step /= 4;
3025   else if (element == EL_MAGIC_WALL_FILLING ||
3026            element == EL_MAGIC_WALL_BD_FILLING ||
3027            element == EL_MAGIC_WALL_EMPTYING ||
3028            element == EL_MAGIC_WALL_BD_EMPTYING)
3029     step /= 2;
3030   else if (CAN_FALL(element) && horiz_move &&
3031            y < lev_fieldy-1 && IS_BELT(Feld[x][y+1]))
3032     step /= 2;
3033   else if (element == EL_SPRING_MOVING)
3034     step*=2;
3035
3036 #if OLD_GAME_BEHAVIOUR
3037   else if (CAN_FALL(element) && horiz_move && !IS_SP_ELEMENT(element))
3038     step*=2;
3039 #endif
3040
3041   MovPos[x][y] += step;
3042
3043   if (ABS(MovPos[x][y])>=TILEX)         /* object reached its destination */
3044   {
3045     Feld[x][y] = EL_LEERRAUM;
3046     Feld[newx][newy] = element;
3047
3048     if (element == EL_MOLE)
3049     {
3050       int i;
3051       static int xy[4][2] =
3052       {
3053         { 0, -1 },
3054         { -1, 0 },
3055         { +1, 0 },
3056         { 0, +1 }
3057       };
3058
3059       Feld[x][y] = EL_ERDREICH;
3060       DrawLevelField(x, y);
3061
3062       for(i=0; i<4; i++)
3063       {
3064         int xx, yy;
3065
3066         xx = x + xy[i][0];
3067         yy = y + xy[i][1];
3068
3069         if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == EL_ERDREICH)
3070           DrawLevelField(xx, yy);       /* for "ErdreichAnbroeckeln()" */
3071       }
3072     }
3073
3074     if (element == EL_QUICKSAND_FILLING)
3075     {
3076       element = Feld[newx][newy] = get_next_element(element);
3077       Store[newx][newy] = Store[x][y];
3078     }
3079     else if (element == EL_QUICKSAND_EMPTYING)
3080     {
3081       Feld[x][y] = get_next_element(element);
3082       element = Feld[newx][newy] = Store[x][y];
3083     }
3084     else if (element == EL_MAGIC_WALL_FILLING)
3085     {
3086       element = Feld[newx][newy] = get_next_element(element);
3087       if (!game.magic_wall_active)
3088         element = Feld[newx][newy] = EL_MAGIC_WALL_DEAD;
3089       Store[newx][newy] = Store[x][y];
3090     }
3091     else if (element == EL_MAGIC_WALL_EMPTYING)
3092     {
3093       Feld[x][y] = get_next_element(element);
3094       if (!game.magic_wall_active)
3095         Feld[x][y] = EL_MAGIC_WALL_DEAD;
3096       element = Feld[newx][newy] = Store[x][y];
3097     }
3098     else if (element == EL_MAGIC_WALL_BD_FILLING)
3099     {
3100       element = Feld[newx][newy] = get_next_element(element);
3101       if (!game.magic_wall_active)
3102         element = Feld[newx][newy] = EL_MAGIC_WALL_BD_DEAD;
3103       Store[newx][newy] = Store[x][y];
3104     }
3105     else if (element == EL_MAGIC_WALL_BD_EMPTYING)
3106     {
3107       Feld[x][y] = get_next_element(element);
3108       if (!game.magic_wall_active)
3109         Feld[x][y] = EL_MAGIC_WALL_BD_DEAD;
3110       element = Feld[newx][newy] = Store[x][y];
3111     }
3112     else if (element == EL_AMOEBA_DRIPPING)
3113     {
3114       Feld[x][y] = get_next_element(element);
3115       element = Feld[newx][newy] = Store[x][y];
3116     }
3117     else if (Store[x][y] == EL_SALZSAEURE)
3118     {
3119       element = Feld[newx][newy] = EL_SALZSAEURE;
3120     }
3121
3122     Store[x][y] = 0;
3123     MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
3124     MovDelay[newx][newy] = 0;
3125
3126     if (!CAN_MOVE(element))
3127       MovDir[newx][newy] = 0;
3128
3129     DrawLevelField(x, y);
3130     DrawLevelField(newx, newy);
3131
3132     Stop[newx][newy] = TRUE;
3133     JustStopped[newx][newy] = 3;
3134
3135     if (DONT_TOUCH(element))    /* object may be nasty to player or others */
3136     {
3137       TestIfBadThingTouchesHero(newx, newy);
3138       TestIfBadThingTouchesFriend(newx, newy);
3139       TestIfBadThingTouchesOtherBadThing(newx, newy);
3140     }
3141     else if (element == EL_PINGUIN)
3142       TestIfFriendTouchesBadThing(newx, newy);
3143
3144     if (CAN_SMASH(element) && direction == MV_DOWN &&
3145         (newy == lev_fieldy-1 || !IS_FREE(x, newy+1)))
3146       Impact(x, newy);
3147   }
3148   else                          /* still moving on */
3149     DrawLevelField(x, y);
3150 }
3151
3152 int AmoebeNachbarNr(int ax, int ay)
3153 {
3154   int i;
3155   int element = Feld[ax][ay];
3156   int group_nr = 0;
3157   static int xy[4][2] =
3158   {
3159     { 0, -1 },
3160     { -1, 0 },
3161     { +1, 0 },
3162     { 0, +1 }
3163   };
3164
3165   for (i=0; i<4; i++)
3166   {
3167     int x = ax + xy[i][0];
3168     int y = ay + xy[i][1];
3169
3170     if (!IN_LEV_FIELD(x, y))
3171       continue;
3172
3173     if (Feld[x][y] == element && AmoebaNr[x][y] > 0)
3174       group_nr = AmoebaNr[x][y];
3175   }
3176
3177   return group_nr;
3178 }
3179
3180 void AmoebenVereinigen(int ax, int ay)
3181 {
3182   int i, x, y, xx, yy;
3183   int new_group_nr = AmoebaNr[ax][ay];
3184   static int xy[4][2] =
3185   {
3186     { 0, -1 },
3187     { -1, 0 },
3188     { +1, 0 },
3189     { 0, +1 }
3190   };
3191
3192   if (new_group_nr == 0)
3193     return;
3194
3195   for (i=0; i<4; i++)
3196   {
3197     x = ax + xy[i][0];
3198     y = ay + xy[i][1];
3199
3200     if (!IN_LEV_FIELD(x, y))
3201       continue;
3202
3203     if ((Feld[x][y] == EL_AMOEBE_VOLL ||
3204          Feld[x][y] == EL_AMOEBE_BD ||
3205          Feld[x][y] == EL_AMOEBE_TOT) &&
3206         AmoebaNr[x][y] != new_group_nr)
3207     {
3208       int old_group_nr = AmoebaNr[x][y];
3209
3210       if (old_group_nr == 0)
3211         return;
3212
3213       AmoebaCnt[new_group_nr] += AmoebaCnt[old_group_nr];
3214       AmoebaCnt[old_group_nr] = 0;
3215       AmoebaCnt2[new_group_nr] += AmoebaCnt2[old_group_nr];
3216       AmoebaCnt2[old_group_nr] = 0;
3217
3218       for (yy=0; yy<lev_fieldy; yy++)
3219       {
3220         for (xx=0; xx<lev_fieldx; xx++)
3221         {
3222           if (AmoebaNr[xx][yy] == old_group_nr)
3223             AmoebaNr[xx][yy] = new_group_nr;
3224         }
3225       }
3226     }
3227   }
3228 }
3229
3230 void AmoebeUmwandeln(int ax, int ay)
3231 {
3232   int i, x, y;
3233
3234   if (Feld[ax][ay] == EL_AMOEBE_TOT)
3235   {
3236     int group_nr = AmoebaNr[ax][ay];
3237
3238 #ifdef DEBUG
3239     if (group_nr == 0)
3240     {
3241       printf("AmoebeUmwandeln(): ax = %d, ay = %d\n", ax, ay);
3242       printf("AmoebeUmwandeln(): This should never happen!\n");
3243       return;
3244     }
3245 #endif
3246
3247     for (y=0; y<lev_fieldy; y++)
3248     {
3249       for (x=0; x<lev_fieldx; x++)
3250       {
3251         if (Feld[x][y] == EL_AMOEBE_TOT && AmoebaNr[x][y] == group_nr)
3252         {
3253           AmoebaNr[x][y] = 0;
3254           Feld[x][y] = EL_AMOEBA2DIAM;
3255         }
3256       }
3257     }
3258     Bang(ax, ay);
3259   }
3260   else
3261   {
3262     static int xy[4][2] =
3263     {
3264       { 0, -1 },
3265       { -1, 0 },
3266       { +1, 0 },
3267       { 0, +1 }
3268     };
3269
3270     for (i=0; i<4; i++)
3271     {
3272       x = ax + xy[i][0];
3273       y = ay + xy[i][1];
3274
3275       if (!IN_LEV_FIELD(x, y))
3276         continue;
3277
3278       if (Feld[x][y] == EL_AMOEBA2DIAM)
3279         Bang(x, y);
3280     }
3281   }
3282 }
3283
3284 void AmoebeUmwandelnBD(int ax, int ay, int new_element)
3285 {
3286   int x, y;
3287   int group_nr = AmoebaNr[ax][ay];
3288   boolean done = FALSE;
3289
3290 #ifdef DEBUG
3291   if (group_nr == 0)
3292   {
3293     printf("AmoebeUmwandelnBD(): ax = %d, ay = %d\n", ax, ay);
3294     printf("AmoebeUmwandelnBD(): This should never happen!\n");
3295     return;
3296   }
3297 #endif
3298
3299   for (y=0; y<lev_fieldy; y++)
3300   {
3301     for (x=0; x<lev_fieldx; x++)
3302     {
3303       if (AmoebaNr[x][y] == group_nr &&
3304           (Feld[x][y] == EL_AMOEBE_TOT ||
3305            Feld[x][y] == EL_AMOEBE_BD ||
3306            Feld[x][y] == EL_AMOEBING))
3307       {
3308         AmoebaNr[x][y] = 0;
3309         Feld[x][y] = new_element;
3310         InitField(x, y, FALSE);
3311         DrawLevelField(x, y);
3312         done = TRUE;
3313       }
3314     }
3315   }
3316
3317   if (done)
3318     PlaySoundLevel(ax, ay,
3319                    (new_element == EL_BD_ROCK ? SND_KLOPF : SND_PLING));
3320 }
3321
3322 void AmoebeWaechst(int x, int y)
3323 {
3324   static unsigned long sound_delay = 0;
3325   static unsigned long sound_delay_value = 0;
3326
3327   if (!MovDelay[x][y])          /* start new growing cycle */
3328   {
3329     MovDelay[x][y] = 7;
3330
3331     if (DelayReached(&sound_delay, sound_delay_value))
3332     {
3333       PlaySoundLevel(x, y, SND_AMOEBE);
3334       sound_delay_value = 30;
3335     }
3336   }
3337
3338   if (MovDelay[x][y])           /* wait some time before growing bigger */
3339   {
3340     MovDelay[x][y]--;
3341     if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3342       DrawGraphic(SCREENX(x), SCREENY(y), GFX_AMOEBING + 3 - MovDelay[x][y]/2);
3343
3344     if (!MovDelay[x][y])
3345     {
3346       Feld[x][y] = Store[x][y];
3347       Store[x][y] = 0;
3348       DrawLevelField(x, y);
3349     }
3350   }
3351 }
3352
3353 void AmoebeSchrumpft(int x, int y)
3354 {
3355   static unsigned long sound_delay = 0;
3356   static unsigned long sound_delay_value = 0;
3357
3358   if (!MovDelay[x][y])          /* start new shrinking cycle */
3359   {
3360     MovDelay[x][y] = 7;
3361
3362     if (DelayReached(&sound_delay, sound_delay_value))
3363     {
3364       PlaySoundLevel(x, y, SND_BLURB);
3365       sound_delay_value = 30;
3366     }
3367   }
3368
3369   if (MovDelay[x][y])           /* wait some time before shrinking */
3370   {
3371     MovDelay[x][y]--;
3372     if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3373       DrawGraphic(SCREENX(x), SCREENY(y), GFX_AMOEBING + MovDelay[x][y]/2);
3374
3375     if (!MovDelay[x][y])
3376     {
3377       Feld[x][y] = EL_LEERRAUM;
3378       DrawLevelField(x, y);
3379
3380       /* don't let mole enter this field in this cycle;
3381          (give priority to objects falling to this field from above) */
3382       Stop[x][y] = TRUE;
3383     }
3384   }
3385 }
3386
3387 void AmoebeAbleger(int ax, int ay)
3388 {
3389   int i;
3390   int element = Feld[ax][ay];
3391   int newax = ax, neway = ay;
3392   static int xy[4][2] =
3393   {
3394     { 0, -1 },
3395     { -1, 0 },
3396     { +1, 0 },
3397     { 0, +1 }
3398   };
3399
3400   if (!level.amoeba_speed)
3401   {
3402     Feld[ax][ay] = EL_AMOEBE_TOT;
3403     DrawLevelField(ax, ay);
3404     return;
3405   }
3406
3407   if (!MovDelay[ax][ay])        /* start making new amoeba field */
3408     MovDelay[ax][ay] = RND(FRAMES_PER_SECOND * 25 / (1 + level.amoeba_speed));
3409
3410   if (MovDelay[ax][ay])         /* wait some time before making new amoeba */
3411   {
3412     MovDelay[ax][ay]--;
3413     if (MovDelay[ax][ay])
3414       return;
3415   }
3416
3417   if (element == EL_AMOEBE_NASS)        /* object is an acid / amoeba drop */
3418   {
3419     int start = RND(4);
3420     int x = ax + xy[start][0];
3421     int y = ay + xy[start][1];
3422
3423     if (!IN_LEV_FIELD(x, y))
3424       return;
3425
3426     if (IS_FREE(x, y) ||
3427         Feld[x][y] == EL_ERDREICH || Feld[x][y] == EL_MORAST_LEER)
3428     {
3429       newax = x;
3430       neway = y;
3431     }
3432
3433     if (newax == ax && neway == ay)
3434       return;
3435   }
3436   else                          /* normal or "filled" (BD style) amoeba */
3437   {
3438     int start = RND(4);
3439     boolean waiting_for_player = FALSE;
3440
3441     for (i=0; i<4; i++)
3442     {
3443       int j = (start + i) % 4;
3444       int x = ax + xy[j][0];
3445       int y = ay + xy[j][1];
3446
3447       if (!IN_LEV_FIELD(x, y))
3448         continue;
3449
3450       if (IS_FREE(x, y) ||
3451           Feld[x][y] == EL_ERDREICH || Feld[x][y] == EL_MORAST_LEER)
3452       {
3453         newax = x;
3454         neway = y;
3455         break;
3456       }
3457       else if (IS_PLAYER(x, y))
3458         waiting_for_player = TRUE;
3459     }
3460
3461     if (newax == ax && neway == ay)             /* amoeba cannot grow */
3462     {
3463       if (i == 4 && (!waiting_for_player || game.emulation == EMU_BOULDERDASH))
3464       {
3465         Feld[ax][ay] = EL_AMOEBE_TOT;
3466         DrawLevelField(ax, ay);
3467         AmoebaCnt[AmoebaNr[ax][ay]]--;
3468
3469         if (AmoebaCnt[AmoebaNr[ax][ay]] <= 0)   /* amoeba is completely dead */
3470         {
3471           if (element == EL_AMOEBE_VOLL)
3472             AmoebeUmwandeln(ax, ay);
3473           else if (element == EL_AMOEBE_BD)
3474             AmoebeUmwandelnBD(ax, ay, level.amoeba_content);
3475         }
3476       }
3477       return;
3478     }
3479     else if (element == EL_AMOEBE_VOLL || element == EL_AMOEBE_BD)
3480     {
3481       /* amoeba gets larger by growing in some direction */
3482
3483       int new_group_nr = AmoebaNr[ax][ay];
3484
3485 #ifdef DEBUG
3486   if (new_group_nr == 0)
3487   {
3488     printf("AmoebeAbleger(): newax = %d, neway = %d\n", newax, neway);
3489     printf("AmoebeAbleger(): This should never happen!\n");
3490     return;
3491   }
3492 #endif
3493
3494       AmoebaNr[newax][neway] = new_group_nr;
3495       AmoebaCnt[new_group_nr]++;
3496       AmoebaCnt2[new_group_nr]++;
3497
3498       /* if amoeba touches other amoeba(s) after growing, unify them */
3499       AmoebenVereinigen(newax, neway);
3500
3501       if (element == EL_AMOEBE_BD && AmoebaCnt2[new_group_nr] >= 200)
3502       {
3503         AmoebeUmwandelnBD(newax, neway, EL_BD_ROCK);
3504         return;
3505       }
3506     }
3507   }
3508
3509   if (element != EL_AMOEBE_NASS || neway < ay || !IS_FREE(newax, neway) ||
3510       (neway == lev_fieldy - 1 && newax != ax))
3511   {
3512     Feld[newax][neway] = EL_AMOEBING;   /* simple growth of new amoeba tile */
3513     Store[newax][neway] = element;
3514   }
3515   else if (neway == ay)
3516     Feld[newax][neway] = EL_TROPFEN;    /* drop left or right from amoeba */
3517   else
3518   {
3519     InitMovingField(ax, ay, MV_DOWN);   /* drop dripping out of amoeba */
3520     Feld[ax][ay] = EL_AMOEBA_DRIPPING;
3521     Store[ax][ay] = EL_TROPFEN;
3522     ContinueMoving(ax, ay);
3523     return;
3524   }
3525
3526   DrawLevelField(newax, neway);
3527 }
3528
3529 void Life(int ax, int ay)
3530 {
3531   int x1, y1, x2, y2;
3532   static int life[4] = { 2, 3, 3, 3 };  /* parameters for "game of life" */
3533   int life_time = 40;
3534   int element = Feld[ax][ay];
3535
3536   if (Stop[ax][ay])
3537     return;
3538
3539   if (!MovDelay[ax][ay])        /* start new "game of life" cycle */
3540     MovDelay[ax][ay] = life_time;
3541
3542   if (MovDelay[ax][ay])         /* wait some time before next cycle */
3543   {
3544     MovDelay[ax][ay]--;
3545     if (MovDelay[ax][ay])
3546       return;
3547   }
3548
3549   for (y1=-1; y1<2; y1++) for(x1=-1; x1<2; x1++)
3550   {
3551     int xx = ax+x1, yy = ay+y1;
3552     int nachbarn = 0;
3553
3554     if (!IN_LEV_FIELD(xx, yy))
3555       continue;
3556
3557     for (y2=-1; y2<2; y2++) for (x2=-1; x2<2; x2++)
3558     {
3559       int x = xx+x2, y = yy+y2;
3560
3561       if (!IN_LEV_FIELD(x, y) || (x == xx && y == yy))
3562         continue;
3563
3564       if (((Feld[x][y] == element ||
3565             (element == EL_LIFE && IS_PLAYER(x, y))) &&
3566            !Stop[x][y]) ||
3567           (IS_FREE(x, y) && Stop[x][y]))
3568         nachbarn++;
3569     }
3570
3571     if (xx == ax && yy == ay)           /* field in the middle */
3572     {
3573       if (nachbarn<life[0] || nachbarn>life[1])
3574       {
3575         Feld[xx][yy] = EL_LEERRAUM;
3576         if (!Stop[xx][yy])
3577           DrawLevelField(xx, yy);
3578         Stop[xx][yy] = TRUE;
3579       }
3580     }
3581     else if (IS_FREE(xx, yy) || Feld[xx][yy] == EL_ERDREICH)
3582     {                                   /* free border field */
3583       if (nachbarn>=life[2] && nachbarn<=life[3])
3584       {
3585         Feld[xx][yy] = element;
3586         MovDelay[xx][yy] = (element == EL_LIFE ? 0 : life_time-1);
3587         if (!Stop[xx][yy])
3588           DrawLevelField(xx, yy);
3589         Stop[xx][yy] = TRUE;
3590       }
3591     }
3592   }
3593 }
3594
3595 void Ablenk(int x, int y)
3596 {
3597   if (!MovDelay[x][y])          /* next animation frame */
3598     MovDelay[x][y] = level.time_wheel * FRAMES_PER_SECOND;
3599
3600   if (MovDelay[x][y])           /* wait some time before next frame */
3601   {
3602     MovDelay[x][y]--;
3603     if (MovDelay[x][y])
3604     {
3605       if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3606         DrawGraphic(SCREENX(x), SCREENY(y), GFX_ABLENK+MovDelay[x][y]%4);
3607       if (!(MovDelay[x][y]%4))
3608         PlaySoundLevel(x, y, SND_MIEP);
3609       return;
3610     }
3611   }
3612
3613   Feld[x][y] = EL_ABLENK_AUS;
3614   DrawLevelField(x, y);
3615   if (ZX == x && ZY == y)
3616     ZX = ZY = -1;
3617 }
3618
3619 void TimegateWheel(int x, int y)
3620 {
3621   if (!MovDelay[x][y])          /* next animation frame */
3622     MovDelay[x][y] = level.time_wheel * FRAMES_PER_SECOND;
3623
3624   if (MovDelay[x][y])           /* wait some time before next frame */
3625   {
3626     MovDelay[x][y]--;
3627     if (MovDelay[x][y])
3628     {
3629       if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3630         DrawGraphic(SCREENX(x), SCREENY(y),
3631                     GFX_TIMEGATE_SWITCH + MovDelay[x][y]%4);
3632       if (!(MovDelay[x][y]%4))
3633         PlaySoundLevel(x, y, SND_MIEP);
3634       return;
3635     }
3636   }
3637
3638   Feld[x][y] = EL_TIMEGATE_SWITCH_OFF;
3639   DrawLevelField(x, y);
3640   if (ZX == x && ZY == y)
3641     ZX = ZY = -1;
3642 }
3643
3644 void Birne(int x, int y)
3645 {
3646   if (!MovDelay[x][y])          /* next animation frame */
3647     MovDelay[x][y] = 800;
3648
3649   if (MovDelay[x][y])           /* wait some time before next frame */
3650   {
3651     MovDelay[x][y]--;
3652     if (MovDelay[x][y])
3653     {
3654       if (!(MovDelay[x][y]%5))
3655       {
3656         if (!(MovDelay[x][y]%10))
3657           Feld[x][y]=EL_ABLENK_EIN;
3658         else
3659           Feld[x][y]=EL_ABLENK_AUS;
3660         DrawLevelField(x, y);
3661         Feld[x][y]=EL_ABLENK_EIN;
3662       }
3663       return;
3664     }
3665   }
3666
3667   Feld[x][y]=EL_ABLENK_AUS;
3668   DrawLevelField(x, y);
3669   if (ZX == x && ZY == y)
3670     ZX=ZY=-1;
3671 }
3672
3673 void Blubber(int x, int y)
3674 {
3675   if (y > 0 && IS_MOVING(x, y-1) && MovDir[x][y-1] == MV_DOWN)
3676     DrawLevelField(x, y-1);
3677   else
3678     DrawGraphicAnimation(x, y, GFX_GEBLUBBER, 4, 10, ANIM_NORMAL);
3679 }
3680
3681 void NussKnacken(int x, int y)
3682 {
3683   if (!MovDelay[x][y])          /* next animation frame */
3684     MovDelay[x][y] = 7;
3685
3686   if (MovDelay[x][y])           /* wait some time before next frame */
3687   {
3688     MovDelay[x][y]--;
3689     if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3690       DrawGraphic(SCREENX(x), SCREENY(y),
3691                   GFX_CRACKINGNUT + 3 - MovDelay[x][y]/2);
3692
3693     if (!MovDelay[x][y])
3694     {
3695       Feld[x][y] = EL_EDELSTEIN;
3696       DrawLevelField(x, y);
3697     }
3698   }
3699 }
3700
3701 void BreakingPearl(int x, int y)
3702 {
3703   if (!MovDelay[x][y])          /* next animation frame */
3704     MovDelay[x][y] = 9;
3705
3706   if (MovDelay[x][y])           /* wait some time before next frame */
3707   {
3708     MovDelay[x][y]--;
3709     if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3710       DrawGraphic(SCREENX(x), SCREENY(y),
3711                   GFX_PEARL_BREAKING + 4 - MovDelay[x][y]/2);
3712
3713     if (!MovDelay[x][y])
3714     {
3715       Feld[x][y] = EL_LEERRAUM;
3716       DrawLevelField(x, y);
3717     }
3718   }
3719 }
3720
3721 void SiebAktivieren(int x, int y, int typ)
3722 {
3723   int graphic = (typ == 1 ? GFX_MAGIC_WALL_FULL : GFX_MAGIC_WALL_BD_FULL) + 3;
3724
3725   DrawGraphicAnimation(x, y, graphic, 4, 4, ANIM_REVERSE);
3726 }
3727
3728 void AusgangstuerPruefen(int x, int y)
3729 {
3730   if (!local_player->gems_still_needed &&
3731       !local_player->sokobanfields_still_needed &&
3732       !local_player->lights_still_needed)
3733   {
3734     Feld[x][y] = EL_AUSGANG_ACT;
3735
3736     PlaySoundLevel(x < LEVELX(BX1) ? LEVELX(BX1) :
3737                    (x > LEVELX(BX2) ? LEVELX(BX2) : x),
3738                    y < LEVELY(BY1) ? LEVELY(BY1) :
3739                    (y > LEVELY(BY2) ? LEVELY(BY2) : y),
3740                    SND_OEFFNEN);
3741   }
3742 }
3743
3744 void AusgangstuerOeffnen(int x, int y)
3745 {
3746   int delay = 6;
3747
3748   if (!MovDelay[x][y])          /* next animation frame */
3749     MovDelay[x][y] = 5*delay;
3750
3751   if (MovDelay[x][y])           /* wait some time before next frame */
3752   {
3753     int tuer;
3754
3755     MovDelay[x][y]--;
3756     tuer = MovDelay[x][y]/delay;
3757     if (!(MovDelay[x][y]%delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3758       DrawGraphic(SCREENX(x), SCREENY(y), GFX_AUSGANG_AUF-tuer);
3759
3760     if (!MovDelay[x][y])
3761     {
3762       Feld[x][y] = EL_AUSGANG_AUF;
3763       DrawLevelField(x, y);
3764     }
3765   }
3766 }
3767
3768 void AusgangstuerBlinken(int x, int y)
3769 {
3770   DrawGraphicAnimation(x, y, GFX_AUSGANG_AUF, 4, 4, ANIM_OSCILLATE);
3771 }
3772
3773 void OpenSwitchgate(int x, int y)
3774 {
3775   int delay = 6;
3776
3777   if (!MovDelay[x][y])          /* next animation frame */
3778     MovDelay[x][y] = 5 * delay;
3779
3780   if (MovDelay[x][y])           /* wait some time before next frame */
3781   {
3782     int phase;
3783
3784     MovDelay[x][y]--;
3785     phase = MovDelay[x][y] / delay;
3786     if (!(MovDelay[x][y] % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3787       DrawGraphic(SCREENX(x), SCREENY(y), GFX_SWITCHGATE_OPEN - phase);
3788
3789     if (!MovDelay[x][y])
3790     {
3791       Feld[x][y] = EL_SWITCHGATE_OPEN;
3792       DrawLevelField(x, y);
3793     }
3794   }
3795 }
3796
3797 void CloseSwitchgate(int x, int y)
3798 {
3799   int delay = 6;
3800
3801   if (!MovDelay[x][y])          /* next animation frame */
3802     MovDelay[x][y] = 5 * delay;
3803
3804   if (MovDelay[x][y])           /* wait some time before next frame */
3805   {
3806     int phase;
3807
3808     MovDelay[x][y]--;
3809     phase = MovDelay[x][y] / delay;
3810     if (!(MovDelay[x][y] % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3811       DrawGraphic(SCREENX(x), SCREENY(y), GFX_SWITCHGATE_CLOSED + phase);
3812
3813     if (!MovDelay[x][y])
3814     {
3815       Feld[x][y] = EL_SWITCHGATE_CLOSED;
3816       DrawLevelField(x, y);
3817     }
3818   }
3819 }
3820
3821 void OpenTimegate(int x, int y)
3822 {
3823   int delay = 6;
3824
3825   if (!MovDelay[x][y])          /* next animation frame */
3826     MovDelay[x][y] = 5 * delay;
3827
3828   if (MovDelay[x][y])           /* wait some time before next frame */
3829   {
3830     int phase;
3831
3832     MovDelay[x][y]--;
3833     phase = MovDelay[x][y] / delay;
3834     if (!(MovDelay[x][y] % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3835       DrawGraphic(SCREENX(x), SCREENY(y), GFX_TIMEGATE_OPEN - phase);
3836
3837     if (!MovDelay[x][y])
3838     {
3839       Feld[x][y] = EL_TIMEGATE_OPEN;
3840       DrawLevelField(x, y);
3841     }
3842   }
3843 }
3844
3845 void CloseTimegate(int x, int y)
3846 {
3847   int delay = 6;
3848
3849   if (!MovDelay[x][y])          /* next animation frame */
3850     MovDelay[x][y] = 5 * delay;
3851
3852   if (MovDelay[x][y])           /* wait some time before next frame */
3853   {
3854     int phase;
3855
3856     MovDelay[x][y]--;
3857     phase = MovDelay[x][y] / delay;
3858     if (!(MovDelay[x][y] % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3859       DrawGraphic(SCREENX(x), SCREENY(y), GFX_TIMEGATE_CLOSED + phase);
3860
3861     if (!MovDelay[x][y])
3862     {
3863       Feld[x][y] = EL_TIMEGATE_CLOSED;
3864       DrawLevelField(x, y);
3865     }
3866   }
3867 }
3868
3869 static void CloseAllOpenTimegates()
3870 {
3871   int x, y;
3872
3873   for (y=0; y<lev_fieldy; y++)
3874   {
3875     for (x=0; x<lev_fieldx; x++)
3876     {
3877       int element = Feld[x][y];
3878
3879       if (element == EL_TIMEGATE_OPEN || element == EL_TIMEGATE_OPENING)
3880       {
3881         Feld[x][y] = EL_TIMEGATE_CLOSING;
3882         PlaySoundLevel(x, y, SND_OEFFNEN);
3883       }
3884     }
3885   }
3886 }
3887
3888 void EdelsteinFunkeln(int x, int y)
3889 {
3890   if (!IN_SCR_FIELD(SCREENX(x), SCREENY(y)) || IS_MOVING(x, y))
3891     return;
3892
3893   if (Feld[x][y] == EL_EDELSTEIN_BD)
3894     DrawGraphicAnimation(x, y, GFX_EDELSTEIN_BD, 4, 4, ANIM_REVERSE);
3895   else
3896   {
3897     if (!MovDelay[x][y])        /* next animation frame */
3898       MovDelay[x][y] = 11 * !SimpleRND(500);
3899
3900     if (MovDelay[x][y])         /* wait some time before next frame */
3901     {
3902       MovDelay[x][y]--;
3903
3904       if (setup.direct_draw && MovDelay[x][y])
3905         SetDrawtoField(DRAW_BUFFERED);
3906
3907       DrawGraphic(SCREENX(x), SCREENY(y), el2gfx(Feld[x][y]));
3908
3909       if (MovDelay[x][y])
3910       {
3911         int phase = (MovDelay[x][y]-1)/2;
3912
3913         if (phase > 2)
3914           phase = 4-phase;
3915
3916         DrawGraphicThruMask(SCREENX(x), SCREENY(y), GFX_FUNKELN_WEISS + phase);
3917
3918         if (setup.direct_draw)
3919         {
3920           int dest_x, dest_y;
3921
3922           dest_x = FX + SCREENX(x)*TILEX;
3923           dest_y = FY + SCREENY(y)*TILEY;
3924
3925           BlitBitmap(drawto_field, window,
3926                      dest_x, dest_y, TILEX, TILEY, dest_x, dest_y);
3927           SetDrawtoField(DRAW_DIRECT);
3928         }
3929       }
3930     }
3931   }
3932 }
3933
3934 void MauerWaechst(int x, int y)
3935 {
3936   int delay = 6;
3937
3938   if (!MovDelay[x][y])          /* next animation frame */
3939     MovDelay[x][y] = 3*delay;
3940
3941   if (MovDelay[x][y])           /* wait some time before next frame */
3942   {
3943     int phase;
3944
3945     MovDelay[x][y]--;
3946     phase = 2-MovDelay[x][y]/delay;
3947     if (!(MovDelay[x][y]%delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3948       DrawGraphic(SCREENX(x), SCREENY(y),
3949                   (MovDir[x][y] == MV_LEFT  ? GFX_MAUER_LEFT  :
3950                    MovDir[x][y] == MV_RIGHT ? GFX_MAUER_RIGHT :
3951                    MovDir[x][y] == MV_UP    ? GFX_MAUER_UP    :
3952                                               GFX_MAUER_DOWN  ) + phase);
3953
3954     if (!MovDelay[x][y])
3955     {
3956       if (MovDir[x][y] == MV_LEFT)
3957       {
3958         if (IN_LEV_FIELD(x-1, y) && IS_MAUER(Feld[x-1][y]))
3959           DrawLevelField(x-1, y);
3960       }
3961       else if (MovDir[x][y] == MV_RIGHT)
3962       {
3963         if (IN_LEV_FIELD(x+1, y) && IS_MAUER(Feld[x+1][y]))
3964           DrawLevelField(x+1, y);
3965       }
3966       else if (MovDir[x][y] == MV_UP)
3967       {
3968         if (IN_LEV_FIELD(x, y-1) && IS_MAUER(Feld[x][y-1]))
3969           DrawLevelField(x, y-1);
3970       }
3971       else
3972       {
3973         if (IN_LEV_FIELD(x, y+1) && IS_MAUER(Feld[x][y+1]))
3974           DrawLevelField(x, y+1);
3975       }
3976
3977       Feld[x][y] = Store[x][y];
3978       Store[x][y] = 0;
3979       MovDir[x][y] = MV_NO_MOVING;
3980       DrawLevelField(x, y);
3981     }
3982   }
3983 }
3984
3985 void MauerAbleger(int ax, int ay)
3986 {
3987   int element = Feld[ax][ay];
3988   boolean oben_frei = FALSE, unten_frei = FALSE;
3989   boolean links_frei = FALSE, rechts_frei = FALSE;
3990   boolean oben_massiv = FALSE, unten_massiv = FALSE;
3991   boolean links_massiv = FALSE, rechts_massiv = FALSE;
3992
3993   if (!MovDelay[ax][ay])        /* start building new wall */
3994     MovDelay[ax][ay] = 6;
3995
3996   if (MovDelay[ax][ay])         /* wait some time before building new wall */
3997   {
3998     MovDelay[ax][ay]--;
3999     if (MovDelay[ax][ay])
4000       return;
4001   }
4002
4003   if (IN_LEV_FIELD(ax, ay-1) && IS_FREE(ax, ay-1))
4004     oben_frei = TRUE;
4005   if (IN_LEV_FIELD(ax, ay+1) && IS_FREE(ax, ay+1))
4006     unten_frei = TRUE;
4007   if (IN_LEV_FIELD(ax-1, ay) && IS_FREE(ax-1, ay))
4008     links_frei = TRUE;
4009   if (IN_LEV_FIELD(ax+1, ay) && IS_FREE(ax+1, ay))
4010     rechts_frei = TRUE;
4011
4012   if (element == EL_MAUER_Y || element == EL_MAUER_XY)
4013   {
4014     if (oben_frei)
4015     {
4016       Feld[ax][ay-1] = EL_MAUERND;
4017       Store[ax][ay-1] = element;
4018       MovDir[ax][ay-1] = MV_UP;
4019       if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay-1)))
4020         DrawGraphic(SCREENX(ax), SCREENY(ay-1), GFX_MAUER_UP);
4021     }
4022     if (unten_frei)
4023     {
4024       Feld[ax][ay+1] = EL_MAUERND;
4025       Store[ax][ay+1] = element;
4026       MovDir[ax][ay+1] = MV_DOWN;
4027       if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay+1)))
4028         DrawGraphic(SCREENX(ax), SCREENY(ay+1), GFX_MAUER_DOWN);
4029     }
4030   }
4031
4032   if (element == EL_MAUER_X || element == EL_MAUER_XY ||
4033       element == EL_MAUER_LEBT)
4034   {
4035     if (links_frei)
4036     {
4037       Feld[ax-1][ay] = EL_MAUERND;
4038       Store[ax-1][ay] = element;
4039       MovDir[ax-1][ay] = MV_LEFT;
4040       if (IN_SCR_FIELD(SCREENX(ax-1), SCREENY(ay)))
4041         DrawGraphic(SCREENX(ax-1), SCREENY(ay), GFX_MAUER_LEFT);
4042     }
4043     if (rechts_frei)
4044     {
4045       Feld[ax+1][ay] = EL_MAUERND;
4046       Store[ax+1][ay] = element;
4047       MovDir[ax+1][ay] = MV_RIGHT;
4048       if (IN_SCR_FIELD(SCREENX(ax+1), SCREENY(ay)))
4049         DrawGraphic(SCREENX(ax+1), SCREENY(ay), GFX_MAUER_RIGHT);
4050     }
4051   }
4052
4053   if (element == EL_MAUER_LEBT && (links_frei || rechts_frei))
4054     DrawLevelField(ax, ay);
4055
4056   if (!IN_LEV_FIELD(ax, ay-1) || IS_MAUER(Feld[ax][ay-1]))
4057     oben_massiv = TRUE;
4058   if (!IN_LEV_FIELD(ax, ay+1) || IS_MAUER(Feld[ax][ay+1]))
4059     unten_massiv = TRUE;
4060   if (!IN_LEV_FIELD(ax-1, ay) || IS_MAUER(Feld[ax-1][ay]))
4061     links_massiv = TRUE;
4062   if (!IN_LEV_FIELD(ax+1, ay) || IS_MAUER(Feld[ax+1][ay]))
4063     rechts_massiv = TRUE;
4064
4065   if (((oben_massiv && unten_massiv) ||
4066        element == EL_MAUER_X || element == EL_MAUER_LEBT) &&
4067       ((links_massiv && rechts_massiv) ||
4068        element == EL_MAUER_Y))
4069     Feld[ax][ay] = EL_MAUERWERK;
4070 }
4071
4072 void CheckForDragon(int x, int y)
4073 {
4074   int i, j;
4075   boolean dragon_found = FALSE;
4076   static int xy[4][2] =
4077   {
4078     { 0, -1 },
4079     { -1, 0 },
4080     { +1, 0 },
4081     { 0, +1 }
4082   };
4083
4084   for (i=0; i<4; i++)
4085   {
4086     for (j=0; j<4; j++)
4087     {
4088       int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
4089
4090       if (IN_LEV_FIELD(xx, yy) &&
4091           (Feld[xx][yy] == EL_BURNING || Feld[xx][yy] == EL_DRACHE))
4092       {
4093         if (Feld[xx][yy] == EL_DRACHE)
4094           dragon_found = TRUE;
4095       }
4096       else
4097         break;
4098     }
4099   }
4100
4101   if (!dragon_found)
4102   {
4103     for (i=0; i<4; i++)
4104     {
4105       for (j=0; j<3; j++)
4106       {
4107         int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
4108   
4109         if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == EL_BURNING)
4110         {
4111           Feld[xx][yy] = EL_LEERRAUM;
4112           DrawLevelField(xx, yy);
4113         }
4114         else
4115           break;
4116       }
4117     }
4118   }
4119 }
4120
4121 static void CheckBuggyBase(int x, int y)
4122 {
4123   int element = Feld[x][y];
4124
4125   if (element == EL_SP_BUG)
4126   {
4127     if (!MovDelay[x][y])        /* wait some time before activating base */
4128       MovDelay[x][y] = 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND);
4129
4130     if (MovDelay[x][y])
4131     {
4132       MovDelay[x][y]--;
4133       if (MovDelay[x][y] < 5 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
4134         DrawGraphic(SCREENX(x), SCREENY(y), GFX_SP_BUG_WARNING);
4135       if (MovDelay[x][y])
4136         return;
4137
4138       Feld[x][y] = EL_SP_BUG_ACTIVE;
4139     }
4140   }
4141   else if (element == EL_SP_BUG_ACTIVE)
4142   {
4143     if (!MovDelay[x][y])        /* start activating buggy base */
4144       MovDelay[x][y] = 1 * FRAMES_PER_SECOND + RND(1 * FRAMES_PER_SECOND);
4145
4146     if (MovDelay[x][y])
4147     {
4148       MovDelay[x][y]--;
4149       if (MovDelay[x][y])
4150       {
4151         int i;
4152         static int xy[4][2] =
4153         {
4154           { 0, -1 },
4155           { -1, 0 },
4156           { +1, 0 },
4157           { 0, +1 }
4158         };
4159
4160         if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
4161           DrawGraphic(SCREENX(x),SCREENY(y), GFX_SP_BUG_ACTIVE + SimpleRND(4));
4162
4163         for (i=0; i<4; i++)
4164         {
4165           int xx = x + xy[i][0], yy = y + xy[i][1];
4166
4167           if (IS_PLAYER(xx, yy))
4168           {
4169             PlaySoundLevel(x, y, SND_SP_BUG);
4170             break;
4171           }
4172         }
4173
4174         return;
4175       }
4176
4177       Feld[x][y] = EL_SP_BUG;
4178       DrawLevelField(x, y);
4179     }
4180   }
4181 }
4182
4183 static void CheckTrap(int x, int y)
4184 {
4185   int element = Feld[x][y];
4186
4187   if (element == EL_TRAP_INACTIVE)
4188   {
4189     if (!MovDelay[x][y])        /* wait some time before activating trap */
4190       MovDelay[x][y] = 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND);
4191
4192     if (MovDelay[x][y])
4193     {
4194       MovDelay[x][y]--;
4195       if (MovDelay[x][y])
4196         return;
4197
4198       Feld[x][y] = EL_TRAP_ACTIVE;
4199     }
4200   }
4201   else if (element == EL_TRAP_ACTIVE)
4202   {
4203     int delay = 4;
4204     int num_frames = 8;
4205
4206     if (!MovDelay[x][y])        /* start activating trap */
4207       MovDelay[x][y] = num_frames * delay;
4208
4209     if (MovDelay[x][y])
4210     {
4211       MovDelay[x][y]--;
4212
4213       if (MovDelay[x][y])
4214       {
4215         if (!(MovDelay[x][y] % delay))
4216         {
4217           int phase = MovDelay[x][y]/delay;
4218
4219           if (phase >= num_frames/2)
4220             phase = num_frames - phase;
4221
4222           if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
4223           {
4224             DrawGraphic(SCREENX(x),SCREENY(y), GFX_TRAP_INACTIVE + phase - 1);
4225             ErdreichAnbroeckeln(SCREENX(x), SCREENY(y));
4226           }
4227         }
4228
4229         return;
4230       }
4231
4232       Feld[x][y] = EL_TRAP_INACTIVE;
4233       DrawLevelField(x, y);
4234     }
4235   }
4236 }
4237
4238 static void DrawBeltAnimation(int x, int y, int element)
4239 {
4240   int belt_nr = getBeltNrFromElement(element);
4241   int belt_dir = game.belt_dir[belt_nr];
4242
4243   if (belt_dir != MV_NO_MOVING)
4244   {
4245     int delay = 2;
4246     int mode = (belt_dir == MV_LEFT ? ANIM_NORMAL : ANIM_REVERSE);
4247     int graphic = el2gfx(element) + (belt_dir == MV_LEFT ? 0 : 7);
4248
4249     DrawGraphicAnimation(x, y, graphic, 8, delay, mode);
4250   }
4251 }
4252
4253 static void PlayerActions(struct PlayerInfo *player, byte player_action)
4254 {
4255   static byte stored_player_action[MAX_PLAYERS];
4256   static int num_stored_actions = 0;
4257 #if 0
4258   static boolean save_tape_entry = FALSE;
4259 #endif
4260   boolean moved = FALSE, snapped = FALSE, bombed = FALSE;
4261   int left      = player_action & JOY_LEFT;
4262   int right     = player_action & JOY_RIGHT;
4263   int up        = player_action & JOY_UP;
4264   int down      = player_action & JOY_DOWN;
4265   int button1   = player_action & JOY_BUTTON_1;
4266   int button2   = player_action & JOY_BUTTON_2;
4267   int dx        = (left ? -1    : right ? 1     : 0);
4268   int dy        = (up   ? -1    : down  ? 1     : 0);
4269
4270   stored_player_action[player->index_nr] = 0;
4271   num_stored_actions++;
4272
4273   if (!player->active || tape.pausing)
4274     return;
4275
4276   if (player_action)
4277   {
4278 #if 0
4279     save_tape_entry = TRUE;
4280 #endif
4281     player->frame_reset_delay = 0;
4282
4283     if (button1)
4284       snapped = SnapField(player, dx, dy);
4285     else
4286     {
4287       if (button2)
4288         bombed = PlaceBomb(player);
4289       moved = MoveFigure(player, dx, dy);
4290     }
4291
4292     if (tape.single_step && tape.recording && !tape.pausing)
4293     {
4294       if (button1 || (bombed && !moved))
4295       {
4296         TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
4297         SnapField(player, 0, 0);                /* stop snapping */
4298       }
4299     }
4300
4301 #if 0
4302     if (tape.recording && (moved || snapped || bombed))
4303     {
4304       if (bombed && !moved)
4305         player_action &= JOY_BUTTON;
4306
4307       stored_player_action[player->index_nr] = player_action;
4308       save_tape_entry = TRUE;
4309     }
4310     else if (tape.playing && snapped)
4311       SnapField(player, 0, 0);                  /* stop snapping */
4312 #else
4313     stored_player_action[player->index_nr] = player_action;
4314 #endif
4315   }
4316   else
4317   {
4318     /* no actions for this player (no input at player's configured device) */
4319
4320     DigField(player, 0, 0, 0, 0, DF_NO_PUSH);
4321     SnapField(player, 0, 0);
4322     CheckGravityMovement(player);
4323
4324 #if 1
4325     if (player->MovPos == 0)    /* needed for tape.playing */
4326       player->is_moving = FALSE;
4327 #endif
4328 #if 0
4329     if (player->MovPos == 0)    /* needed for tape.playing */
4330       player->last_move_dir = MV_NO_MOVING;
4331
4332     /* !!! CHECK THIS AGAIN !!!
4333        (Seems to be needed for some EL_ROBOT stuff, but breaks
4334        tapes when walking through pipes!)
4335     */
4336
4337     /* it seems that "player->last_move_dir" is misused as some sort of
4338        "player->is_just_moving_in_this_moment", which is needed for the
4339        robot stuff (robots don't kill players when they are moving)
4340     */
4341 #endif 
4342
4343     if (++player->frame_reset_delay > player->move_delay_value)
4344       player->Frame = 0;
4345   }
4346
4347 #if 0
4348   if (tape.recording && num_stored_actions >= MAX_PLAYERS && save_tape_entry)
4349   {
4350     TapeRecordAction(stored_player_action);
4351     num_stored_actions = 0;
4352     save_tape_entry = FALSE;
4353   }
4354 #else
4355   if (tape.recording && num_stored_actions >= MAX_PLAYERS)
4356   {
4357     TapeRecordAction(stored_player_action);
4358     num_stored_actions = 0;
4359   }
4360 #endif
4361
4362 #if 0
4363   if (tape.playing && !tape.pausing && !player_action &&
4364       tape.counter < tape.length)
4365   {
4366     int jx = player->jx, jy = player->jy;
4367     int next_joy =
4368       tape.pos[tape.counter].action[player->index_nr] & (JOY_LEFT|JOY_RIGHT);
4369
4370     if ((next_joy == JOY_LEFT || next_joy == JOY_RIGHT) &&
4371         (player->MovDir != JOY_UP && player->MovDir != JOY_DOWN))
4372     {
4373       int dx = (next_joy == JOY_LEFT ? -1 : +1);
4374
4375       if (IN_LEV_FIELD(jx+dx, jy) && IS_PUSHABLE(Feld[jx+dx][jy]))
4376       {
4377         int el = Feld[jx+dx][jy];
4378         int push_delay = (IS_SB_ELEMENT(el) || el == EL_SONDE ? 2 :
4379                           (el == EL_BALLOON || el == EL_SPRING) ? 0 : 10);
4380
4381         if (tape.delay_played + push_delay >= tape.pos[tape.counter].delay)
4382         {
4383           player->MovDir = next_joy;
4384           player->Frame = FrameCounter % 4;
4385           player->Pushing = TRUE;
4386         }
4387       }
4388     }
4389   }
4390 #endif
4391 }
4392
4393 void GameActions()
4394 {
4395   static unsigned long action_delay = 0;
4396   unsigned long action_delay_value;
4397   int sieb_x = 0, sieb_y = 0;
4398   int i, x, y, element;
4399   byte *recorded_player_action;
4400   byte summarized_player_action = 0;
4401
4402   if (game_status != PLAYING)
4403     return;
4404
4405   action_delay_value =
4406     (tape.playing && tape.fast_forward ? FfwdFrameDelay : GameFrameDelay);
4407
4408   if (tape.playing && tape.index_search && !tape.pausing)
4409     action_delay_value = 0;
4410
4411   /* ---------- main game synchronization point ---------- */
4412
4413   WaitUntilDelayReached(&action_delay, action_delay_value);
4414
4415   if (network_playing && !network_player_action_received)
4416   {
4417     /*
4418 #ifdef DEBUG
4419     printf("DEBUG: try to get network player actions in time\n");
4420 #endif
4421     */
4422
4423 #if defined(PLATFORM_UNIX)
4424     /* last chance to get network player actions without main loop delay */
4425     HandleNetworking();
4426 #endif
4427
4428     if (game_status != PLAYING)
4429       return;
4430
4431     if (!network_player_action_received)
4432     {
4433       /*
4434 #ifdef DEBUG
4435       printf("DEBUG: failed to get network player actions in time\n");
4436 #endif
4437       */
4438       return;
4439     }
4440   }
4441
4442   if (tape.pausing)
4443     return;
4444
4445   recorded_player_action = (tape.playing ? TapePlayAction() : NULL);
4446
4447   for (i=0; i<MAX_PLAYERS; i++)
4448   {
4449     summarized_player_action |= stored_player[i].action;
4450
4451     if (!network_playing)
4452       stored_player[i].effective_action = stored_player[i].action;
4453   }
4454
4455 #if defined(PLATFORM_UNIX)
4456   if (network_playing)
4457     SendToServer_MovePlayer(summarized_player_action);
4458 #endif
4459
4460   if (!options.network && !setup.team_mode)
4461     local_player->effective_action = summarized_player_action;
4462
4463   for (i=0; i<MAX_PLAYERS; i++)
4464   {
4465     int actual_player_action = stored_player[i].effective_action;
4466
4467     if (stored_player[i].programmed_action)
4468       actual_player_action = stored_player[i].programmed_action;
4469
4470     if (recorded_player_action)
4471       actual_player_action = recorded_player_action[i];
4472
4473     PlayerActions(&stored_player[i], actual_player_action);
4474     ScrollFigure(&stored_player[i], SCROLL_GO_ON);
4475   }
4476
4477   network_player_action_received = FALSE;
4478
4479   ScrollScreen(NULL, SCROLL_GO_ON);
4480
4481
4482
4483 #ifdef DEBUG
4484 #if 0
4485   if (TimeFrames == 0 && local_player->active)
4486   {
4487     extern unsigned int last_RND();
4488
4489     printf("DEBUG: %03d last RND was %d \t [state checksum is %d]\n",
4490            TimePlayed, last_RND(), getStateCheckSum(TimePlayed));
4491   }
4492 #endif
4493 #endif
4494
4495 #ifdef DEBUG
4496 #if 0
4497   if (GameFrameDelay >= 500)
4498     printf("FrameCounter == %d\n", FrameCounter);
4499 #endif
4500 #endif
4501
4502
4503
4504   FrameCounter++;
4505   TimeFrames++;
4506
4507   for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
4508   {
4509     Stop[x][y] = FALSE;
4510     if (JustStopped[x][y] > 0)
4511       JustStopped[x][y]--;
4512
4513 #if DEBUG
4514     if (IS_BLOCKED(x, y))
4515     {
4516       int oldx, oldy;
4517
4518       Blocked2Moving(x, y, &oldx, &oldy);
4519       if (!IS_MOVING(oldx, oldy))
4520       {
4521         printf("GameActions(): (BLOCKED => MOVING) context corrupted!\n");
4522         printf("GameActions(): BLOCKED: x = %d, y = %d\n", x, y);
4523         printf("GameActions(): !MOVING: oldx = %d, oldy = %d\n", oldx, oldy);
4524         printf("GameActions(): This should never happen!\n");
4525       }
4526     }
4527 #endif
4528   }
4529
4530   for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
4531   {
4532     element = Feld[x][y];
4533
4534     if (IS_INACTIVE(element))
4535       continue;
4536
4537     if (!IS_MOVING(x, y) && (CAN_FALL(element) || CAN_MOVE(element)))
4538     {
4539       StartMoving(x, y);
4540
4541       if (IS_GEM(element) || element == EL_SP_INFOTRON)
4542         EdelsteinFunkeln(x, y);
4543     }
4544     else if (IS_MOVING(x, y))
4545       ContinueMoving(x, y);
4546     else if (IS_ACTIVE_BOMB(element))
4547       CheckDynamite(x, y);
4548 #if 0
4549     else if (element == EL_EXPLODING && !game.explosions_delayed)
4550       Explode(x, y, Frame[x][y], EX_NORMAL);
4551 #endif
4552     else if (element == EL_AMOEBING)
4553       AmoebeWaechst(x, y);
4554     else if (element == EL_DEAMOEBING)
4555       AmoebeSchrumpft(x, y);
4556
4557 #if !USE_NEW_AMOEBA_CODE
4558     else if (IS_AMOEBALIVE(element))
4559       AmoebeAbleger(x, y);
4560 #endif
4561
4562     else if (element == EL_LIFE || element == EL_LIFE_ASYNC)
4563       Life(x, y);
4564     else if (element == EL_ABLENK_EIN)
4565       Ablenk(x, y);
4566     else if (element == EL_TIMEGATE_SWITCH_ON)
4567       TimegateWheel(x, y);
4568     else if (element == EL_SALZSAEURE)
4569       Blubber(x, y);
4570     else if (element == EL_BLURB_LEFT || element == EL_BLURB_RIGHT)
4571       Blurb(x, y);
4572     else if (element == EL_CRACKINGNUT)
4573       NussKnacken(x, y);
4574     else if (element == EL_PEARL_BREAKING)
4575       BreakingPearl(x, y);
4576     else if (element == EL_AUSGANG_ZU)
4577       AusgangstuerPruefen(x, y);
4578     else if (element == EL_AUSGANG_ACT)
4579       AusgangstuerOeffnen(x, y);
4580     else if (element == EL_AUSGANG_AUF)
4581       AusgangstuerBlinken(x, y);
4582     else if (element == EL_MAUERND)
4583       MauerWaechst(x, y);
4584     else if (element == EL_MAUER_LEBT ||
4585              element == EL_MAUER_X ||
4586              element == EL_MAUER_Y ||
4587              element == EL_MAUER_XY)
4588       MauerAbleger(x, y);
4589     else if (element == EL_BURNING)
4590       CheckForDragon(x, y);
4591     else if (element == EL_SP_BUG || element == EL_SP_BUG_ACTIVE)
4592       CheckBuggyBase(x, y);
4593     else if (element == EL_TRAP_INACTIVE || element == EL_TRAP_ACTIVE)
4594       CheckTrap(x, y);
4595     else if (element == EL_SP_TERMINAL)
4596       DrawGraphicAnimation(x, y, GFX2_SP_TERMINAL, 7, 12, ANIM_NORMAL);
4597     else if (element == EL_SP_TERMINAL_ACTIVE)
4598       DrawGraphicAnimation(x, y, GFX2_SP_TERMINAL_ACTIVE, 7, 4, ANIM_NORMAL);
4599     else if (IS_BELT(element))
4600       DrawBeltAnimation(x, y, element);
4601     else if (element == EL_SWITCHGATE_OPENING)
4602       OpenSwitchgate(x, y);
4603     else if (element == EL_SWITCHGATE_CLOSING)
4604       CloseSwitchgate(x, y);
4605     else if (element == EL_TIMEGATE_OPENING)
4606       OpenTimegate(x, y);
4607     else if (element == EL_TIMEGATE_CLOSING)
4608       CloseTimegate(x, y);
4609     else if (element == EL_EXTRA_TIME)
4610       DrawGraphicAnimation(x, y, GFX_EXTRA_TIME, 6, 4, ANIM_NORMAL);
4611     else if (element == EL_SHIELD_PASSIVE)
4612       DrawGraphicAnimation(x, y, GFX_SHIELD_PASSIVE, 6, 4, ANIM_NORMAL);
4613     else if (element == EL_SHIELD_ACTIVE)
4614       DrawGraphicAnimation(x, y, GFX_SHIELD_ACTIVE, 6, 4, ANIM_NORMAL);
4615
4616     if (game.magic_wall_active)
4617     {
4618       boolean sieb = FALSE;
4619       int jx = local_player->jx, jy = local_player->jy;
4620
4621       if (element == EL_MAGIC_WALL_FULL ||
4622           element == EL_MAGIC_WALL_EMPTY ||
4623           element == EL_MAGIC_WALL_EMPTYING)
4624       {
4625         SiebAktivieren(x, y, 1);
4626         sieb = TRUE;
4627       }
4628       else if (element == EL_MAGIC_WALL_BD_FULL ||
4629                element == EL_MAGIC_WALL_BD_EMPTY ||
4630                element == EL_MAGIC_WALL_BD_EMPTYING)
4631       {
4632         SiebAktivieren(x, y, 2);
4633         sieb = TRUE;
4634       }
4635
4636       /* play the element sound at the position nearest to the player */
4637       if (sieb && ABS(x-jx)+ABS(y-jy) < ABS(sieb_x-jx)+ABS(sieb_y-jy))
4638       {
4639         sieb_x = x;
4640         sieb_y = y;
4641       }
4642     }
4643   }
4644
4645 #if USE_NEW_AMOEBA_CODE
4646   /* new experimental amoeba growth stuff */
4647 #if 1
4648   if (!(FrameCounter % 8))
4649 #endif
4650   {
4651     static unsigned long random = 1684108901;
4652
4653     for (i = 0; i < level.amoeba_speed * 28 / 8; i++)
4654     {
4655 #if 0
4656       x = (random >> 10) % lev_fieldx;
4657       y = (random >> 20) % lev_fieldy;
4658 #else
4659       x = RND(lev_fieldx);
4660       y = RND(lev_fieldy);
4661 #endif
4662       element = Feld[x][y];
4663
4664       if (!IS_PLAYER(x,y) &&
4665           (element == EL_LEERRAUM ||
4666            element == EL_ERDREICH ||
4667            element == EL_MORAST_LEER ||
4668            element == EL_BLURB_LEFT ||
4669            element == EL_BLURB_RIGHT))
4670       {
4671         if ((IN_LEV_FIELD(x, y-1) && Feld[x][y-1] == EL_AMOEBE_NASS) ||
4672             (IN_LEV_FIELD(x-1, y) && Feld[x-1][y] == EL_AMOEBE_NASS) ||
4673             (IN_LEV_FIELD(x+1, y) && Feld[x+1][y] == EL_AMOEBE_NASS) ||
4674             (IN_LEV_FIELD(x, y+1) && Feld[x][y+1] == EL_AMOEBE_NASS))
4675           Feld[x][y] = EL_TROPFEN;
4676       }
4677
4678       random = random * 129 + 1;
4679     }
4680   }
4681 #endif
4682
4683 #if 0
4684   if (game.explosions_delayed)
4685 #endif
4686   {
4687     game.explosions_delayed = FALSE;
4688
4689     for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
4690     {
4691       element = Feld[x][y];
4692
4693       if (ExplodeField[x][y])
4694         Explode(x, y, EX_PHASE_START, ExplodeField[x][y]);
4695       else if (element == EL_EXPLODING)
4696         Explode(x, y, Frame[x][y], EX_NORMAL);
4697
4698       ExplodeField[x][y] = EX_NO_EXPLOSION;
4699     }
4700
4701     game.explosions_delayed = TRUE;
4702   }
4703
4704   if (game.magic_wall_active)
4705   {
4706     if (!(game.magic_wall_time_left % 4))
4707       PlaySoundLevel(sieb_x, sieb_y, SND_MIEP);
4708
4709     if (game.magic_wall_time_left > 0)
4710     {
4711       game.magic_wall_time_left--;
4712       if (!game.magic_wall_time_left)
4713       {
4714         for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
4715         {
4716           element = Feld[x][y];
4717
4718           if (element == EL_MAGIC_WALL_EMPTY ||
4719               element == EL_MAGIC_WALL_FULL)
4720           {
4721             Feld[x][y] = EL_MAGIC_WALL_DEAD;
4722             DrawLevelField(x, y);
4723           }
4724           else if (element == EL_MAGIC_WALL_BD_EMPTY ||
4725                    element == EL_MAGIC_WALL_BD_FULL)
4726           {
4727             Feld[x][y] = EL_MAGIC_WALL_BD_DEAD;
4728             DrawLevelField(x, y);
4729           }
4730         }
4731
4732         game.magic_wall_active = FALSE;
4733       }
4734     }
4735   }
4736
4737   if (game.light_time_left > 0)
4738   {
4739     game.light_time_left--;
4740
4741     if (game.light_time_left == 0)
4742     {
4743       for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
4744       {
4745         element = Feld[x][y];
4746
4747         if (element == EL_LIGHT_SWITCH_ON)
4748         {
4749           Feld[x][y] = EL_LIGHT_SWITCH_OFF;
4750           DrawLevelField(x, y);
4751         }
4752         else if (element == EL_INVISIBLE_STEEL ||
4753                  element == EL_UNSICHTBAR ||
4754                  element == EL_SAND_INVISIBLE)
4755           DrawLevelField(x, y);
4756       }
4757     }
4758   }
4759
4760   if (game.timegate_time_left > 0)
4761   {
4762     game.timegate_time_left--;
4763
4764     if (game.timegate_time_left == 0)
4765       CloseAllOpenTimegates();
4766   }
4767
4768   if (TimeFrames >= (1000 / GameFrameDelay))
4769   {
4770     TimeFrames = 0;
4771     TimePlayed++;
4772
4773     for (i=0; i<MAX_PLAYERS; i++)
4774     {
4775       if (SHIELD_ON(&stored_player[i]))
4776       {
4777         stored_player[i].shield_passive_time_left--;
4778
4779         if (stored_player[i].shield_active_time_left > 0)
4780           stored_player[i].shield_active_time_left--;
4781       }
4782     }
4783
4784     if (tape.recording || tape.playing)
4785       DrawVideoDisplay(VIDEO_STATE_TIME_ON, TimePlayed);
4786
4787     if (TimeLeft > 0)
4788     {
4789       TimeLeft--;
4790
4791       if (TimeLeft <= 10 && setup.time_limit)
4792         PlaySoundStereo(SND_GONG, PSND_MAX_RIGHT);
4793
4794       DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
4795
4796       if (!TimeLeft && setup.time_limit)
4797         for (i=0; i<MAX_PLAYERS; i++)
4798           KillHero(&stored_player[i]);
4799     }
4800     else if (level.time == 0)           /* level without time limit */
4801       DrawText(DX_TIME, DY_TIME, int2str(TimePlayed, 3), FS_SMALL, FC_YELLOW);
4802   }
4803
4804   DrawAllPlayers();
4805
4806   if (options.debug)                    /* calculate frames per second */
4807   {
4808     static unsigned long fps_counter = 0;
4809     static int fps_frames = 0;
4810     unsigned long fps_delay_ms = Counter() - fps_counter;
4811
4812     fps_frames++;
4813
4814     if (fps_delay_ms >= 500)    /* calculate fps every 0.5 seconds */
4815     {
4816       global.frames_per_second = 1000 * (float)fps_frames / fps_delay_ms;
4817
4818       fps_frames = 0;
4819       fps_counter = Counter();
4820     }
4821
4822     redraw_mask |= REDRAW_FPS;
4823   }
4824 }
4825
4826 static boolean AllPlayersInSight(struct PlayerInfo *player, int x, int y)
4827 {
4828   int min_x = x, min_y = y, max_x = x, max_y = y;
4829   int i;
4830
4831   for (i=0; i<MAX_PLAYERS; i++)
4832   {
4833     int jx = stored_player[i].jx, jy = stored_player[i].jy;
4834
4835     if (!stored_player[i].active || &stored_player[i] == player)
4836       continue;
4837
4838     min_x = MIN(min_x, jx);
4839     min_y = MIN(min_y, jy);
4840     max_x = MAX(max_x, jx);
4841     max_y = MAX(max_y, jy);
4842   }
4843
4844   return (max_x - min_x < SCR_FIELDX && max_y - min_y < SCR_FIELDY);
4845 }
4846
4847 static boolean AllPlayersInVisibleScreen()
4848 {
4849   int i;
4850
4851   for (i=0; i<MAX_PLAYERS; i++)
4852   {
4853     int jx = stored_player[i].jx, jy = stored_player[i].jy;
4854
4855     if (!stored_player[i].active)
4856       continue;
4857
4858     if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
4859       return FALSE;
4860   }
4861
4862   return TRUE;
4863 }
4864
4865 void ScrollLevel(int dx, int dy)
4866 {
4867   int softscroll_offset = (setup.soft_scrolling ? TILEX : 0);
4868   int x, y;
4869
4870   BlitBitmap(drawto_field, drawto_field,
4871              FX + TILEX*(dx == -1) - softscroll_offset,
4872              FY + TILEY*(dy == -1) - softscroll_offset,
4873              SXSIZE - TILEX*(dx!=0) + 2*softscroll_offset,
4874              SYSIZE - TILEY*(dy!=0) + 2*softscroll_offset,
4875              FX + TILEX*(dx == 1) - softscroll_offset,
4876              FY + TILEY*(dy == 1) - softscroll_offset);
4877
4878   if (dx)
4879   {
4880     x = (dx == 1 ? BX1 : BX2);
4881     for (y=BY1; y<=BY2; y++)
4882       DrawScreenField(x, y);
4883   }
4884   if (dy)
4885   {
4886     y = (dy == 1 ? BY1 : BY2);
4887     for (x=BX1; x<=BX2; x++)
4888       DrawScreenField(x, y);
4889   }
4890
4891   redraw_mask |= REDRAW_FIELD;
4892 }
4893
4894 static void CheckGravityMovement(struct PlayerInfo *player)
4895 {
4896   if (level.gravity && !player->programmed_action)
4897   {
4898     int move_dir_vertical = player->action & (MV_UP | MV_DOWN);
4899     int move_dir_horizontal = player->action & (MV_LEFT | MV_RIGHT);
4900     int move_dir =
4901       (player->last_move_dir & (MV_LEFT | MV_RIGHT) ?
4902        (move_dir_vertical ? move_dir_vertical : move_dir_horizontal) :
4903        (move_dir_horizontal ? move_dir_horizontal : move_dir_vertical));
4904     int jx = player->jx, jy = player->jy;
4905     int dx = (move_dir & MV_LEFT ? -1 : move_dir & MV_RIGHT ? +1 : 0);
4906     int dy = (move_dir & MV_UP ? -1 : move_dir & MV_DOWN ? +1 : 0);
4907     int new_jx = jx + dx, new_jy = jy + dy;
4908     boolean field_under_player_is_free =
4909       (IN_LEV_FIELD(jx, jy + 1) && IS_FREE(jx, jy + 1));
4910     boolean player_is_moving_to_valid_field =
4911       (IN_LEV_FIELD(new_jx, new_jy) &&
4912        (Feld[new_jx][new_jy] == EL_SP_BASE ||
4913         Feld[new_jx][new_jy] == EL_ERDREICH));
4914
4915     if (field_under_player_is_free && !player_is_moving_to_valid_field)
4916       player->programmed_action = MV_DOWN;
4917   }
4918 }
4919
4920 boolean MoveFigureOneStep(struct PlayerInfo *player,
4921                           int dx, int dy, int real_dx, int real_dy)
4922 {
4923   int jx = player->jx, jy = player->jy;
4924   int new_jx = jx+dx, new_jy = jy+dy;
4925   int element;
4926   int can_move;
4927
4928   if (!player->active || (!dx && !dy))
4929     return MF_NO_ACTION;
4930
4931   player->MovDir = (dx < 0 ? MV_LEFT :
4932                     dx > 0 ? MV_RIGHT :
4933                     dy < 0 ? MV_UP :
4934                     dy > 0 ? MV_DOWN :  MV_NO_MOVING);
4935
4936   if (!IN_LEV_FIELD(new_jx, new_jy))
4937     return MF_NO_ACTION;
4938
4939   if (!options.network && !AllPlayersInSight(player, new_jx, new_jy))
4940     return MF_NO_ACTION;
4941
4942 #if 0
4943   element = MovingOrBlocked2Element(new_jx, new_jy);
4944 #else
4945   element = MovingOrBlocked2ElementIfNotLeaving(new_jx, new_jy);
4946 #endif
4947
4948   if (DONT_GO_TO(element))
4949   {
4950     if (element == EL_SALZSAEURE && dx == 0 && dy == 1)
4951     {
4952       Blurb(jx, jy);
4953       Feld[jx][jy] = EL_SPIELFIGUR;
4954       InitMovingField(jx, jy, MV_DOWN);
4955       Store[jx][jy] = EL_SALZSAEURE;
4956       ContinueMoving(jx, jy);
4957       BuryHero(player);
4958     }
4959     else
4960       TestIfHeroRunsIntoBadThing(jx, jy, player->MovDir);
4961
4962     return MF_MOVING;
4963   }
4964
4965   can_move = DigField(player, new_jx, new_jy, real_dx, real_dy, DF_DIG);
4966   if (can_move != MF_MOVING)
4967     return can_move;
4968
4969   StorePlayer[jx][jy] = 0;
4970   player->last_jx = jx;
4971   player->last_jy = jy;
4972   jx = player->jx = new_jx;
4973   jy = player->jy = new_jy;
4974   StorePlayer[jx][jy] = player->element_nr;
4975
4976   player->MovPos =
4977     (dx > 0 || dy > 0 ? -1 : 1) * (TILEX - TILEX / player->move_delay_value);
4978
4979   ScrollFigure(player, SCROLL_INIT);
4980
4981   return MF_MOVING;
4982 }
4983
4984 boolean MoveFigure(struct PlayerInfo *player, int dx, int dy)
4985 {
4986   int jx = player->jx, jy = player->jy;
4987   int old_jx = jx, old_jy = jy;
4988   int moved = MF_NO_ACTION;
4989
4990   if (!player->active || (!dx && !dy))
4991     return FALSE;
4992
4993 #if 0
4994   if (!FrameReached(&player->move_delay, player->move_delay_value) &&
4995       !tape.playing)
4996     return FALSE;
4997 #else
4998   if (!FrameReached(&player->move_delay, player->move_delay_value) &&
4999       !(tape.playing && tape.game_version < GAME_VERSION_2_0))
5000     return FALSE;
5001 #endif
5002
5003   /* remove the last programmed player action */
5004   player->programmed_action = 0;
5005
5006   if (player->MovPos)
5007   {
5008     /* should only happen if pre-1.2 tape recordings are played */
5009     /* this is only for backward compatibility */
5010
5011     int original_move_delay_value = player->move_delay_value;
5012
5013 #if DEBUG
5014     printf("THIS SHOULD ONLY HAPPEN WITH PRE-1.2 LEVEL TAPES.\n");
5015 #endif
5016
5017     /* scroll remaining steps with finest movement resolution */
5018     player->move_delay_value = MOVE_DELAY_NORMAL_SPEED;
5019
5020     while (player->MovPos)
5021     {
5022       ScrollFigure(player, SCROLL_GO_ON);
5023       ScrollScreen(NULL, SCROLL_GO_ON);
5024       FrameCounter++;
5025       DrawAllPlayers();
5026       BackToFront();
5027     }
5028
5029     player->move_delay_value = original_move_delay_value;
5030   }
5031
5032   if (player->last_move_dir & (MV_LEFT | MV_RIGHT))
5033   {
5034     if (!(moved |= MoveFigureOneStep(player, 0, dy, dx, dy)))
5035       moved |= MoveFigureOneStep(player, dx, 0, dx, dy);
5036   }
5037   else
5038   {
5039     if (!(moved |= MoveFigureOneStep(player, dx, 0, dx, dy)))
5040       moved |= MoveFigureOneStep(player, 0, dy, dx, dy);
5041   }
5042
5043   jx = player->jx;
5044   jy = player->jy;
5045
5046   if (moved & MF_MOVING && !ScreenMovPos &&
5047       (player == local_player || !options.network))
5048   {
5049     int old_scroll_x = scroll_x, old_scroll_y = scroll_y;
5050     int offset = (setup.scroll_delay ? 3 : 0);
5051
5052     if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
5053     {
5054       /* actual player has left the screen -- scroll in that direction */
5055       if (jx != old_jx)         /* player has moved horizontally */
5056         scroll_x += (jx - old_jx);
5057       else                      /* player has moved vertically */
5058         scroll_y += (jy - old_jy);
5059     }
5060     else
5061     {
5062       if (jx != old_jx)         /* player has moved horizontally */
5063       {
5064         if ((player->MovDir == MV_LEFT && scroll_x > jx - MIDPOSX + offset) ||
5065             (player->MovDir == MV_RIGHT && scroll_x < jx - MIDPOSX - offset))
5066           scroll_x = jx-MIDPOSX + (scroll_x < jx-MIDPOSX ? -offset : +offset);
5067
5068         /* don't scroll over playfield boundaries */
5069         if (scroll_x < SBX_Left || scroll_x > SBX_Right)
5070           scroll_x = (scroll_x < SBX_Left ? SBX_Left : SBX_Right);
5071
5072         /* don't scroll more than one field at a time */
5073         scroll_x = old_scroll_x + SIGN(scroll_x - old_scroll_x);
5074
5075         /* don't scroll against the player's moving direction */
5076         if ((player->MovDir == MV_LEFT && scroll_x > old_scroll_x) ||
5077             (player->MovDir == MV_RIGHT && scroll_x < old_scroll_x))
5078           scroll_x = old_scroll_x;
5079       }
5080       else                      /* player has moved vertically */
5081       {
5082         if ((player->MovDir == MV_UP && scroll_y > jy - MIDPOSY + offset) ||
5083             (player->MovDir == MV_DOWN && scroll_y < jy - MIDPOSY - offset))
5084           scroll_y = jy-MIDPOSY + (scroll_y < jy-MIDPOSY ? -offset : +offset);
5085
5086         /* don't scroll over playfield boundaries */
5087         if (scroll_y < SBY_Upper || scroll_y > SBY_Lower)
5088           scroll_y = (scroll_y < SBY_Upper ? SBY_Upper : SBY_Lower);
5089
5090         /* don't scroll more than one field at a time */
5091         scroll_y = old_scroll_y + SIGN(scroll_y - old_scroll_y);
5092
5093         /* don't scroll against the player's moving direction */
5094         if ((player->MovDir == MV_UP && scroll_y > old_scroll_y) ||
5095             (player->MovDir == MV_DOWN && scroll_y < old_scroll_y))
5096           scroll_y = old_scroll_y;
5097       }
5098     }
5099
5100     if (scroll_x != old_scroll_x || scroll_y != old_scroll_y)
5101     {
5102       if (!options.network && !AllPlayersInVisibleScreen())
5103       {
5104         scroll_x = old_scroll_x;
5105         scroll_y = old_scroll_y;
5106       }
5107       else
5108       {
5109         ScrollScreen(player, SCROLL_INIT);
5110         ScrollLevel(old_scroll_x - scroll_x, old_scroll_y - scroll_y);
5111       }
5112     }
5113   }
5114
5115   if (!(moved & MF_MOVING) && !player->Pushing)
5116     player->Frame = 0;
5117   else
5118     player->Frame = (player->Frame + 1) % 4;
5119
5120   if (moved & MF_MOVING)
5121   {
5122     if (old_jx != jx && old_jy == jy)
5123       player->MovDir = (old_jx < jx ? MV_RIGHT : MV_LEFT);
5124     else if (old_jx == jx && old_jy != jy)
5125       player->MovDir = (old_jy < jy ? MV_DOWN : MV_UP);
5126
5127     DrawLevelField(jx, jy);     /* for "ErdreichAnbroeckeln()" */
5128
5129     player->last_move_dir = player->MovDir;
5130     player->is_moving = TRUE;
5131   }
5132   else
5133   {
5134     CheckGravityMovement(player);
5135
5136     /*
5137     player->last_move_dir = MV_NO_MOVING;
5138     */
5139     player->is_moving = FALSE;
5140   }
5141
5142   TestIfHeroTouchesBadThing(jx, jy);
5143
5144   if (!player->active)
5145     RemoveHero(player);
5146
5147   return moved;
5148 }
5149
5150 void ScrollFigure(struct PlayerInfo *player, int mode)
5151 {
5152   int jx = player->jx, jy = player->jy;
5153   int last_jx = player->last_jx, last_jy = player->last_jy;
5154   int move_stepsize = TILEX / player->move_delay_value;
5155
5156   if (!player->active || !player->MovPos)
5157     return;
5158
5159   if (mode == SCROLL_INIT)
5160   {
5161     player->actual_frame_counter = FrameCounter;
5162     player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
5163
5164     if (Feld[last_jx][last_jy] == EL_LEERRAUM)
5165       Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING;
5166
5167     DrawPlayer(player);
5168     return;
5169   }
5170   else if (!FrameReached(&player->actual_frame_counter, 1))
5171     return;
5172
5173   player->MovPos += (player->MovPos > 0 ? -1 : 1) * move_stepsize;
5174   player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
5175
5176   if (Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING)
5177     Feld[last_jx][last_jy] = EL_LEERRAUM;
5178
5179   /* before DrawPlayer() to draw correct player graphic for this case */
5180   if (player->MovPos == 0)
5181     CheckGravityMovement(player);
5182
5183   DrawPlayer(player);
5184
5185   if (player->MovPos == 0)
5186   {
5187     if (IS_QUICK_GATE(Feld[last_jx][last_jy]))
5188     {
5189       /* continue with normal speed after quickly moving through gate */
5190       HALVE_PLAYER_SPEED(player);
5191
5192       /* be able to make the next move without delay */
5193       player->move_delay = 0;
5194     }
5195
5196     player->last_jx = jx;
5197     player->last_jy = jy;
5198
5199     if (Feld[jx][jy] == EL_AUSGANG_AUF)
5200     {
5201       RemoveHero(player);
5202
5203       if (!local_player->friends_still_needed)
5204         player->LevelSolved = player->GameOver = TRUE;
5205     }
5206
5207     if (tape.single_step && tape.recording && !tape.pausing &&
5208         !player->programmed_action)
5209       TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
5210   }
5211 }
5212
5213 void ScrollScreen(struct PlayerInfo *player, int mode)
5214 {
5215   static unsigned long screen_frame_counter = 0;
5216
5217   if (mode == SCROLL_INIT)
5218   {
5219     /* set scrolling step size according to actual player's moving speed */
5220     ScrollStepSize = TILEX / player->move_delay_value;
5221
5222     screen_frame_counter = FrameCounter;
5223     ScreenMovDir = player->MovDir;
5224     ScreenMovPos = player->MovPos;
5225     ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
5226     return;
5227   }
5228   else if (!FrameReached(&screen_frame_counter, 1))
5229     return;
5230
5231   if (ScreenMovPos)
5232   {
5233     ScreenMovPos += (ScreenMovPos > 0 ? -1 : 1) * ScrollStepSize;
5234     ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
5235     redraw_mask |= REDRAW_FIELD;
5236   }
5237   else
5238     ScreenMovDir = MV_NO_MOVING;
5239 }
5240
5241 void TestIfGoodThingHitsBadThing(int good_x, int good_y, int good_move_dir)
5242 {
5243   int i, kill_x = -1, kill_y = -1;
5244   static int test_xy[4][2] =
5245   {
5246     { 0, -1 },
5247     { -1, 0 },
5248     { +1, 0 },
5249     { 0, +1 }
5250   };
5251   static int test_dir[4] =
5252   {
5253     MV_UP,
5254     MV_LEFT,
5255     MV_RIGHT,
5256     MV_DOWN
5257   };
5258
5259   for (i=0; i<4; i++)
5260   {
5261     int test_x, test_y, test_move_dir, test_element;
5262
5263     test_x = good_x + test_xy[i][0];
5264     test_y = good_y + test_xy[i][1];
5265     if (!IN_LEV_FIELD(test_x, test_y))
5266       continue;
5267
5268     test_move_dir =
5269       (IS_MOVING(test_x, test_y) ? MovDir[test_x][test_y] : MV_NO_MOVING);
5270
5271 #if 0
5272     test_element = Feld[test_x][test_y];
5273 #else
5274     test_element = MovingOrBlocked2ElementIfNotLeaving(test_x, test_y);
5275 #endif
5276
5277     /* 1st case: good thing is moving towards DONT_GO_TO style bad thing;
5278        2nd case: DONT_TOUCH style bad thing does not move away from good thing
5279     */
5280     if ((DONT_GO_TO(test_element) && good_move_dir == test_dir[i]) ||
5281         (DONT_TOUCH(test_element) && test_move_dir != test_dir[i]))
5282     {
5283       kill_x = test_x;
5284       kill_y = test_y;
5285       break;
5286     }
5287   }
5288
5289   if (kill_x != -1 || kill_y != -1)
5290   {
5291     if (IS_PLAYER(good_x, good_y))
5292     {
5293       struct PlayerInfo *player = PLAYERINFO(good_x, good_y);
5294
5295       if (player->shield_active_time_left > 0)
5296         Bang(kill_x, kill_y);
5297       else if (!PLAYER_PROTECTED(good_x, good_y))
5298         KillHero(player);
5299     }
5300     else
5301       Bang(good_x, good_y);
5302   }
5303 }
5304
5305 void TestIfBadThingHitsGoodThing(int bad_x, int bad_y, int bad_move_dir)
5306 {
5307   int i, kill_x = -1, kill_y = -1;
5308   int bad_element = Feld[bad_x][bad_y];
5309   static int test_xy[4][2] =
5310   {
5311     { 0, -1 },
5312     { -1, 0 },
5313     { +1, 0 },
5314     { 0, +1 }
5315   };
5316   static int test_dir[4] =
5317   {
5318     MV_UP,
5319     MV_LEFT,
5320     MV_RIGHT,
5321     MV_DOWN
5322   };
5323
5324   if (bad_element == EL_EXPLODING)      /* skip just exploding bad things */
5325     return;
5326
5327   for (i=0; i<4; i++)
5328   {
5329     int test_x, test_y, test_move_dir, test_element;
5330
5331     test_x = bad_x + test_xy[i][0];
5332     test_y = bad_y + test_xy[i][1];
5333     if (!IN_LEV_FIELD(test_x, test_y))
5334       continue;
5335
5336     test_move_dir =
5337       (IS_MOVING(test_x, test_y) ? MovDir[test_x][test_y] : MV_NO_MOVING);
5338
5339     test_element = Feld[test_x][test_y];
5340
5341     /* 1st case: good thing is moving towards DONT_GO_TO style bad thing;
5342        2nd case: DONT_TOUCH style bad thing does not move away from good thing
5343     */
5344     if ((DONT_GO_TO(bad_element) &&  bad_move_dir == test_dir[i]) ||
5345         (DONT_TOUCH(bad_element) && test_move_dir != test_dir[i]))
5346     {
5347       /* good thing is player or penguin that does not move away */
5348       if (IS_PLAYER(test_x, test_y))
5349       {
5350         struct PlayerInfo *player = PLAYERINFO(test_x, test_y);
5351
5352         if (bad_element == EL_ROBOT && player->is_moving)
5353           continue;     /* robot does not kill player if he is moving */
5354
5355         kill_x = test_x;
5356         kill_y = test_y;
5357         break;
5358       }
5359       else if (test_element == EL_PINGUIN)
5360       {
5361         kill_x = test_x;
5362         kill_y = test_y;
5363         break;
5364       }
5365     }
5366   }
5367
5368   if (kill_x != -1 || kill_y != -1)
5369   {
5370     if (IS_PLAYER(kill_x, kill_y))
5371     {
5372       struct PlayerInfo *player = PLAYERINFO(kill_x, kill_y);
5373
5374 #if 0
5375       int dir = player->MovDir;
5376       int newx = player->jx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
5377       int newy = player->jy + (dir == MV_UP   ? -1 : dir == MV_DOWN  ? +1 : 0);
5378
5379       if (Feld[bad_x][bad_y] == EL_ROBOT && player->is_moving &&
5380           newx != bad_x && newy != bad_y)
5381         ;       /* robot does not kill player if he is moving */
5382       else
5383         printf("-> %d\n", player->MovDir);
5384
5385       if (Feld[bad_x][bad_y] == EL_ROBOT && player->is_moving &&
5386           newx != bad_x && newy != bad_y)
5387         ;       /* robot does not kill player if he is moving */
5388       else
5389         ;
5390 #endif
5391
5392       if (player->shield_active_time_left > 0)
5393         Bang(bad_x, bad_y);
5394       else if (!PLAYER_PROTECTED(kill_x, kill_y))
5395         KillHero(player);
5396     }
5397     else
5398       Bang(kill_x, kill_y);
5399   }
5400 }
5401
5402 void TestIfHeroTouchesBadThing(int x, int y)
5403 {
5404   TestIfGoodThingHitsBadThing(x, y, MV_NO_MOVING);
5405 }
5406
5407 void TestIfHeroRunsIntoBadThing(int x, int y, int move_dir)
5408 {
5409   TestIfGoodThingHitsBadThing(x, y, move_dir);
5410 }
5411
5412 void TestIfBadThingTouchesHero(int x, int y)
5413 {
5414   TestIfBadThingHitsGoodThing(x, y, MV_NO_MOVING);
5415 }
5416
5417 void TestIfBadThingRunsIntoHero(int x, int y, int move_dir)
5418 {
5419   TestIfBadThingHitsGoodThing(x, y, move_dir);
5420 }
5421
5422 void TestIfFriendTouchesBadThing(int x, int y)
5423 {
5424   TestIfGoodThingHitsBadThing(x, y, MV_NO_MOVING);
5425 }
5426
5427 void TestIfBadThingTouchesFriend(int x, int y)
5428 {
5429   TestIfBadThingHitsGoodThing(x, y, MV_NO_MOVING);
5430 }
5431
5432 void TestIfBadThingTouchesOtherBadThing(int bad_x, int bad_y)
5433 {
5434   int i, kill_x = bad_x, kill_y = bad_y;
5435   static int xy[4][2] =
5436   {
5437     { 0, -1 },
5438     { -1, 0 },
5439     { +1, 0 },
5440     { 0, +1 }
5441   };
5442
5443   for (i=0; i<4; i++)
5444   {
5445     int x, y, element;
5446
5447     x = bad_x + xy[i][0];
5448     y = bad_y + xy[i][1];
5449     if (!IN_LEV_FIELD(x, y))
5450       continue;
5451
5452     element = Feld[x][y];
5453     if (IS_AMOEBOID(element) || element == EL_LIFE ||
5454         element == EL_AMOEBING || element == EL_TROPFEN)
5455     {
5456       kill_x = x;
5457       kill_y = y;
5458       break;
5459     }
5460   }
5461
5462   if (kill_x != bad_x || kill_y != bad_y)
5463     Bang(bad_x, bad_y);
5464 }
5465
5466 void KillHero(struct PlayerInfo *player)
5467 {
5468   int jx = player->jx, jy = player->jy;
5469
5470   if (!player->active)
5471     return;
5472
5473   if (IS_PFORTE(Feld[jx][jy]))
5474     Feld[jx][jy] = EL_LEERRAUM;
5475
5476   /* deactivate shield (else Bang()/Explode() would not work right) */
5477   player->shield_passive_time_left = 0;
5478   player->shield_active_time_left = 0;
5479
5480   Bang(jx, jy);
5481   BuryHero(player);
5482 }
5483
5484 static void KillHeroUnlessProtected(int x, int y)
5485 {
5486   if (!PLAYER_PROTECTED(x, y))
5487     KillHero(PLAYERINFO(x, y));
5488 }
5489
5490 void BuryHero(struct PlayerInfo *player)
5491 {
5492   int jx = player->jx, jy = player->jy;
5493
5494   if (!player->active)
5495     return;
5496
5497   PlaySoundLevel(jx, jy, SND_AUTSCH);
5498   PlaySoundLevel(jx, jy, SND_LACHEN);
5499
5500   player->GameOver = TRUE;
5501   RemoveHero(player);
5502 }
5503
5504 void RemoveHero(struct PlayerInfo *player)
5505 {
5506   int jx = player->jx, jy = player->jy;
5507   int i, found = FALSE;
5508
5509   player->present = FALSE;
5510   player->active = FALSE;
5511
5512   if (!ExplodeField[jx][jy])
5513     StorePlayer[jx][jy] = 0;
5514
5515   for (i=0; i<MAX_PLAYERS; i++)
5516     if (stored_player[i].active)
5517       found = TRUE;
5518
5519   if (!found)
5520     AllPlayersGone = TRUE;
5521
5522   ExitX = ZX = jx;
5523   ExitY = ZY = jy;
5524 }
5525
5526 int DigField(struct PlayerInfo *player,
5527              int x, int y, int real_dx, int real_dy, int mode)
5528 {
5529   int jx = player->jx, jy = player->jy;
5530   int dx = x - jx, dy = y - jy;
5531   int move_direction = (dx == -1 ? MV_LEFT :
5532                         dx == +1 ? MV_RIGHT :
5533                         dy == -1 ? MV_UP :
5534                         dy == +1 ? MV_DOWN : MV_NO_MOVING);
5535   int element;
5536
5537   if (!player->MovPos)
5538     player->Pushing = FALSE;
5539
5540   if (mode == DF_NO_PUSH)
5541   {
5542     player->Switching = FALSE;
5543     player->push_delay = 0;
5544     return MF_NO_ACTION;
5545   }
5546
5547   if (IS_MOVING(x, y) || IS_PLAYER(x, y))
5548     return MF_NO_ACTION;
5549
5550   if (IS_TUBE(Feld[jx][jy]))
5551   {
5552     int i = 0;
5553     int tube_leave_directions[][2] =
5554     {
5555       { EL_TUBE_CROSS,          MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN },
5556       { EL_TUBE_VERTICAL,                            MV_UP | MV_DOWN },
5557       { EL_TUBE_HORIZONTAL,     MV_LEFT | MV_RIGHT                   },
5558       { EL_TUBE_VERT_LEFT,      MV_LEFT |            MV_UP | MV_DOWN },
5559       { EL_TUBE_VERT_RIGHT,               MV_RIGHT | MV_UP | MV_DOWN },
5560       { EL_TUBE_HORIZ_UP,       MV_LEFT | MV_RIGHT | MV_UP           },
5561       { EL_TUBE_HORIZ_DOWN,     MV_LEFT | MV_RIGHT |         MV_DOWN },
5562       { EL_TUBE_LEFT_UP,        MV_LEFT |            MV_UP           },
5563       { EL_TUBE_LEFT_DOWN,      MV_LEFT |                    MV_DOWN },
5564       { EL_TUBE_RIGHT_UP,                 MV_RIGHT | MV_UP           },
5565       { EL_TUBE_RIGHT_DOWN,               MV_RIGHT |         MV_DOWN },
5566       { -1,                     MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN }
5567     };
5568
5569     while (tube_leave_directions[i][0] != Feld[jx][jy])
5570     {
5571       i++;
5572       if (tube_leave_directions[i][0] == -1)    /* should not happen */
5573         break;
5574     }
5575
5576     if (!(tube_leave_directions[i][1] & move_direction))
5577       return MF_NO_ACTION;      /* tube has no opening in this direction */
5578   }
5579
5580   element = Feld[x][y];
5581
5582   switch (element)
5583   {
5584     case EL_LEERRAUM:
5585       PlaySoundLevel(x, y, SND_EMPTY);
5586       break;
5587
5588     case EL_ERDREICH:
5589     case EL_SAND_INVISIBLE:
5590     case EL_TRAP_INACTIVE:
5591       Feld[x][y] = EL_LEERRAUM;
5592       PlaySoundLevel(x, y, SND_SCHLURF);
5593       break;
5594
5595     case EL_SP_BASE:
5596     case EL_SP_BUG:
5597       Feld[x][y] = EL_LEERRAUM;
5598       PlaySoundLevel(x, y, SND_SP_BASE);
5599       break;
5600
5601     case EL_EDELSTEIN:
5602     case EL_EDELSTEIN_BD:
5603     case EL_EDELSTEIN_GELB:
5604     case EL_EDELSTEIN_ROT:
5605     case EL_EDELSTEIN_LILA:
5606     case EL_DIAMANT:
5607     case EL_SP_INFOTRON:
5608     case EL_PEARL:
5609     case EL_CRYSTAL:
5610       RemoveField(x, y);
5611       local_player->gems_still_needed -= (element == EL_DIAMANT ? 3 :
5612                                           element == EL_PEARL ? 5 :
5613                                           element == EL_CRYSTAL ? 8 : 1);
5614       if (local_player->gems_still_needed < 0)
5615         local_player->gems_still_needed = 0;
5616       RaiseScoreElement(element);
5617       DrawText(DX_EMERALDS, DY_EMERALDS,
5618                int2str(local_player->gems_still_needed, 3),
5619                FS_SMALL, FC_YELLOW);
5620       if (element == EL_SP_INFOTRON)
5621         PlaySoundLevel(x, y, SND_SP_INFOTRON);
5622       else
5623         PlaySoundLevel(x, y, SND_PONG);
5624       break;
5625
5626     case EL_SPEED_PILL:
5627       RemoveField(x, y);
5628       player->move_delay_value = MOVE_DELAY_HIGH_SPEED;
5629       PlaySoundLevel(x, y, SND_PONG);
5630       break;
5631
5632     case EL_ENVELOPE:
5633       Feld[x][y] = EL_LEERRAUM;
5634       PlaySoundLevel(x, y, SND_PONG);
5635       break;
5636
5637     case EL_EXTRA_TIME:
5638       RemoveField(x, y);
5639       if (level.time > 0)
5640       {
5641         TimeLeft += 10;
5642         DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
5643       }
5644       PlaySoundStereo(SND_GONG, PSND_MAX_RIGHT);
5645       break;
5646
5647     case EL_SHIELD_PASSIVE:
5648       RemoveField(x, y);
5649       player->shield_passive_time_left += 10;
5650       PlaySoundLevel(x, y, SND_PONG);
5651       break;
5652
5653     case EL_SHIELD_ACTIVE:
5654       RemoveField(x, y);
5655       player->shield_passive_time_left += 10;
5656       player->shield_active_time_left += 10;
5657       PlaySoundLevel(x, y, SND_PONG);
5658       break;
5659
5660     case EL_DYNAMITE_INACTIVE:
5661     case EL_SP_DISK_RED:
5662       RemoveField(x, y);
5663       player->dynamite++;
5664       RaiseScoreElement(EL_DYNAMITE_INACTIVE);
5665       DrawText(DX_DYNAMITE, DY_DYNAMITE,
5666                int2str(local_player->dynamite, 3),
5667                FS_SMALL, FC_YELLOW);
5668       if (element == EL_SP_DISK_RED)
5669         PlaySoundLevel(x, y, SND_SP_INFOTRON);
5670       else
5671         PlaySoundLevel(x, y, SND_PONG);
5672       break;
5673
5674     case EL_DYNABOMB_NR:
5675       RemoveField(x, y);
5676       player->dynabomb_count++;
5677       player->dynabombs_left++;
5678       RaiseScoreElement(EL_DYNAMITE_INACTIVE);
5679       PlaySoundLevel(x, y, SND_PONG);
5680       break;
5681
5682     case EL_DYNABOMB_SZ:
5683       RemoveField(x, y);
5684       player->dynabomb_size++;
5685       RaiseScoreElement(EL_DYNAMITE_INACTIVE);
5686       PlaySoundLevel(x, y, SND_PONG);
5687       break;
5688
5689     case EL_DYNABOMB_XL:
5690       RemoveField(x, y);
5691       player->dynabomb_xl = TRUE;
5692       RaiseScoreElement(EL_DYNAMITE_INACTIVE);
5693       PlaySoundLevel(x, y, SND_PONG);
5694       break;
5695
5696     case EL_SCHLUESSEL1:
5697     case EL_SCHLUESSEL2:
5698     case EL_SCHLUESSEL3:
5699     case EL_SCHLUESSEL4:
5700     {
5701       int key_nr = element - EL_SCHLUESSEL1;
5702
5703       RemoveField(x, y);
5704       player->key[key_nr] = TRUE;
5705       RaiseScoreElement(EL_SCHLUESSEL);
5706       DrawMiniGraphicExt(drawto, DX_KEYS + key_nr * MINI_TILEX, DY_KEYS,
5707                          GFX_SCHLUESSEL1 + key_nr);
5708       DrawMiniGraphicExt(window, DX_KEYS + key_nr * MINI_TILEX, DY_KEYS,
5709                          GFX_SCHLUESSEL1 + key_nr);
5710       PlaySoundLevel(x, y, SND_PONG);
5711       break;
5712     }
5713
5714     case EL_EM_KEY_1:
5715     case EL_EM_KEY_2:
5716     case EL_EM_KEY_3:
5717     case EL_EM_KEY_4:
5718     {
5719       int key_nr = element - EL_EM_KEY_1;
5720
5721       RemoveField(x, y);
5722       player->key[key_nr] = TRUE;
5723       RaiseScoreElement(EL_SCHLUESSEL);
5724       DrawMiniGraphicExt(drawto, DX_KEYS + key_nr * MINI_TILEX, DY_KEYS,
5725                          GFX_SCHLUESSEL1 + key_nr);
5726       DrawMiniGraphicExt(window, DX_KEYS + key_nr * MINI_TILEX, DY_KEYS,
5727                          GFX_SCHLUESSEL1 + key_nr);
5728       PlaySoundLevel(x, y, SND_PONG);
5729       break;
5730     }
5731
5732     case EL_ABLENK_AUS:
5733       Feld[x][y] = EL_ABLENK_EIN;
5734       ZX = x;
5735       ZY = y;
5736       DrawLevelField(x, y);
5737       return MF_ACTION;
5738       break;
5739
5740     case EL_SP_TERMINAL:
5741       {
5742         int xx, yy;
5743
5744         for (yy=0; yy<lev_fieldy; yy++)
5745         {
5746           for (xx=0; xx<lev_fieldx; xx++)
5747           {
5748             if (Feld[xx][yy] == EL_SP_DISK_YELLOW)
5749               Bang(xx, yy);
5750             else if (Feld[xx][yy] == EL_SP_TERMINAL)
5751               Feld[xx][yy] = EL_SP_TERMINAL_ACTIVE;
5752           }
5753         }
5754
5755         return MF_ACTION;
5756       }
5757       break;
5758
5759     case EL_BELT1_SWITCH_LEFT:
5760     case EL_BELT1_SWITCH_MIDDLE:
5761     case EL_BELT1_SWITCH_RIGHT:
5762     case EL_BELT2_SWITCH_LEFT:
5763     case EL_BELT2_SWITCH_MIDDLE:
5764     case EL_BELT2_SWITCH_RIGHT:
5765     case EL_BELT3_SWITCH_LEFT:
5766     case EL_BELT3_SWITCH_MIDDLE:
5767     case EL_BELT3_SWITCH_RIGHT:
5768     case EL_BELT4_SWITCH_LEFT:
5769     case EL_BELT4_SWITCH_MIDDLE:
5770     case EL_BELT4_SWITCH_RIGHT:
5771       if (!player->Switching)
5772       {
5773         player->Switching = TRUE;
5774         ToggleBeltSwitch(x, y);
5775       }
5776       return MF_ACTION;
5777       break;
5778
5779     case EL_SWITCHGATE_SWITCH_1:
5780     case EL_SWITCHGATE_SWITCH_2:
5781       if (!player->Switching)
5782       {
5783         player->Switching = TRUE;
5784         ToggleSwitchgateSwitch(x, y);
5785       }
5786       return MF_ACTION;
5787       break;
5788
5789     case EL_LIGHT_SWITCH_OFF:
5790     case EL_LIGHT_SWITCH_ON:
5791       if (!player->Switching)
5792       {
5793         player->Switching = TRUE;
5794         ToggleLightSwitch(x, y);
5795       }
5796       return MF_ACTION;
5797       break;
5798
5799     case EL_TIMEGATE_SWITCH_OFF:
5800       ActivateTimegateSwitch(x, y);
5801
5802       return MF_ACTION;
5803       break;
5804
5805     case EL_BALLOON_SEND_LEFT:
5806     case EL_BALLOON_SEND_RIGHT:
5807     case EL_BALLOON_SEND_UP:
5808     case EL_BALLOON_SEND_DOWN:
5809     case EL_BALLOON_SEND_ANY:
5810       if (element == EL_BALLOON_SEND_ANY)
5811         game.balloon_dir = move_direction;
5812       else
5813         game.balloon_dir = (element == EL_BALLOON_SEND_LEFT  ? MV_LEFT :
5814                             element == EL_BALLOON_SEND_RIGHT ? MV_RIGHT :
5815                             element == EL_BALLOON_SEND_UP    ? MV_UP :
5816                             element == EL_BALLOON_SEND_DOWN  ? MV_DOWN :
5817                             MV_NO_MOVING);
5818
5819       return MF_ACTION;
5820       break;
5821
5822     case EL_SP_EXIT:
5823       if (local_player->gems_still_needed > 0)
5824         return MF_NO_ACTION;
5825
5826       player->LevelSolved = player->GameOver = TRUE;
5827       PlaySoundStereo(SND_SP_EXIT, PSND_MAX_RIGHT);
5828       break;
5829
5830     case EL_FELSBROCKEN:
5831     case EL_BD_ROCK:
5832     case EL_BOMBE:
5833     case EL_DX_SUPABOMB:
5834     case EL_KOKOSNUSS:
5835     case EL_ZEIT_LEER:
5836     case EL_SP_ZONK:
5837     case EL_SP_DISK_ORANGE:
5838     case EL_SPRING:
5839       if (dy || mode == DF_SNAP)
5840         return MF_NO_ACTION;
5841
5842       player->Pushing = TRUE;
5843
5844       if (!IN_LEV_FIELD(x+dx, y+dy) || !IS_FREE(x+dx, y+dy))
5845         return MF_NO_ACTION;
5846
5847       if (real_dy)
5848       {
5849         if (IN_LEV_FIELD(jx, jy+real_dy) && !IS_SOLID(Feld[jx][jy+real_dy]))
5850           return MF_NO_ACTION;
5851       }
5852
5853       if (player->push_delay == 0)
5854         player->push_delay = FrameCounter;
5855 #if 0
5856       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
5857           !tape.playing && element != EL_SPRING)
5858         return MF_NO_ACTION;
5859 #else
5860       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
5861           !(tape.playing && tape.game_version < GAME_VERSION_2_0) &&
5862           element != EL_SPRING)
5863         return MF_NO_ACTION;
5864 #endif
5865
5866       RemoveField(x, y);
5867       Feld[x+dx][y+dy] = element;
5868
5869       if (element == EL_SPRING)
5870       {
5871         Feld[x+dx][y+dy] = EL_SPRING_MOVING;
5872         MovDir[x+dx][y+dy] = move_direction;
5873       }
5874
5875       player->push_delay_value = (element == EL_SPRING ? 0 : 2 + RND(8));
5876
5877       DrawLevelField(x+dx, y+dy);
5878       if (element == EL_FELSBROCKEN || element == EL_BD_ROCK)
5879         PlaySoundLevel(x+dx, y+dy, SND_PUSCH);
5880       else if (element == EL_KOKOSNUSS)
5881         PlaySoundLevel(x+dx, y+dy, SND_KNURK);
5882       else if (IS_SP_ELEMENT(element))
5883         PlaySoundLevel(x+dx, y+dy, SND_SP_ZONKPUSH);
5884       else
5885         PlaySoundLevel(x+dx, y+dy, SND_PUSCH);  /* better than "SND_KLOPF" */
5886       break;
5887
5888     case EL_PFORTE1:
5889     case EL_PFORTE2:
5890     case EL_PFORTE3:
5891     case EL_PFORTE4:
5892       if (!player->key[element - EL_PFORTE1])
5893         return MF_NO_ACTION;
5894       break;
5895
5896     case EL_PFORTE1X:
5897     case EL_PFORTE2X:
5898     case EL_PFORTE3X:
5899     case EL_PFORTE4X:
5900       if (!player->key[element - EL_PFORTE1X])
5901         return MF_NO_ACTION;
5902       break;
5903
5904     case EL_EM_GATE_1:
5905     case EL_EM_GATE_2:
5906     case EL_EM_GATE_3:
5907     case EL_EM_GATE_4:
5908       if (!player->key[element - EL_EM_GATE_1])
5909         return MF_NO_ACTION;
5910       if (!IN_LEV_FIELD(x + dx, y + dy) || !IS_FREE(x + dx, y + dy))
5911         return MF_NO_ACTION;
5912
5913       /* automatically move to the next field with double speed */
5914       player->programmed_action = move_direction;
5915       DOUBLE_PLAYER_SPEED(player);
5916
5917       PlaySoundLevel(x, y, SND_GATE);
5918
5919       break;
5920
5921     case EL_EM_GATE_1X:
5922     case EL_EM_GATE_2X:
5923     case EL_EM_GATE_3X:
5924     case EL_EM_GATE_4X:
5925       if (!player->key[element - EL_EM_GATE_1X])
5926         return MF_NO_ACTION;
5927       if (!IN_LEV_FIELD(x + dx, y + dy) || !IS_FREE(x + dx, y + dy))
5928         return MF_NO_ACTION;
5929
5930       /* automatically move to the next field with double speed */
5931       player->programmed_action = move_direction;
5932       DOUBLE_PLAYER_SPEED(player);
5933
5934       PlaySoundLevel(x, y, SND_GATE);
5935
5936       break;
5937
5938     case EL_SWITCHGATE_OPEN:
5939     case EL_TIMEGATE_OPEN:
5940       if (!IN_LEV_FIELD(x + dx, y + dy) || !IS_FREE(x + dx, y + dy))
5941         return MF_NO_ACTION;
5942
5943       /* automatically move to the next field with double speed */
5944       player->programmed_action = move_direction;
5945       DOUBLE_PLAYER_SPEED(player);
5946
5947       PlaySoundLevel(x, y, SND_GATE);
5948
5949       break;
5950
5951     case EL_SP_PORT1_LEFT:
5952     case EL_SP_PORT2_LEFT:
5953     case EL_SP_PORT1_RIGHT:
5954     case EL_SP_PORT2_RIGHT:
5955     case EL_SP_PORT1_UP:
5956     case EL_SP_PORT2_UP:
5957     case EL_SP_PORT1_DOWN:
5958     case EL_SP_PORT2_DOWN:
5959     case EL_SP_PORT_X:
5960     case EL_SP_PORT_Y:
5961     case EL_SP_PORT_XY:
5962       if ((dx == -1 &&
5963            element != EL_SP_PORT1_LEFT &&
5964            element != EL_SP_PORT2_LEFT &&
5965            element != EL_SP_PORT_X &&
5966            element != EL_SP_PORT_XY) ||
5967           (dx == +1 &&
5968            element != EL_SP_PORT1_RIGHT &&
5969            element != EL_SP_PORT2_RIGHT &&
5970            element != EL_SP_PORT_X &&
5971            element != EL_SP_PORT_XY) ||
5972           (dy == -1 &&
5973            element != EL_SP_PORT1_UP &&
5974            element != EL_SP_PORT2_UP &&
5975            element != EL_SP_PORT_Y &&
5976            element != EL_SP_PORT_XY) ||
5977           (dy == +1 &&
5978            element != EL_SP_PORT1_DOWN &&
5979            element != EL_SP_PORT2_DOWN &&
5980            element != EL_SP_PORT_Y &&
5981            element != EL_SP_PORT_XY) ||
5982           !IN_LEV_FIELD(x + dx, y + dy) ||
5983           !IS_FREE(x + dx, y + dy))
5984         return MF_NO_ACTION;
5985
5986       /* automatically move to the next field with double speed */
5987       player->programmed_action = move_direction;
5988       DOUBLE_PLAYER_SPEED(player);
5989
5990       PlaySoundLevel(x, y, SND_GATE);
5991       break;
5992
5993     case EL_TUBE_CROSS:
5994     case EL_TUBE_VERTICAL:
5995     case EL_TUBE_HORIZONTAL:
5996     case EL_TUBE_VERT_LEFT:
5997     case EL_TUBE_VERT_RIGHT:
5998     case EL_TUBE_HORIZ_UP:
5999     case EL_TUBE_HORIZ_DOWN:
6000     case EL_TUBE_LEFT_UP:
6001     case EL_TUBE_LEFT_DOWN:
6002     case EL_TUBE_RIGHT_UP:
6003     case EL_TUBE_RIGHT_DOWN:
6004       {
6005         int i = 0;
6006         int tube_enter_directions[][2] =
6007         {
6008           { EL_TUBE_CROSS,      MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN },
6009           { EL_TUBE_VERTICAL,                        MV_UP | MV_DOWN },
6010           { EL_TUBE_HORIZONTAL, MV_LEFT | MV_RIGHT                   },
6011           { EL_TUBE_VERT_LEFT,            MV_RIGHT | MV_UP | MV_DOWN },
6012           { EL_TUBE_VERT_RIGHT, MV_LEFT            | MV_UP | MV_DOWN },
6013           { EL_TUBE_HORIZ_UP,   MV_LEFT | MV_RIGHT |         MV_DOWN },
6014           { EL_TUBE_HORIZ_DOWN, MV_LEFT | MV_RIGHT | MV_UP           },
6015           { EL_TUBE_LEFT_UP,              MV_RIGHT |         MV_DOWN },
6016           { EL_TUBE_LEFT_DOWN,            MV_RIGHT | MV_UP           },
6017           { EL_TUBE_RIGHT_UP,   MV_LEFT |                    MV_DOWN },
6018           { EL_TUBE_RIGHT_DOWN, MV_LEFT |            MV_UP           },
6019           { -1,                 MV_NO_MOVING                         }
6020         };
6021
6022         while (tube_enter_directions[i][0] != element)
6023         {
6024           i++;
6025           if (tube_enter_directions[i][0] == -1)        /* should not happen */
6026             break;
6027         }
6028
6029         if (!(tube_enter_directions[i][1] & move_direction))
6030           return MF_NO_ACTION;  /* tube has no opening in this direction */
6031       }
6032       break;
6033
6034     case EL_AUSGANG_ZU:
6035     case EL_AUSGANG_ACT:
6036       /* door is not (yet) open */
6037       return MF_NO_ACTION;
6038       break;
6039
6040     case EL_AUSGANG_AUF:
6041       if (mode == DF_SNAP)
6042         return MF_NO_ACTION;
6043
6044       PlaySoundLevel(x, y, SND_BUING);
6045
6046       break;
6047
6048     case EL_BIRNE_AUS:
6049       Feld[x][y] = EL_BIRNE_EIN;
6050       local_player->lights_still_needed--;
6051       DrawLevelField(x, y);
6052       PlaySoundLevel(x, y, SND_DENG);
6053       return MF_ACTION;
6054       break;
6055
6056     case EL_ZEIT_VOLL:
6057       Feld[x][y] = EL_ZEIT_LEER;
6058       TimeLeft += 10;
6059       DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
6060       DrawLevelField(x, y);
6061       PlaySoundStereo(SND_GONG, PSND_MAX_RIGHT);
6062       return MF_ACTION;
6063       break;
6064
6065     case EL_SOKOBAN_FELD_LEER:
6066       break;
6067
6068     case EL_SOKOBAN_FELD_VOLL:
6069     case EL_SOKOBAN_OBJEKT:
6070     case EL_SONDE:
6071     case EL_SP_DISK_YELLOW:
6072     case EL_BALLOON:
6073       if (mode == DF_SNAP)
6074         return MF_NO_ACTION;
6075
6076       player->Pushing = TRUE;
6077
6078       if (!IN_LEV_FIELD(x+dx, y+dy)
6079           || (!IS_FREE(x+dx, y+dy)
6080               && (Feld[x+dx][y+dy] != EL_SOKOBAN_FELD_LEER
6081                   || !IS_SB_ELEMENT(element))))
6082         return MF_NO_ACTION;
6083
6084       if (dx && real_dy)
6085       {
6086         if (IN_LEV_FIELD(jx, jy+real_dy) && !IS_SOLID(Feld[jx][jy+real_dy]))
6087           return MF_NO_ACTION;
6088       }
6089       else if (dy && real_dx)
6090       {
6091         if (IN_LEV_FIELD(jx+real_dx, jy) && !IS_SOLID(Feld[jx+real_dx][jy]))
6092           return MF_NO_ACTION;
6093       }
6094
6095       if (player->push_delay == 0)
6096         player->push_delay = FrameCounter;
6097 #if 0
6098       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
6099           !tape.playing && element != EL_BALLOON)
6100         return MF_NO_ACTION;
6101 #else
6102       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
6103           !(tape.playing && tape.game_version < GAME_VERSION_2_0) &&
6104           element != EL_BALLOON)
6105         return MF_NO_ACTION;
6106 #endif
6107
6108       if (IS_SB_ELEMENT(element))
6109       {
6110         if (element == EL_SOKOBAN_FELD_VOLL)
6111         {
6112           Feld[x][y] = EL_SOKOBAN_FELD_LEER;
6113           local_player->sokobanfields_still_needed++;
6114         }
6115         else
6116           RemoveField(x, y);
6117
6118         if (Feld[x+dx][y+dy] == EL_SOKOBAN_FELD_LEER)
6119         {
6120           Feld[x+dx][y+dy] = EL_SOKOBAN_FELD_VOLL;
6121           local_player->sokobanfields_still_needed--;
6122           if (element == EL_SOKOBAN_OBJEKT)
6123             PlaySoundLevel(x, y, SND_DENG);
6124         }
6125         else
6126           Feld[x+dx][y+dy] = EL_SOKOBAN_OBJEKT;
6127       }
6128       else
6129       {
6130         RemoveField(x, y);
6131         Feld[x+dx][y+dy] = element;
6132       }
6133
6134       player->push_delay_value = (element == EL_BALLOON ? 0 : 2);
6135
6136       DrawLevelField(x, y);
6137       DrawLevelField(x+dx, y+dy);
6138       if (element == EL_BALLOON)
6139         PlaySoundLevel(x+dx, y+dy, SND_SCHLURF);
6140       else
6141         PlaySoundLevel(x+dx, y+dy, SND_PUSCH);
6142
6143       if (IS_SB_ELEMENT(element) &&
6144           local_player->sokobanfields_still_needed == 0 &&
6145           game.emulation == EMU_SOKOBAN)
6146       {
6147         player->LevelSolved = player->GameOver = TRUE;
6148         PlaySoundLevel(x, y, SND_BUING);
6149       }
6150
6151       break;
6152
6153     case EL_PINGUIN:
6154     case EL_SCHWEIN:
6155     case EL_DRACHE:
6156       break;
6157
6158     default:
6159       return MF_NO_ACTION;
6160   }
6161
6162   player->push_delay = 0;
6163
6164   return MF_MOVING;
6165 }
6166
6167 boolean SnapField(struct PlayerInfo *player, int dx, int dy)
6168 {
6169   int jx = player->jx, jy = player->jy;
6170   int x = jx + dx, y = jy + dy;
6171
6172   if (!player->active || !IN_LEV_FIELD(x, y))
6173     return FALSE;
6174
6175   if (dx && dy)
6176     return FALSE;
6177
6178   if (!dx && !dy)
6179   {
6180     player->snapped = FALSE;
6181     return FALSE;
6182   }
6183
6184   if (player->snapped)
6185     return FALSE;
6186
6187   player->MovDir = (dx < 0 ? MV_LEFT :
6188                     dx > 0 ? MV_RIGHT :
6189                     dy < 0 ? MV_UP :
6190                     dy > 0 ? MV_DOWN :  MV_NO_MOVING);
6191
6192   if (!DigField(player, x, y, 0, 0, DF_SNAP))
6193     return FALSE;
6194
6195   player->snapped = TRUE;
6196   DrawLevelField(x, y);
6197   BackToFront();
6198
6199   return TRUE;
6200 }
6201
6202 boolean PlaceBomb(struct PlayerInfo *player)
6203 {
6204   int jx = player->jx, jy = player->jy;
6205   int element;
6206
6207   if (!player->active || player->MovPos)
6208     return FALSE;
6209
6210   element = Feld[jx][jy];
6211
6212   if ((player->dynamite == 0 && player->dynabombs_left == 0) ||
6213       IS_ACTIVE_BOMB(element) || element == EL_EXPLODING)
6214     return FALSE;
6215
6216   if (element != EL_LEERRAUM)
6217     Store[jx][jy] = element;
6218
6219   if (player->dynamite)
6220   {
6221     Feld[jx][jy] = EL_DYNAMITE_ACTIVE;
6222     MovDelay[jx][jy] = 96;
6223     player->dynamite--;
6224     DrawText(DX_DYNAMITE, DY_DYNAMITE, int2str(local_player->dynamite, 3),
6225              FS_SMALL, FC_YELLOW);
6226     if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy)))
6227     {
6228       if (game.emulation == EMU_SUPAPLEX)
6229         DrawGraphic(SCREENX(jx), SCREENY(jy), GFX_SP_DISK_RED);
6230       else
6231         DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), GFX_DYNAMIT);
6232     }
6233   }
6234   else
6235   {
6236     Feld[jx][jy] = EL_DYNABOMB_ACTIVE_1 + (player->element_nr - EL_SPIELER1);
6237     MovDelay[jx][jy] = 96;
6238     player->dynabombs_left--;
6239     if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy)))
6240       DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), GFX_DYNABOMB);
6241   }
6242
6243   return TRUE;
6244 }
6245
6246 void PlaySoundLevel(int x, int y, int sound_nr)
6247 {
6248   int sx = SCREENX(x), sy = SCREENY(y);
6249   int volume, stereo;
6250   int silence_distance = 8;
6251
6252   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound_nr)) ||
6253       (!setup.sound_loops && IS_LOOP_SOUND(sound_nr)))
6254     return;
6255
6256   if (!IN_LEV_FIELD(x, y) ||
6257       sx < -silence_distance || sx >= SCR_FIELDX+silence_distance ||
6258       sy < -silence_distance || sy >= SCR_FIELDY+silence_distance)
6259     return;
6260
6261   volume = PSND_MAX_VOLUME;
6262
6263 #if !defined(PLATFORM_MSDOS)
6264   stereo = (sx - SCR_FIELDX/2) * 12;
6265 #else
6266   stereo = PSND_MIDDLE + (2 * sx - (SCR_FIELDX - 1)) * 5;
6267   if (stereo > PSND_MAX_RIGHT)
6268     stereo = PSND_MAX_RIGHT;
6269   if (stereo < PSND_MAX_LEFT)
6270     stereo = PSND_MAX_LEFT;
6271 #endif
6272
6273   if (!IN_SCR_FIELD(sx, sy))
6274   {
6275     int dx = ABS(sx - SCR_FIELDX/2) - SCR_FIELDX/2;
6276     int dy = ABS(sy - SCR_FIELDY/2) - SCR_FIELDY/2;
6277
6278     volume -= volume * (dx > dy ? dx : dy) / silence_distance;
6279   }
6280
6281   PlaySoundExt(sound_nr, volume, stereo, PSND_NO_LOOP);
6282 }
6283
6284 void RaiseScore(int value)
6285 {
6286   local_player->score += value;
6287   DrawText(DX_SCORE, DY_SCORE, int2str(local_player->score, 5),
6288            FS_SMALL, FC_YELLOW);
6289 }
6290
6291 void RaiseScoreElement(int element)
6292 {
6293   switch(element)
6294   {
6295     case EL_EDELSTEIN:
6296     case EL_EDELSTEIN_BD:
6297     case EL_EDELSTEIN_GELB:
6298     case EL_EDELSTEIN_ROT:
6299     case EL_EDELSTEIN_LILA:
6300       RaiseScore(level.score[SC_EDELSTEIN]);
6301       break;
6302     case EL_DIAMANT:
6303       RaiseScore(level.score[SC_DIAMANT]);
6304       break;
6305     case EL_KAEFER:
6306     case EL_BUTTERFLY:
6307       RaiseScore(level.score[SC_KAEFER]);
6308       break;
6309     case EL_FLIEGER:
6310     case EL_FIREFLY:
6311       RaiseScore(level.score[SC_FLIEGER]);
6312       break;
6313     case EL_MAMPFER:
6314     case EL_MAMPFER2:
6315       RaiseScore(level.score[SC_MAMPFER]);
6316       break;
6317     case EL_ROBOT:
6318       RaiseScore(level.score[SC_ROBOT]);
6319       break;
6320     case EL_PACMAN:
6321       RaiseScore(level.score[SC_PACMAN]);
6322       break;
6323     case EL_KOKOSNUSS:
6324       RaiseScore(level.score[SC_KOKOSNUSS]);
6325       break;
6326     case EL_DYNAMITE_INACTIVE:
6327       RaiseScore(level.score[SC_DYNAMIT]);
6328       break;
6329     case EL_SCHLUESSEL:
6330       RaiseScore(level.score[SC_SCHLUESSEL]);
6331       break;
6332     default:
6333       break;
6334   }
6335 }
6336
6337 void RequestQuitGame(boolean ask_if_really_quit)
6338 {
6339   if (AllPlayersGone ||
6340       !ask_if_really_quit ||
6341       level_editor_test_game ||
6342       Request("Do you really want to quit the game ?",
6343               REQ_ASK | REQ_STAY_CLOSED))
6344   {
6345 #if defined(PLATFORM_UNIX)
6346     if (options.network)
6347       SendToServer_StopPlaying();
6348     else
6349 #endif
6350     {
6351       game_status = MAINMENU;
6352       DrawMainMenu();
6353     }
6354   }
6355   else
6356   {
6357     OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
6358   }
6359 }
6360
6361
6362 /* ---------- new game button stuff ---------------------------------------- */
6363
6364 /* graphic position values for game buttons */
6365 #define GAME_BUTTON_XSIZE       30
6366 #define GAME_BUTTON_YSIZE       30
6367 #define GAME_BUTTON_XPOS        5
6368 #define GAME_BUTTON_YPOS        215
6369 #define SOUND_BUTTON_XPOS       5
6370 #define SOUND_BUTTON_YPOS       (GAME_BUTTON_YPOS + GAME_BUTTON_YSIZE)
6371
6372 #define GAME_BUTTON_STOP_XPOS   (GAME_BUTTON_XPOS + 0 * GAME_BUTTON_XSIZE)
6373 #define GAME_BUTTON_PAUSE_XPOS  (GAME_BUTTON_XPOS + 1 * GAME_BUTTON_XSIZE)
6374 #define GAME_BUTTON_PLAY_XPOS   (GAME_BUTTON_XPOS + 2 * GAME_BUTTON_XSIZE)
6375 #define SOUND_BUTTON_MUSIC_XPOS (SOUND_BUTTON_XPOS + 0 * GAME_BUTTON_XSIZE)
6376 #define SOUND_BUTTON_LOOPS_XPOS (SOUND_BUTTON_XPOS + 1 * GAME_BUTTON_XSIZE)
6377 #define SOUND_BUTTON_SIMPLE_XPOS (SOUND_BUTTON_XPOS + 2 * GAME_BUTTON_XSIZE)
6378
6379 static struct
6380 {
6381   int x, y;
6382   int gadget_id;
6383   char *infotext;
6384 } gamebutton_info[NUM_GAME_BUTTONS] =
6385 {
6386   {
6387     GAME_BUTTON_STOP_XPOS,      GAME_BUTTON_YPOS,
6388     GAME_CTRL_ID_STOP,
6389     "stop game"
6390   },
6391   {
6392     GAME_BUTTON_PAUSE_XPOS,     GAME_BUTTON_YPOS,
6393     GAME_CTRL_ID_PAUSE,
6394     "pause game"
6395   },
6396   {
6397     GAME_BUTTON_PLAY_XPOS,      GAME_BUTTON_YPOS,
6398     GAME_CTRL_ID_PLAY,
6399     "play game"
6400   },
6401   {
6402     SOUND_BUTTON_MUSIC_XPOS,    SOUND_BUTTON_YPOS,
6403     SOUND_CTRL_ID_MUSIC,
6404     "background music on/off"
6405   },
6406   {
6407     SOUND_BUTTON_LOOPS_XPOS,    SOUND_BUTTON_YPOS,
6408     SOUND_CTRL_ID_LOOPS,
6409     "sound loops on/off"
6410   },
6411   {
6412     SOUND_BUTTON_SIMPLE_XPOS,   SOUND_BUTTON_YPOS,
6413     SOUND_CTRL_ID_SIMPLE,
6414     "normal sounds on/off"
6415   }
6416 };
6417
6418 void CreateGameButtons()
6419 {
6420   int i;
6421
6422   for (i=0; i<NUM_GAME_BUTTONS; i++)
6423   {
6424     Bitmap *gd_bitmap = pix[PIX_DOOR];
6425     struct GadgetInfo *gi;
6426     int button_type;
6427     boolean checked;
6428     unsigned long event_mask;
6429     int gd_xoffset, gd_yoffset;
6430     int gd_x1, gd_x2, gd_y1, gd_y2;
6431     int id = i;
6432
6433     gd_xoffset = gamebutton_info[i].x;
6434     gd_yoffset = gamebutton_info[i].y;
6435     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
6436     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
6437
6438     if (id == GAME_CTRL_ID_STOP ||
6439         id == GAME_CTRL_ID_PAUSE ||
6440         id == GAME_CTRL_ID_PLAY)
6441     {
6442       button_type = GD_TYPE_NORMAL_BUTTON;
6443       checked = FALSE;
6444       event_mask = GD_EVENT_RELEASED;
6445       gd_y1  = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
6446       gd_y2  = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
6447     }
6448     else
6449     {
6450       button_type = GD_TYPE_CHECK_BUTTON;
6451       checked =
6452         ((id == SOUND_CTRL_ID_MUSIC && setup.sound_music) ||
6453          (id == SOUND_CTRL_ID_LOOPS && setup.sound_loops) ||
6454          (id == SOUND_CTRL_ID_SIMPLE && setup.sound_simple) ? TRUE : FALSE);
6455       event_mask = GD_EVENT_PRESSED;
6456       gd_y1  = DOOR_GFX_PAGEY1 + gd_yoffset;
6457       gd_y2  = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
6458     }
6459
6460     gi = CreateGadget(GDI_CUSTOM_ID, id,
6461                       GDI_INFO_TEXT, gamebutton_info[i].infotext,
6462                       GDI_X, DX + gd_xoffset,
6463                       GDI_Y, DY + gd_yoffset,
6464                       GDI_WIDTH, GAME_BUTTON_XSIZE,
6465                       GDI_HEIGHT, GAME_BUTTON_YSIZE,
6466                       GDI_TYPE, button_type,
6467                       GDI_STATE, GD_BUTTON_UNPRESSED,
6468                       GDI_CHECKED, checked,
6469                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
6470                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y1,
6471                       GDI_ALT_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y2,
6472                       GDI_ALT_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
6473                       GDI_EVENT_MASK, event_mask,
6474                       GDI_CALLBACK_ACTION, HandleGameButtons,
6475                       GDI_END);
6476
6477     if (gi == NULL)
6478       Error(ERR_EXIT, "cannot create gadget");
6479
6480     game_gadget[id] = gi;
6481   }
6482 }
6483
6484 static void MapGameButtons()
6485 {
6486   int i;
6487
6488   for (i=0; i<NUM_GAME_BUTTONS; i++)
6489     MapGadget(game_gadget[i]);
6490 }
6491
6492 void UnmapGameButtons()
6493 {
6494   int i;
6495
6496   for (i=0; i<NUM_GAME_BUTTONS; i++)
6497     UnmapGadget(game_gadget[i]);
6498 }
6499
6500 static void HandleGameButtons(struct GadgetInfo *gi)
6501 {
6502   int id = gi->custom_id;
6503
6504   if (game_status != PLAYING)
6505     return;
6506
6507   switch (id)
6508   {
6509     case GAME_CTRL_ID_STOP:
6510       RequestQuitGame(TRUE);
6511       break;
6512
6513     case GAME_CTRL_ID_PAUSE:
6514       if (options.network)
6515       {
6516 #if defined(PLATFORM_UNIX)
6517         if (tape.pausing)
6518           SendToServer_ContinuePlaying();
6519         else
6520           SendToServer_PausePlaying();
6521 #endif
6522       }
6523       else
6524         TapeTogglePause(TAPE_TOGGLE_MANUAL);
6525       break;
6526
6527     case GAME_CTRL_ID_PLAY:
6528       if (tape.pausing)
6529       {
6530 #if defined(PLATFORM_UNIX)
6531         if (options.network)
6532           SendToServer_ContinuePlaying();
6533         else
6534 #endif
6535         {
6536           tape.pausing = FALSE;
6537           DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0);
6538         }
6539       }
6540       break;
6541
6542     case SOUND_CTRL_ID_MUSIC:
6543       if (setup.sound_music)
6544       { 
6545         setup.sound_music = FALSE;
6546         FadeMusic();
6547       }
6548       else if (audio.music_available)
6549       { 
6550         setup.sound = setup.sound_music = TRUE;
6551         if (num_bg_loops)
6552           PlayMusic(level_nr % num_bg_loops);
6553       }
6554       break;
6555
6556     case SOUND_CTRL_ID_LOOPS:
6557       if (setup.sound_loops)
6558         setup.sound_loops = FALSE;
6559       else if (audio.loops_available)
6560         setup.sound = setup.sound_loops = TRUE;
6561       break;
6562
6563     case SOUND_CTRL_ID_SIMPLE:
6564       if (setup.sound_simple)
6565         setup.sound_simple = FALSE;
6566       else if (audio.sound_available)
6567         setup.sound = setup.sound_simple = TRUE;
6568       break;
6569
6570     default:
6571       break;
6572   }
6573 }