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