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