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