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