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