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