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