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