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