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