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