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