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