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