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