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