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