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