rnd-20050103-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 /* EXPERIMENTAL STUFF */
31 #define USE_NEW_STUFF           TRUE                            * 1
32
33 #define USE_NEW_MOVE_STYLE      TRUE    * USE_NEW_STUFF         * 1
34 #define USE_NEW_MOVE_DELAY      TRUE    * USE_NEW_STUFF         * 1
35 #define USE_NEW_PUSH_DELAY      TRUE    * USE_NEW_STUFF         * 1
36 #define USE_NEW_BLOCK_STYLE     TRUE    * USE_NEW_STUFF         * 1 * 1
37 #define USE_NEW_SP_SLIPPERY     TRUE    * USE_NEW_STUFF         * 1
38 #define USE_NEW_RANDOMIZE       TRUE    * USE_NEW_STUFF         * 1
39
40 #define USE_PUSH_BUGFIX         TRUE    * USE_NEW_STUFF         * 1
41
42 /* for DigField() */
43 #define DF_NO_PUSH              0
44 #define DF_DIG                  1
45 #define DF_SNAP                 2
46
47 /* for MovePlayer() */
48 #define MF_NO_ACTION            0
49 #define MF_MOVING               1
50 #define MF_ACTION               2
51
52 /* for ScrollPlayer() */
53 #define SCROLL_INIT             0
54 #define SCROLL_GO_ON            1
55
56 /* for Explode() */
57 #define EX_PHASE_START          0
58 #define EX_TYPE_NONE            0
59 #define EX_TYPE_NORMAL          (1 << 0)
60 #define EX_TYPE_CENTER          (1 << 1)
61 #define EX_TYPE_BORDER          (1 << 2)
62 #define EX_TYPE_CROSS           (1 << 3)
63 #define EX_TYPE_SINGLE_TILE     (EX_TYPE_CENTER | EX_TYPE_BORDER)
64
65 /* special positions in the game control window (relative to control window) */
66 #define XX_LEVEL                37
67 #define YY_LEVEL                20
68 #define XX_EMERALDS             29
69 #define YY_EMERALDS             54
70 #define XX_DYNAMITE             29
71 #define YY_DYNAMITE             89
72 #define XX_KEYS                 18
73 #define YY_KEYS                 123
74 #define XX_SCORE                15
75 #define YY_SCORE                159
76 #define XX_TIME1                29
77 #define XX_TIME2                30
78 #define YY_TIME                 194
79
80 /* special positions in the game control window (relative to main window) */
81 #define DX_LEVEL                (DX + XX_LEVEL)
82 #define DY_LEVEL                (DY + YY_LEVEL)
83 #define DX_EMERALDS             (DX + XX_EMERALDS)
84 #define DY_EMERALDS             (DY + YY_EMERALDS)
85 #define DX_DYNAMITE             (DX + XX_DYNAMITE)
86 #define DY_DYNAMITE             (DY + YY_DYNAMITE)
87 #define DX_KEYS                 (DX + XX_KEYS)
88 #define DY_KEYS                 (DY + YY_KEYS)
89 #define DX_SCORE                (DX + XX_SCORE)
90 #define DY_SCORE                (DY + YY_SCORE)
91 #define DX_TIME1                (DX + XX_TIME1)
92 #define DX_TIME2                (DX + XX_TIME2)
93 #define DY_TIME                 (DY + YY_TIME)
94
95 /* values for initial player move delay (initial delay counter value) */
96 #define INITIAL_MOVE_DELAY_OFF  -1
97 #define INITIAL_MOVE_DELAY_ON   0
98
99 /* values for player movement speed (which is in fact a delay value) */
100 #define MOVE_DELAY_NORMAL_SPEED 8
101 #define MOVE_DELAY_HIGH_SPEED   4
102
103 #define DOUBLE_MOVE_DELAY(x)    (x = (x <= MOVE_DELAY_HIGH_SPEED ? x * 2 : x))
104 #define HALVE_MOVE_DELAY(x)     (x = (x >= MOVE_DELAY_HIGH_SPEED ? x / 2 : x))
105 #define DOUBLE_PLAYER_SPEED(p)  (HALVE_MOVE_DELAY((p)->move_delay_value))
106 #define HALVE_PLAYER_SPEED(p)   (DOUBLE_MOVE_DELAY((p)->move_delay_value))
107
108 /* values for other actions */
109 #define MOVE_STEPSIZE_NORMAL    (TILEX / MOVE_DELAY_NORMAL_SPEED)
110
111 #define GET_DX_FROM_DIR(d)      ((d) == MV_LEFT ? -1 : (d) == MV_RIGHT ? 1 : 0)
112 #define GET_DY_FROM_DIR(d)      ((d) == MV_UP   ? -1 : (d) == MV_DOWN  ? 1 : 0)
113
114 #define INIT_GFX_RANDOM()       (SimpleRND(1000000))
115
116 #define GET_NEW_PUSH_DELAY(e)   (   (element_info[e].push_delay_fixed) + \
117                                  RND(element_info[e].push_delay_random))
118 #define GET_NEW_DROP_DELAY(e)   (   (element_info[e].drop_delay_fixed) + \
119                                  RND(element_info[e].drop_delay_random))
120 #define GET_NEW_MOVE_DELAY(e)   (   (element_info[e].move_delay_fixed) + \
121                                  RND(element_info[e].move_delay_random))
122 #define GET_MAX_MOVE_DELAY(e)   (   (element_info[e].move_delay_fixed) + \
123                                     (element_info[e].move_delay_random))
124
125 #define GET_TARGET_ELEMENT(e, ch)                                       \
126         ((e) == EL_TRIGGER_ELEMENT ? (ch)->actual_trigger_element :     \
127          (e) == EL_TRIGGER_PLAYER  ? (ch)->actual_trigger_player : (e))
128
129 #define GET_VALID_PLAYER_ELEMENT(e)                                     \
130         ((e) >= EL_PLAYER_1 && (e) <= EL_PLAYER_4 ? (e) : EL_PLAYER_1)
131
132 #define CAN_GROW_INTO(e)                                                \
133         ((e) == EL_SAND || (IS_DIGGABLE(e) && level.grow_into_diggable))
134
135 #define ELEMENT_CAN_ENTER_FIELD_BASE_X(x, y, condition)                 \
136                 (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) ||                \
137                                         (condition)))
138
139 #define ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, condition)              \
140                 (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) ||                \
141                                         (CAN_MOVE_INTO_ACID(e) &&       \
142                                          Feld[x][y] == EL_ACID) ||      \
143                                         (condition)))
144
145 #define ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x, y, condition)              \
146                 (IN_LEV_FIELD(x, y) && (IS_FREE_OR_PLAYER(x, y) ||      \
147                                         (CAN_MOVE_INTO_ACID(e) &&       \
148                                          Feld[x][y] == EL_ACID) ||      \
149                                         (condition)))
150
151 #define ELEMENT_CAN_ENTER_FIELD_BASE_4(e, x, y, condition)              \
152                 (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) ||                \
153                                         (condition) ||                  \
154                                         (CAN_MOVE_INTO_ACID(e) &&       \
155                                          Feld[x][y] == EL_ACID) ||      \
156                                         (DONT_COLLIDE_WITH(e) &&        \
157                                          IS_PLAYER(x, y) &&             \
158                                          !PLAYER_ENEMY_PROTECTED(x, y))))
159
160 #if 0
161 #define ELEMENT_CAN_ENTER_FIELD_GENERIC(e, x, y, condition)             \
162                 (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) ||                \
163                                         (condition) ||                  \
164                                         (DONT_COLLIDE_WITH(e) &&        \
165                                          IS_PLAYER(x, y) &&             \
166                                          !PLAYER_ENEMY_PROTECTED(x, y))))
167 #endif
168
169 #define ELEMENT_CAN_ENTER_FIELD(e, x, y)                                \
170         ELEMENT_CAN_ENTER_FIELD_BASE_4(e, x, y, 0)
171
172 #if 1
173 #define SATELLITE_CAN_ENTER_FIELD(x, y)                                 \
174         ELEMENT_CAN_ENTER_FIELD_BASE_2(EL_SATELLITE, x, y, 0)
175 #else
176 #define SATELLITE_CAN_ENTER_FIELD(x, y)                                 \
177         ELEMENT_CAN_ENTER_FIELD_BASE_X(x, y, Feld[x][y] == EL_ACID)
178 #endif
179
180 #if 0
181 #define ENEMY_CAN_ENTER_FIELD(e, x, y) (IN_LEV_FIELD(x, y) && IS_FREE(x, y))
182 #endif
183
184 #define ENEMY_CAN_ENTER_FIELD(e, x, y)                                  \
185         ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, 0)
186
187 #if 1
188
189 #define YAMYAM_CAN_ENTER_FIELD(e, x, y)                                 \
190         ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x, y, Feld[x][y] == EL_DIAMOND)
191
192 #define DARK_YAMYAM_CAN_ENTER_FIELD(e, x, y)                            \
193         ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x,y, IS_FOOD_DARK_YAMYAM(Feld[x][y]))
194
195 #define PACMAN_CAN_ENTER_FIELD(e, x, y)                                 \
196         ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x, y, IS_AMOEBOID(Feld[x][y]))
197
198 #define PIG_CAN_ENTER_FIELD(e, x, y)                                    \
199         ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, IS_FOOD_PIG(Feld[x][y]))
200
201 #define PENGUIN_CAN_ENTER_FIELD(e, x, y)                                \
202         ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, (Feld[x][y] == EL_EXIT_OPEN ||\
203                                                  IS_FOOD_PENGUIN(Feld[x][y])))
204 #define DRAGON_CAN_ENTER_FIELD(e, x, y)                                 \
205         ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, 0)
206
207 #define MOLE_CAN_ENTER_FIELD(e, x, y, condition)                        \
208         ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, (condition))
209
210 #define SPRING_CAN_ENTER_FIELD(e, x, y)                                 \
211         ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, 0)
212
213 #else
214
215 #define YAMYAM_CAN_ENTER_FIELD(e, x, y)                                 \
216                 (IN_LEV_FIELD(x, y) && (IS_FREE_OR_PLAYER(x, y) ||      \
217                                         (CAN_MOVE_INTO_ACID(e) &&       \
218                                          Feld[x][y] == EL_ACID) ||      \
219                                         Feld[x][y] == EL_DIAMOND))
220
221 #define DARK_YAMYAM_CAN_ENTER_FIELD(e, x, y)                            \
222                 (IN_LEV_FIELD(x, y) && (IS_FREE_OR_PLAYER(x, y) ||      \
223                                         (CAN_MOVE_INTO_ACID(e) &&       \
224                                          Feld[x][y] == EL_ACID) ||      \
225                                         IS_FOOD_DARK_YAMYAM(Feld[x][y])))
226
227 #define PACMAN_CAN_ENTER_FIELD(e, x, y)                                 \
228                 (IN_LEV_FIELD(x, y) && (IS_FREE_OR_PLAYER(x, y) ||      \
229                                         (CAN_MOVE_INTO_ACID(e) &&       \
230                                          Feld[x][y] == EL_ACID) ||      \
231                                         IS_AMOEBOID(Feld[x][y])))
232
233 #define PIG_CAN_ENTER_FIELD(e, x, y)                                    \
234                 (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) ||                \
235                                         (CAN_MOVE_INTO_ACID(e) &&       \
236                                          Feld[x][y] == EL_ACID) ||      \
237                                         IS_FOOD_PIG(Feld[x][y])))
238
239 #define PENGUIN_CAN_ENTER_FIELD(e, x, y)                                \
240                 (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) ||                \
241                                         (CAN_MOVE_INTO_ACID(e) &&       \
242                                          Feld[x][y] == EL_ACID) ||      \
243                                         IS_FOOD_PENGUIN(Feld[x][y]) ||  \
244                                         Feld[x][y] == EL_EXIT_OPEN))
245
246 #define DRAGON_CAN_ENTER_FIELD(e, x, y)                                 \
247                 (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) ||                \
248                                         (CAN_MOVE_INTO_ACID(e) &&       \
249                                          Feld[x][y] == EL_ACID)))
250
251 #define MOLE_CAN_ENTER_FIELD(e, x, y, condition)                        \
252                 (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) ||                \
253                                         (CAN_MOVE_INTO_ACID(e) &&       \
254                                          Feld[x][y] == EL_ACID) ||      \
255                                         (condition)))
256
257 #define SPRING_CAN_ENTER_FIELD(e, x, y)                                 \
258                 (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) ||                \
259                                         (CAN_MOVE_INTO_ACID(e) &&       \
260                                          Feld[x][y] == EL_ACID)))
261
262 #endif
263
264 #define GROUP_NR(e)             ((e) - EL_GROUP_START)
265 #define MOVE_ENTER_EL(e)        (element_info[e].move_enter_element)
266 #define IS_IN_GROUP(e, nr)      (element_info[e].in_group[nr] == TRUE)
267 #define IS_IN_GROUP_EL(e, ge)   (IS_IN_GROUP(e, (ge) - EL_GROUP_START))
268
269 #define IS_EQUAL_OR_IN_GROUP(e, ge)                                     \
270         (IS_GROUP_ELEMENT(ge) ? IS_IN_GROUP(e, GROUP_NR(ge)) : (e) == (ge))
271
272 #if 0
273 #define CE_ENTER_FIELD_COND(e, x, y)                                    \
274                 (!IS_PLAYER(x, y) &&                                    \
275                  (Feld[x][y] == EL_ACID ||                              \
276                   IS_EQUAL_OR_IN_GROUP(Feld[x][y], MOVE_ENTER_EL(e))))
277 #else
278 #define CE_ENTER_FIELD_COND(e, x, y)                                    \
279                 (!IS_PLAYER(x, y) &&                                    \
280                  IS_EQUAL_OR_IN_GROUP(Feld[x][y], MOVE_ENTER_EL(e)))
281 #endif
282
283 #define CUSTOM_ELEMENT_CAN_ENTER_FIELD(e, x, y)                         \
284         ELEMENT_CAN_ENTER_FIELD_BASE_4(e, x, y, CE_ENTER_FIELD_COND(e, x, y))
285
286 #define IN_LEV_FIELD_AND_IS_FREE(x, y)  (IN_LEV_FIELD(x, y) &&  IS_FREE(x, y))
287 #define IN_LEV_FIELD_AND_NOT_FREE(x, y) (IN_LEV_FIELD(x, y) && !IS_FREE(x, y))
288
289 #define ACCESS_FROM(e, d)               (element_info[e].access_direction &(d))
290 #define IS_WALKABLE_FROM(e, d)          (IS_WALKABLE(e)   && ACCESS_FROM(e, d))
291 #define IS_PASSABLE_FROM(e, d)          (IS_PASSABLE(e)   && ACCESS_FROM(e, d))
292 #define IS_ACCESSIBLE_FROM(e, d)        (IS_ACCESSIBLE(e) && ACCESS_FROM(e, d))
293
294 /* game button identifiers */
295 #define GAME_CTRL_ID_STOP               0
296 #define GAME_CTRL_ID_PAUSE              1
297 #define GAME_CTRL_ID_PLAY               2
298 #define SOUND_CTRL_ID_MUSIC             3
299 #define SOUND_CTRL_ID_LOOPS             4
300 #define SOUND_CTRL_ID_SIMPLE            5
301
302 #define NUM_GAME_BUTTONS                6
303
304
305 /* forward declaration for internal use */
306
307 static void AdvanceFrameAndPlayerCounters(int);
308
309 static boolean MovePlayerOneStep(struct PlayerInfo *, int, int, int, int);
310 static boolean MovePlayer(struct PlayerInfo *, int, int);
311 static void ScrollPlayer(struct PlayerInfo *, int);
312 static void ScrollScreen(struct PlayerInfo *, int);
313
314 int DigField(struct PlayerInfo *, int, int, int, int, int, int, int);
315
316 static void InitBeltMovement(void);
317 static void CloseAllOpenTimegates(void);
318 static void CheckGravityMovement(struct PlayerInfo *);
319 static void CheckGravityMovementWhenNotMoving(struct PlayerInfo *);
320 static void KillHeroUnlessEnemyProtected(int, int);
321 static void KillHeroUnlessExplosionProtected(int, int);
322
323 static void TestIfPlayerTouchesCustomElement(int, int);
324 static void TestIfElementTouchesCustomElement(int, int);
325 static void TestIfElementHitsCustomElement(int, int, int);
326 #if 0
327 static void TestIfElementSmashesCustomElement(int, int, int);
328 #endif
329
330 static void ChangeElement(int, int, int);
331
332 static boolean CheckTriggeredElementChangeExt(int, int, int, int, int,int,int);
333 #define CheckTriggeredElementChange(x, y, e, ev)                        \
334         CheckTriggeredElementChangeExt(x, y, e, ev, CH_PLAYER_ANY,      \
335                                        CH_SIDE_ANY, -1)
336 #define CheckTriggeredElementChangeByPlayer(x, y, e, ev, p, s)          \
337         CheckTriggeredElementChangeExt(x, y, e, ev, p, s, -1)
338 #define CheckTriggeredElementChangeBySide(x, y, e, ev, s)               \
339         CheckTriggeredElementChangeExt(x, y, e, ev, CH_PLAYER_ANY, s, -1)
340 #define CheckTriggeredElementChangeByPage(x, y, e, ev, p)               \
341         CheckTriggeredElementChangeExt(x, y, e, ev, CH_PLAYER_ANY,      \
342                                        CH_SIDE_ANY, p)
343
344 static boolean CheckElementChangeExt(int, int, int, int, int, int, int, int);
345 #define CheckElementChange(x, y, e, te, ev)                             \
346         CheckElementChangeExt(x, y, e, te, ev, CH_PLAYER_ANY, CH_SIDE_ANY, -1)
347 #define CheckElementChangeByPlayer(x, y, e, ev, p, s)                   \
348         CheckElementChangeExt(x, y, e, EL_EMPTY, ev, p, s, CH_PAGE_ANY)
349 #define CheckElementChangeBySide(x, y, e, te, ev, s)                    \
350         CheckElementChangeExt(x, y, e, te, ev, CH_PLAYER_ANY, s, CH_PAGE_ANY)
351 #define CheckElementChangeByPage(x, y, e, te, ev, p)                    \
352         CheckElementChangeExt(x, y, e, te, ev, CH_PLAYER_ANY, CH_SIDE_ANY, p)
353
354 static void PlayLevelSound(int, int, int);
355 static void PlayLevelSoundNearest(int, int, int);
356 static void PlayLevelSoundAction(int, int, int);
357 static void PlayLevelSoundElementAction(int, int, int, int);
358 static void PlayLevelSoundElementActionIfLoop(int, int, int, int);
359 static void PlayLevelSoundActionIfLoop(int, int, int);
360 static void StopLevelSoundActionIfLoop(int, int, int);
361 static void PlayLevelMusic();
362
363 static void MapGameButtons();
364 static void HandleGameButtons(struct GadgetInfo *);
365
366 static struct GadgetInfo *game_gadget[NUM_GAME_BUTTONS];
367
368
369 /* ------------------------------------------------------------------------- */
370 /* definition of elements that automatically change to other elements after  */
371 /* a specified time, eventually calling a function when changing             */
372 /* ------------------------------------------------------------------------- */
373
374 /* forward declaration for changer functions */
375 static void InitBuggyBase(int x, int y);
376 static void WarnBuggyBase(int x, int y);
377
378 static void InitTrap(int x, int y);
379 static void ActivateTrap(int x, int y);
380 static void ChangeActiveTrap(int x, int y);
381
382 static void InitRobotWheel(int x, int y);
383 static void RunRobotWheel(int x, int y);
384 static void StopRobotWheel(int x, int y);
385
386 static void InitTimegateWheel(int x, int y);
387 static void RunTimegateWheel(int x, int y);
388
389 struct ChangingElementInfo
390 {
391   int element;
392   int target_element;
393   int change_delay;
394   void (*pre_change_function)(int x, int y);
395   void (*change_function)(int x, int y);
396   void (*post_change_function)(int x, int y);
397 };
398
399 static struct ChangingElementInfo change_delay_list[] =
400 {
401   {
402     EL_NUT_BREAKING,
403     EL_EMERALD,
404     6,
405     NULL,
406     NULL,
407     NULL
408   },
409   {
410     EL_PEARL_BREAKING,
411     EL_EMPTY,
412     8,
413     NULL,
414     NULL,
415     NULL
416   },
417   {
418     EL_EXIT_OPENING,
419     EL_EXIT_OPEN,
420     29,
421     NULL,
422     NULL,
423     NULL
424   },
425   {
426     EL_EXIT_CLOSING,
427     EL_EXIT_CLOSED,
428     29,
429     NULL,
430     NULL,
431     NULL
432   },
433   {
434     EL_SP_EXIT_OPENING,
435     EL_SP_EXIT_OPEN,
436     29,
437     NULL,
438     NULL,
439     NULL
440   },
441   {
442     EL_SP_EXIT_CLOSING,
443     EL_SP_EXIT_CLOSED,
444     29,
445     NULL,
446     NULL,
447     NULL
448   },
449   {
450     EL_SWITCHGATE_OPENING,
451     EL_SWITCHGATE_OPEN,
452     29,
453     NULL,
454     NULL,
455     NULL
456   },
457   {
458     EL_SWITCHGATE_CLOSING,
459     EL_SWITCHGATE_CLOSED,
460     29,
461     NULL,
462     NULL,
463     NULL
464   },
465   {
466     EL_TIMEGATE_OPENING,
467     EL_TIMEGATE_OPEN,
468     29,
469     NULL,
470     NULL,
471     NULL
472   },
473   {
474     EL_TIMEGATE_CLOSING,
475     EL_TIMEGATE_CLOSED,
476     29,
477     NULL,
478     NULL,
479     NULL
480   },
481
482   {
483     EL_ACID_SPLASH_LEFT,
484     EL_EMPTY,
485     8,
486     NULL,
487     NULL,
488     NULL
489   },
490   {
491     EL_ACID_SPLASH_RIGHT,
492     EL_EMPTY,
493     8,
494     NULL,
495     NULL,
496     NULL
497   },
498   {
499     EL_SP_BUGGY_BASE,
500     EL_SP_BUGGY_BASE_ACTIVATING,
501     0,
502     InitBuggyBase,
503     NULL,
504     NULL
505   },
506   {
507     EL_SP_BUGGY_BASE_ACTIVATING,
508     EL_SP_BUGGY_BASE_ACTIVE,
509     0,
510     InitBuggyBase,
511     NULL,
512     NULL
513   },
514   {
515     EL_SP_BUGGY_BASE_ACTIVE,
516     EL_SP_BUGGY_BASE,
517     0,
518     InitBuggyBase,
519     WarnBuggyBase,
520     NULL
521   },
522   {
523     EL_TRAP,
524     EL_TRAP_ACTIVE,
525     0,
526     InitTrap,
527     NULL,
528     ActivateTrap
529   },
530   {
531     EL_TRAP_ACTIVE,
532     EL_TRAP,
533     31,
534     NULL,
535     ChangeActiveTrap,
536     NULL
537   },
538   {
539     EL_ROBOT_WHEEL_ACTIVE,
540     EL_ROBOT_WHEEL,
541     0,
542     InitRobotWheel,
543     RunRobotWheel,
544     StopRobotWheel
545   },
546   {
547     EL_TIMEGATE_SWITCH_ACTIVE,
548     EL_TIMEGATE_SWITCH,
549     0,
550     InitTimegateWheel,
551     RunTimegateWheel,
552     NULL
553   },
554
555   {
556     EL_UNDEFINED,
557     EL_UNDEFINED,
558     -1,
559     NULL,
560     NULL,
561     NULL
562   }
563 };
564
565 struct
566 {
567   int element;
568   int push_delay_fixed, push_delay_random;
569 }
570 push_delay_list[] =
571 {
572   { EL_SPRING,                  0, 0 },
573   { EL_BALLOON,                 0, 0 },
574
575   { EL_SOKOBAN_OBJECT,          2, 0 },
576   { EL_SOKOBAN_FIELD_FULL,      2, 0 },
577   { EL_SATELLITE,               2, 0 },
578   { EL_SP_DISK_YELLOW,          2, 0 },
579
580   { EL_UNDEFINED,               0, 0 },
581 };
582
583 struct
584 {
585   int element;
586   int move_stepsize;
587 }
588 move_stepsize_list[] =
589 {
590   { EL_AMOEBA_DROP,             2 },
591   { EL_AMOEBA_DROPPING,         2 },
592   { EL_QUICKSAND_FILLING,       1 },
593   { EL_QUICKSAND_EMPTYING,      1 },
594   { EL_MAGIC_WALL_FILLING,      2 },
595   { EL_BD_MAGIC_WALL_FILLING,   2 },
596   { EL_MAGIC_WALL_EMPTYING,     2 },
597   { EL_BD_MAGIC_WALL_EMPTYING,  2 },
598
599   { EL_UNDEFINED,               0 },
600 };
601
602 struct
603 {
604   int element;
605   int count;
606 }
607 collect_count_list[] =
608 {
609   { EL_EMERALD,                 1 },
610   { EL_BD_DIAMOND,              1 },
611   { EL_EMERALD_YELLOW,          1 },
612   { EL_EMERALD_RED,             1 },
613   { EL_EMERALD_PURPLE,          1 },
614   { EL_DIAMOND,                 3 },
615   { EL_SP_INFOTRON,             1 },
616   { EL_PEARL,                   5 },
617   { EL_CRYSTAL,                 8 },
618
619   { EL_UNDEFINED,               0 },
620 };
621
622 struct
623 {
624   int element;
625   int direction;
626 }
627 access_direction_list[] =
628 {
629   { EL_TUBE_ANY,                        MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN },
630   { EL_TUBE_VERTICAL,                                        MV_UP | MV_DOWN },
631   { EL_TUBE_HORIZONTAL,                 MV_LEFT | MV_RIGHT                   },
632   { EL_TUBE_VERTICAL_LEFT,              MV_LEFT |            MV_UP | MV_DOWN },
633   { EL_TUBE_VERTICAL_RIGHT,                       MV_RIGHT | MV_UP | MV_DOWN },
634   { EL_TUBE_HORIZONTAL_UP,              MV_LEFT | MV_RIGHT | MV_UP           },
635   { EL_TUBE_HORIZONTAL_DOWN,            MV_LEFT | MV_RIGHT |         MV_DOWN },
636   { EL_TUBE_LEFT_UP,                    MV_LEFT |            MV_UP           },
637   { EL_TUBE_LEFT_DOWN,                  MV_LEFT |                    MV_DOWN },
638   { EL_TUBE_RIGHT_UP,                             MV_RIGHT | MV_UP           },
639   { EL_TUBE_RIGHT_DOWN,                           MV_RIGHT |         MV_DOWN },
640
641   { EL_SP_PORT_LEFT,                              MV_RIGHT                   },
642   { EL_SP_PORT_RIGHT,                   MV_LEFT                              },
643   { EL_SP_PORT_UP,                                                   MV_DOWN },
644   { EL_SP_PORT_DOWN,                                         MV_UP           },
645   { EL_SP_PORT_HORIZONTAL,              MV_LEFT | MV_RIGHT                   },
646   { EL_SP_PORT_VERTICAL,                                     MV_UP | MV_DOWN },
647   { EL_SP_PORT_ANY,                     MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN },
648   { EL_SP_GRAVITY_PORT_LEFT,                      MV_RIGHT                   },
649   { EL_SP_GRAVITY_PORT_RIGHT,           MV_LEFT                              },
650   { EL_SP_GRAVITY_PORT_UP,                                           MV_DOWN },
651   { EL_SP_GRAVITY_PORT_DOWN,                                 MV_UP           },
652   { EL_SP_GRAVITY_ON_PORT_LEFT,                   MV_RIGHT                   },
653   { EL_SP_GRAVITY_ON_PORT_RIGHT,        MV_LEFT                              },
654   { EL_SP_GRAVITY_ON_PORT_UP,                                        MV_DOWN },
655   { EL_SP_GRAVITY_ON_PORT_DOWN,                              MV_UP           },
656   { EL_SP_GRAVITY_OFF_PORT_LEFT,                  MV_RIGHT                   },
657   { EL_SP_GRAVITY_OFF_PORT_RIGHT,       MV_LEFT                              },
658   { EL_SP_GRAVITY_OFF_PORT_UP,                                       MV_DOWN },
659   { EL_SP_GRAVITY_OFF_PORT_DOWN,                             MV_UP           },
660
661   { EL_UNDEFINED,                       MV_NO_MOVING                         }
662 };
663
664 static unsigned long trigger_events[MAX_NUM_ELEMENTS];
665
666 #define IS_AUTO_CHANGING(e)     (element_info[e].change_events & \
667                                  CH_EVENT_BIT(CE_DELAY))
668 #define IS_JUST_CHANGING(x, y)  (ChangeDelay[x][y] != 0)
669 #define IS_CHANGING(x, y)       (IS_AUTO_CHANGING(Feld[x][y]) || \
670                                  IS_JUST_CHANGING(x, y))
671
672 #define CE_PAGE(e, ce)          (element_info[e].event_page[ce])
673
674
675 void GetPlayerConfig()
676 {
677   if (!audio.sound_available)
678     setup.sound_simple = FALSE;
679
680   if (!audio.loops_available)
681     setup.sound_loops = FALSE;
682
683   if (!audio.music_available)
684     setup.sound_music = FALSE;
685
686   if (!video.fullscreen_available)
687     setup.fullscreen = FALSE;
688
689   setup.sound = (setup.sound_simple || setup.sound_loops || setup.sound_music);
690
691   SetAudioMode(setup.sound);
692   InitJoysticks();
693 }
694
695 static int getBeltNrFromBeltElement(int element)
696 {
697   return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
698           element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
699           element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
700 }
701
702 static int getBeltNrFromBeltActiveElement(int element)
703 {
704   return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
705           element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
706           element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
707 }
708
709 static int getBeltNrFromBeltSwitchElement(int element)
710 {
711   return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
712           element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
713           element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
714 }
715
716 static int getBeltDirNrFromBeltSwitchElement(int element)
717 {
718   static int belt_base_element[4] =
719   {
720     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
721     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
722     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
723     EL_CONVEYOR_BELT_4_SWITCH_LEFT
724   };
725
726   int belt_nr = getBeltNrFromBeltSwitchElement(element);
727   int belt_dir_nr = element - belt_base_element[belt_nr];
728
729   return (belt_dir_nr % 3);
730 }
731
732 static int getBeltDirFromBeltSwitchElement(int element)
733 {
734   static int belt_move_dir[3] =
735   {
736     MV_LEFT,
737     MV_NO_MOVING,
738     MV_RIGHT
739   };
740
741   int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
742
743   return belt_move_dir[belt_dir_nr];
744 }
745
746 static void InitPlayerField(int x, int y, int element, boolean init_game)
747 {
748   if (element == EL_SP_MURPHY)
749   {
750     if (init_game)
751     {
752       if (stored_player[0].present)
753       {
754         Feld[x][y] = EL_SP_MURPHY_CLONE;
755
756         return;
757       }
758       else
759       {
760         stored_player[0].use_murphy_graphic = TRUE;
761       }
762
763       Feld[x][y] = EL_PLAYER_1;
764     }
765   }
766
767   if (init_game)
768   {
769     struct PlayerInfo *player = &stored_player[Feld[x][y] - EL_PLAYER_1];
770     int jx = player->jx, jy = player->jy;
771
772     player->present = TRUE;
773
774     player->block_last_field = (element == EL_SP_MURPHY ?
775                                 level.sp_block_last_field :
776                                 level.block_last_field);
777
778 #if USE_NEW_BLOCK_STYLE
779 #if 1
780     player->block_delay = (player->block_last_field ?
781                            (element == EL_SP_MURPHY ?
782                             level.sp_block_delay :
783                             level.block_delay) : 0);
784 #else
785     player->block_delay = (element == EL_SP_MURPHY ?
786                            (player->block_last_field ? 7 : 1) :
787                            (player->block_last_field ? 7 : 1));
788 #endif
789
790 #if 0
791     printf("::: block_last_field == %d, block_delay = %d\n",
792            player->block_last_field, player->block_delay);
793 #endif
794 #endif
795
796     if (!options.network || player->connected)
797     {
798       player->active = TRUE;
799
800       /* remove potentially duplicate players */
801       if (StorePlayer[jx][jy] == Feld[x][y])
802         StorePlayer[jx][jy] = 0;
803
804       StorePlayer[x][y] = Feld[x][y];
805
806       if (options.debug)
807       {
808         printf("Player %d activated.\n", player->element_nr);
809         printf("[Local player is %d and currently %s.]\n",
810                local_player->element_nr,
811                local_player->active ? "active" : "not active");
812       }
813     }
814
815     Feld[x][y] = EL_EMPTY;
816
817     player->jx = player->last_jx = x;
818     player->jy = player->last_jy = y;
819   }
820 }
821
822 static void InitField(int x, int y, boolean init_game)
823 {
824   int element = Feld[x][y];
825
826   switch (element)
827   {
828     case EL_SP_MURPHY:
829     case EL_PLAYER_1:
830     case EL_PLAYER_2:
831     case EL_PLAYER_3:
832     case EL_PLAYER_4:
833       InitPlayerField(x, y, element, init_game);
834       break;
835
836     case EL_SOKOBAN_FIELD_PLAYER:
837       element = Feld[x][y] = EL_PLAYER_1;
838       InitField(x, y, init_game);
839
840       element = Feld[x][y] = EL_SOKOBAN_FIELD_EMPTY;
841       InitField(x, y, init_game);
842       break;
843
844     case EL_SOKOBAN_FIELD_EMPTY:
845       local_player->sokobanfields_still_needed++;
846       break;
847
848     case EL_STONEBLOCK:
849       if (x < lev_fieldx-1 && Feld[x+1][y] == EL_ACID)
850         Feld[x][y] = EL_ACID_POOL_TOPLEFT;
851       else if (x > 0 && Feld[x-1][y] == EL_ACID)
852         Feld[x][y] = EL_ACID_POOL_TOPRIGHT;
853       else if (y > 0 && Feld[x][y-1] == EL_ACID_POOL_TOPLEFT)
854         Feld[x][y] = EL_ACID_POOL_BOTTOMLEFT;
855       else if (y > 0 && Feld[x][y-1] == EL_ACID)
856         Feld[x][y] = EL_ACID_POOL_BOTTOM;
857       else if (y > 0 && Feld[x][y-1] == EL_ACID_POOL_TOPRIGHT)
858         Feld[x][y] = EL_ACID_POOL_BOTTOMRIGHT;
859       break;
860
861     case EL_BUG_RIGHT:
862     case EL_BUG_UP:
863     case EL_BUG_LEFT:
864     case EL_BUG_DOWN:
865     case EL_BUG:
866     case EL_SPACESHIP_RIGHT:
867     case EL_SPACESHIP_UP:
868     case EL_SPACESHIP_LEFT:
869     case EL_SPACESHIP_DOWN:
870     case EL_SPACESHIP:
871     case EL_BD_BUTTERFLY_RIGHT:
872     case EL_BD_BUTTERFLY_UP:
873     case EL_BD_BUTTERFLY_LEFT:
874     case EL_BD_BUTTERFLY_DOWN:
875     case EL_BD_BUTTERFLY:
876     case EL_BD_FIREFLY_RIGHT:
877     case EL_BD_FIREFLY_UP:
878     case EL_BD_FIREFLY_LEFT:
879     case EL_BD_FIREFLY_DOWN:
880     case EL_BD_FIREFLY:
881     case EL_PACMAN_RIGHT:
882     case EL_PACMAN_UP:
883     case EL_PACMAN_LEFT:
884     case EL_PACMAN_DOWN:
885     case EL_YAMYAM:
886     case EL_DARK_YAMYAM:
887     case EL_ROBOT:
888     case EL_PACMAN:
889     case EL_SP_SNIKSNAK:
890     case EL_SP_ELECTRON:
891     case EL_MOLE_LEFT:
892     case EL_MOLE_RIGHT:
893     case EL_MOLE_UP:
894     case EL_MOLE_DOWN:
895     case EL_MOLE:
896       InitMovDir(x, y);
897       break;
898
899     case EL_AMOEBA_FULL:
900     case EL_BD_AMOEBA:
901       InitAmoebaNr(x, y);
902       break;
903
904     case EL_AMOEBA_DROP:
905       if (y == lev_fieldy - 1)
906       {
907         Feld[x][y] = EL_AMOEBA_GROWING;
908         Store[x][y] = EL_AMOEBA_WET;
909       }
910       break;
911
912     case EL_DYNAMITE_ACTIVE:
913     case EL_SP_DISK_RED_ACTIVE:
914     case EL_DYNABOMB_PLAYER_1_ACTIVE:
915     case EL_DYNABOMB_PLAYER_2_ACTIVE:
916     case EL_DYNABOMB_PLAYER_3_ACTIVE:
917     case EL_DYNABOMB_PLAYER_4_ACTIVE:
918       MovDelay[x][y] = 96;
919       break;
920
921     case EL_LAMP:
922       local_player->lights_still_needed++;
923       break;
924
925     case EL_PENGUIN:
926       local_player->friends_still_needed++;
927       break;
928
929     case EL_PIG:
930     case EL_DRAGON:
931       GfxDir[x][y] = MovDir[x][y] = 1 << RND(4);
932       break;
933
934 #if 0
935     case EL_SP_EMPTY:
936       Feld[x][y] = EL_EMPTY;
937       break;
938 #endif
939
940 #if 0
941     case EL_EM_KEY_1_FILE:
942       Feld[x][y] = EL_EM_KEY_1;
943       break;
944     case EL_EM_KEY_2_FILE:
945       Feld[x][y] = EL_EM_KEY_2;
946       break;
947     case EL_EM_KEY_3_FILE:
948       Feld[x][y] = EL_EM_KEY_3;
949       break;
950     case EL_EM_KEY_4_FILE:
951       Feld[x][y] = EL_EM_KEY_4;
952       break;
953 #endif
954
955     case EL_CONVEYOR_BELT_1_SWITCH_LEFT:
956     case EL_CONVEYOR_BELT_1_SWITCH_MIDDLE:
957     case EL_CONVEYOR_BELT_1_SWITCH_RIGHT:
958     case EL_CONVEYOR_BELT_2_SWITCH_LEFT:
959     case EL_CONVEYOR_BELT_2_SWITCH_MIDDLE:
960     case EL_CONVEYOR_BELT_2_SWITCH_RIGHT:
961     case EL_CONVEYOR_BELT_3_SWITCH_LEFT:
962     case EL_CONVEYOR_BELT_3_SWITCH_MIDDLE:
963     case EL_CONVEYOR_BELT_3_SWITCH_RIGHT:
964     case EL_CONVEYOR_BELT_4_SWITCH_LEFT:
965     case EL_CONVEYOR_BELT_4_SWITCH_MIDDLE:
966     case EL_CONVEYOR_BELT_4_SWITCH_RIGHT:
967       if (init_game)
968       {
969         int belt_nr = getBeltNrFromBeltSwitchElement(Feld[x][y]);
970         int belt_dir = getBeltDirFromBeltSwitchElement(Feld[x][y]);
971         int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(Feld[x][y]);
972
973         if (game.belt_dir_nr[belt_nr] == 3)     /* initial value */
974         {
975           game.belt_dir[belt_nr] = belt_dir;
976           game.belt_dir_nr[belt_nr] = belt_dir_nr;
977         }
978         else    /* more than one switch -- set it like the first switch */
979         {
980           Feld[x][y] = Feld[x][y] - belt_dir_nr + game.belt_dir_nr[belt_nr];
981         }
982       }
983       break;
984
985     case EL_SWITCHGATE_SWITCH_DOWN:     /* always start with same switch pos */
986       if (init_game)
987         Feld[x][y] = EL_SWITCHGATE_SWITCH_UP;
988       break;
989
990     case EL_LIGHT_SWITCH_ACTIVE:
991       if (init_game)
992         game.light_time_left = level.time_light * FRAMES_PER_SECOND;
993       break;
994
995     default:
996       if (IS_CUSTOM_ELEMENT(element) && CAN_MOVE(element))
997         InitMovDir(x, y);
998       else if (IS_GROUP_ELEMENT(element))
999       {
1000         struct ElementGroupInfo *group = element_info[element].group;
1001         int last_anim_random_frame = gfx.anim_random_frame;
1002         int element_pos;
1003
1004         if (group->choice_mode == ANIM_RANDOM)
1005           gfx.anim_random_frame = RND(group->num_elements_resolved);
1006
1007         element_pos = getAnimationFrame(group->num_elements_resolved, 1,
1008                                         group->choice_mode, 0,
1009                                         group->choice_pos);
1010
1011         if (group->choice_mode == ANIM_RANDOM)
1012           gfx.anim_random_frame = last_anim_random_frame;
1013
1014         group->choice_pos++;
1015
1016         Feld[x][y] = group->element_resolved[element_pos];
1017
1018         InitField(x, y, init_game);
1019       }
1020       break;
1021   }
1022 }
1023
1024 static inline void InitField_WithBug1(int x, int y, boolean init_game)
1025 {
1026   InitField(x, y, init_game);
1027
1028   /* not needed to call InitMovDir() -- already done by InitField()! */
1029   if (game.engine_version < VERSION_IDENT(3,1,0,0) &&
1030       CAN_MOVE(Feld[x][y]))
1031     InitMovDir(x, y);
1032 }
1033
1034 static inline void InitField_WithBug2(int x, int y, boolean init_game)
1035 {
1036   int old_element = Feld[x][y];
1037
1038   InitField(x, y, init_game);
1039
1040   /* not needed to call InitMovDir() -- already done by InitField()! */
1041   if (game.engine_version < VERSION_IDENT(3,1,0,0) &&
1042       CAN_MOVE(old_element) &&
1043       (old_element < EL_MOLE_LEFT || old_element > EL_MOLE_DOWN))
1044     InitMovDir(x, y);
1045
1046   /* this case is in fact a combination of not less than three bugs:
1047      first, it calls InitMovDir() for elements that can move, although this is
1048      already done by InitField(); then, it checks the element that was at this
1049      field _before_ the call to InitField() (which can change it); lastly, it
1050      was not called for "mole with direction" elements, which were treated as
1051      "cannot move" due to (fixed) wrong element initialization in "src/init.c"
1052   */
1053 }
1054
1055 inline void DrawGameValue_Emeralds(int value)
1056 {
1057   DrawText(DX_EMERALDS, DY_EMERALDS, int2str(value, 3), FONT_TEXT_2);
1058 }
1059
1060 inline void DrawGameValue_Dynamite(int value)
1061 {
1062   DrawText(DX_DYNAMITE, DY_DYNAMITE, int2str(value, 3), FONT_TEXT_2);
1063 }
1064
1065 inline void DrawGameValue_Keys(int key[4])
1066 {
1067   int i;
1068
1069   for (i = 0; i < MAX_KEYS; i++)
1070     if (key[i])
1071       DrawMiniGraphicExt(drawto, DX_KEYS + i * MINI_TILEX, DY_KEYS,
1072                          el2edimg(EL_KEY_1 + i));
1073 }
1074
1075 inline void DrawGameValue_Score(int value)
1076 {
1077   DrawText(DX_SCORE, DY_SCORE, int2str(value, 5), FONT_TEXT_2);
1078 }
1079
1080 inline void DrawGameValue_Time(int value)
1081 {
1082   if (value < 1000)
1083     DrawText(DX_TIME1, DY_TIME, int2str(value, 3), FONT_TEXT_2);
1084   else
1085     DrawText(DX_TIME2, DY_TIME, int2str(value, 4), FONT_LEVEL_NUMBER);
1086 }
1087
1088 inline void DrawGameValue_Level(int value)
1089 {
1090   if (level_nr < 100)
1091     DrawText(DX_LEVEL, DY_LEVEL, int2str(value, 2), FONT_TEXT_2);
1092   else
1093   {
1094     /* misuse area for displaying emeralds to draw bigger level number */
1095     DrawTextExt(drawto, DX_EMERALDS, DY_EMERALDS,
1096                 int2str(value, 3), FONT_LEVEL_NUMBER, BLIT_OPAQUE);
1097
1098     /* now copy it to the area for displaying level number */
1099     BlitBitmap(drawto, drawto,
1100                DX_EMERALDS, DY_EMERALDS + 1,
1101                getFontWidth(FONT_LEVEL_NUMBER) * 3,
1102                getFontHeight(FONT_LEVEL_NUMBER) - 1,
1103                DX_LEVEL - 1, DY_LEVEL + 1);
1104
1105     /* restore the area for displaying emeralds */
1106     DrawGameValue_Emeralds(local_player->gems_still_needed);
1107
1108     /* yes, this is all really ugly :-) */
1109   }
1110 }
1111
1112 void DrawAllGameValues(int emeralds, int dynamite, int score, int time,
1113                        int key_bits)
1114 {
1115   int key[4];
1116   int i;
1117
1118   for (i = 0; i < MAX_KEYS; i++)
1119     key[i] = key_bits & (1 << i);
1120
1121   DrawGameValue_Emeralds(emeralds);
1122   DrawGameValue_Dynamite(dynamite);
1123   DrawGameValue_Score(score);
1124   DrawGameValue_Time(time);
1125
1126   DrawGameValue_Keys(key);
1127 }
1128
1129 void DrawGameDoorValues()
1130 {
1131   int i;
1132
1133   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
1134   {
1135     DrawGameDoorValues_EM();
1136
1137     return;
1138   }
1139
1140   DrawGameValue_Level(level_nr);
1141
1142   DrawGameValue_Emeralds(local_player->gems_still_needed);
1143   DrawGameValue_Dynamite(local_player->inventory_size);
1144   DrawGameValue_Score(local_player->score);
1145   DrawGameValue_Time(TimeLeft);
1146
1147   for (i = 0; i < MAX_PLAYERS; i++)
1148     DrawGameValue_Keys(stored_player[i].key);
1149 }
1150
1151 static void resolve_group_element(int group_element, int recursion_depth)
1152 {
1153   static int group_nr;
1154   static struct ElementGroupInfo *group;
1155   struct ElementGroupInfo *actual_group = element_info[group_element].group;
1156   int i;
1157
1158   if (recursion_depth > NUM_GROUP_ELEMENTS)     /* recursion too deep */
1159   {
1160     Error(ERR_WARN, "recursion too deep when resolving group element %d",
1161           group_element - EL_GROUP_START + 1);
1162
1163     /* replace element which caused too deep recursion by question mark */
1164     group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
1165
1166     return;
1167   }
1168
1169   if (recursion_depth == 0)                     /* initialization */
1170   {
1171     group = element_info[group_element].group;
1172     group_nr = group_element - EL_GROUP_START;
1173
1174     group->num_elements_resolved = 0;
1175     group->choice_pos = 0;
1176   }
1177
1178   for (i = 0; i < actual_group->num_elements; i++)
1179   {
1180     int element = actual_group->element[i];
1181
1182     if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
1183       break;
1184
1185     if (IS_GROUP_ELEMENT(element))
1186       resolve_group_element(element, recursion_depth + 1);
1187     else
1188     {
1189       group->element_resolved[group->num_elements_resolved++] = element;
1190       element_info[element].in_group[group_nr] = TRUE;
1191     }
1192   }
1193
1194 #if 0
1195   if (recursion_depth == 0 && group_element <= EL_GROUP_4)
1196   {
1197     printf("::: group %d: %d resolved elements\n",
1198            group_element - EL_GROUP_START, group->num_elements_resolved);
1199     for (i = 0; i < group->num_elements_resolved; i++)
1200       printf("::: - %d ['%s']\n", group->element_resolved[i],
1201              element_info[group->element_resolved[i]].token_name);
1202   }
1203 #endif
1204 }
1205
1206
1207 /*
1208   =============================================================================
1209   InitGameEngine()
1210   -----------------------------------------------------------------------------
1211   initialize game engine due to level / tape version number
1212   =============================================================================
1213 */
1214
1215 static void InitGameEngine()
1216 {
1217   int i, j, k;
1218
1219   /* set game engine from tape file when re-playing, else from level file */
1220   game.engine_version = (tape.playing ? tape.engine_version :
1221                          level.game_version);
1222
1223   /* ---------------------------------------------------------------------- */
1224   /* set flags for bugs and changes according to active game engine version */
1225   /* ---------------------------------------------------------------------- */
1226
1227   /*
1228     Type of bug/change:
1229     Before 3.1.0, custom elements that "change when pushing" changed directly
1230     after the player started pushing them (until then handled in "DigField()").
1231     Since 3.1.0, these custom elements are not changed until the "pushing"
1232     move of the element is finished (now handled in "ContinueMoving()").
1233
1234     Affected levels/tapes:
1235     The first condition is generally needed for all levels/tapes before version
1236     3.1.0, which might use the old behaviour before it was changed; known tapes
1237     that are affected are some tapes from the level set "Walpurgis Gardens" by
1238     Jamie Cullen.
1239     The second condition is an exception from the above case and is needed for
1240     the special case of tapes recorded with game (not engine!) version 3.1.0 or
1241     above (including some development versions of 3.1.0), but before it was
1242     known that this change would break tapes like the above and was fixed in
1243     3.1.1, so that the changed behaviour was active although the engine version
1244     while recording maybe was before 3.1.0. There is at least one tape that is
1245     affected by this exception, which is the tape for the one-level set "Bug
1246     Machine" by Juergen Bonhagen.
1247   */
1248
1249   game.use_bug_change_when_pushing =
1250     (game.engine_version < VERSION_IDENT(3,1,0,0) &&
1251      !(tape.playing &&
1252        tape.game_version >= VERSION_IDENT(3,1,0,0) &&
1253        tape.game_version <  VERSION_IDENT(3,1,1,0)));
1254
1255   /* ---------------------------------------------------------------------- */
1256
1257   /* dynamically adjust element properties according to game engine version */
1258   InitElementPropertiesEngine(game.engine_version);
1259
1260 #if 0
1261   printf("level %d: level version == %06d\n", level_nr, level.game_version);
1262   printf("          tape version == %06d [%s] [file: %06d]\n",
1263          tape.engine_version, (tape.playing ? "PLAYING" : "RECORDING"),
1264          tape.file_version);
1265   printf("       => game.engine_version == %06d\n", game.engine_version);
1266 #endif
1267
1268   /* ---------- recursively resolve group elements ------------------------- */
1269
1270   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1271     for (j = 0; j < NUM_GROUP_ELEMENTS; j++)
1272       element_info[i].in_group[j] = FALSE;
1273
1274   for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
1275     resolve_group_element(EL_GROUP_START + i, 0);
1276
1277   /* ---------- initialize player's initial move delay --------------------- */
1278
1279 #if USE_NEW_MOVE_DELAY
1280   /* dynamically adjust player properties according to level information */
1281   game.initial_move_delay_value =
1282     (level.double_speed ? MOVE_DELAY_HIGH_SPEED : MOVE_DELAY_NORMAL_SPEED);
1283
1284   /* dynamically adjust player properties according to game engine version */
1285   game.initial_move_delay = (game.engine_version <= VERSION_IDENT(2,0,1,0) ?
1286                              game.initial_move_delay_value : 0);
1287 #else
1288   /* dynamically adjust player properties according to game engine version */
1289   game.initial_move_delay =
1290     (game.engine_version <= VERSION_IDENT(2,0,1,0) ? INITIAL_MOVE_DELAY_ON :
1291      INITIAL_MOVE_DELAY_OFF);
1292
1293   /* dynamically adjust player properties according to level information */
1294   game.initial_move_delay_value =
1295     (level.double_speed ? MOVE_DELAY_HIGH_SPEED : MOVE_DELAY_NORMAL_SPEED);
1296 #endif
1297
1298   /* ---------- initialize player's initial push delay --------------------- */
1299
1300   /* dynamically adjust player properties according to game engine version */
1301   game.initial_push_delay_value =
1302     (game.engine_version < VERSION_IDENT(3,0,7,1) ? 5 : -1);
1303
1304   /* ---------- initialize changing elements ------------------------------- */
1305
1306   /* initialize changing elements information */
1307   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1308   {
1309     struct ElementInfo *ei = &element_info[i];
1310
1311     /* this pointer might have been changed in the level editor */
1312     ei->change = &ei->change_page[0];
1313
1314     if (!IS_CUSTOM_ELEMENT(i))
1315     {
1316       ei->change->target_element = EL_EMPTY_SPACE;
1317       ei->change->delay_fixed = 0;
1318       ei->change->delay_random = 0;
1319       ei->change->delay_frames = 1;
1320     }
1321
1322     ei->change_events = CE_BITMASK_DEFAULT;
1323     for (j = 0; j < NUM_CHANGE_EVENTS; j++)
1324     {
1325       ei->event_page_nr[j] = 0;
1326       ei->event_page[j] = &ei->change_page[0];
1327     }
1328   }
1329
1330   /* add changing elements from pre-defined list */
1331   for (i = 0; change_delay_list[i].element != EL_UNDEFINED; i++)
1332   {
1333     struct ChangingElementInfo *ch_delay = &change_delay_list[i];
1334     struct ElementInfo *ei = &element_info[ch_delay->element];
1335
1336     ei->change->target_element       = ch_delay->target_element;
1337     ei->change->delay_fixed          = ch_delay->change_delay;
1338
1339     ei->change->pre_change_function  = ch_delay->pre_change_function;
1340     ei->change->change_function      = ch_delay->change_function;
1341     ei->change->post_change_function = ch_delay->post_change_function;
1342
1343     ei->change_events |= CH_EVENT_BIT(CE_DELAY);
1344
1345 #if 1
1346     SET_PROPERTY(ch_delay->element, EP_CAN_CHANGE, TRUE);
1347 #endif
1348   }
1349
1350 #if 1
1351   /* add change events from custom element configuration */
1352   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
1353   {
1354     struct ElementInfo *ei = &element_info[EL_CUSTOM_START + i];
1355
1356     for (j = 0; j < ei->num_change_pages; j++)
1357     {
1358       if (!ei->change_page[j].can_change)
1359         continue;
1360
1361       for (k = 0; k < NUM_CHANGE_EVENTS; k++)
1362       {
1363         /* only add event page for the first page found with this event */
1364         if (ei->change_page[j].events & CH_EVENT_BIT(k) &&
1365             !(ei->change_events & CH_EVENT_BIT(k)))
1366         {
1367           ei->change_events |= CH_EVENT_BIT(k);
1368           ei->event_page_nr[k] = j;
1369           ei->event_page[k] = &ei->change_page[j];
1370         }
1371       }
1372     }
1373   }
1374
1375 #else
1376
1377   /* add change events from custom element configuration */
1378   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
1379   {
1380     int element = EL_CUSTOM_START + i;
1381
1382     /* only add custom elements that change after fixed/random frame delay */
1383     if (CAN_CHANGE(element) && HAS_CHANGE_EVENT(element, CE_DELAY))
1384       element_info[element].change_events |= CH_EVENT_BIT(CE_DELAY);
1385   }
1386 #endif
1387
1388   /* ---------- initialize run-time trigger player and element ------------- */
1389
1390   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
1391   {
1392     struct ElementInfo *ei = &element_info[EL_CUSTOM_START + i];
1393
1394     for (j = 0; j < ei->num_change_pages; j++)
1395     {
1396       ei->change_page[j].actual_trigger_element = EL_EMPTY;
1397       ei->change_page[j].actual_trigger_player = EL_PLAYER_1;
1398     }
1399   }
1400
1401   /* ---------- initialize trigger events ---------------------------------- */
1402
1403   /* initialize trigger events information */
1404   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1405     trigger_events[i] = EP_BITMASK_DEFAULT;
1406
1407 #if 1
1408   /* add trigger events from element change event properties */
1409   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1410   {
1411     struct ElementInfo *ei = &element_info[i];
1412
1413     for (j = 0; j < ei->num_change_pages; j++)
1414     {
1415       if (!ei->change_page[j].can_change)
1416         continue;
1417
1418       if (ei->change_page[j].events & CH_EVENT_BIT(CE_BY_OTHER_ACTION))
1419       {
1420         int trigger_element = ei->change_page[j].trigger_element;
1421
1422         if (IS_GROUP_ELEMENT(trigger_element))
1423         {
1424           struct ElementGroupInfo *group = element_info[trigger_element].group;
1425
1426           for (k = 0; k < group->num_elements_resolved; k++)
1427             trigger_events[group->element_resolved[k]]
1428               |= ei->change_page[j].events;
1429         }
1430         else
1431           trigger_events[trigger_element] |= ei->change_page[j].events;
1432       }
1433     }
1434   }
1435 #else
1436   /* add trigger events from element change event properties */
1437   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1438     if (HAS_CHANGE_EVENT(i, CE_BY_OTHER_ACTION))
1439       trigger_events[element_info[i].change->trigger_element] |=
1440         element_info[i].change->events;
1441 #endif
1442
1443   /* ---------- initialize push delay -------------------------------------- */
1444
1445   /* initialize push delay values to default */
1446   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1447   {
1448     if (!IS_CUSTOM_ELEMENT(i))
1449     {
1450       element_info[i].push_delay_fixed  = game.default_push_delay_fixed;
1451       element_info[i].push_delay_random = game.default_push_delay_random;
1452     }
1453   }
1454
1455   /* set push delay value for certain elements from pre-defined list */
1456   for (i = 0; push_delay_list[i].element != EL_UNDEFINED; i++)
1457   {
1458     int e = push_delay_list[i].element;
1459
1460     element_info[e].push_delay_fixed  = push_delay_list[i].push_delay_fixed;
1461     element_info[e].push_delay_random = push_delay_list[i].push_delay_random;
1462   }
1463
1464   /* set push delay value for Supaplex elements for newer engine versions */
1465   if (game.engine_version >= VERSION_IDENT(3,1,0,0))
1466   {
1467     for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1468     {
1469       if (IS_SP_ELEMENT(i))
1470       {
1471 #if USE_NEW_MOVE_STYLE
1472         /* set SP push delay to just enough to push under a falling zonk */
1473         int delay = (game.engine_version >= VERSION_IDENT(3,1,1,0) ? 8 : 6);
1474
1475         element_info[i].push_delay_fixed  = delay;
1476         element_info[i].push_delay_random = 0;
1477 #else
1478         element_info[i].push_delay_fixed  = 6;  /* just enough to escape ... */
1479         element_info[i].push_delay_random = 0;  /* ... from falling zonk     */
1480 #endif
1481       }
1482     }
1483   }
1484
1485   /* ---------- initialize move stepsize ----------------------------------- */
1486
1487   /* initialize move stepsize values to default */
1488   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1489     if (!IS_CUSTOM_ELEMENT(i))
1490       element_info[i].move_stepsize = MOVE_STEPSIZE_NORMAL;
1491
1492   /* set move stepsize value for certain elements from pre-defined list */
1493   for (i = 0; move_stepsize_list[i].element != EL_UNDEFINED; i++)
1494   {
1495     int e = move_stepsize_list[i].element;
1496
1497     element_info[e].move_stepsize = move_stepsize_list[i].move_stepsize;
1498   }
1499
1500 #if 0
1501   /* ---------- initialize move dig/leave ---------------------------------- */
1502
1503   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1504   {
1505     element_info[i].can_leave_element = FALSE;
1506     element_info[i].can_leave_element_last = FALSE;
1507   }
1508 #endif
1509
1510   /* ---------- initialize gem count --------------------------------------- */
1511
1512   /* initialize gem count values for each element */
1513   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1514     if (!IS_CUSTOM_ELEMENT(i))
1515       element_info[i].collect_count = 0;
1516
1517   /* add gem count values for all elements from pre-defined list */
1518   for (i = 0; collect_count_list[i].element != EL_UNDEFINED; i++)
1519     element_info[collect_count_list[i].element].collect_count =
1520       collect_count_list[i].count;
1521
1522   /* ---------- initialize access direction -------------------------------- */
1523
1524   /* initialize access direction values to default (access from every side) */
1525   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1526     if (!IS_CUSTOM_ELEMENT(i))
1527       element_info[i].access_direction = MV_ALL_DIRECTIONS;
1528
1529   /* set access direction value for certain elements from pre-defined list */
1530   for (i = 0; access_direction_list[i].element != EL_UNDEFINED; i++)
1531     element_info[access_direction_list[i].element].access_direction =
1532       access_direction_list[i].direction;
1533 }
1534
1535
1536 /*
1537   =============================================================================
1538   InitGame()
1539   -----------------------------------------------------------------------------
1540   initialize and start new game
1541   =============================================================================
1542 */
1543
1544 void InitGame()
1545 {
1546   boolean emulate_bd = TRUE;    /* unless non-BOULDERDASH elements found */
1547   boolean emulate_sb = TRUE;    /* unless non-SOKOBAN     elements found */
1548   boolean emulate_sp = TRUE;    /* unless non-SUPAPLEX    elements found */
1549   int i, j, k, x, y;
1550
1551   InitGameEngine();
1552
1553 #if 0
1554 #if DEBUG
1555 #if USE_NEW_AMOEBA_CODE
1556   printf("Using new amoeba code.\n");
1557 #else
1558   printf("Using old amoeba code.\n");
1559 #endif
1560 #endif
1561 #endif
1562
1563   /* don't play tapes over network */
1564   network_playing = (options.network && !tape.playing);
1565
1566   for (i = 0; i < MAX_PLAYERS; i++)
1567   {
1568     struct PlayerInfo *player = &stored_player[i];
1569
1570     player->index_nr = i;
1571     player->index_bit = (1 << i);
1572     player->element_nr = EL_PLAYER_1 + i;
1573
1574     player->present = FALSE;
1575     player->active = FALSE;
1576
1577     player->action = 0;
1578     player->effective_action = 0;
1579     player->programmed_action = 0;
1580
1581     player->score = 0;
1582     player->gems_still_needed = level.gems_needed;
1583     player->sokobanfields_still_needed = 0;
1584     player->lights_still_needed = 0;
1585     player->friends_still_needed = 0;
1586
1587     for (j = 0; j < MAX_KEYS; j++)
1588       player->key[j] = FALSE;
1589
1590     player->dynabomb_count = 0;
1591     player->dynabomb_size = 1;
1592     player->dynabombs_left = 0;
1593     player->dynabomb_xl = FALSE;
1594
1595     player->MovDir = MV_NO_MOVING;
1596     player->MovPos = 0;
1597     player->GfxPos = 0;
1598     player->GfxDir = MV_NO_MOVING;
1599     player->GfxAction = ACTION_DEFAULT;
1600     player->Frame = 0;
1601     player->StepFrame = 0;
1602
1603     player->use_murphy_graphic = FALSE;
1604
1605     player->block_last_field = FALSE;   /* initialized in InitPlayerField() */
1606     player->block_delay = -1;           /* initialized in InitPlayerField() */
1607
1608     player->can_fall_into_acid = CAN_MOVE_INTO_ACID(player->element_nr);
1609
1610     player->actual_frame_counter = 0;
1611
1612     player->step_counter = 0;
1613
1614     player->last_move_dir = MV_NO_MOVING;
1615
1616     player->is_waiting = FALSE;
1617     player->is_moving = FALSE;
1618     player->is_auto_moving = FALSE;
1619     player->is_digging = FALSE;
1620     player->is_snapping = FALSE;
1621     player->is_collecting = FALSE;
1622     player->is_pushing = FALSE;
1623     player->is_switching = FALSE;
1624     player->is_dropping = FALSE;
1625
1626     player->is_bored = FALSE;
1627     player->is_sleeping = FALSE;
1628
1629     player->frame_counter_bored = -1;
1630     player->frame_counter_sleeping = -1;
1631
1632     player->anim_delay_counter = 0;
1633     player->post_delay_counter = 0;
1634
1635     player->action_waiting = ACTION_DEFAULT;
1636     player->last_action_waiting = ACTION_DEFAULT;
1637     player->special_action_bored = ACTION_DEFAULT;
1638     player->special_action_sleeping = ACTION_DEFAULT;
1639
1640     player->num_special_action_bored = 0;
1641     player->num_special_action_sleeping = 0;
1642
1643     /* determine number of special actions for bored and sleeping animation */
1644     for (j = ACTION_BORING_1; j <= ACTION_BORING_LAST; j++)
1645     {
1646       boolean found = FALSE;
1647
1648       for (k = 0; k < NUM_DIRECTIONS; k++)
1649         if (el_act_dir2img(player->element_nr, j, k) !=
1650             el_act_dir2img(player->element_nr, ACTION_DEFAULT, k))
1651           found = TRUE;
1652
1653       if (found)
1654         player->num_special_action_bored++;
1655       else
1656         break;
1657     }
1658     for (j = ACTION_SLEEPING_1; j <= ACTION_SLEEPING_LAST; j++)
1659     {
1660       boolean found = FALSE;
1661
1662       for (k = 0; k < NUM_DIRECTIONS; k++)
1663         if (el_act_dir2img(player->element_nr, j, k) !=
1664             el_act_dir2img(player->element_nr, ACTION_DEFAULT, k))
1665           found = TRUE;
1666
1667       if (found)
1668         player->num_special_action_sleeping++;
1669       else
1670         break;
1671     }
1672
1673     player->switch_x = -1;
1674     player->switch_y = -1;
1675
1676     player->show_envelope = 0;
1677
1678     player->move_delay       = game.initial_move_delay;
1679     player->move_delay_value = game.initial_move_delay_value;
1680
1681     player->move_delay_reset_counter = 0;
1682
1683 #if USE_NEW_PUSH_DELAY
1684     player->push_delay       = -1;      /* initialized when pushing starts */
1685     player->push_delay_value = game.initial_push_delay_value;
1686 #else
1687     player->push_delay       = 0;
1688     player->push_delay_value = game.initial_push_delay_value;
1689 #endif
1690
1691     player->drop_delay = 0;
1692
1693     player->last_jx = player->last_jy = 0;
1694     player->jx = player->jy = 0;
1695
1696     player->shield_normal_time_left = 0;
1697     player->shield_deadly_time_left = 0;
1698
1699     player->inventory_infinite_element = EL_UNDEFINED;
1700     player->inventory_size = 0;
1701
1702     DigField(player, 0, 0, 0, 0, 0, 0, DF_NO_PUSH);
1703     SnapField(player, 0, 0);
1704
1705     player->LevelSolved = FALSE;
1706     player->GameOver = FALSE;
1707   }
1708
1709   network_player_action_received = FALSE;
1710
1711 #if defined(NETWORK_AVALIABLE)
1712   /* initial null action */
1713   if (network_playing)
1714     SendToServer_MovePlayer(MV_NO_MOVING);
1715 #endif
1716
1717   ZX = ZY = -1;
1718   ExitX = ExitY = -1;
1719
1720   FrameCounter = 0;
1721   TimeFrames = 0;
1722   TimePlayed = 0;
1723   TimeLeft = level.time;
1724   TapeTime = 0;
1725
1726   ScreenMovDir = MV_NO_MOVING;
1727   ScreenMovPos = 0;
1728   ScreenGfxPos = 0;
1729
1730   ScrollStepSize = 0;   /* will be correctly initialized by ScrollScreen() */
1731
1732   AllPlayersGone = FALSE;
1733
1734   game.yamyam_content_nr = 0;
1735   game.magic_wall_active = FALSE;
1736   game.magic_wall_time_left = 0;
1737   game.light_time_left = 0;
1738   game.timegate_time_left = 0;
1739   game.switchgate_pos = 0;
1740   game.balloon_dir = MV_NO_MOVING;
1741   game.gravity = level.initial_gravity;
1742   game.explosions_delayed = TRUE;
1743
1744   game.envelope_active = FALSE;
1745
1746   for (i = 0; i < NUM_BELTS; i++)
1747   {
1748     game.belt_dir[i] = MV_NO_MOVING;
1749     game.belt_dir_nr[i] = 3;            /* not moving, next moving left */
1750   }
1751
1752   for (i = 0; i < MAX_NUM_AMOEBA; i++)
1753     AmoebaCnt[i] = AmoebaCnt2[i] = 0;
1754
1755   for (x = 0; x < lev_fieldx; x++)
1756   {
1757     for (y = 0; y < lev_fieldy; y++)
1758     {
1759       Feld[x][y] = level.field[x][y];
1760       MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
1761       ChangeDelay[x][y] = 0;
1762       ChangePage[x][y] = -1;
1763       Store[x][y] = Store2[x][y] = StorePlayer[x][y] = Back[x][y] = 0;
1764       AmoebaNr[x][y] = 0;
1765       WasJustMoving[x][y] = 0;
1766       WasJustFalling[x][y] = 0;
1767       CheckCollision[x][y] = 0;
1768       Stop[x][y] = FALSE;
1769       Pushed[x][y] = FALSE;
1770
1771       Changed[x][y] = CE_BITMASK_DEFAULT;
1772       ChangeEvent[x][y] = CE_BITMASK_DEFAULT;
1773
1774       ExplodePhase[x][y] = 0;
1775       ExplodeDelay[x][y] = 0;
1776       ExplodeField[x][y] = EX_TYPE_NONE;
1777
1778       RunnerVisit[x][y] = 0;
1779       PlayerVisit[x][y] = 0;
1780
1781       GfxFrame[x][y] = 0;
1782       GfxRandom[x][y] = INIT_GFX_RANDOM();
1783       GfxElement[x][y] = EL_UNDEFINED;
1784       GfxAction[x][y] = ACTION_DEFAULT;
1785       GfxDir[x][y] = MV_NO_MOVING;
1786     }
1787   }
1788
1789   for (y = 0; y < lev_fieldy; y++)
1790   {
1791     for (x = 0; x < lev_fieldx; x++)
1792     {
1793       if (emulate_bd && !IS_BD_ELEMENT(Feld[x][y]))
1794         emulate_bd = FALSE;
1795       if (emulate_sb && !IS_SB_ELEMENT(Feld[x][y]))
1796         emulate_sb = FALSE;
1797       if (emulate_sp && !IS_SP_ELEMENT(Feld[x][y]))
1798         emulate_sp = FALSE;
1799
1800       InitField(x, y, TRUE);
1801     }
1802   }
1803
1804   InitBeltMovement();
1805
1806   game.emulation = (emulate_bd ? EMU_BOULDERDASH :
1807                     emulate_sb ? EMU_SOKOBAN :
1808                     emulate_sp ? EMU_SUPAPLEX : EMU_NONE);
1809
1810   /* initialize explosion and ignition delay */
1811   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1812   {
1813     if (!IS_CUSTOM_ELEMENT(i))
1814     {
1815       int num_phase = 8;
1816       int delay = (((IS_SP_ELEMENT(i) && i != EL_EMPTY_SPACE) &&
1817                     game.engine_version >= VERSION_IDENT(3,1,0,0)) ||
1818                    game.emulation == EMU_SUPAPLEX ? 3 : 2);
1819       int last_phase = (num_phase + 1) * delay;
1820       int half_phase = (num_phase / 2) * delay;
1821
1822       element_info[i].explosion_delay = last_phase - 1;
1823       element_info[i].ignition_delay = half_phase;
1824
1825 #if 0
1826       if (i == EL_BLACK_ORB)
1827         element_info[i].ignition_delay = 0;
1828 #else
1829       if (i == EL_BLACK_ORB)
1830         element_info[i].ignition_delay = 1;
1831 #endif
1832     }
1833
1834 #if 0
1835     if (element_info[i].explosion_delay < 1)    /* !!! check again !!! */
1836       element_info[i].explosion_delay = 1;
1837
1838     if (element_info[i].ignition_delay < 1)     /* !!! check again !!! */
1839       element_info[i].ignition_delay = 1;
1840 #endif
1841   }
1842
1843   /* correct non-moving belts to start moving left */
1844   for (i = 0; i < NUM_BELTS; i++)
1845     if (game.belt_dir[i] == MV_NO_MOVING)
1846       game.belt_dir_nr[i] = 3;          /* not moving, next moving left */
1847
1848   /* check if any connected player was not found in playfield */
1849   for (i = 0; i < MAX_PLAYERS; i++)
1850   {
1851     struct PlayerInfo *player = &stored_player[i];
1852
1853     if (player->connected && !player->present)
1854     {
1855       for (j = 0; j < MAX_PLAYERS; j++)
1856       {
1857         struct PlayerInfo *some_player = &stored_player[j];
1858         int jx = some_player->jx, jy = some_player->jy;
1859
1860         /* assign first free player found that is present in the playfield */
1861         if (some_player->present && !some_player->connected)
1862         {
1863           player->present = TRUE;
1864           player->active = TRUE;
1865
1866           some_player->present = FALSE;
1867           some_player->active = FALSE;
1868
1869 #if 0
1870           player->element_nr = some_player->element_nr;
1871 #endif
1872
1873 #if USE_NEW_BLOCK_STYLE
1874           player->block_last_field = some_player->block_last_field;
1875           player->block_delay = some_player->block_delay;
1876 #endif
1877
1878           StorePlayer[jx][jy] = player->element_nr;
1879           player->jx = player->last_jx = jx;
1880           player->jy = player->last_jy = jy;
1881
1882           break;
1883         }
1884       }
1885     }
1886   }
1887
1888   if (tape.playing)
1889   {
1890     /* when playing a tape, eliminate all players which do not participate */
1891
1892     for (i = 0; i < MAX_PLAYERS; i++)
1893     {
1894       if (stored_player[i].active && !tape.player_participates[i])
1895       {
1896         struct PlayerInfo *player = &stored_player[i];
1897         int jx = player->jx, jy = player->jy;
1898
1899         player->active = FALSE;
1900         StorePlayer[jx][jy] = 0;
1901         Feld[jx][jy] = EL_EMPTY;
1902       }
1903     }
1904   }
1905   else if (!options.network && !setup.team_mode)        /* && !tape.playing */
1906   {
1907     /* when in single player mode, eliminate all but the first active player */
1908
1909     for (i = 0; i < MAX_PLAYERS; i++)
1910     {
1911       if (stored_player[i].active)
1912       {
1913         for (j = i + 1; j < MAX_PLAYERS; j++)
1914         {
1915           if (stored_player[j].active)
1916           {
1917             struct PlayerInfo *player = &stored_player[j];
1918             int jx = player->jx, jy = player->jy;
1919
1920             player->active = FALSE;
1921             player->present = FALSE;
1922
1923             StorePlayer[jx][jy] = 0;
1924             Feld[jx][jy] = EL_EMPTY;
1925           }
1926         }
1927       }
1928     }
1929   }
1930
1931   /* when recording the game, store which players take part in the game */
1932   if (tape.recording)
1933   {
1934     for (i = 0; i < MAX_PLAYERS; i++)
1935       if (stored_player[i].active)
1936         tape.player_participates[i] = TRUE;
1937   }
1938
1939   if (options.debug)
1940   {
1941     for (i = 0; i < MAX_PLAYERS; i++)
1942     {
1943       struct PlayerInfo *player = &stored_player[i];
1944
1945       printf("Player %d: present == %d, connected == %d, active == %d.\n",
1946              i+1,
1947              player->present,
1948              player->connected,
1949              player->active);
1950       if (local_player == player)
1951         printf("Player  %d is local player.\n", i+1);
1952     }
1953   }
1954
1955   if (BorderElement == EL_EMPTY)
1956   {
1957     SBX_Left = 0;
1958     SBX_Right = lev_fieldx - SCR_FIELDX;
1959     SBY_Upper = 0;
1960     SBY_Lower = lev_fieldy - SCR_FIELDY;
1961   }
1962   else
1963   {
1964     SBX_Left = -1;
1965     SBX_Right = lev_fieldx - SCR_FIELDX + 1;
1966     SBY_Upper = -1;
1967     SBY_Lower = lev_fieldy - SCR_FIELDY + 1;
1968   }
1969
1970   if (lev_fieldx + (SBX_Left == -1 ? 2 : 0) <= SCR_FIELDX)
1971     SBX_Left = SBX_Right = -1 * (SCR_FIELDX - lev_fieldx) / 2;
1972
1973   if (lev_fieldy + (SBY_Upper == -1 ? 2 : 0) <= SCR_FIELDY)
1974     SBY_Upper = SBY_Lower = -1 * (SCR_FIELDY - lev_fieldy) / 2;
1975
1976   /* if local player not found, look for custom element that might create
1977      the player (make some assumptions about the right custom element) */
1978   if (!local_player->present)
1979   {
1980     int start_x = 0, start_y = 0;
1981     int found_rating = 0;
1982     int found_element = EL_UNDEFINED;
1983
1984     for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
1985     {
1986       int element = Feld[x][y];
1987       int content;
1988       int xx, yy;
1989       boolean is_player;
1990
1991       if (!IS_CUSTOM_ELEMENT(element))
1992         continue;
1993
1994       if (CAN_CHANGE(element))
1995       {
1996         for (i = 0; i < element_info[element].num_change_pages; i++)
1997         {
1998           content = element_info[element].change_page[i].target_element;
1999           is_player = ELEM_IS_PLAYER(content);
2000
2001           if (is_player && (found_rating < 3 || element < found_element))
2002           {
2003             start_x = x;
2004             start_y = y;
2005
2006             found_rating = 3;
2007             found_element = element;
2008           }
2009         }
2010       }
2011
2012       for (yy = 0; yy < 3; yy++) for (xx = 0; xx < 3; xx++)
2013       {
2014         content = element_info[element].content[xx][yy];
2015         is_player = ELEM_IS_PLAYER(content);
2016
2017         if (is_player && (found_rating < 2 || element < found_element))
2018         {
2019           start_x = x + xx - 1;
2020           start_y = y + yy - 1;
2021
2022           found_rating = 2;
2023           found_element = element;
2024         }
2025
2026         if (!CAN_CHANGE(element))
2027           continue;
2028
2029         for (i = 0; i < element_info[element].num_change_pages; i++)
2030         {
2031           content= element_info[element].change_page[i].target_content[xx][yy];
2032           is_player = ELEM_IS_PLAYER(content);
2033
2034           if (is_player && (found_rating < 1 || element < found_element))
2035           {
2036             start_x = x + xx - 1;
2037             start_y = y + yy - 1;
2038
2039             found_rating = 1;
2040             found_element = element;
2041           }
2042         }
2043       }
2044     }
2045
2046     scroll_x = (start_x < SBX_Left  + MIDPOSX ? SBX_Left :
2047                 start_x > SBX_Right + MIDPOSX ? SBX_Right :
2048                 start_x - MIDPOSX);
2049
2050     scroll_y = (start_y < SBY_Upper + MIDPOSY ? SBY_Upper :
2051                 start_y > SBY_Lower + MIDPOSY ? SBY_Lower :
2052                 start_y - MIDPOSY);
2053   }
2054   else
2055   {
2056 #if 1
2057     scroll_x = (local_player->jx < SBX_Left  + MIDPOSX ? SBX_Left :
2058                 local_player->jx > SBX_Right + MIDPOSX ? SBX_Right :
2059                 local_player->jx - MIDPOSX);
2060
2061     scroll_y = (local_player->jy < SBY_Upper + MIDPOSY ? SBY_Upper :
2062                 local_player->jy > SBY_Lower + MIDPOSY ? SBY_Lower :
2063                 local_player->jy - MIDPOSY);
2064 #else
2065     scroll_x = SBX_Left;
2066     scroll_y = SBY_Upper;
2067     if (local_player->jx >= SBX_Left + MIDPOSX)
2068       scroll_x = (local_player->jx <= SBX_Right + MIDPOSX ?
2069                   local_player->jx - MIDPOSX :
2070                   SBX_Right);
2071     if (local_player->jy >= SBY_Upper + MIDPOSY)
2072       scroll_y = (local_player->jy <= SBY_Lower + MIDPOSY ?
2073                   local_player->jy - MIDPOSY :
2074                   SBY_Lower);
2075 #endif
2076   }
2077
2078   CloseDoor(DOOR_CLOSE_1);
2079
2080   /* !!! FIX THIS (START) !!! */
2081   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
2082   {
2083     InitGameEngine_EM();
2084   }
2085   else
2086   {
2087     DrawLevel();
2088     DrawAllPlayers();
2089
2090     /* after drawing the level, correct some elements */
2091     if (game.timegate_time_left == 0)
2092       CloseAllOpenTimegates();
2093
2094     if (setup.soft_scrolling)
2095       BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2096
2097     redraw_mask |= REDRAW_FROM_BACKBUFFER;
2098     FadeToFront();
2099   }
2100   /* !!! FIX THIS (END) !!! */
2101
2102   /* copy default game door content to main double buffer */
2103   BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2104              DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY);
2105
2106   DrawGameDoorValues();
2107
2108   UnmapGameButtons();
2109   UnmapTapeButtons();
2110   game_gadget[SOUND_CTRL_ID_MUSIC]->checked = setup.sound_music;
2111   game_gadget[SOUND_CTRL_ID_LOOPS]->checked = setup.sound_loops;
2112   game_gadget[SOUND_CTRL_ID_SIMPLE]->checked = setup.sound_simple;
2113   MapGameButtons();
2114   MapTapeButtons();
2115
2116   /* copy actual game door content to door double buffer for OpenDoor() */
2117   BlitBitmap(drawto, bitmap_db_door,
2118              DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2119
2120   OpenDoor(DOOR_OPEN_ALL);
2121
2122   PlaySoundStereo(SND_GAME_STARTING, SOUND_MIDDLE);
2123
2124   if (setup.sound_music)
2125     PlayLevelMusic();
2126
2127   KeyboardAutoRepeatOffUnlessAutoplay();
2128
2129   if (options.debug)
2130   {
2131     for (i = 0; i < MAX_PLAYERS; i++)
2132       printf("Player %d %sactive.\n",
2133              i + 1, (stored_player[i].active ? "" : "not "));
2134   }
2135
2136 #if 0
2137   printf("::: starting game [%d]\n", FrameCounter);
2138 #endif
2139 }
2140
2141 void UpdateEngineValues(int actual_scroll_x, int actual_scroll_y)
2142 {
2143   /* this is used for non-R'n'D game engines to update certain engine values */
2144
2145   /* needed to determine if sounds are played within the visible screen area */
2146   scroll_x = actual_scroll_x;
2147   scroll_y = actual_scroll_y;
2148 }
2149
2150 void InitMovDir(int x, int y)
2151 {
2152   int i, element = Feld[x][y];
2153   static int xy[4][2] =
2154   {
2155     {  0, +1 },
2156     { +1,  0 },
2157     {  0, -1 },
2158     { -1,  0 }
2159   };
2160   static int direction[3][4] =
2161   {
2162     { MV_RIGHT, MV_UP,   MV_LEFT,  MV_DOWN },
2163     { MV_LEFT,  MV_DOWN, MV_RIGHT, MV_UP },
2164     { MV_LEFT,  MV_RIGHT, MV_UP, MV_DOWN }
2165   };
2166
2167   switch(element)
2168   {
2169     case EL_BUG_RIGHT:
2170     case EL_BUG_UP:
2171     case EL_BUG_LEFT:
2172     case EL_BUG_DOWN:
2173       Feld[x][y] = EL_BUG;
2174       MovDir[x][y] = direction[0][element - EL_BUG_RIGHT];
2175       break;
2176
2177     case EL_SPACESHIP_RIGHT:
2178     case EL_SPACESHIP_UP:
2179     case EL_SPACESHIP_LEFT:
2180     case EL_SPACESHIP_DOWN:
2181       Feld[x][y] = EL_SPACESHIP;
2182       MovDir[x][y] = direction[0][element - EL_SPACESHIP_RIGHT];
2183       break;
2184
2185     case EL_BD_BUTTERFLY_RIGHT:
2186     case EL_BD_BUTTERFLY_UP:
2187     case EL_BD_BUTTERFLY_LEFT:
2188     case EL_BD_BUTTERFLY_DOWN:
2189       Feld[x][y] = EL_BD_BUTTERFLY;
2190       MovDir[x][y] = direction[0][element - EL_BD_BUTTERFLY_RIGHT];
2191       break;
2192
2193     case EL_BD_FIREFLY_RIGHT:
2194     case EL_BD_FIREFLY_UP:
2195     case EL_BD_FIREFLY_LEFT:
2196     case EL_BD_FIREFLY_DOWN:
2197       Feld[x][y] = EL_BD_FIREFLY;
2198       MovDir[x][y] = direction[0][element - EL_BD_FIREFLY_RIGHT];
2199       break;
2200
2201     case EL_PACMAN_RIGHT:
2202     case EL_PACMAN_UP:
2203     case EL_PACMAN_LEFT:
2204     case EL_PACMAN_DOWN:
2205       Feld[x][y] = EL_PACMAN;
2206       MovDir[x][y] = direction[0][element - EL_PACMAN_RIGHT];
2207       break;
2208
2209     case EL_SP_SNIKSNAK:
2210       MovDir[x][y] = MV_UP;
2211       break;
2212
2213     case EL_SP_ELECTRON:
2214       MovDir[x][y] = MV_LEFT;
2215       break;
2216
2217     case EL_MOLE_LEFT:
2218     case EL_MOLE_RIGHT:
2219     case EL_MOLE_UP:
2220     case EL_MOLE_DOWN:
2221       Feld[x][y] = EL_MOLE;
2222       MovDir[x][y] = direction[2][element - EL_MOLE_LEFT];
2223       break;
2224
2225     default:
2226       if (IS_CUSTOM_ELEMENT(element))
2227       {
2228         struct ElementInfo *ei = &element_info[element];
2229         int move_direction_initial = ei->move_direction_initial;
2230         int move_pattern = ei->move_pattern;
2231
2232         if (move_direction_initial == MV_START_PREVIOUS)
2233         {
2234           if (MovDir[x][y] != MV_NO_MOVING)
2235             return;
2236
2237           move_direction_initial = MV_START_AUTOMATIC;
2238         }
2239
2240         if (move_direction_initial == MV_START_RANDOM)
2241           MovDir[x][y] = 1 << RND(4);
2242         else if (move_direction_initial & MV_ANY_DIRECTION)
2243           MovDir[x][y] = move_direction_initial;
2244         else if (move_pattern == MV_ALL_DIRECTIONS ||
2245                  move_pattern == MV_TURNING_LEFT ||
2246                  move_pattern == MV_TURNING_RIGHT ||
2247                  move_pattern == MV_TURNING_LEFT_RIGHT ||
2248                  move_pattern == MV_TURNING_RIGHT_LEFT ||
2249                  move_pattern == MV_TURNING_RANDOM)
2250           MovDir[x][y] = 1 << RND(4);
2251         else if (move_pattern == MV_HORIZONTAL)
2252           MovDir[x][y] = (RND(2) ? MV_LEFT : MV_RIGHT);
2253         else if (move_pattern == MV_VERTICAL)
2254           MovDir[x][y] = (RND(2) ? MV_UP : MV_DOWN);
2255         else if (move_pattern & MV_ANY_DIRECTION)
2256           MovDir[x][y] = element_info[element].move_pattern;
2257         else if (move_pattern == MV_ALONG_LEFT_SIDE ||
2258                  move_pattern == MV_ALONG_RIGHT_SIDE)
2259         {
2260 #if 1
2261           /* use random direction as default start direction */
2262           if (game.engine_version >= VERSION_IDENT(3,1,0,0))
2263             MovDir[x][y] = 1 << RND(4);
2264 #endif
2265
2266           for (i = 0; i < NUM_DIRECTIONS; i++)
2267           {
2268             int x1 = x + xy[i][0];
2269             int y1 = y + xy[i][1];
2270
2271             if (!IN_LEV_FIELD(x1, y1) || !IS_FREE(x1, y1))
2272             {
2273               if (move_pattern == MV_ALONG_RIGHT_SIDE)
2274                 MovDir[x][y] = direction[0][i];
2275               else
2276                 MovDir[x][y] = direction[1][i];
2277
2278               break;
2279             }
2280           }
2281         }                
2282       }
2283       else
2284       {
2285         MovDir[x][y] = 1 << RND(4);
2286
2287         if (element != EL_BUG &&
2288             element != EL_SPACESHIP &&
2289             element != EL_BD_BUTTERFLY &&
2290             element != EL_BD_FIREFLY)
2291           break;
2292
2293         for (i = 0; i < NUM_DIRECTIONS; i++)
2294         {
2295           int x1 = x + xy[i][0];
2296           int y1 = y + xy[i][1];
2297
2298           if (!IN_LEV_FIELD(x1, y1) || !IS_FREE(x1, y1))
2299           {
2300             if (element == EL_BUG || element == EL_BD_BUTTERFLY)
2301             {
2302               MovDir[x][y] = direction[0][i];
2303               break;
2304             }
2305             else if (element == EL_SPACESHIP || element == EL_BD_FIREFLY ||
2306                      element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
2307             {
2308               MovDir[x][y] = direction[1][i];
2309               break;
2310             }
2311           }
2312         }
2313       }
2314       break;
2315   }
2316
2317   GfxDir[x][y] = MovDir[x][y];
2318 }
2319
2320 void InitAmoebaNr(int x, int y)
2321 {
2322   int i;
2323   int group_nr = AmoebeNachbarNr(x, y);
2324
2325   if (group_nr == 0)
2326   {
2327     for (i = 1; i < MAX_NUM_AMOEBA; i++)
2328     {
2329       if (AmoebaCnt[i] == 0)
2330       {
2331         group_nr = i;
2332         break;
2333       }
2334     }
2335   }
2336
2337   AmoebaNr[x][y] = group_nr;
2338   AmoebaCnt[group_nr]++;
2339   AmoebaCnt2[group_nr]++;
2340 }
2341
2342 void GameWon()
2343 {
2344   int hi_pos;
2345   boolean raise_level = FALSE;
2346
2347   if (local_player->MovPos)
2348     return;
2349
2350 #if 1
2351   if (tape.auto_play)           /* tape might already be stopped here */
2352     tape.auto_play_level_solved = TRUE;
2353 #else
2354   if (tape.playing && tape.auto_play)
2355     tape.auto_play_level_solved = TRUE;
2356 #endif
2357
2358   local_player->LevelSolved = FALSE;
2359
2360   PlaySoundStereo(SND_GAME_WINNING, SOUND_MIDDLE);
2361
2362   if (TimeLeft)
2363   {
2364     if (!tape.playing && setup.sound_loops)
2365       PlaySoundExt(SND_GAME_LEVELTIME_BONUS, SOUND_MAX_VOLUME, SOUND_MIDDLE,
2366                    SND_CTRL_PLAY_LOOP);
2367
2368     while (TimeLeft > 0)
2369     {
2370       if (!tape.playing && !setup.sound_loops)
2371         PlaySoundStereo(SND_GAME_LEVELTIME_BONUS, SOUND_MIDDLE);
2372       if (TimeLeft > 0 && !(TimeLeft % 10))
2373         RaiseScore(level.score[SC_TIME_BONUS]);
2374       if (TimeLeft > 100 && !(TimeLeft % 10))
2375         TimeLeft -= 10;
2376       else
2377         TimeLeft--;
2378
2379       DrawGameValue_Time(TimeLeft);
2380
2381       BackToFront();
2382
2383       if (!tape.playing)
2384         Delay(10);
2385     }
2386
2387     if (!tape.playing && setup.sound_loops)
2388       StopSound(SND_GAME_LEVELTIME_BONUS);
2389   }
2390   else if (level.time == 0)             /* level without time limit */
2391   {
2392     if (!tape.playing && setup.sound_loops)
2393       PlaySoundExt(SND_GAME_LEVELTIME_BONUS, SOUND_MAX_VOLUME, SOUND_MIDDLE,
2394                    SND_CTRL_PLAY_LOOP);
2395
2396     while (TimePlayed < 999)
2397     {
2398       if (!tape.playing && !setup.sound_loops)
2399         PlaySoundStereo(SND_GAME_LEVELTIME_BONUS, SOUND_MIDDLE);
2400       if (TimePlayed < 999 && !(TimePlayed % 10))
2401         RaiseScore(level.score[SC_TIME_BONUS]);
2402       if (TimePlayed < 900 && !(TimePlayed % 10))
2403         TimePlayed += 10;
2404       else
2405         TimePlayed++;
2406
2407       DrawGameValue_Time(TimePlayed);
2408
2409       BackToFront();
2410
2411       if (!tape.playing)
2412         Delay(10);
2413     }
2414
2415     if (!tape.playing && setup.sound_loops)
2416       StopSound(SND_GAME_LEVELTIME_BONUS);
2417   }
2418
2419   /* close exit door after last player */
2420   if (AllPlayersGone && ExitX >= 0 && ExitY >= 0 &&
2421       (Feld[ExitX][ExitY] == EL_EXIT_OPEN ||
2422        Feld[ExitX][ExitY] == EL_SP_EXIT_OPEN))
2423   {
2424     int element = Feld[ExitX][ExitY];
2425
2426     Feld[ExitX][ExitY] = (element == EL_EXIT_OPEN ? EL_EXIT_CLOSING :
2427                           EL_SP_EXIT_CLOSING);
2428
2429     PlayLevelSoundElementAction(ExitX, ExitY, element, ACTION_CLOSING);
2430   }
2431
2432   /* Hero disappears */
2433   if (ExitX >= 0 && ExitY >= 0)
2434     DrawLevelField(ExitX, ExitY);
2435
2436   BackToFront();
2437
2438   if (tape.playing)
2439     return;
2440
2441   CloseDoor(DOOR_CLOSE_1);
2442
2443   if (tape.recording)
2444   {
2445     TapeStop();
2446     SaveTape(tape.level_nr);            /* Ask to save tape */
2447   }
2448
2449   if (level_nr == leveldir_current->handicap_level)
2450   {
2451     leveldir_current->handicap_level++;
2452     SaveLevelSetup_SeriesInfo();
2453   }
2454
2455   if (level_editor_test_game)
2456     local_player->score = -1;   /* no highscore when playing from editor */
2457   else if (level_nr < leveldir_current->last_level)
2458     raise_level = TRUE;         /* advance to next level */
2459
2460   if ((hi_pos = NewHiScore()) >= 0) 
2461   {
2462     game_status = GAME_MODE_SCORES;
2463     DrawHallOfFame(hi_pos);
2464     if (raise_level)
2465     {
2466       level_nr++;
2467       TapeErase();
2468     }
2469   }
2470   else
2471   {
2472     game_status = GAME_MODE_MAIN;
2473     if (raise_level)
2474     {
2475       level_nr++;
2476       TapeErase();
2477     }
2478     DrawMainMenu();
2479   }
2480
2481   BackToFront();
2482 }
2483
2484 int NewHiScore()
2485 {
2486   int k, l;
2487   int position = -1;
2488
2489   LoadScore(level_nr);
2490
2491   if (strcmp(setup.player_name, EMPTY_PLAYER_NAME) == 0 ||
2492       local_player->score < highscore[MAX_SCORE_ENTRIES - 1].Score) 
2493     return -1;
2494
2495   for (k = 0; k < MAX_SCORE_ENTRIES; k++) 
2496   {
2497     if (local_player->score > highscore[k].Score)
2498     {
2499       /* player has made it to the hall of fame */
2500
2501       if (k < MAX_SCORE_ENTRIES - 1)
2502       {
2503         int m = MAX_SCORE_ENTRIES - 1;
2504
2505 #ifdef ONE_PER_NAME
2506         for (l = k; l < MAX_SCORE_ENTRIES; l++)
2507           if (!strcmp(setup.player_name, highscore[l].Name))
2508             m = l;
2509         if (m == k)     /* player's new highscore overwrites his old one */
2510           goto put_into_list;
2511 #endif
2512
2513         for (l = m; l > k; l--)
2514         {
2515           strcpy(highscore[l].Name, highscore[l - 1].Name);
2516           highscore[l].Score = highscore[l - 1].Score;
2517         }
2518       }
2519
2520 #ifdef ONE_PER_NAME
2521       put_into_list:
2522 #endif
2523       strncpy(highscore[k].Name, setup.player_name, MAX_PLAYER_NAME_LEN);
2524       highscore[k].Name[MAX_PLAYER_NAME_LEN] = '\0';
2525       highscore[k].Score = local_player->score; 
2526       position = k;
2527       break;
2528     }
2529
2530 #ifdef ONE_PER_NAME
2531     else if (!strncmp(setup.player_name, highscore[k].Name,
2532                       MAX_PLAYER_NAME_LEN))
2533       break;    /* player already there with a higher score */
2534 #endif
2535
2536   }
2537
2538   if (position >= 0) 
2539     SaveScore(level_nr);
2540
2541   return position;
2542 }
2543
2544 void InitPlayerGfxAnimation(struct PlayerInfo *player, int action, int dir)
2545 {
2546   if (player->GfxAction != action || player->GfxDir != dir)
2547   {
2548 #if 0
2549     printf("Player frame reset! (%d => %d, %d => %d)\n",
2550            player->GfxAction, action, player->GfxDir, dir);
2551 #endif
2552
2553     player->GfxAction = action;
2554     player->GfxDir = dir;
2555     player->Frame = 0;
2556     player->StepFrame = 0;
2557   }
2558 }
2559
2560 static void ResetRandomAnimationValue(int x, int y)
2561 {
2562   GfxRandom[x][y] = INIT_GFX_RANDOM();
2563 }
2564
2565 static void ResetGfxAnimation(int x, int y)
2566 {
2567   GfxFrame[x][y] = 0;
2568   GfxAction[x][y] = ACTION_DEFAULT;
2569   GfxDir[x][y] = MovDir[x][y];
2570 }
2571
2572 void InitMovingField(int x, int y, int direction)
2573 {
2574   int element = Feld[x][y];
2575   int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
2576   int dy = (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
2577   int newx = x + dx;
2578   int newy = y + dy;
2579
2580   if (!WasJustMoving[x][y] || direction != MovDir[x][y])
2581     ResetGfxAnimation(x, y);
2582
2583   MovDir[newx][newy] = MovDir[x][y] = direction;
2584   GfxDir[x][y] = direction;
2585
2586   if (Feld[newx][newy] == EL_EMPTY)
2587     Feld[newx][newy] = EL_BLOCKED;
2588
2589   if (direction == MV_DOWN && CAN_FALL(element))
2590     GfxAction[x][y] = ACTION_FALLING;
2591   else
2592     GfxAction[x][y] = ACTION_MOVING;
2593
2594   GfxFrame[newx][newy] = GfxFrame[x][y];
2595   GfxRandom[newx][newy] = GfxRandom[x][y];
2596   GfxAction[newx][newy] = GfxAction[x][y];
2597   GfxDir[newx][newy] = GfxDir[x][y];
2598 }
2599
2600 void Moving2Blocked(int x, int y, int *goes_to_x, int *goes_to_y)
2601 {
2602   int direction = MovDir[x][y];
2603   int newx = x + (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
2604   int newy = y + (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
2605
2606   *goes_to_x = newx;
2607   *goes_to_y = newy;
2608 }
2609
2610 void Blocked2Moving(int x, int y, int *comes_from_x, int *comes_from_y)
2611 {
2612   int oldx = x, oldy = y;
2613   int direction = MovDir[x][y];
2614
2615   if (direction == MV_LEFT)
2616     oldx++;
2617   else if (direction == MV_RIGHT)
2618     oldx--;
2619   else if (direction == MV_UP)
2620     oldy++;
2621   else if (direction == MV_DOWN)
2622     oldy--;
2623
2624   *comes_from_x = oldx;
2625   *comes_from_y = oldy;
2626 }
2627
2628 int MovingOrBlocked2Element(int x, int y)
2629 {
2630   int element = Feld[x][y];
2631
2632   if (element == EL_BLOCKED)
2633   {
2634     int oldx, oldy;
2635
2636     Blocked2Moving(x, y, &oldx, &oldy);
2637     return Feld[oldx][oldy];
2638   }
2639   else
2640     return element;
2641 }
2642
2643 static int MovingOrBlocked2ElementIfNotLeaving(int x, int y)
2644 {
2645   /* like MovingOrBlocked2Element(), but if element is moving
2646      and (x,y) is the field the moving element is just leaving,
2647      return EL_BLOCKED instead of the element value */
2648   int element = Feld[x][y];
2649
2650   if (IS_MOVING(x, y))
2651   {
2652     if (element == EL_BLOCKED)
2653     {
2654       int oldx, oldy;
2655
2656       Blocked2Moving(x, y, &oldx, &oldy);
2657       return Feld[oldx][oldy];
2658     }
2659     else
2660       return EL_BLOCKED;
2661   }
2662   else
2663     return element;
2664 }
2665
2666 static void RemoveField(int x, int y)
2667 {
2668   Feld[x][y] = EL_EMPTY;
2669
2670   MovPos[x][y] = 0;
2671   MovDir[x][y] = 0;
2672   MovDelay[x][y] = 0;
2673
2674   AmoebaNr[x][y] = 0;
2675   ChangeDelay[x][y] = 0;
2676   ChangePage[x][y] = -1;
2677   Pushed[x][y] = FALSE;
2678
2679 #if 0
2680   ExplodeField[x][y] = EX_TYPE_NONE;
2681 #endif
2682
2683   GfxElement[x][y] = EL_UNDEFINED;
2684   GfxAction[x][y] = ACTION_DEFAULT;
2685   GfxDir[x][y] = MV_NO_MOVING;
2686 }
2687
2688 void RemoveMovingField(int x, int y)
2689 {
2690   int oldx = x, oldy = y, newx = x, newy = y;
2691   int element = Feld[x][y];
2692   int next_element = EL_UNDEFINED;
2693
2694   if (element != EL_BLOCKED && !IS_MOVING(x, y))
2695     return;
2696
2697   if (IS_MOVING(x, y))
2698   {
2699     Moving2Blocked(x, y, &newx, &newy);
2700 #if 0
2701     if (Feld[newx][newy] != EL_BLOCKED)
2702       return;
2703 #else
2704     if (Feld[newx][newy] != EL_BLOCKED)
2705     {
2706       /* element is moving, but target field is not free (blocked), but
2707          already occupied by something different (example: acid pool);
2708          in this case, only remove the moving field, but not the target */
2709
2710       RemoveField(oldx, oldy);
2711
2712       Store[oldx][oldy] = Store2[oldx][oldy] = 0;
2713
2714       DrawLevelField(oldx, oldy);
2715
2716       return;
2717     }
2718 #endif
2719   }
2720   else if (element == EL_BLOCKED)
2721   {
2722     Blocked2Moving(x, y, &oldx, &oldy);
2723     if (!IS_MOVING(oldx, oldy))
2724       return;
2725   }
2726
2727   if (element == EL_BLOCKED &&
2728       (Feld[oldx][oldy] == EL_QUICKSAND_EMPTYING ||
2729        Feld[oldx][oldy] == EL_MAGIC_WALL_EMPTYING ||
2730        Feld[oldx][oldy] == EL_BD_MAGIC_WALL_EMPTYING ||
2731        Feld[oldx][oldy] == EL_AMOEBA_DROPPING))
2732     next_element = get_next_element(Feld[oldx][oldy]);
2733
2734   RemoveField(oldx, oldy);
2735   RemoveField(newx, newy);
2736
2737   Store[oldx][oldy] = Store2[oldx][oldy] = 0;
2738
2739   if (next_element != EL_UNDEFINED)
2740     Feld[oldx][oldy] = next_element;
2741
2742   DrawLevelField(oldx, oldy);
2743   DrawLevelField(newx, newy);
2744 }
2745
2746 void DrawDynamite(int x, int y)
2747 {
2748   int sx = SCREENX(x), sy = SCREENY(y);
2749   int graphic = el2img(Feld[x][y]);
2750   int frame;
2751
2752   if (!IN_SCR_FIELD(sx, sy) || IS_PLAYER(x, y))
2753     return;
2754
2755   if (IS_WALKABLE_INSIDE(Back[x][y]))
2756     return;
2757
2758   if (Back[x][y])
2759     DrawGraphic(sx, sy, el2img(Back[x][y]), 0);
2760   else if (Store[x][y])
2761     DrawGraphic(sx, sy, el2img(Store[x][y]), 0);
2762
2763   frame = getGraphicAnimationFrame(graphic, GfxFrame[x][y]);
2764
2765 #if 1
2766   if (Back[x][y] || Store[x][y])
2767     DrawGraphicThruMask(sx, sy, graphic, frame);
2768   else
2769     DrawGraphic(sx, sy, graphic, frame);
2770 #else
2771   if (game.emulation == EMU_SUPAPLEX)
2772     DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2773   else if (Store[x][y])
2774     DrawGraphicThruMask(sx, sy, graphic, frame);
2775   else
2776     DrawGraphic(sx, sy, graphic, frame);
2777 #endif
2778 }
2779
2780 void CheckDynamite(int x, int y)
2781 {
2782   if (MovDelay[x][y] != 0)      /* dynamite is still waiting to explode */
2783   {
2784     MovDelay[x][y]--;
2785
2786     if (MovDelay[x][y] != 0)
2787     {
2788       DrawDynamite(x, y);
2789       PlayLevelSoundActionIfLoop(x, y, ACTION_ACTIVE);
2790
2791       return;
2792     }
2793   }
2794
2795 #if 1
2796   StopLevelSoundActionIfLoop(x, y, ACTION_ACTIVE);
2797 #else
2798   if (Feld[x][y] == EL_DYNAMITE_ACTIVE ||
2799       Feld[x][y] == EL_SP_DISK_RED_ACTIVE)
2800     StopSound(SND_DYNAMITE_ACTIVE);
2801   else
2802     StopSound(SND_DYNABOMB_ACTIVE);
2803 #endif
2804
2805   Bang(x, y);
2806 }
2807
2808 void DrawRelocatePlayer(struct PlayerInfo *player)
2809 {
2810   boolean ffwd_delay = (tape.playing && tape.fast_forward);
2811   boolean no_delay = (tape.warp_forward);
2812   int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2813   int wait_delay_value = (no_delay ? 0 : frame_delay_value);
2814   int jx = player->jx;
2815   int jy = player->jy;
2816
2817   if (level.instant_relocation)
2818   {
2819 #if 1
2820     int offset = (setup.scroll_delay ? 3 : 0);
2821
2822     if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
2823     {
2824       scroll_x = (local_player->jx < SBX_Left  + MIDPOSX ? SBX_Left :
2825                   local_player->jx > SBX_Right + MIDPOSX ? SBX_Right :
2826                   local_player->jx - MIDPOSX);
2827
2828       scroll_y = (local_player->jy < SBY_Upper + MIDPOSY ? SBY_Upper :
2829                   local_player->jy > SBY_Lower + MIDPOSY ? SBY_Lower :
2830                   local_player->jy - MIDPOSY);
2831     }
2832     else
2833     {
2834       if ((player->MovDir == MV_LEFT  && scroll_x > jx - MIDPOSX + offset) ||
2835           (player->MovDir == MV_RIGHT && scroll_x < jx - MIDPOSX - offset))
2836         scroll_x = jx - MIDPOSX + (scroll_x < jx-MIDPOSX ? -offset : +offset);
2837
2838       if ((player->MovDir == MV_UP  && scroll_y > jy - MIDPOSY + offset) ||
2839           (player->MovDir == MV_DOWN && scroll_y < jy - MIDPOSY - offset))
2840         scroll_y = jy - MIDPOSY + (scroll_y < jy-MIDPOSY ? -offset : +offset);
2841
2842       /* don't scroll over playfield boundaries */
2843       if (scroll_x < SBX_Left || scroll_x > SBX_Right)
2844         scroll_x = (scroll_x < SBX_Left ? SBX_Left : SBX_Right);
2845
2846       /* don't scroll over playfield boundaries */
2847       if (scroll_y < SBY_Upper || scroll_y > SBY_Lower)
2848         scroll_y = (scroll_y < SBY_Upper ? SBY_Upper : SBY_Lower);
2849     }
2850 #else
2851     scroll_x += (local_player->jx - old_jx);
2852     scroll_y += (local_player->jy - old_jy);
2853
2854     /* don't scroll over playfield boundaries */
2855     if (scroll_x < SBX_Left || scroll_x > SBX_Right)
2856       scroll_x = (scroll_x < SBX_Left ? SBX_Left : SBX_Right);
2857
2858     /* don't scroll over playfield boundaries */
2859     if (scroll_y < SBY_Upper || scroll_y > SBY_Lower)
2860       scroll_y = (scroll_y < SBY_Upper ? SBY_Upper : SBY_Lower);
2861 #endif
2862
2863     RedrawPlayfield(TRUE, 0,0,0,0);
2864   }
2865   else
2866   {
2867 #if 1
2868 #if 0
2869     int offset = (setup.scroll_delay ? 3 : 0);
2870 #endif
2871     int scroll_xx = -999, scroll_yy = -999;
2872
2873     ScrollScreen(NULL, SCROLL_GO_ON);   /* scroll last frame to full tile */
2874
2875     while (scroll_xx != scroll_x || scroll_yy != scroll_y)
2876     {
2877       int dx = 0, dy = 0;
2878       int fx = FX, fy = FY;
2879
2880       scroll_xx = (local_player->jx < SBX_Left  + MIDPOSX ? SBX_Left :
2881                    local_player->jx > SBX_Right + MIDPOSX ? SBX_Right :
2882                    local_player->jx - MIDPOSX);
2883
2884       scroll_yy = (local_player->jy < SBY_Upper + MIDPOSY ? SBY_Upper :
2885                    local_player->jy > SBY_Lower + MIDPOSY ? SBY_Lower :
2886                    local_player->jy - MIDPOSY);
2887
2888       dx = (scroll_xx < scroll_x ? +1 : scroll_xx > scroll_x ? -1 : 0);
2889       dy = (scroll_yy < scroll_y ? +1 : scroll_yy > scroll_y ? -1 : 0);
2890
2891 #if 1
2892       if (dx == 0 && dy == 0)           /* no scrolling needed at all */
2893         break;
2894 #else
2895       if (scroll_xx == scroll_x && scroll_yy == scroll_y)
2896         break;
2897 #endif
2898
2899       scroll_x -= dx;
2900       scroll_y -= dy;
2901
2902       fx += dx * TILEX / 2;
2903       fy += dy * TILEY / 2;
2904
2905       ScrollLevel(dx, dy);
2906       DrawAllPlayers();
2907
2908       /* scroll in two steps of half tile size to make things smoother */
2909       BlitBitmap(drawto_field, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
2910       FlushDisplay();
2911       Delay(wait_delay_value);
2912
2913       /* scroll second step to align at full tile size */
2914       BackToFront();
2915       Delay(wait_delay_value);
2916     }
2917 #else
2918     int scroll_xx = -999, scroll_yy = -999;
2919
2920     ScrollScreen(NULL, SCROLL_GO_ON);   /* scroll last frame to full tile */
2921
2922     while (scroll_xx != scroll_x || scroll_yy != scroll_y)
2923     {
2924       int dx = 0, dy = 0;
2925       int fx = FX, fy = FY;
2926
2927       scroll_xx = (local_player->jx < SBX_Left  + MIDPOSX ? SBX_Left :
2928                    local_player->jx > SBX_Right + MIDPOSX ? SBX_Right :
2929                    local_player->jx - MIDPOSX);
2930
2931       scroll_yy = (local_player->jy < SBY_Upper + MIDPOSY ? SBY_Upper :
2932                    local_player->jy > SBY_Lower + MIDPOSY ? SBY_Lower :
2933                    local_player->jy - MIDPOSY);
2934
2935       dx = (scroll_xx < scroll_x ? +1 : scroll_xx > scroll_x ? -1 : 0);
2936       dy = (scroll_yy < scroll_y ? +1 : scroll_yy > scroll_y ? -1 : 0);
2937
2938 #if 1
2939       if (dx == 0 && dy == 0)           /* no scrolling needed at all */
2940         break;
2941 #else
2942       if (scroll_xx == scroll_x && scroll_yy == scroll_y)
2943         break;
2944 #endif
2945
2946       scroll_x -= dx;
2947       scroll_y -= dy;
2948
2949       fx += dx * TILEX / 2;
2950       fy += dy * TILEY / 2;
2951
2952       ScrollLevel(dx, dy);
2953       DrawAllPlayers();
2954
2955       /* scroll in two steps of half tile size to make things smoother */
2956       BlitBitmap(drawto_field, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
2957       FlushDisplay();
2958       Delay(wait_delay_value);
2959
2960       /* scroll second step to align at full tile size */
2961       BackToFront();
2962       Delay(wait_delay_value);
2963     }
2964 #endif
2965
2966     DrawPlayer(player);
2967     BackToFront();
2968     Delay(wait_delay_value);
2969   }
2970 }
2971
2972 void RelocatePlayer(int jx, int jy, int el_player_raw)
2973 {
2974 #if 1
2975   int el_player = GET_VALID_PLAYER_ELEMENT(el_player_raw);
2976 #else
2977   int el_player = (el_player_raw == EL_SP_MURPHY ? EL_PLAYER_1 :el_player_raw);
2978 #endif
2979   struct PlayerInfo *player = &stored_player[el_player - EL_PLAYER_1];
2980   boolean ffwd_delay = (tape.playing && tape.fast_forward);
2981   boolean no_delay = (tape.warp_forward);
2982   int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2983   int wait_delay_value = (no_delay ? 0 : frame_delay_value);
2984   int old_jx = player->jx;
2985   int old_jy = player->jy;
2986   int old_element = Feld[old_jx][old_jy];
2987   int element = Feld[jx][jy];
2988   boolean player_relocated = (old_jx != jx || old_jy != jy);
2989
2990   int move_dir_horiz = (jx < old_jx ? MV_LEFT : jx > old_jx ? MV_RIGHT : 0);
2991   int move_dir_vert  = (jy < old_jy ? MV_UP   : jy > old_jy ? MV_DOWN  : 0);
2992 #if 1
2993   int enter_side_horiz = MV_DIR_OPPOSITE(move_dir_horiz);
2994   int enter_side_vert  = MV_DIR_OPPOSITE(move_dir_vert);
2995   int leave_side_horiz = move_dir_horiz;
2996   int leave_side_vert  = move_dir_vert;
2997 #else
2998   static int trigger_sides[4][2] =
2999   {
3000     /* enter side               leave side */
3001     { CH_SIDE_RIGHT,            CH_SIDE_LEFT    },      /* moving left  */
3002     { CH_SIDE_LEFT,             CH_SIDE_RIGHT   },      /* moving right */
3003     { CH_SIDE_BOTTOM,           CH_SIDE_TOP     },      /* moving up    */
3004     { CH_SIDE_TOP,              CH_SIDE_BOTTOM  }       /* moving down  */
3005   };
3006   int enter_side_horiz = trigger_sides[MV_DIR_BIT(move_dir_horiz)][0];
3007   int enter_side_vert  = trigger_sides[MV_DIR_BIT(move_dir_vert)][0];
3008   int leave_side_horiz = trigger_sides[MV_DIR_BIT(move_dir_horiz)][1];
3009   int leave_side_vert  = trigger_sides[MV_DIR_BIT(move_dir_vert)][1];
3010 #endif
3011   int enter_side = enter_side_horiz | enter_side_vert;
3012   int leave_side = leave_side_horiz | leave_side_vert;
3013
3014   if (player->GameOver)         /* do not reanimate dead player */
3015     return;
3016
3017   if (!player_relocated)        /* no need to relocate the player */
3018     return;
3019
3020   if (IS_PLAYER(jx, jy))        /* player already placed at new position */
3021   {
3022     RemoveField(jx, jy);        /* temporarily remove newly placed player */
3023     DrawLevelField(jx, jy);
3024   }
3025
3026   if (player->present)
3027   {
3028     while (player->MovPos)
3029     {
3030       ScrollPlayer(player, SCROLL_GO_ON);
3031       ScrollScreen(NULL, SCROLL_GO_ON);
3032
3033 #if USE_NEW_MOVE_DELAY
3034       AdvanceFrameAndPlayerCounters(player->index_nr);
3035 #else
3036       FrameCounter++;
3037 #endif
3038
3039       DrawPlayer(player);
3040
3041       BackToFront();
3042       Delay(wait_delay_value);
3043     }
3044
3045     DrawPlayer(player);         /* needed here only to cleanup last field */
3046     DrawLevelField(player->jx, player->jy);     /* remove player graphic */
3047
3048     player->is_moving = FALSE;
3049   }
3050
3051 #if 1
3052   if (IS_CUSTOM_ELEMENT(old_element))
3053     CheckElementChangeByPlayer(old_jx, old_jy, old_element,
3054                                CE_LEFT_BY_PLAYER,
3055                                player->index_bit, leave_side);
3056
3057   CheckTriggeredElementChangeByPlayer(old_jx, old_jy, old_element,
3058                                       CE_OTHER_GETS_LEFT,
3059                                       player->index_bit, leave_side);
3060 #endif
3061
3062   Feld[jx][jy] = el_player;
3063   InitPlayerField(jx, jy, el_player, TRUE);
3064
3065   if (!ELEM_IS_PLAYER(element)) /* player may be set on walkable element */
3066   {
3067     Feld[jx][jy] = element;
3068     InitField(jx, jy, FALSE);
3069   }
3070
3071 #if 1
3072   if (player == local_player)   /* only visually relocate local player */
3073     DrawRelocatePlayer(player);
3074 #endif
3075
3076 #if 1
3077   TestIfHeroTouchesBadThing(jx, jy);
3078   TestIfPlayerTouchesCustomElement(jx, jy);
3079 #endif
3080
3081 #if 0
3082   printf("::: %d,%d: %d\n", jx, jy-1, Changed[jx][jy-1]);
3083 #endif
3084
3085 #if 0
3086 #if 0
3087   /* needed to allow change of walkable custom element by entering player */
3088   if (!(Changed[jx][jy] & CH_EVENT_BIT(CE_ENTERED_BY_PLAYER)))
3089     Changed[jx][jy] = 0;        /* allow another change (but prevent loop) */
3090 #else
3091   /* needed to allow change of walkable custom element by entering player */
3092   Changed[jx][jy] = 0;          /* allow another change */
3093 #endif
3094 #endif
3095
3096 #if 0
3097   printf("::: player entering %d, %d from %s ...\n", jx, jy,
3098          enter_side == MV_LEFT  ? "left" :
3099          enter_side == MV_RIGHT ? "right" :
3100          enter_side == MV_UP    ? "top" :
3101          enter_side == MV_DOWN  ? "bottom" : "oops! no idea!");
3102 #endif
3103
3104 #if 1
3105   if (IS_CUSTOM_ELEMENT(element))
3106     CheckElementChangeByPlayer(jx, jy, element, CE_ENTERED_BY_PLAYER,
3107                                player->index_bit, enter_side);
3108
3109   CheckTriggeredElementChangeByPlayer(jx, jy, element,
3110                                       CE_OTHER_GETS_ENTERED,
3111                                       player->index_bit, enter_side);
3112 #endif
3113 }
3114
3115 void Explode(int ex, int ey, int phase, int mode)
3116 {
3117   int x, y;
3118 #if 0
3119   int num_phase = 9;
3120 #endif
3121
3122   /* !!! eliminate this variable !!! */
3123   int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3124
3125 #if 1
3126   int last_phase;
3127 #else
3128   int last_phase = num_phase * delay;
3129   int half_phase = (num_phase / 2) * delay;
3130   int first_phase_after_start = EX_PHASE_START + 1;
3131 #endif
3132   int border_element;
3133
3134   if (game.explosions_delayed)
3135   {
3136     ExplodeField[ex][ey] = mode;
3137     return;
3138   }
3139
3140   if (phase == EX_PHASE_START)          /* initialize 'Store[][]' field */
3141   {
3142     int center_element = Feld[ex][ey];
3143
3144 #if 0
3145     printf("::: start explosion %d,%d [%d]\n", ex, ey, FrameCounter);
3146 #endif
3147
3148 #if 0
3149     /* --- This is only really needed (and now handled) in "Impact()". --- */
3150     /* do not explode moving elements that left the explode field in time */
3151     if (game.engine_version >= VERSION_IDENT(2,2,0,7) &&
3152         center_element == EL_EMPTY &&
3153         (mode == EX_TYPE_NORMAL || mode == EX_TYPE_CENTER))
3154       return;
3155 #endif
3156
3157 #if 1
3158     if (mode == EX_TYPE_NORMAL ||
3159         mode == EX_TYPE_CENTER ||
3160         mode == EX_TYPE_CROSS)
3161       PlayLevelSoundAction(ex, ey, ACTION_EXPLODING);
3162 #else
3163     if (mode == EX_TYPE_NORMAL || mode == EX_TYPE_CENTER)
3164       PlayLevelSoundAction(ex, ey, ACTION_EXPLODING);
3165 #endif
3166
3167     /* remove things displayed in background while burning dynamite */
3168     if (Back[ex][ey] != EL_EMPTY && !IS_INDESTRUCTIBLE(Back[ex][ey]))
3169       Back[ex][ey] = 0;
3170
3171     if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey))
3172     {
3173       /* put moving element to center field (and let it explode there) */
3174       center_element = MovingOrBlocked2Element(ex, ey);
3175       RemoveMovingField(ex, ey);
3176       Feld[ex][ey] = center_element;
3177     }
3178
3179 #if 1
3180
3181 #if 1
3182     last_phase = element_info[center_element].explosion_delay + 1;
3183 #else
3184     last_phase = element_info[center_element].explosion_delay;
3185 #endif
3186
3187 #if 0
3188     printf("::: %d -> %d\n", center_element, last_phase);
3189 #endif
3190 #endif
3191
3192     for (y = ey - 1; y <= ey + 1; y++) for (x = ex - 1; x <= ex + 1; x++)
3193     {
3194       int xx = x - ex + 1;
3195       int yy = y - ey + 1;
3196       int element;
3197
3198 #if 1
3199 #if 1
3200       if (!IN_LEV_FIELD(x, y) ||
3201           (mode & EX_TYPE_SINGLE_TILE && (x != ex || y != ey)) ||
3202           (mode == EX_TYPE_CROSS      && (x != ex && y != ey)))
3203         continue;
3204 #else
3205       if (!IN_LEV_FIELD(x, y) ||
3206           (mode != EX_TYPE_NORMAL && (x != ex || y != ey)))
3207         continue;
3208 #endif
3209 #else
3210       if (!IN_LEV_FIELD(x, y) ||
3211           ((mode != EX_TYPE_NORMAL ||
3212             center_element == EL_AMOEBA_TO_DIAMOND) &&
3213            (x != ex || y != ey)))
3214         continue;
3215 #endif
3216
3217       element = Feld[x][y];
3218
3219       if (IS_MOVING(x, y) || IS_BLOCKED(x, y))
3220       {
3221         element = MovingOrBlocked2Element(x, y);
3222
3223         if (!IS_EXPLOSION_PROOF(element))
3224           RemoveMovingField(x, y);
3225       }
3226
3227 #if 1
3228
3229 #if 0
3230       if (IS_EXPLOSION_PROOF(element))
3231         continue;
3232 #else
3233       /* indestructible elements can only explode in center (but not flames) */
3234 #if 1
3235       if ((IS_EXPLOSION_PROOF(element) && (x != ex || y != ey ||
3236                                            mode == EX_TYPE_BORDER)) ||
3237           element == EL_FLAMES)
3238         continue;
3239 #else
3240       if ((IS_EXPLOSION_PROOF(element) && (x != ex || y != ey)) ||
3241           element == EL_FLAMES)
3242         continue;
3243 #endif
3244 #endif
3245
3246 #else
3247       if ((IS_INDESTRUCTIBLE(element) &&
3248            (game.engine_version < VERSION_IDENT(2,2,0,0) ||
3249             (!IS_WALKABLE_OVER(element) && !IS_WALKABLE_UNDER(element)))) ||
3250           element == EL_FLAMES)
3251         continue;
3252 #endif
3253
3254 #if 1
3255       if (IS_PLAYER(x, y) && SHIELD_ON(PLAYERINFO(x, y)) &&
3256           (game.engine_version < VERSION_IDENT(3,1,0,0) ||
3257            (x == ex && y == ey && mode != EX_TYPE_BORDER)))
3258 #else
3259       if (IS_PLAYER(x, y) && SHIELD_ON(PLAYERINFO(x, y)))
3260 #endif
3261       {
3262         if (IS_ACTIVE_BOMB(element))
3263         {
3264           /* re-activate things under the bomb like gate or penguin */
3265 #if 1
3266           Feld[x][y] = (Back[x][y] ? Back[x][y] : EL_EMPTY);
3267           Back[x][y] = 0;
3268 #else
3269           Feld[x][y] = (Store[x][y] ? Store[x][y] : EL_EMPTY);
3270           Store[x][y] = 0;
3271 #endif
3272
3273 #if 0
3274         printf("::: %d,%d: %d %s [%d, %d]\n", x, y, Feld[x][y],
3275                element_info[Feld[x][y]].token_name,
3276                Store[x][y], Store2[x][y]);
3277 #endif
3278         }
3279
3280         continue;
3281       }
3282
3283       /* save walkable background elements while explosion on same tile */
3284 #if 0
3285       if (IS_INDESTRUCTIBLE(element))
3286         Back[x][y] = element;
3287 #else
3288 #if 1
3289 #if 1
3290       if (IS_WALKABLE(element) && IS_INDESTRUCTIBLE(element) &&
3291           (x != ex || y != ey || mode == EX_TYPE_BORDER))
3292         Back[x][y] = element;
3293 #else
3294       if (IS_WALKABLE(element) && IS_INDESTRUCTIBLE(element) &&
3295           (x != ex || y != ey))
3296         Back[x][y] = element;
3297 #endif
3298 #else
3299       if (IS_WALKABLE(element) && IS_INDESTRUCTIBLE(element))
3300         Back[x][y] = element;
3301 #endif
3302 #endif
3303
3304       /* ignite explodable elements reached by other explosion */
3305       if (element == EL_EXPLOSION)
3306         element = Store2[x][y];
3307
3308 #if 1
3309       if (AmoebaNr[x][y] &&
3310           (element == EL_AMOEBA_FULL ||
3311            element == EL_BD_AMOEBA ||
3312            element == EL_AMOEBA_GROWING))
3313       {
3314         AmoebaCnt[AmoebaNr[x][y]]--;
3315         AmoebaCnt2[AmoebaNr[x][y]]--;
3316       }
3317
3318       RemoveField(x, y);
3319 #endif
3320
3321       if (IS_PLAYER(ex, ey) && !PLAYER_EXPLOSION_PROTECTED(ex, ey))
3322       {
3323         switch(StorePlayer[ex][ey])
3324         {
3325           case EL_PLAYER_2:
3326             Store[x][y] = EL_PLAYER_IS_EXPLODING_2;
3327             break;
3328           case EL_PLAYER_3:
3329             Store[x][y] = EL_PLAYER_IS_EXPLODING_3;
3330             break;
3331           case EL_PLAYER_4:
3332             Store[x][y] = EL_PLAYER_IS_EXPLODING_4;
3333             break;
3334           case EL_PLAYER_1:
3335           default:
3336             Store[x][y] = EL_PLAYER_IS_EXPLODING_1;
3337             break;
3338         }
3339
3340 #if 1
3341         if (PLAYERINFO(ex, ey)->use_murphy_graphic)
3342           Store[x][y] = EL_EMPTY;
3343 #else
3344         if (game.emulation == EMU_SUPAPLEX)
3345           Store[x][y] = EL_EMPTY;
3346 #endif
3347       }
3348       else if (center_element == EL_MOLE)
3349         Store[x][y] = EL_EMERALD_RED;
3350       else if (center_element == EL_PENGUIN)
3351         Store[x][y] = EL_EMERALD_PURPLE;
3352       else if (center_element == EL_BUG)
3353         Store[x][y] = ((x == ex && y == ey) ? EL_DIAMOND : EL_EMERALD);
3354       else if (center_element == EL_BD_BUTTERFLY)
3355         Store[x][y] = EL_BD_DIAMOND;
3356       else if (center_element == EL_SP_ELECTRON)
3357         Store[x][y] = EL_SP_INFOTRON;
3358       else if (center_element == EL_AMOEBA_TO_DIAMOND)
3359         Store[x][y] = level.amoeba_content;
3360       else if (center_element == EL_YAMYAM)
3361         Store[x][y] = level.yamyam_content[game.yamyam_content_nr][xx][yy];
3362       else if (IS_CUSTOM_ELEMENT(center_element) &&
3363                element_info[center_element].content[xx][yy] != EL_EMPTY)
3364         Store[x][y] = element_info[center_element].content[xx][yy];
3365       else if (element == EL_WALL_EMERALD)
3366         Store[x][y] = EL_EMERALD;
3367       else if (element == EL_WALL_DIAMOND)
3368         Store[x][y] = EL_DIAMOND;
3369       else if (element == EL_WALL_BD_DIAMOND)
3370         Store[x][y] = EL_BD_DIAMOND;
3371       else if (element == EL_WALL_EMERALD_YELLOW)
3372         Store[x][y] = EL_EMERALD_YELLOW;
3373       else if (element == EL_WALL_EMERALD_RED)
3374         Store[x][y] = EL_EMERALD_RED;
3375       else if (element == EL_WALL_EMERALD_PURPLE)
3376         Store[x][y] = EL_EMERALD_PURPLE;
3377       else if (element == EL_WALL_PEARL)
3378         Store[x][y] = EL_PEARL;
3379       else if (element == EL_WALL_CRYSTAL)
3380         Store[x][y] = EL_CRYSTAL;
3381       else if (IS_CUSTOM_ELEMENT(element) && !CAN_EXPLODE(element))
3382         Store[x][y] = element_info[element].content[1][1];
3383       else
3384         Store[x][y] = EL_EMPTY;
3385
3386       if (x != ex || y != ey || mode == EX_TYPE_BORDER ||
3387           center_element == EL_AMOEBA_TO_DIAMOND)
3388         Store2[x][y] = element;
3389
3390 #if 0
3391       printf("::: %d,%d: %d %s\n", x, y, Store2[x][y],
3392              element_info[Store2[x][y]].token_name);
3393 #endif
3394
3395 #if 0
3396       if (AmoebaNr[x][y] &&
3397           (element == EL_AMOEBA_FULL ||
3398            element == EL_BD_AMOEBA ||
3399            element == EL_AMOEBA_GROWING))
3400       {
3401         AmoebaCnt[AmoebaNr[x][y]]--;
3402         AmoebaCnt2[AmoebaNr[x][y]]--;
3403       }
3404
3405 #if 1
3406       RemoveField(x, y);
3407 #else
3408       MovDir[x][y] = MovPos[x][y] = 0;
3409       GfxDir[x][y] = MovDir[x][y];
3410       AmoebaNr[x][y] = 0;
3411 #endif
3412 #endif
3413
3414       Feld[x][y] = EL_EXPLOSION;
3415 #if 1
3416       GfxElement[x][y] = center_element;
3417 #else
3418       GfxElement[x][y] = EL_UNDEFINED;
3419 #endif
3420
3421       ExplodePhase[x][y] = 1;
3422 #if 1
3423       ExplodeDelay[x][y] = last_phase;
3424 #endif
3425
3426 #if 0
3427 #if 1
3428       GfxFrame[x][y] = 0;       /* animation does not start until next frame */
3429 #else
3430       GfxFrame[x][y] = -1;      /* animation does not start until next frame */
3431 #endif
3432 #endif
3433
3434       Stop[x][y] = TRUE;
3435     }
3436
3437     if (center_element == EL_YAMYAM)
3438       game.yamyam_content_nr =
3439         (game.yamyam_content_nr + 1) % level.num_yamyam_contents;
3440
3441 #if 0
3442   printf("::: %d,%d: %d %s [%d]\n", ex + 1, ey, Feld[ex + 1][ey],
3443          element_info[Feld[ex + 1][ey]].token_name, Store2[ex + 1][ey]);
3444 #endif
3445
3446     return;
3447   }
3448
3449   if (Stop[ex][ey])
3450     return;
3451
3452   x = ex;
3453   y = ey;
3454
3455 #if 1
3456   if (phase == 1)
3457     GfxFrame[x][y] = 0;         /* restart explosion animation */
3458 #endif
3459
3460 #if 0
3461   printf(":X: phase == %d [%d]\n", phase, GfxFrame[x][y]);
3462 #endif
3463
3464 #if 1
3465   last_phase = ExplodeDelay[x][y];
3466 #endif
3467
3468   ExplodePhase[x][y] = (phase < last_phase ? phase + 1 : 0);
3469
3470 #ifdef DEBUG
3471
3472   /* activate this even in non-DEBUG version until cause for crash in
3473      getGraphicAnimationFrame() (see below) is found and eliminated */
3474 #endif
3475 #if 1
3476
3477   if (GfxElement[x][y] == EL_UNDEFINED)
3478   {
3479     printf("\n\n");
3480     printf("Explode(): x = %d, y = %d: GfxElement == EL_UNDEFINED\n", x, y);
3481     printf("Explode(): This should never happen!\n");
3482     printf("\n\n");
3483
3484     GfxElement[x][y] = EL_EMPTY;
3485   }
3486 #endif
3487
3488 #if 1
3489
3490   border_element = Store2[x][y];
3491 #if 1
3492   if (IS_PLAYER(x, y) && !PLAYER_EXPLOSION_PROTECTED(x, y))
3493     border_element = StorePlayer[x][y];
3494 #else
3495   if (IS_PLAYER(x, y))
3496     border_element = StorePlayer[x][y];
3497 #endif
3498
3499 #if 0
3500   printf("::: %d,%d: %d %s [%d]\n", x, y, border_element,
3501          element_info[border_element].token_name, Store2[x][y]);
3502 #endif
3503
3504 #if 0
3505   printf("::: phase == %d\n", phase);
3506 #endif
3507
3508   if (phase == element_info[border_element].ignition_delay ||
3509       phase == last_phase)
3510   {
3511     boolean border_explosion = FALSE;
3512
3513 #if 1
3514 #if 1
3515     if (IS_PLAYER(x, y) && PLAYERINFO(x, y)->present &&
3516         !PLAYER_EXPLOSION_PROTECTED(x, y))
3517 #else
3518     if (IS_PLAYER(x, y) && PLAYERINFO(x, y)->present)
3519 #endif
3520 #else
3521     if (IS_PLAYER(x, y))
3522 #endif
3523     {
3524       KillHeroUnlessExplosionProtected(x, y);
3525       border_explosion = TRUE;
3526
3527 #if 0
3528       if (phase == last_phase)
3529         printf("::: IS_PLAYER\n");
3530 #endif
3531     }
3532     else if (CAN_EXPLODE_BY_EXPLOSION(border_element))
3533     {
3534 #if 0
3535       printf("::: %d,%d: %d %s\n", x, y, border_element,
3536              element_info[border_element].token_name);
3537 #endif
3538
3539       Feld[x][y] = Store2[x][y];
3540       Store2[x][y] = 0;
3541       Bang(x, y);
3542       border_explosion = TRUE;
3543
3544 #if 0
3545       if (phase == last_phase)
3546         printf("::: CAN_EXPLODE_BY_EXPLOSION\n");
3547 #endif
3548     }
3549     else if (border_element == EL_AMOEBA_TO_DIAMOND)
3550     {
3551       AmoebeUmwandeln(x, y);
3552       Store2[x][y] = 0;
3553       border_explosion = TRUE;
3554
3555 #if 0
3556       if (phase == last_phase)
3557         printf("::: EL_AMOEBA_TO_DIAMOND [%d, %d] [%d]\n",
3558                element_info[border_element].explosion_delay,
3559                element_info[border_element].ignition_delay,
3560                phase);
3561 #endif
3562     }
3563
3564 #if 1
3565     /* if an element just explodes due to another explosion (chain-reaction),
3566        do not immediately end the new explosion when it was the last frame of
3567        the explosion (as it would be done in the following "if"-statement!) */
3568     if (border_explosion && phase == last_phase)
3569       return;
3570 #endif
3571   }
3572
3573 #else
3574
3575   if (phase == first_phase_after_start)
3576   {
3577     int element = Store2[x][y];
3578
3579     if (element == EL_BLACK_ORB)
3580     {
3581       Feld[x][y] = Store2[x][y];
3582       Store2[x][y] = 0;
3583       Bang(x, y);
3584     }
3585   }
3586   else if (phase == half_phase)
3587   {
3588     int element = Store2[x][y];
3589
3590     if (IS_PLAYER(x, y))
3591       KillHeroUnlessExplosionProtected(x, y);
3592     else if (CAN_EXPLODE_BY_EXPLOSION(element))
3593     {
3594       Feld[x][y] = Store2[x][y];
3595       Store2[x][y] = 0;
3596       Bang(x, y);
3597     }
3598     else if (element == EL_AMOEBA_TO_DIAMOND)
3599       AmoebeUmwandeln(x, y);
3600   }
3601 #endif
3602
3603   if (phase == last_phase)
3604   {
3605     int element;
3606
3607 #if 0
3608   printf("::: done: phase == %d\n", phase);
3609 #endif
3610
3611 #if 0
3612     printf("::: explosion %d,%d done [%d]\n", x, y, FrameCounter);
3613 #endif
3614
3615     element = Feld[x][y] = Store[x][y];
3616     Store[x][y] = Store2[x][y] = 0;
3617     GfxElement[x][y] = EL_UNDEFINED;
3618
3619     /* player can escape from explosions and might therefore be still alive */
3620     if (element >= EL_PLAYER_IS_EXPLODING_1 &&
3621         element <= EL_PLAYER_IS_EXPLODING_4)
3622       Feld[x][y] = (stored_player[element - EL_PLAYER_IS_EXPLODING_1].active ?
3623                     EL_EMPTY :
3624                     element == EL_PLAYER_IS_EXPLODING_1 ? EL_EMERALD_YELLOW :
3625                     element == EL_PLAYER_IS_EXPLODING_2 ? EL_EMERALD_RED :
3626                     element == EL_PLAYER_IS_EXPLODING_3 ? EL_EMERALD :
3627                     EL_EMERALD_PURPLE);
3628
3629     /* restore probably existing indestructible background element */
3630     if (Back[x][y] && IS_INDESTRUCTIBLE(Back[x][y]))
3631       element = Feld[x][y] = Back[x][y];
3632     Back[x][y] = 0;
3633
3634     MovDir[x][y] = MovPos[x][y] = MovDelay[x][y] = 0;
3635     GfxDir[x][y] = MV_NO_MOVING;
3636     ChangeDelay[x][y] = 0;
3637     ChangePage[x][y] = -1;
3638
3639 #if 1
3640     InitField_WithBug2(x, y, FALSE);
3641 #else
3642     InitField(x, y, FALSE);
3643 #if 1
3644     /* !!! not needed !!! */
3645 #if 1
3646     if (game.engine_version < VERSION_IDENT(3,1,0,0) &&
3647         CAN_MOVE(Feld[x][y]) && Feld[x][y] != EL_MOLE)
3648       InitMovDir(x, y);
3649 #else
3650     if (CAN_MOVE(element))
3651       InitMovDir(x, y);
3652 #endif
3653 #endif
3654 #endif
3655     DrawLevelField(x, y);
3656
3657     TestIfElementTouchesCustomElement(x, y);
3658
3659     if (GFX_CRUMBLED(element))
3660       DrawLevelFieldCrumbledSandNeighbours(x, y);
3661
3662     if (IS_PLAYER(x, y) && !PLAYERINFO(x, y)->present)
3663       StorePlayer[x][y] = 0;
3664
3665     if (ELEM_IS_PLAYER(element))
3666       RelocatePlayer(x, y, element);
3667   }
3668 #if 1
3669   else if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3670 #else
3671   else if (phase >= delay && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3672 #endif
3673   {
3674 #if 1
3675     int graphic = el_act2img(GfxElement[x][y], ACTION_EXPLODING);
3676 #else
3677     int stored = Store[x][y];
3678     int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION :
3679                    stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
3680                    IMG_SP_EXPLOSION);
3681 #endif
3682 #if 1
3683     int frame = getGraphicAnimationFrame(graphic, GfxFrame[x][y]);
3684 #else
3685     int frame = getGraphicAnimationFrame(graphic, phase - delay);
3686 #endif
3687
3688 #if 0
3689   printf("::: phase == %d [%d]\n", phase, GfxFrame[x][y]);
3690 #endif
3691
3692 #if 0
3693     printf("::: %d / %d [%d - %d]\n",
3694            GfxFrame[x][y], phase - delay, phase, delay);
3695 #endif
3696
3697 #if 0
3698     printf("::: %d ['%s'] -> %d\n", GfxElement[x][y],
3699            element_info[GfxElement[x][y]].token_name,
3700            graphic);
3701 #endif
3702
3703     if (phase == delay)
3704       DrawLevelFieldCrumbledSand(x, y);
3705
3706     if (IS_WALKABLE_OVER(Back[x][y]) && Back[x][y] != EL_EMPTY)
3707     {
3708       DrawLevelElement(x, y, Back[x][y]);
3709       DrawGraphicThruMask(SCREENX(x), SCREENY(y), graphic, frame);
3710     }
3711     else if (IS_WALKABLE_UNDER(Back[x][y]))
3712     {
3713       DrawGraphic(SCREENX(x), SCREENY(y), graphic, frame);
3714       DrawLevelElementThruMask(x, y, Back[x][y]);
3715     }
3716     else if (!IS_WALKABLE_INSIDE(Back[x][y]))
3717       DrawGraphic(SCREENX(x), SCREENY(y), graphic, frame);
3718   }
3719 }
3720
3721 void DynaExplode(int ex, int ey)
3722 {
3723   int i, j;
3724   int dynabomb_element = Feld[ex][ey];
3725   int dynabomb_size = 1;
3726   boolean dynabomb_xl = FALSE;
3727   struct PlayerInfo *player;
3728   static int xy[4][2] =
3729   {
3730     { 0, -1 },
3731     { -1, 0 },
3732     { +1, 0 },
3733     { 0, +1 }
3734   };
3735
3736   if (IS_ACTIVE_BOMB(dynabomb_element))
3737   {
3738     player = &stored_player[dynabomb_element - EL_DYNABOMB_PLAYER_1_ACTIVE];
3739     dynabomb_size = player->dynabomb_size;
3740     dynabomb_xl = player->dynabomb_xl;
3741     player->dynabombs_left++;
3742   }
3743
3744   Explode(ex, ey, EX_PHASE_START, EX_TYPE_CENTER);
3745
3746   for (i = 0; i < NUM_DIRECTIONS; i++)
3747   {
3748     for (j = 1; j <= dynabomb_size; j++)
3749     {
3750       int x = ex + j * xy[i][0];
3751       int y = ey + j * xy[i][1];
3752       int element;
3753
3754       if (!IN_LEV_FIELD(x, y) || IS_INDESTRUCTIBLE(Feld[x][y]))
3755         break;
3756
3757       element = Feld[x][y];
3758
3759       /* do not restart explosions of fields with active bombs */
3760       if (element == EL_EXPLOSION && IS_ACTIVE_BOMB(Store2[x][y]))
3761         continue;
3762
3763       Explode(x, y, EX_PHASE_START, EX_TYPE_BORDER);
3764
3765 #if 1
3766 #if 1
3767       if (element != EL_EMPTY && element != EL_EXPLOSION &&
3768           !IS_DIGGABLE(element) && !dynabomb_xl)
3769         break;
3770 #else
3771       if (element != EL_EMPTY && element != EL_EXPLOSION &&
3772           !CAN_GROW_INTO(element) && !dynabomb_xl)
3773         break;
3774 #endif
3775 #else
3776       /* !!! extend EL_SAND to anything diggable (but maybe not SP_BASE) !!! */
3777       if (element != EL_EMPTY && element != EL_EXPLOSION &&
3778           element != EL_SAND && !dynabomb_xl)
3779         break;
3780 #endif
3781     }
3782   }
3783 }
3784
3785 void Bang(int x, int y)
3786 {
3787 #if 1
3788   int element = MovingOrBlocked2Element(x, y);
3789 #else
3790   int element = Feld[x][y];
3791 #endif
3792
3793 #if 1
3794   if (IS_PLAYER(x, y) && !PLAYER_EXPLOSION_PROTECTED(x, y))
3795 #else
3796   if (IS_PLAYER(x, y))
3797 #endif
3798   {
3799     struct PlayerInfo *player = PLAYERINFO(x, y);
3800
3801     element = Feld[x][y] = (player->use_murphy_graphic ? EL_SP_MURPHY :
3802                             player->element_nr);
3803   }
3804
3805 #if 0
3806 #if 1
3807   PlayLevelSoundAction(x, y, ACTION_EXPLODING);
3808 #else
3809   if (game.emulation == EMU_SUPAPLEX)
3810     PlayLevelSound(x, y, SND_SP_ELEMENT_EXPLODING);
3811   else
3812     PlayLevelSound(x, y, SND_ELEMENT_EXPLODING);
3813 #endif
3814 #endif
3815
3816 #if 0
3817   if (IS_PLAYER(x, y))  /* remove objects that might cause smaller explosion */
3818     element = EL_EMPTY;
3819 #endif
3820
3821   switch(element)
3822   {
3823     case EL_BUG:
3824     case EL_SPACESHIP:
3825     case EL_BD_BUTTERFLY:
3826     case EL_BD_FIREFLY:
3827     case EL_YAMYAM:
3828     case EL_DARK_YAMYAM:
3829     case EL_ROBOT:
3830     case EL_PACMAN:
3831     case EL_MOLE:
3832       RaiseScoreElement(element);
3833       Explode(x, y, EX_PHASE_START, EX_TYPE_NORMAL);
3834       break;
3835     case EL_DYNABOMB_PLAYER_1_ACTIVE:
3836     case EL_DYNABOMB_PLAYER_2_ACTIVE:
3837     case EL_DYNABOMB_PLAYER_3_ACTIVE:
3838     case EL_DYNABOMB_PLAYER_4_ACTIVE:
3839     case EL_DYNABOMB_INCREASE_NUMBER:
3840     case EL_DYNABOMB_INCREASE_SIZE:
3841     case EL_DYNABOMB_INCREASE_POWER:
3842       DynaExplode(x, y);
3843       break;
3844     case EL_PENGUIN:
3845     case EL_LAMP:
3846     case EL_LAMP_ACTIVE:
3847 #if 1
3848     case EL_AMOEBA_TO_DIAMOND:
3849 #endif
3850       if (IS_PLAYER(x, y))
3851         Explode(x, y, EX_PHASE_START, EX_TYPE_NORMAL);
3852       else
3853         Explode(x, y, EX_PHASE_START, EX_TYPE_CENTER);
3854       break;
3855     default:
3856 #if 1
3857       if (element_info[element].explosion_type == EXPLODES_CROSS)
3858 #else
3859       if (CAN_EXPLODE_CROSS(element))
3860 #endif
3861 #if 1
3862         Explode(x, y, EX_PHASE_START, EX_TYPE_CROSS);
3863 #else
3864         DynaExplode(x, y);
3865 #endif
3866 #if 1
3867       else if (element_info[element].explosion_type == EXPLODES_1X1)
3868 #else
3869       else if (CAN_EXPLODE_1X1(element))
3870 #endif
3871         Explode(x, y, EX_PHASE_START, EX_TYPE_CENTER);
3872       else
3873         Explode(x, y, EX_PHASE_START, EX_TYPE_NORMAL);
3874       break;
3875   }
3876
3877   CheckTriggeredElementChange(x, y, element, CE_OTHER_IS_EXPLODING);
3878 }
3879
3880 void SplashAcid(int x, int y)
3881 {
3882 #if 1
3883   if (IN_LEV_FIELD(x - 1, y - 1) && IS_FREE(x - 1, y - 1) &&
3884       (!IN_LEV_FIELD(x - 1, y - 2) ||
3885        !CAN_FALL(MovingOrBlocked2Element(x - 1, y - 2))))
3886     Feld[x - 1][y - 1] = EL_ACID_SPLASH_LEFT;
3887
3888   if (IN_LEV_FIELD(x + 1, y - 1) && IS_FREE(x + 1, y - 1) &&
3889       (!IN_LEV_FIELD(x + 1, y - 2) ||
3890        !CAN_FALL(MovingOrBlocked2Element(x + 1, y - 2))))
3891     Feld[x + 1][y - 1] = EL_ACID_SPLASH_RIGHT;
3892
3893   PlayLevelSound(x, y, SND_ACID_SPLASHING);
3894 #else
3895   /* input: position of element entering acid (obsolete) */
3896
3897   int element = Feld[x][y];
3898
3899   if (!IN_LEV_FIELD(x, y + 1) || Feld[x][y + 1] != EL_ACID)
3900     return;
3901
3902   if (element != EL_ACID_SPLASH_LEFT &&
3903       element != EL_ACID_SPLASH_RIGHT)
3904   {
3905     PlayLevelSound(x, y, SND_ACID_SPLASHING);
3906
3907     if (IN_LEV_FIELD(x - 1, y) && IS_FREE(x - 1, y) &&
3908         (!IN_LEV_FIELD(x - 1, y - 1) ||
3909          !CAN_FALL(MovingOrBlocked2Element(x - 1, y - 1))))
3910       Feld[x - 1][y] = EL_ACID_SPLASH_LEFT;
3911
3912     if (IN_LEV_FIELD(x + 1, y) && IS_FREE(x + 1, y) &&
3913         (!IN_LEV_FIELD(x + 1, y - 1) ||
3914          !CAN_FALL(MovingOrBlocked2Element(x + 1, y - 1))))
3915       Feld[x + 1][y] = EL_ACID_SPLASH_RIGHT;
3916   }
3917 #endif
3918 }
3919
3920 static void InitBeltMovement()
3921 {
3922   static int belt_base_element[4] =
3923   {
3924     EL_CONVEYOR_BELT_1_LEFT,
3925     EL_CONVEYOR_BELT_2_LEFT,
3926     EL_CONVEYOR_BELT_3_LEFT,
3927     EL_CONVEYOR_BELT_4_LEFT
3928   };
3929   static int belt_base_active_element[4] =
3930   {
3931     EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3932     EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3933     EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3934     EL_CONVEYOR_BELT_4_LEFT_ACTIVE
3935   };
3936
3937   int x, y, i, j;
3938
3939   /* set frame order for belt animation graphic according to belt direction */
3940   for (i = 0; i < NUM_BELTS; i++)
3941   {
3942     int belt_nr = i;
3943
3944     for (j = 0; j < NUM_BELT_PARTS; j++)
3945     {
3946       int element = belt_base_active_element[belt_nr] + j;
3947       int graphic = el2img(element);
3948
3949       if (game.belt_dir[i] == MV_LEFT)
3950         graphic_info[graphic].anim_mode &= ~ANIM_REVERSE;
3951       else
3952         graphic_info[graphic].anim_mode |=  ANIM_REVERSE;
3953     }
3954   }
3955
3956   for (y = 0; y < lev_fieldy; y++)
3957   {
3958     for (x = 0; x < lev_fieldx; x++)
3959     {
3960       int element = Feld[x][y];
3961
3962       for (i = 0; i < NUM_BELTS; i++)
3963       {
3964         if (IS_BELT(element) && game.belt_dir[i] != MV_NO_MOVING)
3965         {
3966           int e_belt_nr = getBeltNrFromBeltElement(element);
3967           int belt_nr = i;
3968
3969           if (e_belt_nr == belt_nr)
3970           {
3971             int belt_part = Feld[x][y] - belt_base_element[belt_nr];
3972
3973             Feld[x][y] = belt_base_active_element[belt_nr] + belt_part;
3974           }
3975         }
3976       }
3977     }
3978   }
3979 }
3980
3981 static void ToggleBeltSwitch(int x, int y)
3982 {
3983   static int belt_base_element[4] =
3984   {
3985     EL_CONVEYOR_BELT_1_LEFT,
3986     EL_CONVEYOR_BELT_2_LEFT,
3987     EL_CONVEYOR_BELT_3_LEFT,
3988     EL_CONVEYOR_BELT_4_LEFT
3989   };
3990   static int belt_base_active_element[4] =
3991   {
3992     EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3993     EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3994     EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3995     EL_CONVEYOR_BELT_4_LEFT_ACTIVE
3996   };
3997   static int belt_base_switch_element[4] =
3998   {
3999     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4000     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4001     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4002     EL_CONVEYOR_BELT_4_SWITCH_LEFT
4003   };
4004   static int belt_move_dir[4] =
4005   {
4006     MV_LEFT,
4007     MV_NO_MOVING,
4008     MV_RIGHT,
4009     MV_NO_MOVING,
4010   };
4011
4012   int element = Feld[x][y];
4013   int belt_nr = getBeltNrFromBeltSwitchElement(element);
4014   int belt_dir_nr = (game.belt_dir_nr[belt_nr] + 1) % 4;
4015   int belt_dir = belt_move_dir[belt_dir_nr];
4016   int xx, yy, i;
4017
4018   if (!IS_BELT_SWITCH(element))
4019     return;
4020
4021   game.belt_dir_nr[belt_nr] = belt_dir_nr;
4022   game.belt_dir[belt_nr] = belt_dir;
4023
4024   if (belt_dir_nr == 3)
4025     belt_dir_nr = 1;
4026
4027   /* set frame order for belt animation graphic according to belt direction */
4028   for (i = 0; i < NUM_BELT_PARTS; i++)
4029   {
4030     int element = belt_base_active_element[belt_nr] + i;
4031     int graphic = el2img(element);
4032
4033     if (belt_dir == MV_LEFT)
4034       graphic_info[graphic].anim_mode &= ~ANIM_REVERSE;
4035     else
4036       graphic_info[graphic].anim_mode |=  ANIM_REVERSE;
4037   }
4038
4039   for (yy = 0; yy < lev_fieldy; yy++)
4040   {
4041     for (xx = 0; xx < lev_fieldx; xx++)
4042     {
4043       int element = Feld[xx][yy];
4044
4045       if (IS_BELT_SWITCH(element))
4046       {
4047         int e_belt_nr = getBeltNrFromBeltSwitchElement(element);
4048
4049         if (e_belt_nr == belt_nr)
4050         {
4051           Feld[xx][yy] = belt_base_switch_element[belt_nr] + belt_dir_nr;
4052           DrawLevelField(xx, yy);
4053         }
4054       }
4055       else if (IS_BELT(element) && belt_dir != MV_NO_MOVING)
4056       {
4057         int e_belt_nr = getBeltNrFromBeltElement(element);
4058
4059         if (e_belt_nr == belt_nr)
4060         {
4061           int belt_part = Feld[xx][yy] - belt_base_element[belt_nr];
4062
4063           Feld[xx][yy] = belt_base_active_element[belt_nr] + belt_part;
4064           DrawLevelField(xx, yy);
4065         }
4066       }
4067       else if (IS_BELT_ACTIVE(element) && belt_dir == MV_NO_MOVING)
4068       {
4069         int e_belt_nr = getBeltNrFromBeltActiveElement(element);
4070
4071         if (e_belt_nr == belt_nr)
4072         {
4073           int belt_part = Feld[xx][yy] - belt_base_active_element[belt_nr];
4074
4075           Feld[xx][yy] = belt_base_element[belt_nr] + belt_part;
4076           DrawLevelField(xx, yy);
4077         }
4078       }
4079     }
4080   }
4081 }
4082
4083 static void ToggleSwitchgateSwitch(int x, int y)
4084 {
4085   int xx, yy;
4086
4087   game.switchgate_pos = !game.switchgate_pos;
4088
4089   for (yy = 0; yy < lev_fieldy; yy++)
4090   {
4091     for (xx = 0; xx < lev_fieldx; xx++)
4092     {
4093       int element = Feld[xx][yy];
4094
4095       if (element == EL_SWITCHGATE_SWITCH_UP ||
4096           element == EL_SWITCHGATE_SWITCH_DOWN)
4097       {
4098         Feld[xx][yy] = EL_SWITCHGATE_SWITCH_UP + game.switchgate_pos;
4099         DrawLevelField(xx, yy);
4100       }
4101       else if (element == EL_SWITCHGATE_OPEN ||
4102                element == EL_SWITCHGATE_OPENING)
4103       {
4104         Feld[xx][yy] = EL_SWITCHGATE_CLOSING;
4105 #if 1
4106         PlayLevelSoundAction(xx, yy, ACTION_CLOSING);
4107 #else
4108         PlayLevelSound(xx, yy, SND_SWITCHGATE_CLOSING);
4109 #endif
4110       }
4111       else if (element == EL_SWITCHGATE_CLOSED ||
4112                element == EL_SWITCHGATE_CLOSING)
4113       {
4114         Feld[xx][yy] = EL_SWITCHGATE_OPENING;
4115 #if 1
4116         PlayLevelSoundAction(xx, yy, ACTION_OPENING);
4117 #else
4118         PlayLevelSound(xx, yy, SND_SWITCHGATE_OPENING);
4119 #endif
4120       }
4121     }
4122   }
4123 }
4124
4125 static int getInvisibleActiveFromInvisibleElement(int element)
4126 {
4127   return (element == EL_INVISIBLE_STEELWALL ? EL_INVISIBLE_STEELWALL_ACTIVE :
4128           element == EL_INVISIBLE_WALL      ? EL_INVISIBLE_WALL_ACTIVE :
4129           element == EL_INVISIBLE_SAND      ? EL_INVISIBLE_SAND_ACTIVE :
4130           element);
4131 }
4132
4133 static int getInvisibleFromInvisibleActiveElement(int element)
4134 {
4135   return (element == EL_INVISIBLE_STEELWALL_ACTIVE ? EL_INVISIBLE_STEELWALL :
4136           element == EL_INVISIBLE_WALL_ACTIVE      ? EL_INVISIBLE_WALL :
4137           element == EL_INVISIBLE_SAND_ACTIVE      ? EL_INVISIBLE_SAND :
4138           element);
4139 }
4140
4141 static void RedrawAllLightSwitchesAndInvisibleElements()
4142 {
4143   int x, y;
4144
4145   for (y = 0; y < lev_fieldy; y++)
4146   {
4147     for (x = 0; x < lev_fieldx; x++)
4148     {
4149       int element = Feld[x][y];
4150
4151       if (element == EL_LIGHT_SWITCH &&
4152           game.light_time_left > 0)
4153       {
4154         Feld[x][y] = EL_LIGHT_SWITCH_ACTIVE;
4155         DrawLevelField(x, y);
4156       }
4157       else if (element == EL_LIGHT_SWITCH_ACTIVE &&
4158                game.light_time_left == 0)
4159       {
4160         Feld[x][y] = EL_LIGHT_SWITCH;
4161         DrawLevelField(x, y);
4162       }
4163       else if (element == EL_INVISIBLE_STEELWALL ||
4164                element == EL_INVISIBLE_WALL ||
4165                element == EL_INVISIBLE_SAND)
4166       {
4167         if (game.light_time_left > 0)
4168           Feld[x][y] = getInvisibleActiveFromInvisibleElement(element);
4169
4170         DrawLevelField(x, y);
4171       }
4172       else if (element == EL_INVISIBLE_STEELWALL_ACTIVE ||
4173                element == EL_INVISIBLE_WALL_ACTIVE ||
4174                element == EL_INVISIBLE_SAND_ACTIVE)
4175       {
4176         if (game.light_time_left == 0)
4177           Feld[x][y] = getInvisibleFromInvisibleActiveElement(element);
4178
4179         DrawLevelField(x, y);
4180       }
4181     }
4182   }
4183 }
4184
4185 static void ToggleLightSwitch(int x, int y)
4186 {
4187   int element = Feld[x][y];
4188
4189   game.light_time_left =
4190     (element == EL_LIGHT_SWITCH ?
4191      level.time_light * FRAMES_PER_SECOND : 0);
4192
4193   RedrawAllLightSwitchesAndInvisibleElements();
4194 }
4195
4196 static void ActivateTimegateSwitch(int x, int y)
4197 {
4198   int xx, yy;
4199
4200   game.timegate_time_left = level.time_timegate * FRAMES_PER_SECOND;
4201
4202   for (yy = 0; yy < lev_fieldy; yy++)
4203   {
4204     for (xx = 0; xx < lev_fieldx; xx++)
4205     {
4206       int element = Feld[xx][yy];
4207
4208       if (element == EL_TIMEGATE_CLOSED ||
4209           element == EL_TIMEGATE_CLOSING)
4210       {
4211         Feld[xx][yy] = EL_TIMEGATE_OPENING;
4212         PlayLevelSound(xx, yy, SND_TIMEGATE_OPENING);
4213       }
4214
4215       /*
4216       else if (element == EL_TIMEGATE_SWITCH_ACTIVE)
4217       {
4218         Feld[xx][yy] = EL_TIMEGATE_SWITCH;
4219         DrawLevelField(xx, yy);
4220       }
4221       */
4222
4223     }
4224   }
4225
4226   Feld[x][y] = EL_TIMEGATE_SWITCH_ACTIVE;
4227 }
4228
4229 inline static int getElementMoveStepsize(int x, int y)
4230 {
4231   int element = Feld[x][y];
4232   int direction = MovDir[x][y];
4233   int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
4234   int dy = (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
4235   int horiz_move = (dx != 0);
4236   int sign = (horiz_move ? dx : dy);
4237   int step = sign * element_info[element].move_stepsize;
4238
4239   /* special values for move stepsize for spring and things on conveyor belt */
4240   if (horiz_move)
4241   {
4242 #if 0
4243     if (element == EL_SPRING)
4244       step = sign * MOVE_STEPSIZE_NORMAL * 2;
4245     else if (CAN_FALL(element) && !CAN_MOVE(element) &&
4246              y < lev_fieldy - 1 && IS_BELT_ACTIVE(Feld[x][y + 1]))
4247       step = sign * MOVE_STEPSIZE_NORMAL / 2;
4248 #else
4249     if (CAN_FALL(element) &&
4250         y < lev_fieldy - 1 && IS_BELT_ACTIVE(Feld[x][y + 1]))
4251       step = sign * MOVE_STEPSIZE_NORMAL / 2;
4252     else if (element == EL_SPRING)
4253       step = sign * MOVE_STEPSIZE_NORMAL * 2;
4254 #endif
4255   }
4256
4257   return step;
4258 }
4259
4260 void Impact(int x, int y)
4261 {
4262   boolean lastline = (y == lev_fieldy-1);
4263   boolean object_hit = FALSE;
4264   boolean impact = (lastline || object_hit);
4265   int element = Feld[x][y];
4266   int smashed = EL_STEELWALL;
4267
4268   if (!lastline)        /* check if element below was hit */
4269   {
4270     if (Feld[x][y + 1] == EL_PLAYER_IS_LEAVING)
4271       return;
4272
4273     object_hit = (!IS_FREE(x, y + 1) && (!IS_MOVING(x, y + 1) ||
4274                                          MovDir[x][y + 1] != MV_DOWN ||
4275                                          MovPos[x][y + 1] <= TILEY / 2));
4276
4277 #if 0
4278     object_hit = !IS_FREE(x, y + 1);
4279 #endif
4280
4281     /* do not smash moving elements that left the smashed field in time */
4282     if (game.engine_version >= VERSION_IDENT(2,2,0,7) && IS_MOVING(x, y + 1) &&
4283         ABS(MovPos[x][y + 1] + getElementMoveStepsize(x, y + 1)) >= TILEX)
4284       object_hit = FALSE;
4285
4286     if (object_hit)
4287       smashed = MovingOrBlocked2Element(x, y + 1);
4288
4289     impact = (lastline || object_hit);
4290   }
4291
4292   if (!lastline && smashed == EL_ACID)  /* element falls into acid */
4293   {
4294     SplashAcid(x, y + 1);
4295     return;
4296   }
4297
4298   /* !!! not sufficient for all cases -- see EL_PEARL below !!! */
4299   /* only reset graphic animation if graphic really changes after impact */
4300   if (impact &&
4301       el_act_dir2img(element, GfxAction[x][y], MV_DOWN) != el2img(element))
4302   {
4303     ResetGfxAnimation(x, y);
4304     DrawLevelField(x, y);
4305   }
4306
4307   if (impact && CAN_EXPLODE_IMPACT(element))
4308   {
4309     Bang(x, y);
4310     return;
4311   }
4312   else if (impact && element == EL_PEARL)
4313   {
4314     ResetGfxAnimation(x, y);
4315
4316     Feld[x][y] = EL_PEARL_BREAKING;
4317     PlayLevelSound(x, y, SND_PEARL_BREAKING);
4318     return;
4319   }
4320   else if (impact && CheckElementChange(x, y, element, smashed, CE_IMPACT))
4321   {
4322     PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT);
4323
4324     return;
4325   }
4326
4327   if (impact && element == EL_AMOEBA_DROP)
4328   {
4329     if (object_hit && IS_PLAYER(x, y + 1))
4330       KillHeroUnlessEnemyProtected(x, y + 1);
4331     else if (object_hit && smashed == EL_PENGUIN)
4332       Bang(x, y + 1);
4333     else
4334     {
4335       Feld[x][y] = EL_AMOEBA_GROWING;
4336       Store[x][y] = EL_AMOEBA_WET;
4337
4338       ResetRandomAnimationValue(x, y);
4339     }
4340     return;
4341   }
4342
4343   if (object_hit)               /* check which object was hit */
4344   {
4345     if (CAN_PASS_MAGIC_WALL(element) && 
4346         (smashed == EL_MAGIC_WALL ||
4347          smashed == EL_BD_MAGIC_WALL))
4348     {
4349       int xx, yy;
4350       int activated_magic_wall =
4351         (smashed == EL_MAGIC_WALL ? EL_MAGIC_WALL_ACTIVE :
4352          EL_BD_MAGIC_WALL_ACTIVE);
4353
4354       /* activate magic wall / mill */
4355       for (yy = 0; yy < lev_fieldy; yy++)
4356         for (xx = 0; xx < lev_fieldx; xx++)
4357           if (Feld[xx][yy] == smashed)
4358             Feld[xx][yy] = activated_magic_wall;
4359
4360       game.magic_wall_time_left = level.time_magic_wall * FRAMES_PER_SECOND;
4361       game.magic_wall_active = TRUE;
4362
4363       PlayLevelSound(x, y, (smashed == EL_MAGIC_WALL ?
4364                             SND_MAGIC_WALL_ACTIVATING :
4365                             SND_BD_MAGIC_WALL_ACTIVATING));
4366     }
4367
4368     if (IS_PLAYER(x, y + 1))
4369     {
4370       if (CAN_SMASH_PLAYER(element))
4371       {
4372         KillHeroUnlessEnemyProtected(x, y + 1);
4373         return;
4374       }
4375     }
4376     else if (smashed == EL_PENGUIN)
4377     {
4378       if (CAN_SMASH_PLAYER(element))
4379       {
4380         Bang(x, y + 1);
4381         return;
4382       }
4383     }
4384     else if (element == EL_BD_DIAMOND)
4385     {
4386       if (IS_CLASSIC_ENEMY(smashed) && IS_BD_ELEMENT(smashed))
4387       {
4388         Bang(x, y + 1);
4389         return;
4390       }
4391     }
4392     else if (((element == EL_SP_INFOTRON ||
4393                element == EL_SP_ZONK) &&
4394               (smashed == EL_SP_SNIKSNAK ||
4395                smashed == EL_SP_ELECTRON ||
4396                smashed == EL_SP_DISK_ORANGE)) ||
4397              (element == EL_SP_INFOTRON &&
4398               smashed == EL_SP_DISK_YELLOW))
4399     {
4400       Bang(x, y + 1);
4401       return;
4402     }
4403 #if 0
4404     else if (CAN_SMASH_ENEMIES(element) && IS_CLASSIC_ENEMY(smashed))
4405     {
4406       Bang(x, y + 1);
4407       return;
4408     }
4409 #endif
4410     else if (CAN_SMASH_EVERYTHING(element))
4411     {
4412       if (IS_CLASSIC_ENEMY(smashed) ||
4413           CAN_EXPLODE_SMASHED(smashed))
4414       {
4415         Bang(x, y + 1);
4416         return;
4417       }
4418       else if (!IS_MOVING(x, y + 1) && !IS_BLOCKED(x, y + 1))
4419       {
4420         if (smashed == EL_LAMP ||
4421             smashed == EL_LAMP_ACTIVE)
4422         {
4423           Bang(x, y + 1);
4424           return;
4425         }
4426         else if (smashed == EL_NUT)
4427         {
4428           Feld[x][y + 1] = EL_NUT_BREAKING;
4429           PlayLevelSound(x, y, SND_NUT_BREAKING);
4430           RaiseScoreElement(EL_NUT);
4431           return;
4432         }
4433         else if (smashed == EL_PEARL)
4434         {
4435           ResetGfxAnimation(x, y);
4436
4437           Feld[x][y + 1] = EL_PEARL_BREAKING;
4438           PlayLevelSound(x, y, SND_PEARL_BREAKING);
4439           return;
4440         }
4441         else if (smashed == EL_DIAMOND)
4442         {
4443           Feld[x][y + 1] = EL_DIAMOND_BREAKING;
4444           PlayLevelSound(x, y, SND_DIAMOND_BREAKING);
4445           return;
4446         }
4447         else if (IS_BELT_SWITCH(smashed))
4448         {
4449           ToggleBeltSwitch(x, y + 1);
4450         }
4451         else if (smashed == EL_SWITCHGATE_SWITCH_UP ||
4452                  smashed == EL_SWITCHGATE_SWITCH_DOWN)
4453         {
4454           ToggleSwitchgateSwitch(x, y + 1);
4455         }
4456         else if (smashed == EL_LIGHT_SWITCH ||
4457                  smashed == EL_LIGHT_SWITCH_ACTIVE)
4458         {
4459           ToggleLightSwitch(x, y + 1);
4460         }
4461         else
4462         {
4463 #if 0
4464           TestIfElementSmashesCustomElement(x, y, MV_DOWN);
4465 #endif
4466
4467           CheckElementChange(x, y + 1, smashed, element, CE_SMASHED);
4468
4469 #if 1
4470           /* !!! TEST ONLY !!! */
4471           CheckElementChangeBySide(x, y + 1, smashed, element,
4472                                    CE_SWITCHED, CH_SIDE_TOP);
4473           CheckTriggeredElementChangeBySide(x, y + 1, smashed,
4474                                             CE_OTHER_IS_SWITCHING,CH_SIDE_TOP);
4475 #else
4476           CheckTriggeredElementChangeBySide(x, y + 1, smashed,
4477                                             CE_OTHER_IS_SWITCHING,CH_SIDE_TOP);
4478           CheckElementChangeBySide(x, y + 1, smashed, element,
4479                                    CE_SWITCHED, CH_SIDE_TOP);
4480 #endif
4481         }
4482       }
4483       else
4484       {
4485         CheckElementChange(x, y + 1, smashed, element, CE_SMASHED);
4486       }
4487     }
4488   }
4489
4490   /* play sound of magic wall / mill */
4491   if (!lastline &&
4492       (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE ||
4493        Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE))
4494   {
4495     if (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE)
4496       PlayLevelSound(x, y, SND_MAGIC_WALL_FILLING);
4497     else if (Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE)
4498       PlayLevelSound(x, y, SND_BD_MAGIC_WALL_FILLING);
4499
4500     return;
4501   }
4502
4503   /* play sound of object that hits the ground */
4504   if (lastline || object_hit)
4505     PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT);
4506 }
4507
4508 inline static void TurnRoundExt(int x, int y)
4509 {
4510   static struct
4511   {
4512     int x, y;
4513   } move_xy[] =
4514   {
4515     {  0,  0 },
4516     { -1,  0 },
4517     { +1,  0 },
4518     {  0,  0 },
4519     {  0, -1 },
4520     {  0,  0 }, { 0, 0 }, { 0, 0 },
4521     {  0, +1 }
4522   };
4523   static struct
4524   {
4525     int left, right, back;
4526   } turn[] =
4527   {
4528     { 0,        0,              0        },
4529     { MV_DOWN,  MV_UP,          MV_RIGHT },
4530     { MV_UP,    MV_DOWN,        MV_LEFT  },
4531     { 0,        0,              0        },
4532     { MV_LEFT,  MV_RIGHT,       MV_DOWN  },
4533     { 0,        0,              0        },
4534     { 0,        0,              0        },
4535     { 0,        0,              0        },
4536     { MV_RIGHT, MV_LEFT,        MV_UP    }
4537   };
4538
4539   int element = Feld[x][y];
4540   int move_pattern = element_info[element].move_pattern;
4541
4542   int old_move_dir = MovDir[x][y];
4543   int left_dir  = turn[old_move_dir].left;
4544   int right_dir = turn[old_move_dir].right;
4545   int back_dir  = turn[old_move_dir].back;
4546
4547   int left_dx  = move_xy[left_dir].x,     left_dy  = move_xy[left_dir].y;
4548   int right_dx = move_xy[right_dir].x,    right_dy = move_xy[right_dir].y;
4549   int move_dx  = move_xy[old_move_dir].x, move_dy  = move_xy[old_move_dir].y;
4550   int back_dx  = move_xy[back_dir].x,     back_dy  = move_xy[back_dir].y;
4551
4552   int left_x  = x + left_dx,  left_y  = y + left_dy;
4553   int right_x = x + right_dx, right_y = y + right_dy;
4554   int move_x  = x + move_dx,  move_y  = y + move_dy;
4555
4556   int xx, yy;
4557
4558   if (element == EL_BUG || element == EL_BD_BUTTERFLY)
4559   {
4560     TestIfBadThingTouchesOtherBadThing(x, y);
4561
4562     if (ENEMY_CAN_ENTER_FIELD(element, right_x, right_y))
4563       MovDir[x][y] = right_dir;
4564     else if (!ENEMY_CAN_ENTER_FIELD(element, move_x, move_y))
4565       MovDir[x][y] = left_dir;
4566
4567     if (element == EL_BUG && MovDir[x][y] != old_move_dir)
4568       MovDelay[x][y] = 9;
4569     else if (element == EL_BD_BUTTERFLY)     /* && MovDir[x][y] == left_dir) */
4570       MovDelay[x][y] = 1;
4571   }
4572 #if 0
4573   else if (element == EL_SPACESHIP || element == EL_BD_FIREFLY ||
4574            element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
4575   {
4576     TestIfBadThingTouchesOtherBadThing(x, y);
4577
4578     if (ENEMY_CAN_ENTER_FIELD(element, left_x, left_y))
4579       MovDir[x][y] = left_dir;
4580     else if (!ENEMY_CAN_ENTER_FIELD(element, move_x, move_y))
4581       MovDir[x][y] = right_dir;
4582
4583     if ((element == EL_SPACESHIP ||
4584          element == EL_SP_SNIKSNAK ||
4585          element == EL_SP_ELECTRON)
4586         && MovDir[x][y] != old_move_dir)
4587       MovDelay[x][y] = 9;
4588     else if (element == EL_BD_FIREFLY)      /* && MovDir[x][y] == right_dir) */
4589       MovDelay[x][y] = 1;
4590   }
4591 #else
4592   else if (element == EL_SPACESHIP || element == EL_BD_FIREFLY)
4593   {
4594     TestIfBadThingTouchesOtherBadThing(x, y);
4595
4596     if (ENEMY_CAN_ENTER_FIELD(element, left_x, left_y))
4597       MovDir[x][y] = left_dir;
4598     else if (!ENEMY_CAN_ENTER_FIELD(element, move_x, move_y))
4599       MovDir[x][y] = right_dir;
4600
4601     if (element == EL_SPACESHIP && MovDir[x][y] != old_move_dir)
4602       MovDelay[x][y] = 9;
4603     else if (element == EL_BD_FIREFLY)      /* && MovDir[x][y] == right_dir) */
4604       MovDelay[x][y] = 1;
4605   }
4606   else if (element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
4607   {
4608     TestIfBadThingTouchesOtherBadThing(x, y);
4609
4610     if (ELEMENT_CAN_ENTER_FIELD_BASE_4(element, left_x, left_y, 0))
4611       MovDir[x][y] = left_dir;
4612     else if (!ELEMENT_CAN_ENTER_FIELD_BASE_4(element, move_x, move_y, 0))
4613       MovDir[x][y] = right_dir;
4614
4615     if (MovDir[x][y] != old_move_dir)
4616       MovDelay[x][y] = 9;
4617   }
4618 #endif
4619   else if (element == EL_YAMYAM)
4620   {
4621     boolean can_turn_left  = YAMYAM_CAN_ENTER_FIELD(element, left_x, left_y);
4622     boolean can_turn_right = YAMYAM_CAN_ENTER_FIELD(element, right_x, right_y);
4623
4624     if (can_turn_left && can_turn_right)
4625       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
4626     else if (can_turn_left)
4627       MovDir[x][y] = (RND(2) ? left_dir : back_dir);
4628     else if (can_turn_right)
4629       MovDir[x][y] = (RND(2) ? right_dir : back_dir);
4630     else
4631       MovDir[x][y] = back_dir;
4632
4633     MovDelay[x][y] = 16 + 16 * RND(3);
4634   }
4635   else if (element == EL_DARK_YAMYAM)
4636   {
4637     boolean can_turn_left  = DARK_YAMYAM_CAN_ENTER_FIELD(element,
4638                                                          left_x, left_y);
4639     boolean can_turn_right = DARK_YAMYAM_CAN_ENTER_FIELD(element,
4640                                                          right_x, right_y);
4641
4642     if (can_turn_left && can_turn_right)
4643       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
4644     else if (can_turn_left)
4645       MovDir[x][y] = (RND(2) ? left_dir : back_dir);
4646     else if (can_turn_right)
4647       MovDir[x][y] = (RND(2) ? right_dir : back_dir);
4648     else
4649       MovDir[x][y] = back_dir;
4650
4651     MovDelay[x][y] = 16 + 16 * RND(3);
4652   }
4653   else if (element == EL_PACMAN)
4654   {
4655     boolean can_turn_left  = PACMAN_CAN_ENTER_FIELD(element, left_x, left_y);
4656     boolean can_turn_right = PACMAN_CAN_ENTER_FIELD(element, right_x, right_y);
4657
4658     if (can_turn_left && can_turn_right)
4659       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
4660     else if (can_turn_left)
4661       MovDir[x][y] = (RND(2) ? left_dir : back_dir);
4662     else if (can_turn_right)
4663       MovDir[x][y] = (RND(2) ? right_dir : back_dir);
4664     else
4665       MovDir[x][y] = back_dir;
4666
4667     MovDelay[x][y] = 6 + RND(40);
4668   }
4669   else if (element == EL_PIG)
4670   {
4671     boolean can_turn_left  = PIG_CAN_ENTER_FIELD(element, left_x, left_y);
4672     boolean can_turn_right = PIG_CAN_ENTER_FIELD(element, right_x, right_y);
4673     boolean can_move_on    = PIG_CAN_ENTER_FIELD(element, move_x, move_y);
4674     boolean should_turn_left, should_turn_right, should_move_on;
4675     int rnd_value = 24;
4676     int rnd = RND(rnd_value);
4677
4678     should_turn_left = (can_turn_left &&
4679                         (!can_move_on ||
4680                          IN_LEV_FIELD_AND_NOT_FREE(x + back_dx + left_dx,
4681                                                    y + back_dy + left_dy)));
4682     should_turn_right = (can_turn_right &&
4683                          (!can_move_on ||
4684                           IN_LEV_FIELD_AND_NOT_FREE(x + back_dx + right_dx,
4685                                                     y + back_dy + right_dy)));
4686     should_move_on = (can_move_on &&
4687                       (!can_turn_left ||
4688                        !can_turn_right ||
4689                        IN_LEV_FIELD_AND_NOT_FREE(x + move_dx + left_dx,
4690                                                  y + move_dy + left_dy) ||
4691                        IN_LEV_FIELD_AND_NOT_FREE(x + move_dx + right_dx,
4692                                                  y + move_dy + right_dy)));
4693
4694     if (should_turn_left || should_turn_right || should_move_on)
4695     {
4696       if (should_turn_left && should_turn_right && should_move_on)
4697         MovDir[x][y] = (rnd < rnd_value / 3     ? left_dir :
4698                         rnd < 2 * rnd_value / 3 ? right_dir :
4699                         old_move_dir);
4700       else if (should_turn_left && should_turn_right)
4701         MovDir[x][y] = (rnd < rnd_value / 2 ? left_dir : right_dir);
4702       else if (should_turn_left && should_move_on)
4703         MovDir[x][y] = (rnd < rnd_value / 2 ? left_dir : old_move_dir);
4704       else if (should_turn_right && should_move_on)
4705         MovDir[x][y] = (rnd < rnd_value / 2 ? right_dir : old_move_dir);
4706       else if (should_turn_left)
4707         MovDir[x][y] = left_dir;
4708       else if (should_turn_right)
4709         MovDir[x][y] = right_dir;
4710       else if (should_move_on)
4711         MovDir[x][y] = old_move_dir;
4712     }
4713     else if (can_move_on && rnd > rnd_value / 8)
4714       MovDir[x][y] = old_move_dir;
4715     else if (can_turn_left && can_turn_right)
4716       MovDir[x][y] = (rnd < rnd_value / 2 ? left_dir : right_dir);
4717     else if (can_turn_left && rnd > rnd_value / 8)
4718       MovDir[x][y] = left_dir;
4719     else if (can_turn_right && rnd > rnd_value/8)
4720       MovDir[x][y] = right_dir;
4721     else
4722       MovDir[x][y] = back_dir;
4723
4724     xx = x + move_xy[MovDir[x][y]].x;
4725     yy = y + move_xy[MovDir[x][y]].y;
4726
4727 #if 1
4728     /* !!! this bugfix breaks at least BD2K3, level 010 !!! [re-recorded] */
4729     if (!IN_LEV_FIELD(xx, yy) ||
4730         (!IS_FREE(xx, yy) && !IS_FOOD_PIG(Feld[xx][yy])))
4731       MovDir[x][y] = old_move_dir;
4732 #else
4733     if (!IS_FREE(xx, yy) && !IS_FOOD_PIG(Feld[xx][yy]))
4734       MovDir[x][y] = old_move_dir;
4735 #endif
4736
4737     MovDelay[x][y] = 0;
4738   }
4739   else if (element == EL_DRAGON)
4740   {
4741     boolean can_turn_left  = DRAGON_CAN_ENTER_FIELD(element, left_x, left_y);
4742     boolean can_turn_right = DRAGON_CAN_ENTER_FIELD(element, right_x, right_y);
4743     boolean can_move_on    = DRAGON_CAN_ENTER_FIELD(element, move_x, move_y);
4744     int rnd_value = 24;
4745     int rnd = RND(rnd_value);
4746
4747 #if 0
4748     if (FrameCounter < 1 && x == 0 && y == 29)
4749       printf(":2: %d/%d: %d [%d]\n", x, y, MovDir[x][y], FrameCounter);
4750 #endif
4751
4752     if (can_move_on && rnd > rnd_value / 8)
4753       MovDir[x][y] = old_move_dir;
4754     else if (can_turn_left && can_turn_right)
4755       MovDir[x][y] = (rnd < rnd_value / 2 ? left_dir : right_dir);
4756     else if (can_turn_left && rnd > rnd_value / 8)
4757       MovDir[x][y] = left_dir;
4758     else if (can_turn_right && rnd > rnd_value / 8)
4759       MovDir[x][y] = right_dir;
4760     else
4761       MovDir[x][y] = back_dir;
4762
4763     xx = x + move_xy[MovDir[x][y]].x;
4764     yy = y + move_xy[MovDir[x][y]].y;
4765
4766 #if 0
4767     if (FrameCounter < 1 && x == 0 && y == 29)
4768       printf(":3: %d/%d: %d (%d/%d: %d) [%d]\n", x, y, MovDir[x][y],
4769              xx, yy, Feld[xx][yy],
4770              FrameCounter);
4771 #endif
4772
4773 #if 1
4774     if (!IN_LEV_FIELD_AND_IS_FREE(xx, yy))
4775       MovDir[x][y] = old_move_dir;
4776 #else
4777     if (!IS_FREE(xx, yy))
4778       MovDir[x][y] = old_move_dir;
4779 #endif
4780
4781 #if 0
4782     if (FrameCounter < 1 && x == 0 && y == 29)
4783       printf(":4: %d/%d: %d [%d]\n", x, y, MovDir[x][y], FrameCounter);
4784 #endif
4785
4786     MovDelay[x][y] = 0;
4787   }
4788   else if (element == EL_MOLE)
4789   {
4790     boolean can_move_on =
4791       (MOLE_CAN_ENTER_FIELD(element, move_x, move_y,
4792                             IS_AMOEBOID(Feld[move_x][move_y]) ||
4793                             Feld[move_x][move_y] == EL_AMOEBA_SHRINKING));
4794     if (!can_move_on)
4795     {
4796       boolean can_turn_left =
4797         (MOLE_CAN_ENTER_FIELD(element, left_x, left_y,
4798                               IS_AMOEBOID(Feld[left_x][left_y])));
4799
4800       boolean can_turn_right =
4801         (MOLE_CAN_ENTER_FIELD(element, right_x, right_y,
4802                               IS_AMOEBOID(Feld[right_x][right_y])));
4803
4804       if (can_turn_left && can_turn_right)
4805         MovDir[x][y] = (RND(2) ? left_dir : right_dir);
4806       else if (can_turn_left)
4807         MovDir[x][y] = left_dir;
4808       else
4809         MovDir[x][y] = right_dir;
4810     }
4811
4812     if (MovDir[x][y] != old_move_dir)
4813       MovDelay[x][y] = 9;
4814   }
4815   else if (element == EL_BALLOON)
4816   {
4817     MovDir[x][y] = game.balloon_dir;
4818     MovDelay[x][y] = 0;
4819   }
4820   else if (element == EL_SPRING)
4821   {
4822 #if 0
4823     if (MovDir[x][y] & MV_HORIZONTAL &&
4824         !SPRING_CAN_ENTER_FIELD(element, move_x, move_y))
4825       MovDir[x][y] = MV_NO_MOVING;
4826 #else
4827     if (MovDir[x][y] & MV_HORIZONTAL &&
4828         (!SPRING_CAN_ENTER_FIELD(element, move_x, move_y) ||
4829          SPRING_CAN_ENTER_FIELD(element, x, y + 1)))
4830       MovDir[x][y] = MV_NO_MOVING;
4831 #endif
4832
4833     MovDelay[x][y] = 0;
4834   }
4835   else if (element == EL_ROBOT ||
4836            element == EL_SATELLITE ||
4837            element == EL_PENGUIN)
4838   {
4839     int attr_x = -1, attr_y = -1;
4840
4841     if (AllPlayersGone)
4842     {
4843       attr_x = ExitX;
4844       attr_y = ExitY;
4845     }
4846     else
4847     {
4848       int i;
4849
4850       for (i = 0; i < MAX_PLAYERS; i++)
4851       {
4852         struct PlayerInfo *player = &stored_player[i];
4853         int jx = player->jx, jy = player->jy;
4854
4855         if (!player->active)
4856           continue;
4857
4858         if (attr_x == -1 ||
4859             ABS(jx - x) + ABS(jy - y) < ABS(attr_x - x) + ABS(attr_y - y))
4860         {
4861           attr_x = jx;
4862           attr_y = jy;
4863         }
4864       }
4865     }
4866
4867 #if 1
4868     if (element == EL_ROBOT && ZX >= 0 && ZY >= 0 &&
4869         (Feld[ZX][ZY] == EL_ROBOT_WHEEL_ACTIVE ||
4870          game.engine_version < VERSION_IDENT(3,1,0,0)))
4871 #else
4872     if (element == EL_ROBOT && ZX >= 0 && ZY >= 0)
4873 #endif
4874     {
4875       attr_x = ZX;
4876       attr_y = ZY;
4877     }
4878
4879     if (element == EL_PENGUIN)
4880     {
4881       int i;
4882       static int xy[4][2] =
4883       {
4884         { 0, -1 },
4885         { -1, 0 },
4886         { +1, 0 },
4887         { 0, +1 }
4888       };
4889
4890       for (i = 0; i < NUM_DIRECTIONS; i++)
4891       {
4892         int ex = x + xy[i][0];
4893         int ey = y + xy[i][1];
4894
4895         if (IN_LEV_FIELD(ex, ey) && Feld[ex][ey] == EL_EXIT_OPEN)
4896         {
4897           attr_x = ex;
4898           attr_y = ey;
4899           break;
4900         }
4901       }
4902     }
4903
4904     MovDir[x][y] = MV_NO_MOVING;
4905     if (attr_x < x)
4906       MovDir[x][y] |= (AllPlayersGone ? MV_RIGHT : MV_LEFT);
4907     else if (attr_x > x)
4908       MovDir[x][y] |= (AllPlayersGone ? MV_LEFT : MV_RIGHT);
4909     if (attr_y < y)
4910       MovDir[x][y] |= (AllPlayersGone ? MV_DOWN : MV_UP);
4911     else if (attr_y > y)
4912       MovDir[x][y] |= (AllPlayersGone ? MV_UP : MV_DOWN);
4913
4914     if (element == EL_ROBOT)
4915     {
4916       int newx, newy;
4917
4918       if (MovDir[x][y] & MV_HORIZONTAL && MovDir[x][y] & MV_VERTICAL)
4919         MovDir[x][y] &= (RND(2) ? MV_HORIZONTAL : MV_VERTICAL);
4920       Moving2Blocked(x, y, &newx, &newy);
4921
4922       if (IN_LEV_FIELD(newx, newy) && IS_FREE_OR_PLAYER(newx, newy))
4923         MovDelay[x][y] = 8 + 8 * !RND(3);
4924       else
4925         MovDelay[x][y] = 16;
4926     }
4927     else if (element == EL_PENGUIN)
4928     {
4929       int newx, newy;
4930
4931       MovDelay[x][y] = 1;
4932
4933       if (MovDir[x][y] & MV_HORIZONTAL && MovDir[x][y] & MV_VERTICAL)
4934       {
4935         boolean first_horiz = RND(2);
4936         int new_move_dir = MovDir[x][y];
4937
4938         MovDir[x][y] =
4939           new_move_dir & (first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
4940         Moving2Blocked(x, y, &newx, &newy);
4941
4942         if (PENGUIN_CAN_ENTER_FIELD(EL_PENGUIN, newx, newy))
4943           return;
4944
4945         MovDir[x][y] =
4946           new_move_dir & (!first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
4947         Moving2Blocked(x, y, &newx, &newy);
4948
4949         if (PENGUIN_CAN_ENTER_FIELD(EL_PENGUIN, newx, newy))
4950           return;
4951
4952         MovDir[x][y] = old_move_dir;
4953         return;
4954       }
4955     }
4956     else        /* (element == EL_SATELLITE) */
4957     {
4958       int newx, newy;
4959
4960       MovDelay[x][y] = 1;
4961
4962       if (MovDir[x][y] & MV_HORIZONTAL && MovDir[x][y] & MV_VERTICAL)
4963       {
4964         boolean first_horiz = RND(2);
4965         int new_move_dir = MovDir[x][y];
4966
4967         MovDir[x][y] =
4968           new_move_dir & (first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
4969         Moving2Blocked(x, y, &newx, &newy);
4970
4971         if (SATELLITE_CAN_ENTER_FIELD(newx, newy))
4972           return;
4973
4974         MovDir[x][y] =
4975           new_move_dir & (!first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
4976         Moving2Blocked(x, y, &newx, &newy);
4977
4978         if (SATELLITE_CAN_ENTER_FIELD(newx, newy))
4979           return;
4980
4981         MovDir[x][y] = old_move_dir;
4982         return;
4983       }
4984     }
4985   }
4986   else if (move_pattern == MV_TURNING_LEFT ||
4987            move_pattern == MV_TURNING_RIGHT ||
4988            move_pattern == MV_TURNING_LEFT_RIGHT ||
4989            move_pattern == MV_TURNING_RIGHT_LEFT ||
4990            move_pattern == MV_TURNING_RANDOM ||
4991            move_pattern == MV_ALL_DIRECTIONS)
4992   {
4993     boolean can_turn_left =
4994       CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, left_x, left_y);
4995     boolean can_turn_right =
4996       CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, right_x,right_y);
4997
4998     if (move_pattern == MV_TURNING_LEFT)
4999       MovDir[x][y] = left_dir;
5000     else if (move_pattern == MV_TURNING_RIGHT)
5001       MovDir[x][y] = right_dir;
5002     else if (move_pattern == MV_TURNING_LEFT_RIGHT)
5003       MovDir[x][y] = (can_turn_left || !can_turn_right ? left_dir : right_dir);
5004     else if (move_pattern == MV_TURNING_RIGHT_LEFT)
5005       MovDir[x][y] = (can_turn_right || !can_turn_left ? right_dir : left_dir);
5006     else if (move_pattern == MV_TURNING_RANDOM)
5007       MovDir[x][y] = (can_turn_left && !can_turn_right ? left_dir :
5008                       can_turn_right && !can_turn_left ? right_dir :
5009                       RND(2) ? left_dir : right_dir);
5010     else if (can_turn_left && can_turn_right)
5011       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
5012     else if (can_turn_left)
5013       MovDir[x][y] = (RND(2) ? left_dir : back_dir);
5014     else if (can_turn_right)
5015       MovDir[x][y] = (RND(2) ? right_dir : back_dir);
5016     else
5017       MovDir[x][y] = back_dir;
5018
5019     MovDelay[x][y] = GET_NEW_MOVE_DELAY(element);
5020   }
5021   else if (move_pattern == MV_HORIZONTAL ||
5022            move_pattern == MV_VERTICAL)
5023   {
5024     if (move_pattern & old_move_dir)
5025       MovDir[x][y] = back_dir;
5026     else if (move_pattern == MV_HORIZONTAL)
5027       MovDir[x][y] = (RND(2) ? MV_LEFT : MV_RIGHT);
5028     else if (move_pattern == MV_VERTICAL)
5029       MovDir[x][y] = (RND(2) ? MV_UP : MV_DOWN);
5030
5031     MovDelay[x][y] = GET_NEW_MOVE_DELAY(element);
5032   }
5033   else if (move_pattern & MV_ANY_DIRECTION)
5034   {
5035     MovDir[x][y] = move_pattern;
5036     MovDelay[x][y] = GET_NEW_MOVE_DELAY(element);
5037   }
5038   else if (move_pattern == MV_ALONG_LEFT_SIDE)
5039   {
5040     if (CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, left_x, left_y))
5041       MovDir[x][y] = left_dir;
5042     else if (!CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, move_x, move_y))
5043       MovDir[x][y] = right_dir;
5044
5045     if (MovDir[x][y] != old_move_dir)
5046       MovDelay[x][y] = GET_NEW_MOVE_DELAY(element);
5047   }
5048   else if (move_pattern == MV_ALONG_RIGHT_SIDE)
5049   {
5050     if (CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, right_x, right_y))
5051       MovDir[x][y] = right_dir;
5052     else if (!CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, move_x, move_y))
5053       MovDir[x][y] = left_dir;
5054
5055     if (MovDir[x][y] != old_move_dir)
5056       MovDelay[x][y] = GET_NEW_MOVE_DELAY(element);
5057   }
5058   else if (move_pattern == MV_TOWARDS_PLAYER ||
5059            move_pattern == MV_AWAY_FROM_PLAYER)
5060   {
5061     int attr_x = -1, attr_y = -1;
5062     int newx, newy;
5063     boolean move_away = (move_pattern == MV_AWAY_FROM_PLAYER);
5064
5065     if (AllPlayersGone)
5066     {
5067       attr_x = ExitX;
5068       attr_y = ExitY;
5069     }
5070     else
5071     {
5072       int i;
5073
5074       for (i = 0; i < MAX_PLAYERS; i++)
5075       {
5076         struct PlayerInfo *player = &stored_player[i];
5077         int jx = player->jx, jy = player->jy;
5078
5079         if (!player->active)
5080           continue;
5081
5082         if (attr_x == -1 ||
5083             ABS(jx - x) + ABS(jy - y) < ABS(attr_x - x) + ABS(attr_y - y))
5084         {
5085           attr_x = jx;
5086           attr_y = jy;
5087         }
5088       }
5089     }
5090
5091     MovDir[x][y] = MV_NO_MOVING;
5092     if (attr_x < x)
5093       MovDir[x][y] |= (move_away ? MV_RIGHT : MV_LEFT);
5094     else if (attr_x > x)
5095       MovDir[x][y] |= (move_away ? MV_LEFT : MV_RIGHT);
5096     if (attr_y < y)
5097       MovDir[x][y] |= (move_away ? MV_DOWN : MV_UP);
5098     else if (attr_y > y)
5099       MovDir[x][y] |= (move_away ? MV_UP : MV_DOWN);
5100
5101     MovDelay[x][y] = GET_NEW_MOVE_DELAY(element);
5102
5103     if (MovDir[x][y] & MV_HORIZONTAL && MovDir[x][y] & MV_VERTICAL)
5104     {
5105       boolean first_horiz = RND(2);
5106       int new_move_dir = MovDir[x][y];
5107
5108       MovDir[x][y] =
5109         new_move_dir & (first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
5110       Moving2Blocked(x, y, &newx, &newy);
5111
5112       if (CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, newx, newy))
5113         return;
5114
5115       MovDir[x][y] =
5116         new_move_dir & (!first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
5117       Moving2Blocked(x, y, &newx, &newy);
5118
5119       if (CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, newx, newy))
5120         return;
5121
5122       MovDir[x][y] = old_move_dir;
5123     }
5124   }
5125   else if (move_pattern == MV_WHEN_PUSHED ||
5126            move_pattern == MV_WHEN_DROPPED)
5127   {
5128     if (!CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, move_x, move_y))
5129       MovDir[x][y] = MV_NO_MOVING;
5130
5131     MovDelay[x][y] = 0;
5132   }
5133   else if (move_pattern & MV_MAZE_RUNNER_STYLE)
5134   {
5135     static int test_xy[7][2] =
5136     {
5137       { 0, -1 },
5138       { -1, 0 },
5139       { +1, 0 },
5140       { 0, +1 },
5141       { 0, -1 },
5142       { -1, 0 },
5143       { +1, 0 },
5144     };
5145     static int test_dir[7] =
5146     {
5147       MV_UP,
5148       MV_LEFT,
5149       MV_RIGHT,
5150       MV_DOWN,
5151       MV_UP,
5152       MV_LEFT,
5153       MV_RIGHT,
5154     };
5155     boolean hunter_mode = (move_pattern == MV_MAZE_HUNTER);
5156     int move_preference = -1000000;     /* start with very low preference */
5157     int new_move_dir = MV_NO_MOVING;
5158     int start_test = RND(4);
5159     int i;
5160
5161     for (i = 0; i < NUM_DIRECTIONS; i++)
5162     {
5163       int move_dir = test_dir[start_test + i];
5164       int move_dir_preference;
5165
5166       xx = x + test_xy[start_test + i][0];
5167       yy = y + test_xy[start_test + i][1];
5168
5169       if (hunter_mode && IN_LEV_FIELD(xx, yy) &&
5170           (IS_PLAYER(xx, yy) || Feld[xx][yy] == EL_PLAYER_IS_LEAVING))
5171       {
5172         new_move_dir = move_dir;
5173
5174         break;
5175       }
5176
5177       if (!CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, xx, yy))
5178         continue;
5179
5180       move_dir_preference = -1 * RunnerVisit[xx][yy];
5181       if (hunter_mode && PlayerVisit[xx][yy] > 0)
5182         move_dir_preference = PlayerVisit[xx][yy];
5183
5184       if (move_dir_preference > move_preference)
5185       {
5186         /* prefer field that has not been visited for the longest time */
5187         move_preference = move_dir_preference;
5188         new_move_dir = move_dir;
5189       }
5190       else if (move_dir_preference == move_preference &&
5191                move_dir == old_move_dir)
5192       {
5193         /* prefer last direction when all directions are preferred equally */
5194         move_preference = move_dir_preference;
5195         new_move_dir = move_dir;
5196       }
5197     }
5198
5199     MovDir[x][y] = new_move_dir;
5200     if (old_move_dir != new_move_dir)
5201     {
5202 #if 1
5203       MovDelay[x][y] = GET_NEW_MOVE_DELAY(element);
5204 #else
5205       MovDelay[x][y] = 9;
5206 #endif
5207     }
5208   }
5209 }
5210
5211 static void TurnRound(int x, int y)
5212 {
5213   int direction = MovDir[x][y];
5214
5215 #if 0
5216   GfxDir[x][y] = MovDir[x][y];
5217 #endif
5218
5219   TurnRoundExt(x, y);
5220
5221 #if 1
5222   GfxDir[x][y] = MovDir[x][y];
5223 #endif
5224
5225   if (direction != MovDir[x][y])
5226     GfxFrame[x][y] = 0;
5227
5228 #if 1
5229   if (MovDelay[x][y])
5230     GfxAction[x][y] = ACTION_TURNING_FROM_LEFT + MV_DIR_BIT(direction);
5231 #else
5232   if (MovDelay[x][y])
5233     GfxAction[x][y] = ACTION_WAITING;
5234 #endif
5235 }
5236
5237 static boolean JustBeingPushed(int x, int y)
5238 {
5239   int i;
5240
5241   for (i = 0; i < MAX_PLAYERS; i++)
5242   {
5243     struct PlayerInfo *player = &stored_player[i];
5244
5245     if (player->active && player->is_pushing && player->MovPos)
5246     {
5247       int next_jx = player->jx + (player->jx - player->last_jx);
5248       int next_jy = player->jy + (player->jy - player->last_jy);
5249
5250       if (x == next_jx && y == next_jy)
5251         return TRUE;
5252     }
5253   }
5254
5255   return FALSE;
5256 }
5257
5258 void StartMoving(int x, int y)
5259 {
5260 #if 0
5261   boolean use_spring_bug = (game.engine_version < VERSION_IDENT(2,2,0,0));
5262 #endif
5263   boolean started_moving = FALSE;       /* some elements can fall _and_ move */
5264   int element = Feld[x][y];
5265
5266   if (Stop[x][y])
5267     return;
5268
5269 #if 1
5270   if (MovDelay[x][y] == 0)
5271     GfxAction[x][y] = ACTION_DEFAULT;
5272 #else
5273   /* !!! this should be handled more generic (not only for mole) !!! */
5274   if (element != EL_MOLE && GfxAction[x][y] != ACTION_DIGGING)
5275     GfxAction[x][y] = ACTION_DEFAULT;
5276 #endif
5277
5278   if (CAN_FALL(element) && y < lev_fieldy - 1)
5279   {
5280     if ((x > 0              && IS_PLAYER(x - 1, y)) ||
5281         (x < lev_fieldx - 1 && IS_PLAYER(x + 1, y)))
5282       if (JustBeingPushed(x, y))
5283         return;
5284
5285     if (element == EL_QUICKSAND_FULL)
5286     {
5287       if (IS_FREE(x, y + 1))
5288       {
5289         InitMovingField(x, y, MV_DOWN);
5290         started_moving = TRUE;
5291
5292         Feld[x][y] = EL_QUICKSAND_EMPTYING;
5293         Store[x][y] = EL_ROCK;
5294 #if 1
5295         PlayLevelSoundAction(x, y, ACTION_EMPTYING);
5296 #else
5297         PlayLevelSound(x, y, SND_QUICKSAND_EMPTYING);
5298 #endif
5299       }
5300       else if (Feld[x][y + 1] == EL_QUICKSAND_EMPTY)
5301       {
5302         if (!MovDelay[x][y])
5303           MovDelay[x][y] = TILEY + 1;
5304
5305         if (MovDelay[x][y])
5306         {
5307           MovDelay[x][y]--;
5308           if (MovDelay[x][y])
5309             return;
5310         }
5311
5312         Feld[x][y] = EL_QUICKSAND_EMPTY;
5313         Feld[x][y + 1] = EL_QUICKSAND_FULL;
5314         Store[x][y + 1] = Store[x][y];
5315         Store[x][y] = 0;
5316 #if 1
5317         PlayLevelSoundAction(x, y, ACTION_FILLING);
5318 #else
5319         PlayLevelSound(x, y, SND_QUICKSAND_FILLING);
5320 #endif
5321       }
5322     }
5323     else if ((element == EL_ROCK || element == EL_BD_ROCK) &&
5324              Feld[x][y + 1] == EL_QUICKSAND_EMPTY)
5325     {
5326       InitMovingField(x, y, MV_DOWN);
5327       started_moving = TRUE;
5328
5329       Feld[x][y] = EL_QUICKSAND_FILLING;
5330       Store[x][y] = element;
5331 #if 1
5332       PlayLevelSoundAction(x, y, ACTION_FILLING);
5333 #else
5334       PlayLevelSound(x, y, SND_QUICKSAND_FILLING);
5335 #endif
5336     }
5337     else if (element == EL_MAGIC_WALL_FULL)
5338     {
5339       if (IS_FREE(x, y + 1))
5340       {
5341         InitMovingField(x, y, MV_DOWN);
5342         started_moving = TRUE;
5343
5344         Feld[x][y] = EL_MAGIC_WALL_EMPTYING;
5345         Store[x][y] = EL_CHANGED(Store[x][y]);
5346       }
5347       else if (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE)
5348       {
5349         if (!MovDelay[x][y])
5350           MovDelay[x][y] = TILEY/4 + 1;
5351
5352         if (MovDelay[x][y])
5353         {
5354           MovDelay[x][y]--;
5355           if (MovDelay[x][y])
5356             return;
5357         }
5358
5359         Feld[x][y] = EL_MAGIC_WALL_ACTIVE;
5360         Feld[x][y + 1] = EL_MAGIC_WALL_FULL;
5361         Store[x][y + 1] = EL_CHANGED(Store[x][y]);
5362         Store[x][y] = 0;
5363       }
5364     }
5365     else if (element == EL_BD_MAGIC_WALL_FULL)
5366     {
5367       if (IS_FREE(x, y + 1))
5368       {
5369         InitMovingField(x, y, MV_DOWN);
5370         started_moving = TRUE;
5371
5372         Feld[x][y] = EL_BD_MAGIC_WALL_EMPTYING;
5373         Store[x][y] = EL_CHANGED2(Store[x][y]);
5374       }
5375       else if (Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE)
5376       {
5377         if (!MovDelay[x][y])
5378           MovDelay[x][y] = TILEY/4 + 1;
5379
5380         if (MovDelay[x][y])
5381         {
5382           MovDelay[x][y]--;
5383           if (MovDelay[x][y])
5384             return;
5385         }
5386
5387         Feld[x][y] = EL_BD_MAGIC_WALL_ACTIVE;
5388         Feld[x][y + 1] = EL_BD_MAGIC_WALL_FULL;
5389         Store[x][y + 1] = EL_CHANGED2(Store[x][y]);
5390         Store[x][y] = 0;
5391       }
5392     }
5393     else if (CAN_PASS_MAGIC_WALL(element) &&
5394              (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE ||
5395               Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE))
5396     {
5397       InitMovingField(x, y, MV_DOWN);
5398       started_moving = TRUE;
5399
5400       Feld[x][y] =
5401         (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE ? EL_MAGIC_WALL_FILLING :
5402          EL_BD_MAGIC_WALL_FILLING);
5403       Store[x][y] = element;
5404     }
5405 #if 0
5406     else if (CAN_SMASH(element) && Feld[x][y + 1] == EL_ACID)
5407 #else
5408     else if (CAN_FALL(element) && Feld[x][y + 1] == EL_ACID)
5409 #endif
5410     {
5411       SplashAcid(x, y + 1);
5412
5413       InitMovingField(x, y, MV_DOWN);
5414       started_moving = TRUE;
5415
5416       Store[x][y] = EL_ACID;
5417 #if 0
5418       /* !!! TEST !!! better use "_FALLING" etc. !!! */
5419       GfxAction[x][y + 1] = ACTION_ACTIVE;
5420 #endif
5421     }
5422 #if 1
5423     else if ((game.engine_version >= VERSION_IDENT(3,1,0,0) &&
5424               CheckCollision[x][y] && !IS_FREE(x, y + 1)) ||
5425
5426              (game.engine_version >= VERSION_IDENT(3,0,7,0) &&
5427               CAN_SMASH(element) && WasJustFalling[x][y] &&
5428               (Feld[x][y + 1] == EL_BLOCKED || IS_PLAYER(x, y + 1))) ||
5429
5430              (game.engine_version < VERSION_IDENT(2,2,0,7) &&
5431               CAN_SMASH(element) && WasJustMoving[x][y] && !Pushed[x][y + 1] &&
5432               (Feld[x][y + 1] == EL_BLOCKED)))
5433
5434 #else
5435 #if 1
5436     else if (game.engine_version < VERSION_IDENT(2,2,0,7) &&
5437              CAN_SMASH(element) && Feld[x][y + 1] == EL_BLOCKED &&
5438              WasJustMoving[x][y] && !Pushed[x][y + 1])
5439 #else
5440     else if (CAN_SMASH(element) && Feld[x][y + 1] == EL_BLOCKED &&
5441              WasJustMoving[x][y])
5442 #endif
5443 #endif
5444
5445     {
5446       /* this is needed for a special case not covered by calling "Impact()"
5447          from "ContinueMoving()": if an element moves to a tile directly below
5448          another element which was just falling on that tile (which was empty
5449          in the previous frame), the falling element above would just stop
5450          instead of smashing the element below (in previous version, the above
5451          element was just checked for "moving" instead of "falling", resulting
5452          in incorrect smashes caused by horizontal movement of the above
5453          element; also, the case of the player being the element to smash was
5454          simply not covered here... :-/ ) */
5455
5456 #if 0
5457       WasJustMoving[x][y] = 0;
5458       WasJustFalling[x][y] = 0;
5459 #endif
5460
5461       CheckCollision[x][y] = 0;
5462
5463 #if 0
5464       if (IS_PLAYER(x, y + 1))
5465         printf("::: we ARE now killing the player [%d]\n", FrameCounter);
5466 #endif
5467
5468       Impact(x, y);
5469     }
5470     else if (IS_FREE(x, y + 1) && element == EL_SPRING && level.use_spring_bug)
5471     {
5472       if (MovDir[x][y] == MV_NO_MOVING)
5473       {
5474         InitMovingField(x, y, MV_DOWN);
5475         started_moving = TRUE;
5476       }
5477     }
5478     else if (IS_FREE(x, y + 1) || Feld[x][y + 1] == EL_DIAMOND_BREAKING)
5479     {
5480       if (WasJustFalling[x][y]) /* prevent animation from being restarted */
5481         MovDir[x][y] = MV_DOWN;
5482
5483       InitMovingField(x, y, MV_DOWN);
5484       started_moving = TRUE;
5485     }
5486     else if (element == EL_AMOEBA_DROP)
5487     {
5488       Feld[x][y] = EL_AMOEBA_GROWING;
5489       Store[x][y] = EL_AMOEBA_WET;
5490     }
5491     /* Store[x][y + 1] must be zero, because:
5492        (EL_QUICKSAND_FULL -> EL_ROCK): Store[x][y + 1] == EL_QUICKSAND_EMPTY
5493     */
5494 #if 0
5495 #if OLD_GAME_BEHAVIOUR
5496     else if (IS_SLIPPERY(Feld[x][y + 1]) && !Store[x][y + 1])
5497 #else
5498     else if (IS_SLIPPERY(Feld[x][y + 1]) && !Store[x][y + 1] &&
5499              !IS_FALLING(x, y + 1) && !WasJustMoving[x][y + 1] &&
5500              element != EL_DX_SUPABOMB)
5501 #endif
5502 #else
5503     else if (((IS_SLIPPERY(Feld[x][y + 1]) && !IS_PLAYER(x, y + 1)) ||
5504               (IS_EM_SLIPPERY_WALL(Feld[x][y + 1]) && IS_GEM(element))) &&
5505              !IS_FALLING(x, y + 1) && !WasJustMoving[x][y + 1] &&
5506              element != EL_DX_SUPABOMB && element != EL_SP_DISK_ORANGE)
5507 #endif
5508     {
5509       boolean can_fall_left  = (x > 0 && IS_FREE(x - 1, y) &&
5510                                 (IS_FREE(x - 1, y + 1) ||
5511                                  Feld[x - 1][y + 1] == EL_ACID));
5512       boolean can_fall_right = (x < lev_fieldx - 1 && IS_FREE(x + 1, y) &&
5513                                 (IS_FREE(x + 1, y + 1) ||
5514                                  Feld[x + 1][y + 1] == EL_ACID));
5515       boolean can_fall_any  = (can_fall_left || can_fall_right);
5516       boolean can_fall_both = (can_fall_left && can_fall_right);
5517
5518       if (can_fall_any && IS_CUSTOM_ELEMENT(Feld[x][y + 1]))
5519       {
5520         int slippery_type = element_info[Feld[x][y + 1]].slippery_type;
5521
5522         if (slippery_type == SLIPPERY_ONLY_LEFT)
5523           can_fall_right = FALSE;
5524         else if (slippery_type == SLIPPERY_ONLY_RIGHT)
5525           can_fall_left = FALSE;
5526         else if (slippery_type == SLIPPERY_ANY_LEFT_RIGHT && can_fall_both)
5527           can_fall_right = FALSE;
5528         else if (slippery_type == SLIPPERY_ANY_RIGHT_LEFT && can_fall_both)
5529           can_fall_left = FALSE;
5530
5531         can_fall_any  = (can_fall_left || can_fall_right);
5532         can_fall_both = (can_fall_left && can_fall_right);
5533       }
5534
5535 #if USE_NEW_SP_SLIPPERY
5536       /* !!! better use the same properties as for custom elements here !!! */
5537       else if (game.engine_version >= VERSION_IDENT(3,1,1,0) &&
5538                can_fall_both && IS_SP_ELEMENT(Feld[x][y + 1]))
5539       {
5540         can_fall_right = FALSE;         /* slip down on left side */
5541         can_fall_both = FALSE;
5542       }
5543 #endif
5544
5545 #if 1
5546       if (can_fall_both)
5547       {
5548         if (game.emulation == EMU_BOULDERDASH ||
5549             element == EL_BD_ROCK || element == EL_BD_DIAMOND)
5550           can_fall_right = FALSE;       /* slip down on left side */
5551         else
5552           can_fall_left = !(can_fall_right = RND(2));
5553
5554         can_fall_both = FALSE;
5555       }
5556 #endif
5557
5558       if (can_fall_any)
5559       {
5560 #if 0
5561         if (can_fall_both &&
5562             (game.emulation != EMU_BOULDERDASH &&
5563              element != EL_BD_ROCK && element != EL_BD_DIAMOND))
5564           can_fall_left = !(can_fall_right = RND(2));
5565 #endif
5566
5567         /* if not determined otherwise, prefer left side for slipping down */
5568         InitMovingField(x, y, can_fall_left ? MV_LEFT : MV_RIGHT);
5569         started_moving = TRUE;
5570       }
5571     }
5572 #if 0
5573     else if (IS_BELT_ACTIVE(Feld[x][y + 1]) && !CAN_MOVE(element))
5574 #else
5575     else if (IS_BELT_ACTIVE(Feld[x][y + 1]))
5576 #endif
5577     {
5578       boolean left_is_free  = (x > 0 && IS_FREE(x - 1, y));
5579       boolean right_is_free = (x < lev_fieldx - 1 && IS_FREE(x + 1, y));
5580       int belt_nr = getBeltNrFromBeltActiveElement(Feld[x][y + 1]);
5581       int belt_dir = game.belt_dir[belt_nr];
5582
5583       if ((belt_dir == MV_LEFT  && left_is_free) ||
5584           (belt_dir == MV_RIGHT && right_is_free))
5585       {
5586 #if 1
5587         int nextx = (belt_dir == MV_LEFT ? x - 1 : x + 1);
5588 #endif
5589
5590         InitMovingField(x, y, belt_dir);
5591         started_moving = TRUE;
5592
5593 #if 1
5594         Pushed[x][y] = TRUE;
5595         Pushed[nextx][y] = TRUE;
5596 #endif
5597
5598         GfxAction[x][y] = ACTION_DEFAULT;
5599       }
5600       else
5601       {
5602         MovDir[x][y] = 0;       /* if element was moving, stop it */
5603       }
5604     }
5605   }
5606
5607   /* not "else if" because of elements that can fall and move (EL_SPRING) */
5608 #if 0
5609   if (CAN_MOVE(element) && !started_moving && MovDir[x][y] != MV_NO_MOVING)
5610 #else
5611   if (CAN_MOVE(element) && !started_moving)
5612 #endif
5613   {
5614     int move_pattern = element_info[element].move_pattern;
5615     int newx, newy;
5616
5617 #if 0
5618 #if DEBUG
5619     if (MovDir[x][y] == MV_NO_MOVING)
5620     {
5621       printf("StartMoving(): %d,%d: element %d ['%s'] not moving\n",
5622              x, y, element, element_info[element].token_name);
5623       printf("StartMoving(): This should never happen!\n");
5624     }
5625 #endif
5626 #endif
5627
5628     Moving2Blocked(x, y, &newx, &newy);
5629
5630 #if 1
5631     if (IS_PUSHABLE(element) && JustBeingPushed(x, y))
5632       return;
5633 #else
5634     if ((element == EL_SATELLITE ||
5635          element == EL_BALLOON ||
5636          element == EL_SPRING)
5637         && JustBeingPushed(x, y))
5638       return;
5639 #endif
5640
5641 #if 1
5642
5643 #if 1
5644     if (game.engine_version >= VERSION_IDENT(3,1,0,0) &&
5645         CheckCollision[x][y] && !IN_LEV_FIELD_AND_IS_FREE(newx, newy))
5646 #else
5647     if (game.engine_version >= VERSION_IDENT(3,1,0,0) &&
5648         WasJustMoving[x][y] && IN_LEV_FIELD(newx, newy) &&
5649         (Feld[newx][newy] == EL_BLOCKED || IS_PLAYER(newx, newy)))
5650 #endif
5651     {
5652 #if 0
5653       printf("::: element %d '%s' WasJustMoving %d [%d, %d, %d, %d]\n",
5654              element, element_info[element].token_name,
5655              WasJustMoving[x][y],
5656              HAS_ANY_CHANGE_EVENT(element, CE_HITTING_SOMETHING),
5657              HAS_ANY_CHANGE_EVENT(element, CE_HIT_BY_SOMETHING),
5658              HAS_ANY_CHANGE_EVENT(element, CE_OTHER_IS_HITTING),
5659              HAS_ANY_CHANGE_EVENT(element, CE_OTHER_GETS_HIT));
5660 #endif
5661
5662 #if 1
5663       WasJustMoving[x][y] = 0;
5664 #endif
5665
5666       CheckCollision[x][y] = 0;
5667
5668       TestIfElementHitsCustomElement(x, y, MovDir[x][y]);
5669
5670 #if 0
5671       if (Feld[x][y] != element)        /* element has changed */
5672       {
5673         element = Feld[x][y];
5674         move_pattern = element_info[element].move_pattern;
5675
5676         if (!CAN_MOVE(element))
5677           return;
5678       }
5679 #else
5680       if (Feld[x][y] != element)        /* element has changed */
5681         return;
5682 #endif
5683     }
5684 #endif
5685
5686 #if 0
5687 #if 0
5688     if (element == EL_SPRING && MovDir[x][y] == MV_DOWN)
5689       Feld[x][y + 1] = EL_EMPTY;        /* was set to EL_BLOCKED above */
5690 #else
5691     if (element == EL_SPRING && MovDir[x][y] != MV_NO_MOVING)
5692     {
5693       Moving2Blocked(x, y, &newx, &newy);
5694       if (Feld[newx][newy] == EL_BLOCKED)
5695         Feld[newx][newy] = EL_EMPTY;    /* was set to EL_BLOCKED above */
5696     }
5697 #endif
5698 #endif
5699
5700 #if 0
5701     if (FrameCounter < 1 && x == 0 && y == 29)
5702       printf(":1: %d/%d: %d [%d]\n", x, y, MovDir[x][y], FrameCounter);
5703 #endif
5704
5705     if (!MovDelay[x][y])        /* start new movement phase */
5706     {
5707       /* all objects that can change their move direction after each step
5708          (YAMYAM, DARK_YAMYAM and PACMAN go straight until they hit a wall */
5709
5710       if (element != EL_YAMYAM &&
5711           element != EL_DARK_YAMYAM &&
5712           element != EL_PACMAN &&
5713           !(move_pattern & MV_ANY_DIRECTION) &&
5714           move_pattern != MV_TURNING_LEFT &&
5715           move_pattern != MV_TURNING_RIGHT &&
5716           move_pattern != MV_TURNING_LEFT_RIGHT &&
5717           move_pattern != MV_TURNING_RIGHT_LEFT &&
5718           move_pattern != MV_TURNING_RANDOM)
5719       {
5720         TurnRound(x, y);
5721
5722 #if 0
5723         if (FrameCounter < 1 && x == 0 && y == 29)
5724           printf(":9: %d: %d [%d]\n", y, MovDir[x][y], FrameCounter);
5725 #endif
5726
5727         if (MovDelay[x][y] && (element == EL_BUG ||
5728                                element == EL_SPACESHIP ||
5729                                element == EL_SP_SNIKSNAK ||
5730                                element == EL_SP_ELECTRON ||
5731                                element == EL_MOLE))
5732           DrawLevelField(x, y);
5733       }
5734     }
5735
5736     if (MovDelay[x][y])         /* wait some time before next movement */
5737     {
5738       MovDelay[x][y]--;
5739
5740 #if 0
5741       if (element == EL_YAMYAM)
5742       {
5743         printf("::: %d\n",
5744                el_act_dir2img(EL_YAMYAM, ACTION_WAITING, MV_LEFT));
5745         DrawLevelElementAnimation(x, y, element);
5746       }
5747 #endif
5748
5749       if (MovDelay[x][y])       /* element still has to wait some time */
5750       {
5751 #if 0
5752         /* !!! PLACE THIS SOMEWHERE AFTER "TurnRound()" !!! */
5753         ResetGfxAnimation(x, y);
5754 #endif
5755
5756 #if 0
5757         if (GfxAction[x][y] != ACTION_WAITING)
5758           printf("::: %d: %d != ACTION_WAITING\n", element, GfxAction[x][y]);
5759
5760         GfxAction[x][y] = ACTION_WAITING;
5761 #endif
5762       }
5763
5764       if (element == EL_ROBOT ||
5765 #if 0
5766           element == EL_PACMAN ||
5767 #endif
5768           element == EL_YAMYAM ||
5769           element == EL_DARK_YAMYAM)
5770       {
5771 #if 0
5772         DrawLevelElementAnimation(x, y, element);
5773 #else
5774         DrawLevelElementAnimationIfNeeded(x, y, element);
5775 #endif
5776         PlayLevelSoundAction(x, y, ACTION_WAITING);
5777       }
5778       else if (element == EL_SP_ELECTRON)
5779         DrawLevelElementAnimationIfNeeded(x, y, element);
5780       else if (element == EL_DRAGON)
5781       {
5782         int i;
5783         int dir = MovDir[x][y];
5784         int dx = (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
5785         int dy = (dir == MV_UP   ? -1 : dir == MV_DOWN  ? +1 : 0);
5786         int graphic = (dir == MV_LEFT   ? IMG_FLAMES_1_LEFT :
5787                        dir == MV_RIGHT  ? IMG_FLAMES_1_RIGHT :
5788                        dir == MV_UP     ? IMG_FLAMES_1_UP :
5789                        dir == MV_DOWN   ? IMG_FLAMES_1_DOWN : IMG_EMPTY);
5790         int frame = getGraphicAnimationFrame(graphic, GfxFrame[x][y]);
5791
5792 #if 0
5793         printf("::: %d, %d\n", GfxAction[x][y], GfxFrame[x][y]);
5794 #endif
5795
5796         GfxAction[x][y] = ACTION_ATTACKING;
5797
5798         if (IS_PLAYER(x, y))
5799           DrawPlayerField(x, y);
5800         else
5801           DrawLevelField(x, y);
5802
5803         PlayLevelSoundActionIfLoop(x, y, ACTION_ATTACKING);
5804
5805         for (i = 1; i <= 3; i++)
5806         {
5807           int xx = x + i * dx;
5808           int yy = y + i * dy;
5809           int sx = SCREENX(xx);
5810           int sy = SCREENY(yy);
5811           int flame_graphic = graphic + (i - 1);
5812
5813           if (!IN_LEV_FIELD(xx, yy) || IS_DRAGONFIRE_PROOF(Feld[xx][yy]))
5814             break;
5815
5816           if (MovDelay[x][y])
5817           {
5818             int flamed = MovingOrBlocked2Element(xx, yy);
5819
5820             /* !!! */
5821 #if 0
5822             if (IS_CLASSIC_ENEMY(flamed) || CAN_EXPLODE_BY_DRAGONFIRE(flamed))
5823               Bang(xx, yy);
5824             else if (IS_MOVING(xx, yy) || IS_BLOCKED(xx, yy))
5825               RemoveMovingField(xx, yy);
5826             else
5827               RemoveField(xx, yy);
5828 #else
5829             if (IS_CLASSIC_ENEMY(flamed) || CAN_EXPLODE_BY_DRAGONFIRE(flamed))
5830               Bang(xx, yy);
5831             else
5832               RemoveMovingField(xx, yy);
5833 #endif
5834
5835 #if 0
5836             if (ChangeDelay[xx][yy])
5837               printf("::: !!! [%d]\n", (IS_MOVING(xx, yy) ||
5838                                         Feld[xx][yy] == EL_BLOCKED));
5839 #endif
5840
5841 #if 1
5842             ChangeDelay[xx][yy] = 0;
5843 #endif
5844             Feld[xx][yy] = EL_FLAMES;
5845             if (IN_SCR_FIELD(sx, sy))
5846             {
5847               DrawLevelFieldCrumbledSand(xx, yy);
5848               DrawGraphic(sx, sy, flame_graphic, frame);
5849             }
5850           }
5851           else
5852           {
5853             if (Feld[xx][yy] == EL_FLAMES)
5854               Feld[xx][yy] = EL_EMPTY;
5855             DrawLevelField(xx, yy);
5856           }
5857         }
5858       }
5859
5860       if (MovDelay[x][y])       /* element still has to wait some time */
5861       {
5862         PlayLevelSoundAction(x, y, ACTION_WAITING);
5863
5864         return;
5865       }
5866
5867 #if 0
5868       /* special case of "moving" animation of waiting elements (FIX THIS !!!);
5869          for all other elements GfxAction will be set by InitMovingField() */
5870       if (element == EL_BD_BUTTERFLY || element == EL_BD_FIREFLY)
5871         GfxAction[x][y] = ACTION_MOVING;
5872 #endif
5873     }
5874
5875     /* now make next step */
5876
5877     Moving2Blocked(x, y, &newx, &newy); /* get next screen position */
5878
5879     if (DONT_COLLIDE_WITH(element) &&
5880         IN_LEV_FIELD(newx, newy) && IS_PLAYER(newx, newy) &&
5881         !PLAYER_ENEMY_PROTECTED(newx, newy))
5882     {
5883 #if 1
5884       TestIfBadThingRunsIntoHero(x, y, MovDir[x][y]);
5885
5886       return;
5887 #else
5888       /* player killed by element which is deadly when colliding with */
5889       MovDir[x][y] = 0;
5890       KillHero(PLAYERINFO(newx, newy));
5891       return;
5892 #endif
5893
5894     }
5895 #if 1
5896 #if 1
5897     else if (CAN_MOVE_INTO_ACID(element) &&
5898              IN_LEV_FIELD(newx, newy) && Feld[newx][newy] == EL_ACID &&
5899              (MovDir[x][y] == MV_DOWN ||
5900               game.engine_version >= VERSION_IDENT(3,1,0,0)))
5901 #else
5902     else if (CAN_MOVE_INTO_ACID(element) && MovDir[x][y] == MV_DOWN &&
5903              IN_LEV_FIELD(newx, newy) && Feld[newx][newy] == EL_ACID)
5904 #endif
5905 #else
5906
5907     else if ((element == EL_PENGUIN ||
5908               element == EL_ROBOT ||
5909               element == EL_SATELLITE ||
5910               element == EL_BALLOON ||
5911               IS_CUSTOM_ELEMENT(element)) &&
5912              IN_LEV_FIELD(newx, newy) &&
5913              MovDir[x][y] == MV_DOWN && Feld[newx][newy] == EL_ACID)
5914 #endif
5915     {
5916       SplashAcid(newx, newy);
5917       Store[x][y] = EL_ACID;
5918     }
5919     else if (element == EL_PENGUIN && IN_LEV_FIELD(newx, newy))
5920     {
5921       if (Feld[newx][newy] == EL_EXIT_OPEN)
5922       {
5923 #if 1
5924         RemoveField(x, y);
5925         DrawLevelField(x, y);
5926 #else
5927         Feld[x][y] = EL_EMPTY;
5928         DrawLevelField(x, y);
5929 #endif
5930
5931         PlayLevelSound(newx, newy, SND_PENGUIN_PASSING);
5932         if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
5933           DrawGraphicThruMask(SCREENX(newx),SCREENY(newy), el2img(element), 0);
5934
5935         local_player->friends_still_needed--;
5936         if (!local_player->friends_still_needed &&
5937             !local_player->GameOver && AllPlayersGone)
5938           local_player->LevelSolved = local_player->GameOver = TRUE;
5939
5940         return;
5941       }
5942       else if (IS_FOOD_PENGUIN(Feld[newx][newy]))
5943       {
5944         if (DigField(local_player, x, y, newx, newy, 0,0, DF_DIG) == MF_MOVING)
5945           DrawLevelField(newx, newy);
5946         else
5947           GfxDir[x][y] = MovDir[x][y] = MV_NO_MOVING;
5948       }
5949       else if (!IS_FREE(newx, newy))
5950       {
5951         GfxAction[x][y] = ACTION_WAITING;
5952
5953         if (IS_PLAYER(x, y))
5954           DrawPlayerField(x, y);
5955         else
5956           DrawLevelField(x, y);
5957
5958         return;
5959       }
5960     }
5961     else if (element == EL_PIG && IN_LEV_FIELD(newx, newy))
5962     {
5963       if (IS_FOOD_PIG(Feld[newx][newy]))
5964       {
5965         if (IS_MOVING(newx, newy))
5966           RemoveMovingField(newx, newy);
5967         else
5968         {
5969           Feld[newx][newy] = EL_EMPTY;
5970           DrawLevelField(newx, newy);
5971         }
5972
5973         PlayLevelSound(x, y, SND_PIG_DIGGING);
5974       }
5975       else if (!IS_FREE(newx, newy))
5976       {
5977         if (IS_PLAYER(x, y))
5978           DrawPlayerField(x, y);
5979         else
5980           DrawLevelField(x, y);
5981
5982         return;
5983       }
5984     }
5985
5986 #if 1
5987
5988     /*
5989     else if (move_pattern & MV_MAZE_RUNNER_STYLE && IN_LEV_FIELD(newx, newy))
5990     */
5991
5992     else if (IS_CUSTOM_ELEMENT(element) &&
5993              CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, newx, newy)
5994
5995 #if 0
5996  &&
5997              !IS_FREE(newx, newy)
5998 #endif
5999
6000 )
6001     {
6002       int new_element = Feld[newx][newy];
6003
6004 #if 0
6005       printf("::: '%s' digs '%s' [%d]\n",
6006              element_info[element].token_name,
6007              element_info[Feld[newx][newy]].token_name,
6008              StorePlayer[newx][newy]);
6009 #endif
6010
6011       if (!IS_FREE(newx, newy))
6012       {
6013         int action = (IS_DIGGABLE(new_element) ? ACTION_DIGGING :
6014                       IS_COLLECTIBLE(new_element) ? ACTION_COLLECTING :
6015                       ACTION_BREAKING);
6016
6017         /* no element can dig solid indestructible elements */
6018         if (IS_INDESTRUCTIBLE(new_element) &&
6019             !IS_DIGGABLE(new_element) &&
6020             !IS_COLLECTIBLE(new_element))
6021           return;
6022
6023         if (AmoebaNr[newx][newy] &&
6024             (new_element == EL_AMOEBA_FULL ||
6025              new_element == EL_BD_AMOEBA ||
6026              new_element == EL_AMOEBA_GROWING))
6027         {
6028           AmoebaCnt[AmoebaNr[newx][newy]]--;
6029           AmoebaCnt2[AmoebaNr[newx][newy]]--;
6030         }
6031
6032         if (IS_MOVING(newx, newy))
6033           RemoveMovingField(newx, newy);
6034         else
6035         {
6036           RemoveField(newx, newy);
6037           DrawLevelField(newx, newy);
6038         }
6039
6040         /* if digged element was about to explode, prevent the explosion */
6041         ExplodeField[newx][newy] = EX_TYPE_NONE;
6042
6043         PlayLevelSoundAction(x, y, action);
6044       }
6045
6046 #if 1
6047 #if 1
6048       Store[newx][newy] = EL_EMPTY;
6049       if (IS_EQUAL_OR_IN_GROUP(new_element, MOVE_ENTER_EL(element)))
6050         Store[newx][newy] = element_info[element].move_leave_element;
6051 #else
6052       Store[newx][newy] = EL_EMPTY;
6053       if (IS_EQUAL_OR_IN_GROUP(new_element, MOVE_ENTER_EL(element)) ||
6054           element_info[element].move_leave_type == LEAVE_TYPE_UNLIMITED)
6055         Store[newx][newy] = element_info[element].move_leave_element;
6056 #endif
6057 #else
6058       if (IS_EQUAL_OR_IN_GROUP(new_element, MOVE_ENTER_EL(element)))
6059         element_info[element].can_leave_element = TRUE;
6060 #endif
6061
6062       if (move_pattern & MV_MAZE_RUNNER_STYLE)
6063       {
6064         RunnerVisit[x][y] = FrameCounter;
6065         PlayerVisit[x][y] /= 8;         /* expire player visit path */
6066       }
6067     }
6068
6069 #endif
6070
6071     else if (element == EL_DRAGON && IN_LEV_FIELD(newx, newy))
6072     {
6073       if (!IS_FREE(newx, newy))
6074       {
6075         if (IS_PLAYER(x, y))
6076           DrawPlayerField(x, y);
6077         else
6078           DrawLevelField(x, y);
6079
6080         return;
6081       }
6082       else
6083       {
6084         boolean wanna_flame = !RND(10);
6085         int dx = newx - x, dy = newy - y;
6086         int newx1 = newx + 1 * dx, newy1 = newy + 1 * dy;
6087         int newx2 = newx + 2 * dx, newy2 = newy + 2 * dy;
6088         int element1 = (IN_LEV_FIELD(newx1, newy1) ?
6089                         MovingOrBlocked2Element(newx1, newy1) : EL_STEELWALL);
6090         int element2 = (IN_LEV_FIELD(newx2, newy2) ?
6091                         MovingOrBlocked2Element(newx2, newy2) : EL_STEELWALL);
6092
6093         if ((wanna_flame ||
6094              IS_CLASSIC_ENEMY(element1) ||
6095              IS_CLASSIC_ENEMY(element2)) &&
6096             element1 != EL_DRAGON && element2 != EL_DRAGON &&
6097             element1 != EL_FLAMES && element2 != EL_FLAMES)
6098         {
6099 #if 1
6100           ResetGfxAnimation(x, y);
6101           GfxAction[x][y] = ACTION_ATTACKING;
6102 #endif
6103
6104           if (IS_PLAYER(x, y))
6105             DrawPlayerField(x, y);
6106           else
6107             DrawLevelField(x, y);
6108
6109           PlayLevelSound(x, y, SND_DRAGON_ATTACKING);
6110
6111           MovDelay[x][y] = 50;
6112
6113           /* !!! */
6114 #if 0
6115           RemoveField(newx, newy);
6116 #endif
6117           Feld[newx][newy] = EL_FLAMES;
6118           if (IN_LEV_FIELD(newx1, newy1) && Feld[newx1][newy1] == EL_EMPTY)
6119           {
6120 #if 0
6121             RemoveField(newx1, newy1);
6122 #endif
6123             Feld[newx1][newy1] = EL_FLAMES;
6124           }
6125           if (IN_LEV_FIELD(newx2, newy2) && Feld[newx2][newy2] == EL_EMPTY)
6126           {
6127 #if 0
6128             RemoveField(newx2, newy2);
6129 #endif
6130             Feld[newx2][newy2] = EL_FLAMES;
6131           }
6132
6133           return;
6134         }
6135       }
6136     }
6137     else if (element == EL_YAMYAM && IN_LEV_FIELD(newx, newy) &&
6138              Feld[newx][newy] == EL_DIAMOND)
6139     {
6140       if (IS_MOVING(newx, newy))
6141         RemoveMovingField(newx, newy);
6142       else
6143       {
6144         Feld[newx][newy] = EL_EMPTY;
6145         DrawLevelField(newx, newy);
6146       }
6147
6148       PlayLevelSound(x, y, SND_YAMYAM_DIGGING);
6149     }
6150     else if (element == EL_DARK_YAMYAM && IN_LEV_FIELD(newx, newy) &&
6151              IS_FOOD_DARK_YAMYAM(Feld[newx][newy]))
6152     {
6153       if (AmoebaNr[newx][newy])
6154       {
6155         AmoebaCnt2[AmoebaNr[newx][newy]]--;
6156         if (Feld[newx][newy] == EL_AMOEBA_FULL ||
6157             Feld[newx][newy] == EL_BD_AMOEBA)
6158           AmoebaCnt[AmoebaNr[newx][newy]]--;
6159       }
6160
6161 #if 0
6162       /* !!! test !!! */
6163       if (IS_MOVING(newx, newy) || IS_BLOCKED(newx, newy))
6164 #else
6165       if (IS_MOVING(newx, newy))
6166 #endif
6167       {
6168         RemoveMovingField(newx, newy);
6169       }
6170       else
6171       {
6172         Feld[newx][newy] = EL_EMPTY;
6173         DrawLevelField(newx, newy);
6174       }
6175
6176       PlayLevelSound(x, y, SND_DARK_YAMYAM_DIGGING);
6177     }
6178     else if ((element == EL_PACMAN || element == EL_MOLE)
6179              && IN_LEV_FIELD(newx, newy) && IS_AMOEBOID(Feld[newx][newy]))
6180     {
6181       if (AmoebaNr[newx][newy])
6182       {
6183         AmoebaCnt2[AmoebaNr[newx][newy]]--;
6184         if (Feld[newx][newy] == EL_AMOEBA_FULL ||
6185             Feld[newx][newy] == EL_BD_AMOEBA)
6186           AmoebaCnt[AmoebaNr[newx][newy]]--;
6187       }
6188
6189       if (element == EL_MOLE)
6190       {
6191         Feld[newx][newy] = EL_AMOEBA_SHRINKING;
6192         PlayLevelSound(x, y, SND_MOLE_DIGGING);
6193
6194         ResetGfxAnimation(x, y);
6195         GfxAction[x][y] = ACTION_DIGGING;
6196         DrawLevelField(x, y);
6197
6198         MovDelay[newx][newy] = 0;       /* start amoeba shrinking delay */
6199
6200         return;                         /* wait for shrinking amoeba */
6201       }
6202       else      /* element == EL_PACMAN */
6203       {
6204         Feld[newx][newy] = EL_EMPTY;
6205         DrawLevelField(newx, newy);
6206         PlayLevelSound(x, y, SND_PACMAN_DIGGING);
6207       }
6208     }
6209     else if (element == EL_MOLE && IN_LEV_FIELD(newx, newy) &&
6210              (Feld[newx][newy] == EL_AMOEBA_SHRINKING ||
6211               (Feld[newx][newy] == EL_EMPTY && Stop[newx][newy])))
6212     {
6213       /* wait for shrinking amoeba to completely disappear */
6214       return;
6215     }
6216     else if (!IN_LEV_FIELD(newx, newy) || !IS_FREE(newx, newy))
6217     {
6218       /* object was running against a wall */
6219
6220       TurnRound(x, y);
6221
6222 #if 0
6223       if (move_pattern & MV_ANY_DIRECTION &&
6224           move_pattern == MovDir[x][y])
6225       {
6226         int blocking_element =
6227           (IN_LEV_FIELD(newx, newy) ? Feld[newx][newy] : BorderElement);
6228
6229 #if 0
6230         printf("::: '%s' is blocked by '%s'! [%d,%d -> %d,%d]\n",
6231                element_info[element].token_name,
6232                element_info[blocking_element].token_name,
6233                x, y, newx, newy);
6234 #endif
6235
6236         CheckElementChangeBySide(x, y, element, blocking_element, CE_BLOCKED,
6237                                  MovDir[x][y]);
6238
6239         element = Feld[x][y];   /* element might have changed */
6240       }
6241 #endif
6242
6243 #if 1
6244       if (GFX_ELEMENT(element) != EL_SAND)     /* !!! FIX THIS (crumble) !!! */
6245         DrawLevelElementAnimation(x, y, element);
6246 #else
6247       if (element == EL_BUG ||
6248           element == EL_SPACESHIP ||
6249           element == EL_SP_SNIKSNAK)
6250         DrawLevelField(x, y);
6251       else if (element == EL_MOLE)
6252         DrawLevelField(x, y);
6253       else if (element == EL_BD_BUTTERFLY ||
6254                element == EL_BD_FIREFLY)
6255         DrawLevelElementAnimationIfNeeded(x, y, element);
6256       else if (element == EL_SATELLITE)
6257         DrawLevelElementAnimationIfNeeded(x, y, element);
6258       else if (element == EL_SP_ELECTRON)
6259         DrawLevelElementAnimationIfNeeded(x, y, element);
6260 #endif
6261
6262       if (DONT_TOUCH(element))
6263         TestIfBadThingTouchesHero(x, y);
6264
6265 #if 0
6266       PlayLevelSoundAction(x, y, ACTION_WAITING);
6267 #endif
6268
6269       return;
6270     }
6271
6272     InitMovingField(x, y, MovDir[x][y]);
6273
6274     PlayLevelSoundAction(x, y, ACTION_MOVING);
6275   }
6276
6277   if (MovDir[x][y])
6278     ContinueMoving(x, y);
6279 }
6280
6281 void ContinueMoving(int x, int y)
6282 {
6283   int element = Feld[x][y];
6284   int stored = Store[x][y];
6285   struct ElementInfo *ei = &element_info[element];
6286   int direction = MovDir[x][y];
6287   int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
6288   int dy = (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
6289   int newx = x + dx, newy = y + dy;
6290 #if 0
6291   int nextx = newx + dx, nexty = newy + dy;
6292 #endif
6293 #if 1
6294   boolean pushed_by_player   = (Pushed[x][y] && IS_PLAYER(x, y));
6295   boolean pushed_by_conveyor = (Pushed[x][y] && !IS_PLAYER(x, y));
6296 #else
6297   boolean pushed_by_player = Pushed[x][y];
6298 #endif
6299
6300   MovPos[x][y] += getElementMoveStepsize(x, y);
6301
6302 #if 0
6303   if (pushed_by_player && IS_PLAYER(x, y))
6304   {
6305     /* special case: moving object pushed by player */
6306     MovPos[x][y] = SIGN(MovPos[x][y]) * (TILEX - ABS(PLAYERINFO(x,y)->MovPos));
6307   }
6308 #else
6309   if (pushed_by_player) /* special case: moving object pushed by player */
6310     MovPos[x][y] = SIGN(MovPos[x][y]) * (TILEX - ABS(PLAYERINFO(x,y)->MovPos));
6311 #endif
6312
6313   if (ABS(MovPos[x][y]) < TILEX)
6314   {
6315     DrawLevelField(x, y);
6316
6317     return;     /* element is still moving */
6318   }
6319
6320   /* element reached destination field */
6321
6322   Feld[x][y] = EL_EMPTY;
6323   Feld[newx][newy] = element;
6324   MovPos[x][y] = 0;     /* force "not moving" for "crumbled sand" */
6325
6326 #if 1
6327   if (Store[x][y] == EL_ACID)   /* element is moving into acid pool */
6328   {
6329     element = Feld[newx][newy] = EL_ACID;
6330   }
6331 #endif
6332   else if (element == EL_MOLE)
6333   {
6334     Feld[x][y] = EL_SAND;
6335
6336     DrawLevelFieldCrumbledSandNeighbours(x, y);
6337   }
6338   else if (element == EL_QUICKSAND_FILLING)
6339   {
6340     element = Feld[newx][newy] = get_next_element(element);
6341     Store[newx][newy] = Store[x][y];
6342   }
6343   else if (element == EL_QUICKSAND_EMPTYING)
6344   {
6345     Feld[x][y] = get_next_element(element);
6346     element = Feld[newx][newy] = Store[x][y];
6347   }
6348   else if (element == EL_MAGIC_WALL_FILLING)
6349   {
6350     element = Feld[newx][newy] = get_next_element(element);
6351     if (!game.magic_wall_active)
6352       element = Feld[newx][newy] = EL_MAGIC_WALL_DEAD;
6353     Store[newx][newy] = Store[x][y];
6354   }
6355   else if (element == EL_MAGIC_WALL_EMPTYING)
6356   {
6357     Feld[x][y] = get_next_element(element);
6358     if (!game.magic_wall_active)
6359       Feld[x][y] = EL_MAGIC_WALL_DEAD;
6360     element = Feld[newx][newy] = Store[x][y];
6361   }
6362   else if (element == EL_BD_MAGIC_WALL_FILLING)
6363   {
6364     element = Feld[newx][newy] = get_next_element(element);
6365     if (!game.magic_wall_active)
6366       element = Feld[newx][newy] = EL_BD_MAGIC_WALL_DEAD;
6367     Store[newx][newy] = Store[x][y];
6368   }
6369   else if (element == EL_BD_MAGIC_WALL_EMPTYING)
6370   {
6371     Feld[x][y] = get_next_element(element);
6372     if (!game.magic_wall_active)
6373       Feld[x][y] = EL_BD_MAGIC_WALL_DEAD;
6374     element = Feld[newx][newy] = Store[x][y];
6375   }
6376   else if (element == EL_AMOEBA_DROPPING)
6377   {
6378     Feld[x][y] = get_next_element(element);
6379     element = Feld[newx][newy] = Store[x][y];
6380   }
6381   else if (element == EL_SOKOBAN_OBJECT)
6382   {
6383     if (Back[x][y])
6384       Feld[x][y] = Back[x][y];
6385
6386     if (Back[newx][newy])
6387       Feld[newx][newy] = EL_SOKOBAN_FIELD_FULL;
6388
6389     Back[x][y] = Back[newx][newy] = 0;
6390   }
6391 #if 0
6392   else if (Store[x][y] == EL_ACID)
6393   {
6394     element = Feld[newx][newy] = EL_ACID;
6395   }
6396 #endif
6397 #if 0
6398   else if (IS_CUSTOM_ELEMENT(element) && !IS_PLAYER(x, y) &&
6399            ei->move_leave_element != EL_EMPTY &&
6400            (ei->move_leave_type == LEAVE_TYPE_UNLIMITED ||
6401             Store[x][y] != EL_EMPTY))
6402   {
6403     /* some elements can leave other elements behind after moving */
6404
6405     Feld[x][y] = ei->move_leave_element;
6406     InitField(x, y, FALSE);
6407
6408     if (GFX_CRUMBLED(Feld[x][y]))
6409       DrawLevelFieldCrumbledSandNeighbours(x, y);
6410   }
6411 #endif
6412
6413   Store[x][y] = EL_EMPTY;
6414   MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
6415   MovDelay[newx][newy] = 0;
6416
6417   if (CAN_CHANGE(element))
6418   {
6419     /* copy element change control values to new field */
6420     ChangeDelay[newx][newy] = ChangeDelay[x][y];
6421     ChangePage[newx][newy]  = ChangePage[x][y];
6422     Changed[newx][newy]     = Changed[x][y];
6423     ChangeEvent[newx][newy] = ChangeEvent[x][y];
6424   }
6425
6426   ChangeDelay[x][y] = 0;
6427   ChangePage[x][y] = -1;
6428   Changed[x][y] = CE_BITMASK_DEFAULT;
6429   ChangeEvent[x][y] = CE_BITMASK_DEFAULT;
6430
6431   /* copy animation control values to new field */
6432   GfxFrame[newx][newy]  = GfxFrame[x][y];
6433   GfxRandom[newx][newy] = GfxRandom[x][y];      /* keep same random value */
6434   GfxAction[newx][newy] = GfxAction[x][y];      /* keep action one frame  */
6435   GfxDir[newx][newy]    = GfxDir[x][y];         /* keep element direction */
6436
6437   Pushed[x][y] = Pushed[newx][newy] = FALSE;
6438
6439   ResetGfxAnimation(x, y);      /* reset animation values for old field */
6440
6441 #if 1
6442   /* some elements can leave other elements behind after moving */
6443 #if 1
6444   if (IS_CUSTOM_ELEMENT(element) && ei->move_leave_element != EL_EMPTY &&
6445       (ei->move_leave_type == LEAVE_TYPE_UNLIMITED || stored != EL_EMPTY) &&
6446       (!IS_PLAYER(x, y) || IS_WALKABLE(ei->move_leave_element)))
6447 #else
6448   if (IS_CUSTOM_ELEMENT(element) && ei->move_leave_element != EL_EMPTY &&
6449       (ei->move_leave_type == LEAVE_TYPE_UNLIMITED || stored != EL_EMPTY) &&
6450       !IS_PLAYER(x, y))
6451 #endif
6452   {
6453     int move_leave_element = ei->move_leave_element;
6454
6455     Feld[x][y] = move_leave_element;
6456     InitField(x, y, FALSE);
6457
6458     if (GFX_CRUMBLED(Feld[x][y]))
6459       DrawLevelFieldCrumbledSandNeighbours(x, y);
6460
6461     if (ELEM_IS_PLAYER(move_leave_element))
6462       RelocatePlayer(x, y, move_leave_element);
6463   }
6464 #endif
6465
6466 #if 0
6467   /* some elements can leave other elements behind after moving */
6468   if (IS_CUSTOM_ELEMENT(element) && !IS_PLAYER(x, y) &&
6469       ei->move_leave_element != EL_EMPTY &&
6470       (ei->move_leave_type == LEAVE_TYPE_UNLIMITED ||
6471        ei->can_leave_element_last))
6472   {
6473     Feld[x][y] = ei->move_leave_element;
6474     InitField(x, y, FALSE);
6475
6476     if (GFX_CRUMBLED(Feld[x][y]))
6477       DrawLevelFieldCrumbledSandNeighbours(x, y);
6478   }
6479
6480   ei->can_leave_element_last = ei->can_leave_element;
6481   ei->can_leave_element = FALSE;
6482 #endif
6483
6484 #if 0
6485   /* 2.1.1 (does not work correctly for spring) */
6486   if (!CAN_MOVE(element))
6487     MovDir[newx][newy] = 0;
6488 #else
6489
6490 #if 0
6491   /* (does not work for falling objects that slide horizontally) */
6492   if (CAN_FALL(element) && MovDir[newx][newy] == MV_DOWN)
6493     MovDir[newx][newy] = 0;
6494 #else
6495   /*
6496   if (!CAN_MOVE(element) ||
6497       (element == EL_SPRING && MovDir[newx][newy] == MV_DOWN))
6498     MovDir[newx][newy] = 0;
6499   */
6500
6501 #if 0
6502   if (!CAN_MOVE(element) ||
6503       (CAN_FALL(element) && direction == MV_DOWN))
6504     GfxDir[x][y] = MovDir[newx][newy] = 0;
6505 #else
6506   if (!CAN_MOVE(element) ||
6507       (CAN_FALL(element) && direction == MV_DOWN &&
6508        (element == EL_SPRING ||
6509         element_info[element].move_pattern == MV_WHEN_PUSHED ||
6510         element_info[element].move_pattern == MV_WHEN_DROPPED)))
6511     GfxDir[x][y] = MovDir[newx][newy] = 0;
6512 #endif
6513
6514 #endif
6515 #endif
6516
6517   DrawLevelField(x, y);
6518   DrawLevelField(newx, newy);
6519
6520   Stop[newx][newy] = TRUE;      /* ignore this element until the next frame */
6521
6522   /* prevent pushed element from moving on in pushed direction */
6523   if (pushed_by_player && CAN_MOVE(element) &&
6524       element_info[element].move_pattern & MV_ANY_DIRECTION &&
6525       !(element_info[element].move_pattern & direction))
6526     TurnRound(newx, newy);
6527
6528 #if 1
6529   /* prevent elements on conveyor belt from moving on in last direction */
6530   if (pushed_by_conveyor && CAN_FALL(element) &&
6531       direction & MV_HORIZONTAL)
6532   {
6533 #if 0
6534     if (CAN_MOVE(element))
6535       InitMovDir(newx, newy);
6536     else
6537       MovDir[newx][newy] = 0;
6538 #else
6539     MovDir[newx][newy] = 0;
6540 #endif
6541   }
6542 #endif
6543
6544   if (!pushed_by_player)
6545   {
6546     int nextx = newx + dx, nexty = newy + dy;
6547     boolean check_collision_again = IN_LEV_FIELD_AND_IS_FREE(nextx, nexty);
6548
6549     WasJustMoving[newx][newy] = 3;
6550
6551     if (CAN_FALL(element) && direction == MV_DOWN)
6552       WasJustFalling[newx][newy] = 3;
6553
6554     if ((!CAN_FALL(element) || direction == MV_DOWN) && check_collision_again)
6555       CheckCollision[newx][newy] = 2;
6556   }
6557
6558   if (DONT_TOUCH(element))      /* object may be nasty to player or others */
6559   {
6560     TestIfBadThingTouchesHero(newx, newy);
6561     TestIfBadThingTouchesFriend(newx, newy);
6562
6563     if (!IS_CUSTOM_ELEMENT(element))
6564       TestIfBadThingTouchesOtherBadThing(newx, newy);
6565   }
6566   else if (element == EL_PENGUIN)
6567     TestIfFriendTouchesBadThing(newx, newy);
6568
6569 #if USE_NEW_MOVE_STYLE
6570 #if 0
6571   if (CAN_FALL(element) && direction == MV_DOWN &&
6572       (newy == lev_fieldy - 1 || !IS_FREE(x, newy + 1)) &&
6573       IS_PLAYER(x, newy + 1))
6574     printf("::: we would now kill the player [%d]\n", FrameCounter);
6575 #endif
6576
6577   /* give the player one last chance (one more frame) to move away */
6578   if (CAN_FALL(element) && direction == MV_DOWN &&
6579       (newy == lev_fieldy - 1 || !IS_FREE(x, newy + 1)) &&
6580       (!IS_PLAYER(x, newy + 1) ||
6581        game.engine_version < VERSION_IDENT(3,1,1,0)))
6582     Impact(x, newy);
6583 #else
6584   if (CAN_FALL(element) && direction == MV_DOWN &&
6585       (newy == lev_fieldy - 1 || !IS_FREE(x, newy + 1)))
6586     Impact(x, newy);
6587 #endif
6588
6589 #if 1
6590
6591 #if USE_PUSH_BUGFIX
6592 #if 1
6593   if (pushed_by_player && !game.use_bug_change_when_pushing)
6594 #else
6595   if (pushed_by_player && game.engine_version >= VERSION_IDENT(3,1,0,0))
6596 #endif
6597 #else
6598   if (pushed_by_player)
6599 #endif
6600
6601   {
6602 #if 1
6603     int dig_side = MV_DIR_OPPOSITE(direction);
6604 #else
6605     static int trigger_sides[4] =
6606     {
6607       CH_SIDE_RIGHT,    /* moving left  */
6608       CH_SIDE_LEFT,     /* moving right */
6609       CH_SIDE_BOTTOM,   /* moving up    */
6610       CH_SIDE_TOP,      /* moving down  */
6611     };
6612     int dig_side = trigger_sides[MV_DIR_BIT(direction)];
6613 #endif
6614     struct PlayerInfo *player = PLAYERINFO(x, y);
6615
6616     CheckElementChangeByPlayer(newx, newy, element, CE_PUSHED_BY_PLAYER,
6617                                player->index_bit, dig_side);
6618     CheckTriggeredElementChangeByPlayer(newx,newy,element,CE_OTHER_GETS_PUSHED,
6619                                         player->index_bit, dig_side);
6620   }
6621 #endif
6622
6623 #if 1
6624   TestIfElementTouchesCustomElement(x, y);      /* empty or new element */
6625 #endif
6626
6627 #if 0
6628   if (ChangePage[newx][newy] != -1)                     /* delayed change */
6629     ChangeElement(newx, newy, ChangePage[newx][newy]);
6630 #endif
6631
6632 #if 1
6633
6634   TestIfElementHitsCustomElement(newx, newy, direction);
6635
6636 #else
6637
6638   if (!IN_LEV_FIELD(nextx, nexty) || !IS_FREE(nextx, nexty))
6639   {
6640     int hitting_element = Feld[newx][newy];
6641
6642     /* !!! fix side (direction) orientation here and elsewhere !!! */
6643     CheckElementChangeBySide(newx, newy, hitting_element, CE_HITTING_SOMETHING,
6644                              direction);
6645
6646 #if 0
6647     if (IN_LEV_FIELD(nextx, nexty))
6648     {
6649       int opposite_direction = MV_DIR_OPPOSITE(direction);
6650       int hitting_side = direction;
6651       int touched_side = opposite_direction;
6652       int touched_element = MovingOrBlocked2Element(nextx, nexty);
6653       boolean object_hit = (!IS_MOVING(nextx, nexty) ||
6654                             MovDir[nextx][nexty] != direction ||
6655                             ABS(MovPos[nextx][nexty]) <= TILEY / 2);
6656
6657       if (object_hit)
6658       {
6659         int i;
6660
6661         CheckElementChangeBySide(nextx, nexty, touched_element,
6662                                  CE_HIT_BY_SOMETHING, opposite_direction);
6663
6664         if (IS_CUSTOM_ELEMENT(hitting_element) &&
6665             HAS_ANY_CHANGE_EVENT(hitting_element, CE_OTHER_IS_HITTING))
6666         {
6667           for (i = 0; i < element_info[hitting_element].num_change_pages; i++)
6668           {
6669             struct ElementChangeInfo *change =
6670               &element_info[hitting_element].change_page[i];
6671
6672             if (change->can_change &&
6673                 change->events & CH_EVENT_BIT(CE_OTHER_IS_HITTING) &&
6674                 change->trigger_side & touched_side &&
6675                 change->trigger_element == touched_element)
6676             {
6677               CheckElementChangeByPage(newx, newy, hitting_element,
6678                                        touched_element, CE_OTHER_IS_HITTING,i);
6679               break;
6680             }
6681           }
6682         }
6683
6684         if (IS_CUSTOM_ELEMENT(touched_element) &&
6685             HAS_ANY_CHANGE_EVENT(touched_element, CE_OTHER_GETS_HIT))
6686         {
6687           for (i = 0; i < element_info[touched_element].num_change_pages; i++)
6688           {
6689             struct ElementChangeInfo *change =
6690               &element_info[touched_element].change_page[i];
6691
6692             if (change->can_change &&
6693                 change->events & CH_EVENT_BIT(CE_OTHER_GETS_HIT) &&
6694                 change->trigger_side & hitting_side &&
6695                 change->trigger_element == hitting_element)
6696             {
6697               CheckElementChangeByPage(nextx, nexty, touched_element,
6698                                        hitting_element, CE_OTHER_GETS_HIT, i);
6699               break;
6700             }
6701           }
6702         }
6703       }
6704     }
6705 #endif
6706   }
6707 #endif
6708
6709   TestIfPlayerTouchesCustomElement(newx, newy);
6710   TestIfElementTouchesCustomElement(newx, newy);
6711 }
6712
6713 int AmoebeNachbarNr(int ax, int ay)
6714 {
6715   int i;
6716   int element = Feld[ax][ay];
6717   int group_nr = 0;
6718   static int xy[4][2] =
6719   {
6720     { 0, -1 },
6721     { -1, 0 },
6722     { +1, 0 },
6723     { 0, +1 }
6724   };
6725
6726   for (i = 0; i < NUM_DIRECTIONS; i++)
6727   {
6728     int x = ax + xy[i][0];
6729     int y = ay + xy[i][1];
6730
6731     if (!IN_LEV_FIELD(x, y))
6732       continue;
6733
6734     if (Feld[x][y] == element && AmoebaNr[x][y] > 0)
6735       group_nr = AmoebaNr[x][y];
6736   }
6737
6738   return group_nr;
6739 }
6740
6741 void AmoebenVereinigen(int ax, int ay)
6742 {
6743   int i, x, y, xx, yy;
6744   int new_group_nr = AmoebaNr[ax][ay];
6745   static int xy[4][2] =
6746   {
6747     { 0, -1 },
6748     { -1, 0 },
6749     { +1, 0 },
6750     { 0, +1 }
6751   };
6752
6753   if (new_group_nr == 0)
6754     return;
6755
6756   for (i = 0; i < NUM_DIRECTIONS; i++)
6757   {
6758     x = ax + xy[i][0];
6759     y = ay + xy[i][1];
6760
6761     if (!IN_LEV_FIELD(x, y))
6762       continue;
6763
6764     if ((Feld[x][y] == EL_AMOEBA_FULL ||
6765          Feld[x][y] == EL_BD_AMOEBA ||
6766          Feld[x][y] == EL_AMOEBA_DEAD) &&
6767         AmoebaNr[x][y] != new_group_nr)
6768     {
6769       int old_group_nr = AmoebaNr[x][y];
6770
6771       if (old_group_nr == 0)
6772         return;
6773
6774       AmoebaCnt[new_group_nr] += AmoebaCnt[old_group_nr];
6775       AmoebaCnt[old_group_nr] = 0;
6776       AmoebaCnt2[new_group_nr] += AmoebaCnt2[old_group_nr];
6777       AmoebaCnt2[old_group_nr] = 0;
6778
6779       for (yy = 0; yy < lev_fieldy; yy++)
6780       {
6781         for (xx = 0; xx < lev_fieldx; xx++)
6782         {
6783           if (AmoebaNr[xx][yy] == old_group_nr)
6784             AmoebaNr[xx][yy] = new_group_nr;
6785         }
6786       }
6787     }
6788   }
6789 }
6790
6791 void AmoebeUmwandeln(int ax, int ay)
6792 {
6793   int i, x, y;
6794
6795   if (Feld[ax][ay] == EL_AMOEBA_DEAD)
6796   {
6797     int group_nr = AmoebaNr[ax][ay];
6798
6799 #ifdef DEBUG
6800     if (group_nr == 0)
6801     {
6802       printf("AmoebeUmwandeln(): ax = %d, ay = %d\n", ax, ay);
6803       printf("AmoebeUmwandeln(): This should never happen!\n");
6804       return;
6805     }
6806 #endif
6807
6808     for (y = 0; y < lev_fieldy; y++)
6809     {
6810       for (x = 0; x < lev_fieldx; x++)
6811       {
6812         if (Feld[x][y] == EL_AMOEBA_DEAD && AmoebaNr[x][y] == group_nr)
6813         {
6814           AmoebaNr[x][y] = 0;
6815           Feld[x][y] = EL_AMOEBA_TO_DIAMOND;
6816         }
6817       }
6818     }
6819     PlayLevelSound(ax, ay, (IS_GEM(level.amoeba_content) ?
6820                             SND_AMOEBA_TURNING_TO_GEM :
6821                             SND_AMOEBA_TURNING_TO_ROCK));
6822     Bang(ax, ay);
6823   }
6824   else
6825   {
6826     static int xy[4][2] =
6827     {
6828       { 0, -1 },
6829       { -1, 0 },
6830       { +1, 0 },
6831       { 0, +1 }
6832     };
6833
6834     for (i = 0; i < NUM_DIRECTIONS; i++)
6835     {
6836       x = ax + xy[i][0];
6837       y = ay + xy[i][1];
6838
6839       if (!IN_LEV_FIELD(x, y))
6840         continue;
6841
6842       if (Feld[x][y] == EL_AMOEBA_TO_DIAMOND)
6843       {
6844         PlayLevelSound(x, y, (IS_GEM(level.amoeba_content) ?
6845                               SND_AMOEBA_TURNING_TO_GEM :
6846                               SND_AMOEBA_TURNING_TO_ROCK));
6847         Bang(x, y);
6848       }
6849     }
6850   }
6851 }
6852
6853 void AmoebeUmwandelnBD(int ax, int ay, int new_element)
6854 {
6855   int x, y;
6856   int group_nr = AmoebaNr[ax][ay];
6857   boolean done = FALSE;
6858
6859 #ifdef DEBUG
6860   if (group_nr == 0)
6861   {
6862     printf("AmoebeUmwandelnBD(): ax = %d, ay = %d\n", ax, ay);
6863     printf("AmoebeUmwandelnBD(): This should never happen!\n");
6864     return;
6865   }
6866 #endif
6867
6868   for (y = 0; y < lev_fieldy; y++)
6869   {
6870     for (x = 0; x < lev_fieldx; x++)
6871     {
6872       if (AmoebaNr[x][y] == group_nr &&
6873           (Feld[x][y] == EL_AMOEBA_DEAD ||
6874            Feld[x][y] == EL_BD_AMOEBA ||
6875            Feld[x][y] == EL_AMOEBA_GROWING))
6876       {
6877         AmoebaNr[x][y] = 0;
6878         Feld[x][y] = new_element;
6879         InitField(x, y, FALSE);
6880         DrawLevelField(x, y);
6881         done = TRUE;
6882       }
6883     }
6884   }
6885
6886   if (done)
6887     PlayLevelSound(ax, ay, (new_element == EL_BD_ROCK ?
6888                             SND_BD_AMOEBA_TURNING_TO_ROCK :
6889                             SND_BD_AMOEBA_TURNING_TO_GEM));
6890 }
6891
6892 void AmoebeWaechst(int x, int y)
6893 {
6894   static unsigned long sound_delay = 0;
6895   static unsigned long sound_delay_value = 0;
6896
6897   if (!MovDelay[x][y])          /* start new growing cycle */
6898   {
6899     MovDelay[x][y] = 7;
6900
6901     if (DelayReached(&sound_delay, sound_delay_value))
6902     {
6903 #if 1
6904       PlayLevelSoundElementAction(x, y, Store[x][y], ACTION_GROWING);
6905 #else
6906       if (Store[x][y] == EL_BD_AMOEBA)
6907         PlayLevelSound(x, y, SND_BD_AMOEBA_GROWING);
6908       else
6909         PlayLevelSound(x, y, SND_AMOEBA_GROWING);
6910 #endif
6911       sound_delay_value = 30;
6912     }
6913   }
6914
6915   if (MovDelay[x][y])           /* wait some time before growing bigger */
6916   {
6917     MovDelay[x][y]--;
6918     if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
6919     {
6920       int frame = getGraphicAnimationFrame(IMG_AMOEBA_GROWING,
6921                                            6 - MovDelay[x][y]);
6922
6923       DrawGraphic(SCREENX(x), SCREENY(y), IMG_AMOEBA_GROWING, frame);
6924     }
6925
6926     if (!MovDelay[x][y])
6927     {
6928       Feld[x][y] = Store[x][y];
6929       Store[x][y] = 0;
6930       DrawLevelField(x, y);
6931     }
6932   }
6933 }
6934
6935 void AmoebaDisappearing(int x, int y)
6936 {
6937   static unsigned long sound_delay = 0;
6938   static unsigned long sound_delay_value = 0;
6939
6940   if (!MovDelay[x][y])          /* start new shrinking cycle */
6941   {
6942     MovDelay[x][y] = 7;
6943
6944     if (DelayReached(&sound_delay, sound_delay_value))
6945       sound_delay_value = 30;
6946   }
6947
6948   if (MovDelay[x][y])           /* wait some time before shrinking */
6949   {
6950     MovDelay[x][y]--;
6951     if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
6952     {
6953       int frame = getGraphicAnimationFrame(IMG_AMOEBA_SHRINKING,
6954                                            6 - MovDelay[x][y]);
6955
6956       DrawGraphic(SCREENX(x), SCREENY(y), IMG_AMOEBA_SHRINKING, frame);
6957     }
6958
6959     if (!MovDelay[x][y])
6960     {
6961       Feld[x][y] = EL_EMPTY;
6962       DrawLevelField(x, y);
6963
6964       /* don't let mole enter this field in this cycle;
6965          (give priority to objects falling to this field from above) */
6966       Stop[x][y] = TRUE;
6967     }
6968   }
6969 }
6970
6971 void AmoebeAbleger(int ax, int ay)
6972 {
6973   int i;
6974   int element = Feld[ax][ay];
6975   int graphic = el2img(element);
6976   int newax = ax, neway = ay;
6977   static int xy[4][2] =
6978   {
6979     { 0, -1 },
6980     { -1, 0 },
6981     { +1, 0 },
6982     { 0, +1 }
6983   };
6984
6985   if (!level.amoeba_speed)
6986   {
6987     Feld[ax][ay] = EL_AMOEBA_DEAD;
6988     DrawLevelField(ax, ay);
6989     return;
6990   }
6991
6992   if (IS_ANIMATED(graphic))
6993     DrawLevelGraphicAnimationIfNeeded(ax, ay, graphic);
6994
6995   if (!MovDelay[ax][ay])        /* start making new amoeba field */
6996     MovDelay[ax][ay] = RND(FRAMES_PER_SECOND * 25 / (1 + level.amoeba_speed));
6997
6998   if (MovDelay[ax][ay])         /* wait some time before making new amoeba */
6999   {
7000     MovDelay[ax][ay]--;
7001     if (MovDelay[ax][ay])
7002       return;
7003   }
7004
7005   if (element == EL_AMOEBA_WET) /* object is an acid / amoeba drop */
7006   {
7007     int start = RND(4);
7008     int x = ax + xy[start][0];
7009     int y = ay + xy[start][1];
7010
7011     if (!IN_LEV_FIELD(x, y))
7012       return;
7013
7014 #if 1
7015     if (IS_FREE(x, y) ||
7016         CAN_GROW_INTO(Feld[x][y]) ||
7017         Feld[x][y] == EL_QUICKSAND_EMPTY)
7018     {
7019       newax = x;
7020       neway = y;
7021     }
7022 #else
7023     /* !!! extend EL_SAND to anything diggable (but maybe not SP_BASE) !!! */
7024     if (IS_FREE(x, y) ||
7025         Feld[x][y] == EL_SAND || Feld[x][y] == EL_QUICKSAND_EMPTY)
7026     {
7027       newax = x;
7028       neway = y;
7029     }
7030 #endif
7031
7032     if (newax == ax && neway == ay)
7033       return;
7034   }
7035   else                          /* normal or "filled" (BD style) amoeba */
7036   {
7037     int start = RND(4);
7038     boolean waiting_for_player = FALSE;
7039
7040     for (i = 0; i < NUM_DIRECTIONS; i++)
7041     {
7042       int j = (start + i) % 4;
7043       int x = ax + xy[j][0];
7044       int y = ay + xy[j][1];
7045
7046       if (!IN_LEV_FIELD(x, y))
7047         continue;
7048
7049 #if 1
7050       if (IS_FREE(x, y) ||
7051           CAN_GROW_INTO(Feld[x][y]) ||
7052           Feld[x][y] == EL_QUICKSAND_EMPTY)
7053       {
7054         newax = x;
7055         neway = y;
7056         break;
7057       }
7058 #else
7059       /* !!! extend EL_SAND to anything diggable (but maybe not SP_BASE) !!! */
7060       if (IS_FREE(x, y) ||
7061           Feld[x][y] == EL_SAND || Feld[x][y] == EL_QUICKSAND_EMPTY)
7062       {
7063         newax = x;
7064         neway = y;
7065         break;
7066       }
7067 #endif
7068       else if (IS_PLAYER(x, y))
7069         waiting_for_player = TRUE;
7070     }
7071
7072     if (newax == ax && neway == ay)             /* amoeba cannot grow */
7073     {
7074 #if 1
7075       if (i == 4 && (!waiting_for_player || element == EL_BD_AMOEBA))
7076 #else
7077       if (i == 4 && (!waiting_for_player || game.emulation == EMU_BOULDERDASH))
7078 #endif
7079       {
7080         Feld[ax][ay] = EL_AMOEBA_DEAD;
7081         DrawLevelField(ax, ay);
7082         AmoebaCnt[AmoebaNr[ax][ay]]--;
7083
7084         if (AmoebaCnt[AmoebaNr[ax][ay]] <= 0)   /* amoeba is completely dead */
7085         {
7086           if (element == EL_AMOEBA_FULL)
7087             AmoebeUmwandeln(ax, ay);
7088           else if (element == EL_BD_AMOEBA)
7089             AmoebeUmwandelnBD(ax, ay, level.amoeba_content);
7090         }
7091       }
7092       return;
7093     }
7094     else if (element == EL_AMOEBA_FULL || element == EL_BD_AMOEBA)
7095     {
7096       /* amoeba gets larger by growing in some direction */
7097
7098       int new_group_nr = AmoebaNr[ax][ay];
7099
7100 #ifdef DEBUG
7101   if (new_group_nr == 0)
7102   {
7103     printf("AmoebeAbleger(): newax = %d, neway = %d\n", newax, neway);
7104     printf("AmoebeAbleger(): This should never happen!\n");
7105     return;
7106   }
7107 #endif
7108
7109       AmoebaNr[newax][neway] = new_group_nr;
7110       AmoebaCnt[new_group_nr]++;
7111       AmoebaCnt2[new_group_nr]++;
7112
7113       /* if amoeba touches other amoeba(s) after growing, unify them */
7114       AmoebenVereinigen(newax, neway);
7115
7116       if (element == EL_BD_AMOEBA && AmoebaCnt2[new_group_nr] >= 200)
7117       {
7118         AmoebeUmwandelnBD(newax, neway, EL_BD_ROCK);
7119         return;
7120       }
7121     }
7122   }
7123
7124   if (element != EL_AMOEBA_WET || neway < ay || !IS_FREE(newax, neway) ||
7125       (neway == lev_fieldy - 1 && newax != ax))
7126   {
7127     Feld[newax][neway] = EL_AMOEBA_GROWING;     /* creation of new amoeba */
7128     Store[newax][neway] = element;
7129   }
7130   else if (neway == ay)
7131   {
7132     Feld[newax][neway] = EL_AMOEBA_DROP;        /* drop left/right of amoeba */
7133 #if 1
7134     PlayLevelSoundAction(newax, neway, ACTION_GROWING);
7135 #else
7136     PlayLevelSound(newax, neway, SND_AMOEBA_GROWING);
7137 #endif
7138   }
7139   else
7140   {
7141     InitMovingField(ax, ay, MV_DOWN);           /* drop dripping from amoeba */
7142     Feld[ax][ay] = EL_AMOEBA_DROPPING;
7143     Store[ax][ay] = EL_AMOEBA_DROP;
7144     ContinueMoving(ax, ay);
7145     return;
7146   }
7147
7148   DrawLevelField(newax, neway);
7149 }
7150
7151 void Life(int ax, int ay)
7152 {
7153   int x1, y1, x2, y2;
7154   static int life[4] = { 2, 3, 3, 3 };  /* parameters for "game of life" */
7155   int life_time = 40;
7156   int element = Feld[ax][ay];
7157   int graphic = el2img(element);
7158   boolean changed = FALSE;
7159
7160   if (IS_ANIMATED(graphic))
7161     DrawLevelGraphicAnimationIfNeeded(ax, ay, graphic);
7162
7163   if (Stop[ax][ay])
7164     return;
7165
7166   if (!MovDelay[ax][ay])        /* start new "game of life" cycle */
7167     MovDelay[ax][ay] = life_time;
7168
7169   if (MovDelay[ax][ay])         /* wait some time before next cycle */
7170   {
7171     MovDelay[ax][ay]--;
7172     if (MovDelay[ax][ay])
7173       return;
7174   }
7175
7176   for (y1 = -1; y1 < 2; y1++) for (x1 = -1; x1 < 2; x1++)
7177   {
7178     int xx = ax+x1, yy = ay+y1;
7179     int nachbarn = 0;
7180
7181     if (!IN_LEV_FIELD(xx, yy))
7182       continue;
7183
7184     for (y2 = -1; y2 < 2; y2++) for (x2 = -1; x2 < 2; x2++)
7185     {
7186       int x = xx+x2, y = yy+y2;
7187
7188       if (!IN_LEV_FIELD(x, y) || (x == xx && y == yy))
7189         continue;
7190
7191       if (((Feld[x][y] == element ||
7192             (element == EL_GAME_OF_LIFE && IS_PLAYER(x, y))) &&
7193            !Stop[x][y]) ||
7194           (IS_FREE(x, y) && Stop[x][y]))
7195         nachbarn++;
7196     }
7197
7198     if (xx == ax && yy == ay)           /* field in the middle */
7199     {
7200       if (nachbarn < life[0] || nachbarn > life[1])
7201       {
7202         Feld[xx][yy] = EL_EMPTY;
7203         if (!Stop[xx][yy])
7204           DrawLevelField(xx, yy);
7205         Stop[xx][yy] = TRUE;
7206         changed = TRUE;
7207       }
7208     }
7209 #if 1
7210     else if (IS_FREE(xx, yy) || CAN_GROW_INTO(Feld[xx][yy]))
7211     {                                   /* free border field */
7212       if (nachbarn >= life[2] && nachbarn <= life[3])
7213       {
7214         Feld[xx][yy] = element;
7215         MovDelay[xx][yy] = (element == EL_GAME_OF_LIFE ? 0 : life_time-1);
7216         if (!Stop[xx][yy])
7217           DrawLevelField(xx, yy);
7218         Stop[xx][yy] = TRUE;
7219         changed = TRUE;
7220       }
7221     }
7222 #else
7223     /* !!! extend EL_SAND to anything diggable (but maybe not SP_BASE) !!! */
7224     else if (IS_FREE(xx, yy) || Feld[xx][yy] == EL_SAND)
7225     {                                   /* free border field */
7226       if (nachbarn >= life[2] && nachbarn <= life[3])
7227       {
7228         Feld[xx][yy] = element;
7229         MovDelay[xx][yy] = (element == EL_GAME_OF_LIFE ? 0 : life_time-1);
7230         if (!Stop[xx][yy])
7231           DrawLevelField(xx, yy);
7232         Stop[xx][yy] = TRUE;
7233         changed = TRUE;
7234       }
7235     }
7236 #endif
7237   }
7238
7239   if (changed)
7240     PlayLevelSound(ax, ay, element == EL_BIOMAZE ? SND_BIOMAZE_GROWING :
7241                    SND_GAME_OF_LIFE_GROWING);
7242 }
7243
7244 static void InitRobotWheel(int x, int y)
7245 {
7246   ChangeDelay[x][y] = level.time_wheel * FRAMES_PER_SECOND;
7247 }
7248
7249 static void RunRobotWheel(int x, int y)
7250 {
7251   PlayLevelSound(x, y, SND_ROBOT_WHEEL_ACTIVE);
7252 }
7253
7254 static void StopRobotWheel(int x, int y)
7255 {
7256   if (ZX == x && ZY == y)
7257     ZX = ZY = -1;
7258 }
7259
7260 static void InitTimegateWheel(int x, int y)
7261 {
7262 #if 1
7263   ChangeDelay[x][y] = level.time_timegate * FRAMES_PER_SECOND;
7264 #else
7265   /* another brainless, "type style" bug ... :-( */
7266   ChangeDelay[x][y] = level.time_wheel * FRAMES_PER_SECOND;
7267 #endif
7268 }
7269
7270 static void RunTimegateWheel(int x, int y)
7271 {
7272   PlayLevelSound(x, y, SND_TIMEGATE_SWITCH_ACTIVE);
7273 }
7274
7275 void CheckExit(int x, int y)
7276 {
7277   if (local_player->gems_still_needed > 0 ||
7278       local_player->sokobanfields_still_needed > 0 ||
7279       local_player->lights_still_needed > 0)
7280   {
7281     int element = Feld[x][y];
7282     int graphic = el2img(element);
7283
7284     if (IS_ANIMATED(graphic))
7285       DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
7286
7287     return;
7288   }
7289
7290   if (AllPlayersGone)   /* do not re-open exit door closed after last player */
7291     return;
7292
7293   Feld[x][y] = EL_EXIT_OPENING;
7294
7295   PlayLevelSoundNearest(x, y, SND_CLASS_EXIT_OPENING);
7296 }
7297
7298 void CheckExitSP(int x, int y)
7299 {
7300   if (local_player->gems_still_needed > 0)
7301   {
7302     int element = Feld[x][y];
7303     int graphic = el2img(element);
7304
7305     if (IS_ANIMATED(graphic))
7306       DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
7307
7308     return;
7309   }
7310
7311   if (AllPlayersGone)   /* do not re-open exit door closed after last player */
7312     return;
7313
7314   Feld[x][y] = EL_SP_EXIT_OPENING;
7315
7316   PlayLevelSoundNearest(x, y, SND_CLASS_SP_EXIT_OPENING);
7317 }
7318
7319 static void CloseAllOpenTimegates()
7320 {
7321   int x, y;
7322
7323   for (y = 0; y < lev_fieldy; y++)
7324   {
7325     for (x = 0; x < lev_fieldx; x++)
7326     {
7327       int element = Feld[x][y];
7328
7329       if (element == EL_TIMEGATE_OPEN || element == EL_TIMEGATE_OPENING)
7330       {
7331         Feld[x][y] = EL_TIMEGATE_CLOSING;
7332 #if 1
7333         PlayLevelSoundAction(x, y, ACTION_CLOSING);
7334 #else
7335         PlayLevelSound(x, y, SND_TIMEGATE_CLOSING);
7336 #endif
7337       }
7338     }
7339   }
7340 }
7341
7342 void EdelsteinFunkeln(int x, int y)
7343 {
7344   if (!IN_SCR_FIELD(SCREENX(x), SCREENY(y)) || IS_MOVING(x, y))
7345     return;
7346
7347   if (Feld[x][y] == EL_BD_DIAMOND)
7348     return;
7349
7350   if (MovDelay[x][y] == 0)      /* next animation frame */
7351     MovDelay[x][y] = 11 * !SimpleRND(500);
7352
7353   if (MovDelay[x][y] != 0)      /* wait some time before next frame */
7354   {
7355     MovDelay[x][y]--;
7356
7357     if (setup.direct_draw && MovDelay[x][y])
7358       SetDrawtoField(DRAW_BUFFERED);
7359
7360     DrawLevelElementAnimation(x, y, Feld[x][y]);
7361
7362     if (MovDelay[x][y] != 0)
7363     {
7364       int frame = getGraphicAnimationFrame(IMG_TWINKLE_WHITE,
7365                                            10 - MovDelay[x][y]);
7366
7367       DrawGraphicThruMask(SCREENX(x), SCREENY(y), IMG_TWINKLE_WHITE, frame);
7368
7369       if (setup.direct_draw)
7370       {
7371         int dest_x, dest_y;
7372
7373         dest_x = FX + SCREENX(x) * TILEX;
7374         dest_y = FY + SCREENY(y) * TILEY;
7375
7376         BlitBitmap(drawto_field, window,
7377                    dest_x, dest_y, TILEX, TILEY, dest_x, dest_y);
7378         SetDrawtoField(DRAW_DIRECT);
7379       }
7380     }
7381   }
7382 }
7383
7384 void MauerWaechst(int x, int y)
7385 {
7386   int delay = 6;
7387
7388   if (!MovDelay[x][y])          /* next animation frame */
7389     MovDelay[x][y] = 3 * delay;
7390
7391   if (MovDelay[x][y])           /* wait some time before next frame */
7392   {
7393     MovDelay[x][y]--;
7394
7395     if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
7396     {
7397       int graphic = el_dir2img(Feld[x][y], GfxDir[x][y]);
7398       int frame = getGraphicAnimationFrame(graphic, 17 - MovDelay[x][y]);
7399
7400       DrawGraphic(SCREENX(x), SCREENY(y), graphic, frame);
7401     }
7402
7403     if (!MovDelay[x][y])
7404     {
7405       if (MovDir[x][y] == MV_LEFT)
7406       {
7407         if (IN_LEV_FIELD(x - 1, y) && IS_WALL(Feld[x - 1][y]))
7408           DrawLevelField(x - 1, y);
7409       }
7410       else if (MovDir[x][y] == MV_RIGHT)
7411       {
7412         if (IN_LEV_FIELD(x + 1, y) && IS_WALL(Feld[x + 1][y]))
7413           DrawLevelField(x + 1, y);
7414       }
7415       else if (MovDir[x][y] == MV_UP)
7416       {
7417         if (IN_LEV_FIELD(x, y - 1) && IS_WALL(Feld[x][y - 1]))
7418           DrawLevelField(x, y - 1);
7419       }
7420       else
7421       {
7422         if (IN_LEV_FIELD(x, y + 1) && IS_WALL(Feld[x][y + 1]))
7423           DrawLevelField(x, y + 1);
7424       }
7425
7426       Feld[x][y] = Store[x][y];
7427       Store[x][y] = 0;
7428       GfxDir[x][y] = MovDir[x][y] = MV_NO_MOVING;
7429       DrawLevelField(x, y);
7430     }
7431   }
7432 }
7433
7434 void MauerAbleger(int ax, int ay)
7435 {
7436   int element = Feld[ax][ay];
7437   int graphic = el2img(element);
7438   boolean oben_frei = FALSE, unten_frei = FALSE;
7439   boolean links_frei = FALSE, rechts_frei = FALSE;
7440   boolean oben_massiv = FALSE, unten_massiv = FALSE;
7441   boolean links_massiv = FALSE, rechts_massiv = FALSE;
7442   boolean new_wall = FALSE;
7443
7444   if (IS_ANIMATED(graphic))
7445     DrawLevelGraphicAnimationIfNeeded(ax, ay, graphic);
7446
7447   if (!MovDelay[ax][ay])        /* start building new wall */
7448     MovDelay[ax][ay] = 6;
7449
7450   if (MovDelay[ax][ay])         /* wait some time before building new wall */
7451   {
7452     MovDelay[ax][ay]--;
7453     if (MovDelay[ax][ay])
7454       return;
7455   }
7456
7457   if (IN_LEV_FIELD(ax, ay-1) && IS_FREE(ax, ay-1))
7458     oben_frei = TRUE;
7459   if (IN_LEV_FIELD(ax, ay+1) && IS_FREE(ax, ay+1))
7460     unten_frei = TRUE;
7461   if (IN_LEV_FIELD(ax-1, ay) && IS_FREE(ax-1, ay))
7462     links_frei = TRUE;
7463   if (IN_LEV_FIELD(ax+1, ay) && IS_FREE(ax+1, ay))
7464     rechts_frei = TRUE;
7465
7466   if (element == EL_EXPANDABLE_WALL_VERTICAL ||
7467       element == EL_EXPANDABLE_WALL_ANY)
7468   {
7469     if (oben_frei)
7470     {
7471       Feld[ax][ay-1] = EL_EXPANDABLE_WALL_GROWING;
7472       Store[ax][ay-1] = element;
7473       GfxDir[ax][ay-1] = MovDir[ax][ay-1] = MV_UP;
7474       if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay-1)))
7475         DrawGraphic(SCREENX(ax), SCREENY(ay - 1),
7476                     IMG_EXPANDABLE_WALL_GROWING_UP, 0);
7477       new_wall = TRUE;
7478     }
7479     if (unten_frei)
7480     {
7481       Feld[ax][ay+1] = EL_EXPANDABLE_WALL_GROWING;
7482       Store[ax][ay+1] = element;
7483       GfxDir[ax][ay+1] = MovDir[ax][ay+1] = MV_DOWN;
7484       if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay+1)))
7485         DrawGraphic(SCREENX(ax), SCREENY(ay + 1),
7486                     IMG_EXPANDABLE_WALL_GROWING_DOWN, 0);
7487       new_wall = TRUE;
7488     }
7489   }
7490
7491   if (element == EL_EXPANDABLE_WALL_HORIZONTAL ||
7492       element == EL_EXPANDABLE_WALL_ANY ||
7493       element == EL_EXPANDABLE_WALL)
7494   {
7495     if (links_frei)
7496     {
7497       Feld[ax-1][ay] = EL_EXPANDABLE_WALL_GROWING;
7498       Store[ax-1][ay] = element;
7499       GfxDir[ax-1][ay] = MovDir[ax-1][ay] = MV_LEFT;
7500       if (IN_SCR_FIELD(SCREENX(ax-1), SCREENY(ay)))
7501         DrawGraphic(SCREENX(ax - 1), SCREENY(ay),
7502                     IMG_EXPANDABLE_WALL_GROWING_LEFT, 0);
7503       new_wall = TRUE;
7504     }
7505
7506     if (rechts_frei)
7507     {
7508       Feld[ax+1][ay] = EL_EXPANDABLE_WALL_GROWING;
7509       Store[ax+1][ay] = element;
7510       GfxDir[ax+1][ay] = MovDir[ax+1][ay] = MV_RIGHT;
7511       if (IN_SCR_FIELD(SCREENX(ax+1), SCREENY(ay)))
7512         DrawGraphic(SCREENX(ax + 1), SCREENY(ay),
7513                     IMG_EXPANDABLE_WALL_GROWING_RIGHT, 0);
7514       new_wall = TRUE;
7515     }
7516   }
7517
7518   if (element == EL_EXPANDABLE_WALL && (links_frei || rechts_frei))
7519     DrawLevelField(ax, ay);
7520
7521   if (!IN_LEV_FIELD(ax, ay-1) || IS_WALL(Feld[ax][ay-1]))
7522     oben_massiv = TRUE;
7523   if (!IN_LEV_FIELD(ax, ay+1) || IS_WALL(Feld[ax][ay+1]))
7524     unten_massiv = TRUE;
7525   if (!IN_LEV_FIELD(ax-1, ay) || IS_WALL(Feld[ax-1][ay]))
7526     links_massiv = TRUE;
7527   if (!IN_LEV_FIELD(ax+1, ay) || IS_WALL(Feld[ax+1][ay]))
7528     rechts_massiv = TRUE;
7529
7530   if (((oben_massiv && unten_massiv) ||
7531        element == EL_EXPANDABLE_WALL_HORIZONTAL ||
7532        element == EL_EXPANDABLE_WALL) &&
7533       ((links_massiv && rechts_massiv) ||
7534        element == EL_EXPANDABLE_WALL_VERTICAL))
7535     Feld[ax][ay] = EL_WALL;
7536
7537   if (new_wall)
7538 #if 1
7539     PlayLevelSoundAction(ax, ay, ACTION_GROWING);
7540 #else
7541     PlayLevelSound(ax, ay, SND_EXPANDABLE_WALL_GROWING);
7542 #endif
7543 }
7544
7545 void CheckForDragon(int x, int y)
7546 {
7547   int i, j;
7548   boolean dragon_found = FALSE;
7549   static int xy[4][2] =
7550   {
7551     { 0, -1 },
7552     { -1, 0 },
7553     { +1, 0 },
7554     { 0, +1 }
7555   };
7556
7557   for (i = 0; i < NUM_DIRECTIONS; i++)
7558   {
7559     for (j = 0; j < 4; j++)
7560     {
7561       int xx = x + j * xy[i][0], yy = y + j * xy[i][1];
7562
7563       if (IN_LEV_FIELD(xx, yy) &&
7564           (Feld[xx][yy] == EL_FLAMES || Feld[xx][yy] == EL_DRAGON))
7565       {
7566         if (Feld[xx][yy] == EL_DRAGON)
7567           dragon_found = TRUE;
7568       }
7569       else
7570         break;
7571     }
7572   }
7573
7574   if (!dragon_found)
7575   {
7576     for (i = 0; i < NUM_DIRECTIONS; i++)
7577     {
7578       for (j = 0; j < 3; j++)
7579       {
7580         int xx = x + j * xy[i][0], yy = y + j * xy[i][1];
7581   
7582         if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == EL_FLAMES)
7583         {
7584           Feld[xx][yy] = EL_EMPTY;
7585           DrawLevelField(xx, yy);
7586         }
7587         else
7588           break;
7589       }
7590     }
7591   }
7592 }
7593
7594 static void InitBuggyBase(int x, int y)
7595 {
7596   int element = Feld[x][y];
7597   int activating_delay = FRAMES_PER_SECOND / 4;
7598
7599   ChangeDelay[x][y] =
7600     (element == EL_SP_BUGGY_BASE ?
7601      2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND) - activating_delay :
7602      element == EL_SP_BUGGY_BASE_ACTIVATING ?
7603      activating_delay :
7604      element == EL_SP_BUGGY_BASE_ACTIVE ?
7605      1 * FRAMES_PER_SECOND + RND(1 * FRAMES_PER_SECOND) : 1);
7606 }
7607
7608 static void WarnBuggyBase(int x, int y)
7609 {
7610   int i;
7611   static int xy[4][2] =
7612   {
7613     { 0, -1 },
7614     { -1, 0 },
7615     { +1, 0 },
7616     { 0, +1 }
7617   };
7618
7619   for (i = 0; i < NUM_DIRECTIONS; i++)
7620   {
7621     int xx = x + xy[i][0], yy = y + xy[i][1];
7622
7623     if (IS_PLAYER(xx, yy))
7624     {
7625       PlayLevelSound(x, y, SND_SP_BUGGY_BASE_ACTIVE);
7626
7627       break;
7628     }
7629   }
7630 }
7631
7632 static void InitTrap(int x, int y)
7633 {
7634   ChangeDelay[x][y] = 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND);
7635 }
7636
7637 static void ActivateTrap(int x, int y)
7638 {
7639   PlayLevelSound(x, y, SND_TRAP_ACTIVATING);
7640 }
7641
7642 static void ChangeActiveTrap(int x, int y)
7643 {
7644   int graphic = IMG_TRAP_ACTIVE;
7645
7646   /* if new animation frame was drawn, correct crumbled sand border */
7647   if (IS_NEW_FRAME(GfxFrame[x][y], graphic))
7648     DrawLevelFieldCrumbledSand(x, y);
7649 }
7650
7651 static void ChangeElementNowExt(int x, int y, int target_element)
7652 {
7653   int previous_move_direction = MovDir[x][y];
7654 #if 1
7655   boolean add_player = (ELEM_IS_PLAYER(target_element) &&
7656                         IS_WALKABLE(Feld[x][y]));
7657 #else
7658   boolean add_player = (ELEM_IS_PLAYER(target_element) &&
7659                         IS_WALKABLE(Feld[x][y]) &&
7660                         !IS_MOVING(x, y));
7661 #endif
7662
7663   /* check if element under player changes from accessible to unaccessible
7664      (needed for special case of dropping element which then changes) */
7665   if (IS_PLAYER(x, y) && !PLAYER_EXPLOSION_PROTECTED(x, y) &&
7666       IS_ACCESSIBLE(Feld[x][y]) && !IS_ACCESSIBLE(target_element))
7667   {
7668 #if 0
7669     printf("::: BOOOM! [%d, '%s']\n", target_element,
7670            element_info[target_element].token_name);
7671 #endif
7672
7673     Bang(x, y);
7674     return;
7675   }
7676
7677 #if 1
7678   if (!add_player)
7679 #endif
7680   {
7681 #if 1
7682     if (IS_MOVING(x, y) || IS_BLOCKED(x, y))
7683       RemoveMovingField(x, y);
7684     else
7685       RemoveField(x, y);
7686
7687     Feld[x][y] = target_element;
7688 #else
7689     RemoveField(x, y);
7690     Feld[x][y] = target_element;
7691 #endif
7692
7693     ResetGfxAnimation(x, y);
7694     ResetRandomAnimationValue(x, y);
7695
7696     if (element_info[Feld[x][y]].move_direction_initial == MV_START_PREVIOUS)
7697       MovDir[x][y] = previous_move_direction;
7698
7699 #if 1
7700     InitField_WithBug1(x, y, FALSE);
7701 #else
7702     InitField(x, y, FALSE);
7703     if (CAN_MOVE(Feld[x][y]))
7704       InitMovDir(x, y);
7705 #endif
7706
7707     DrawLevelField(x, y);
7708
7709     if (GFX_CRUMBLED(Feld[x][y]))
7710       DrawLevelFieldCrumbledSandNeighbours(x, y);
7711   }
7712
7713 #if 0
7714   Changed[x][y] |= ChangeEvent[x][y];   /* ignore same changes in this frame */
7715 #endif
7716
7717 #if 0
7718   TestIfBadThingTouchesHero(x, y);
7719   TestIfPlayerTouchesCustomElement(x, y);
7720   TestIfElementTouchesCustomElement(x, y);
7721 #endif
7722
7723   /* "Changed[][]" not set yet to allow "entered by player" change one time */
7724   if (ELEM_IS_PLAYER(target_element))
7725     RelocatePlayer(x, y, target_element);
7726
7727 #if 1
7728   Changed[x][y] |= ChangeEvent[x][y];   /* ignore same changes in this frame */
7729 #endif
7730
7731 #if 1
7732   TestIfBadThingTouchesHero(x, y);
7733   TestIfPlayerTouchesCustomElement(x, y);
7734   TestIfElementTouchesCustomElement(x, y);
7735 #endif
7736 }
7737
7738 static boolean ChangeElementNow(int x, int y, int element, int page)
7739 {
7740   struct ElementChangeInfo *change = &element_info[element].change_page[page];
7741   int target_element;
7742   int old_element = Feld[x][y];
7743
7744   /* always use default change event to prevent running into a loop */
7745   if (ChangeEvent[x][y] == CE_BITMASK_DEFAULT)
7746     ChangeEvent[x][y] = CH_EVENT_BIT(CE_DELAY);
7747
7748   if (ChangeEvent[x][y] == CH_EVENT_BIT(CE_DELAY))
7749   {
7750     /* reset actual trigger element and player */
7751     change->actual_trigger_element = EL_EMPTY;
7752     change->actual_trigger_player = EL_PLAYER_1;
7753   }
7754
7755   /* do not change already changed elements with same change event */
7756 #if 0
7757   if (Changed[x][y] & ChangeEvent[x][y])
7758     return FALSE;
7759 #else
7760   if (Changed[x][y])
7761     return FALSE;
7762 #endif
7763
7764   Changed[x][y] |= ChangeEvent[x][y];   /* ignore same changes in this frame */
7765
7766 #if 0
7767   /* !!! indirect change before direct change !!! */
7768   CheckTriggeredElementChangeByPage(x,y,Feld[x][y], CE_OTHER_IS_CHANGING,page);
7769 #endif
7770
7771   if (change->explode)
7772   {
7773     Bang(x, y);
7774
7775     return TRUE;
7776   }
7777
7778   if (change->use_target_content)
7779   {
7780     boolean complete_replace = TRUE;
7781     boolean can_replace[3][3];
7782     int xx, yy;
7783
7784     for (yy = 0; yy < 3; yy++) for (xx = 0; xx < 3 ; xx++)
7785     {
7786       boolean is_empty;
7787       boolean is_walkable;
7788       boolean is_diggable;
7789       boolean is_collectible;
7790       boolean is_removable;
7791       boolean is_destructible;
7792       int ex = x + xx - 1;
7793       int ey = y + yy - 1;
7794       int content_element = change->target_content[xx][yy];
7795       int e;
7796
7797       can_replace[xx][yy] = TRUE;
7798
7799       if (ex == x && ey == y)   /* do not check changing element itself */
7800         continue;
7801
7802       if (content_element == EL_EMPTY_SPACE)
7803       {
7804         can_replace[xx][yy] = FALSE;    /* do not replace border with space */
7805
7806         continue;
7807       }
7808
7809       if (!IN_LEV_FIELD(ex, ey))
7810       {
7811         can_replace[xx][yy] = FALSE;
7812         complete_replace = FALSE;
7813
7814         continue;
7815       }
7816
7817 #if 0
7818       if (Changed[ex][ey])      /* do not change already changed elements */
7819       {
7820         can_replace[xx][yy] = FALSE;
7821         complete_replace = FALSE;
7822
7823         continue;
7824       }
7825 #endif
7826
7827       e = Feld[ex][ey];
7828
7829       if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey))
7830         e = MovingOrBlocked2Element(ex, ey);
7831
7832 #if 1
7833
7834 #if 0
7835       is_empty = (IS_FREE(ex, ey) ||
7836                   (IS_PLAYER(ex, ey) && IS_WALKABLE(content_element)) ||
7837                   (IS_WALKABLE(e) && ELEM_IS_PLAYER(content_element) &&
7838                    !IS_MOVING(ex, ey) && !IS_BLOCKED(ex, ey)));
7839 #else
7840
7841 #if 0
7842       is_empty = (IS_FREE(ex, ey) ||
7843                   (IS_PLAYER(ex, ey) && IS_WALKABLE(content_element)));
7844 #else
7845       is_empty = (IS_FREE(ex, ey) ||
7846                   (IS_FREE_OR_PLAYER(ex, ey) && IS_WALKABLE(content_element)));
7847 #endif
7848
7849 #endif
7850
7851       is_walkable     = (is_empty || IS_WALKABLE(e));
7852       is_diggable     = (is_empty || IS_DIGGABLE(e));
7853       is_collectible  = (is_empty || IS_COLLECTIBLE(e));
7854       is_destructible = (is_empty || !IS_INDESTRUCTIBLE(e));
7855       is_removable    = (is_diggable || is_collectible);
7856
7857       can_replace[xx][yy] =
7858         (((change->replace_when == CP_WHEN_EMPTY        && is_empty) ||
7859           (change->replace_when == CP_WHEN_WALKABLE     && is_walkable) ||
7860           (change->replace_when == CP_WHEN_DIGGABLE     && is_diggable) ||
7861           (change->replace_when == CP_WHEN_COLLECTIBLE  && is_collectible) ||
7862           (change->replace_when == CP_WHEN_REMOVABLE    && is_removable) ||
7863           (change->replace_when == CP_WHEN_DESTRUCTIBLE && is_destructible)) &&
7864          !(IS_PLAYER(ex, ey) && ELEM_IS_PLAYER(content_element)));
7865
7866       if (!can_replace[xx][yy])
7867         complete_replace = FALSE;
7868 #else
7869       empty_for_element = (IS_FREE(ex, ey) || (IS_FREE_OR_PLAYER(ex, ey) &&
7870                                                IS_WALKABLE(content_element)));
7871 #if 1
7872       half_destructible = (empty_for_element || IS_DIGGABLE(e));
7873 #else
7874       half_destructible = (IS_FREE(ex, ey) || IS_DIGGABLE(e));
7875 #endif
7876
7877       if ((change->replace_when <= CP_WHEN_EMPTY  && !empty_for_element) ||
7878           (change->replace_when <= CP_WHEN_DIGGABLE && !half_destructible) ||
7879           (change->replace_when <= CP_WHEN_DESTRUCTIBLE && IS_INDESTRUCTIBLE(e)))
7880       {
7881         can_replace[xx][yy] = FALSE;
7882         complete_replace = FALSE;
7883       }
7884 #endif
7885     }
7886
7887     if (!change->only_if_complete || complete_replace)
7888     {
7889       boolean something_has_changed = FALSE;
7890
7891       if (change->only_if_complete && change->use_random_replace &&
7892           RND(100) < change->random_percentage)
7893         return FALSE;
7894
7895       for (yy = 0; yy < 3; yy++) for (xx = 0; xx < 3 ; xx++)
7896       {
7897         int ex = x + xx - 1;
7898         int ey = y + yy - 1;
7899         int content_element;
7900
7901         if (can_replace[xx][yy] && (!change->use_random_replace ||
7902                                     RND(100) < change->random_percentage))
7903         {
7904           if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey))
7905             RemoveMovingField(ex, ey);
7906
7907           ChangeEvent[ex][ey] = ChangeEvent[x][y];
7908
7909           content_element = change->target_content[xx][yy];
7910           target_element = GET_TARGET_ELEMENT(content_element, change);
7911
7912           ChangeElementNowExt(ex, ey, target_element);
7913
7914           something_has_changed = TRUE;
7915
7916           /* for symmetry reasons, freeze newly created border elements */
7917           if (ex != x || ey != y)
7918             Stop[ex][ey] = TRUE;        /* no more moving in this frame */
7919         }
7920       }
7921
7922       if (something_has_changed)
7923         PlayLevelSoundElementAction(x, y, element, ACTION_CHANGING);
7924     }
7925   }
7926   else
7927   {
7928     target_element = GET_TARGET_ELEMENT(change->target_element, change);
7929
7930     ChangeElementNowExt(x, y, target_element);
7931
7932     PlayLevelSoundElementAction(x, y, element, ACTION_CHANGING);
7933   }
7934
7935 #if 1
7936   /* this uses direct change before indirect change */
7937   CheckTriggeredElementChangeByPage(x,y,old_element,CE_OTHER_IS_CHANGING,page);
7938 #endif
7939
7940   return TRUE;
7941 }
7942
7943 static void ChangeElement(int x, int y, int page)
7944 {
7945   int element = MovingOrBlocked2Element(x, y);
7946   struct ElementInfo *ei = &element_info[element];
7947   struct ElementChangeInfo *change = &ei->change_page[page];
7948
7949 #ifdef DEBUG
7950   if (!CAN_CHANGE(element) && !CAN_CHANGE(Back[x][y]))
7951   {
7952     printf("\n\n");
7953     printf("ChangeElement(): %d,%d: element = %d ('%s')\n",
7954            x, y, element, element_info[element].token_name);
7955     printf("ChangeElement(): This should never happen!\n");
7956     printf("\n\n");
7957   }
7958 #endif
7959
7960   /* this can happen with classic bombs on walkable, changing elements */
7961   if (!CAN_CHANGE(element))
7962   {
7963 #if 0
7964     if (!CAN_CHANGE(Back[x][y]))        /* prevent permanent repetition */
7965       ChangeDelay[x][y] = 0;
7966 #endif
7967
7968     return;
7969   }
7970
7971   if (ChangeDelay[x][y] == 0)           /* initialize element change */
7972   {
7973     ChangeDelay[x][y] = (    change->delay_fixed  * change->delay_frames +
7974                          RND(change->delay_random * change->delay_frames)) + 1;
7975
7976     ResetGfxAnimation(x, y);
7977     ResetRandomAnimationValue(x, y);
7978
7979     if (change->pre_change_function)
7980       change->pre_change_function(x, y);
7981   }
7982
7983   ChangeDelay[x][y]--;
7984
7985   if (ChangeDelay[x][y] != 0)           /* continue element change */
7986   {
7987     int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
7988
7989     if (IS_ANIMATED(graphic))
7990       DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
7991
7992     if (change->change_function)
7993       change->change_function(x, y);
7994   }
7995   else                                  /* finish element change */
7996   {
7997     if (ChangePage[x][y] != -1)         /* remember page from delayed change */
7998     {
7999       page = ChangePage[x][y];
8000       ChangePage[x][y] = -1;
8001
8002       change = &ei->change_page[page];
8003     }
8004
8005 #if 0
8006     if (IS_MOVING(x, y) && !change->explode)
8007 #else
8008     if (IS_MOVING(x, y))                /* never change a running system ;-) */
8009 #endif
8010     {
8011       ChangeDelay[x][y] = 1;            /* try change after next move step */
8012       ChangePage[x][y] = page;          /* remember page to use for change */
8013
8014       return;
8015     }
8016
8017     if (ChangeElementNow(x, y, element, page))
8018     {
8019       if (change->post_change_function)
8020         change->post_change_function(x, y);
8021     }
8022   }
8023 }
8024
8025 static boolean CheckTriggeredElementChangeExt(int lx, int ly,
8026                                               int trigger_element,
8027                                               int trigger_event,
8028                                               int trigger_player,
8029                                               int trigger_side,
8030                                               int trigger_page)
8031 {
8032   int i, j, x, y;
8033   int trigger_page_bits = (trigger_page < 0 ? CH_PAGE_ANY : 1 << trigger_page);
8034
8035   if (!(trigger_events[trigger_element] & CH_EVENT_BIT(trigger_event)))
8036     return FALSE;
8037
8038   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
8039   {
8040     int element = EL_CUSTOM_START + i;
8041
8042     boolean change_element = FALSE;
8043     int page = 0;
8044
8045     if (!CAN_CHANGE(element) || !HAS_ANY_CHANGE_EVENT(element, trigger_event))
8046       continue;
8047
8048     for (j = 0; j < element_info[element].num_change_pages; j++)
8049     {
8050       struct ElementChangeInfo *change = &element_info[element].change_page[j];
8051
8052       if (change->can_change &&
8053           change->events & CH_EVENT_BIT(trigger_event) &&
8054           change->trigger_side & trigger_side &&
8055           change->trigger_player & trigger_player &&
8056           change->trigger_page & trigger_page_bits &&
8057           IS_EQUAL_OR_IN_GROUP(trigger_element, change->trigger_element))
8058       {
8059 #if 0
8060         if (!(change->events & CH_EVENT_BIT(trigger_event)))
8061           printf("::: !!! %d triggers %d: using wrong page %d [event %d]\n",
8062                  trigger_element-EL_CUSTOM_START+1, i+1, j, trigger_event);
8063 #endif
8064
8065         change_element = TRUE;
8066         page = j;
8067
8068         change->actual_trigger_element = trigger_element;
8069         change->actual_trigger_player = EL_PLAYER_1 + log_2(trigger_player);
8070
8071         break;
8072       }
8073     }
8074
8075     if (!change_element)
8076       continue;
8077
8078     for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
8079     {
8080 #if 0
8081       if (x == lx && y == ly)   /* do not change trigger element itself */
8082         continue;
8083 #endif
8084
8085       if (Feld[x][y] == element)
8086       {
8087         ChangeDelay[x][y] = 1;
8088         ChangeEvent[x][y] = CH_EVENT_BIT(trigger_event);
8089         ChangeElement(x, y, page);
8090       }
8091     }
8092   }
8093
8094   return TRUE;
8095 }
8096
8097 static boolean CheckElementChangeExt(int x, int y,
8098                                      int element,
8099                                      int trigger_element,
8100                                      int trigger_event,
8101                                      int trigger_player,
8102                                      int trigger_side,
8103                                      int trigger_page)
8104 {
8105   if (!CAN_CHANGE(element) || !HAS_ANY_CHANGE_EVENT(element, trigger_event))
8106     return FALSE;
8107
8108   if (Feld[x][y] == EL_BLOCKED)
8109   {
8110     Blocked2Moving(x, y, &x, &y);
8111     element = Feld[x][y];
8112   }
8113
8114 #if 1
8115   if (Feld[x][y] != element)    /* check if element has already changed */
8116   {
8117 #if 0
8118     printf("::: %d ('%s') != %d ('%s') [%d]\n",
8119            Feld[x][y], element_info[Feld[x][y]].token_name,
8120            element, element_info[element].token_name,
8121            trigger_event);
8122 #endif
8123
8124     return FALSE;
8125   }
8126 #endif
8127
8128 #if 1
8129   if (trigger_page < 0)
8130   {
8131     boolean change_element = FALSE;
8132     int i;
8133
8134     for (i = 0; i < element_info[element].num_change_pages; i++)
8135     {
8136       struct ElementChangeInfo *change = &element_info[element].change_page[i];
8137
8138       if (change->can_change &&
8139           change->events & CH_EVENT_BIT(trigger_event) &&
8140           change->trigger_side & trigger_side &&
8141           change->trigger_player & trigger_player)
8142       {
8143         change_element = TRUE;
8144         trigger_page = i;
8145
8146         change->actual_trigger_element = trigger_element;
8147         change->actual_trigger_player = EL_PLAYER_1 + log_2(trigger_player);
8148
8149         break;
8150       }
8151     }
8152
8153     if (!change_element)
8154       return FALSE;
8155   }
8156   else
8157   {
8158     struct ElementInfo *ei = &element_info[element];
8159     struct ElementChangeInfo *change = &ei->change_page[trigger_page];
8160
8161     change->actual_trigger_element = trigger_element;
8162     change->actual_trigger_player = EL_PLAYER_1;        /* unused */
8163   }
8164
8165 #else
8166
8167   /* !!! this check misses pages with same event, but different side !!! */
8168
8169   if (trigger_page < 0)
8170     trigger_page = element_info[element].event_page_nr[trigger_event];
8171
8172   if (!(element_info[element].change_page[trigger_page].trigger_side & trigger_side))
8173     return FALSE;
8174 #endif
8175
8176   ChangeDelay[x][y] = 1;
8177   ChangeEvent[x][y] = CH_EVENT_BIT(trigger_event);
8178   ChangeElement(x, y, trigger_page);
8179
8180   return TRUE;
8181 }
8182
8183 static void PlayPlayerSound(struct PlayerInfo *player)
8184 {
8185   int jx = player->jx, jy = player->jy;
8186   int element = player->element_nr;
8187   int last_action = player->last_action_waiting;
8188   int action = player->action_waiting;
8189
8190   if (player->is_waiting)
8191   {
8192     if (action != last_action)
8193       PlayLevelSoundElementAction(jx, jy, element, action);
8194     else
8195       PlayLevelSoundElementActionIfLoop(jx, jy, element, action);
8196   }
8197   else
8198   {
8199     if (action != last_action)
8200       StopSound(element_info[element].sound[last_action]);
8201
8202     if (last_action == ACTION_SLEEPING)
8203       PlayLevelSoundElementAction(jx, jy, element, ACTION_AWAKENING);
8204   }
8205 }
8206
8207 static void PlayAllPlayersSound()
8208 {
8209   int i;
8210
8211   for (i = 0; i < MAX_PLAYERS; i++)
8212     if (stored_player[i].active)
8213       PlayPlayerSound(&stored_player[i]);
8214 }
8215
8216 static void SetPlayerWaiting(struct PlayerInfo *player, boolean is_waiting)
8217 {
8218   boolean last_waiting = player->is_waiting;
8219   int move_dir = player->MovDir;
8220
8221   player->last_action_waiting = player->action_waiting;
8222
8223   if (is_waiting)
8224   {
8225     if (!last_waiting)          /* not waiting -> waiting */
8226     {
8227       player->is_waiting = TRUE;
8228
8229       player->frame_counter_bored =
8230         FrameCounter +
8231         game.player_boring_delay_fixed +
8232         SimpleRND(game.player_boring_delay_random);
8233       player->frame_counter_sleeping =
8234         FrameCounter +
8235         game.player_sleeping_delay_fixed +
8236         SimpleRND(game.player_sleeping_delay_random);
8237
8238       InitPlayerGfxAnimation(player, ACTION_WAITING, player->MovDir);
8239     }
8240
8241     if (game.player_sleeping_delay_fixed +
8242         game.player_sleeping_delay_random > 0 &&
8243         player->anim_delay_counter == 0 &&
8244         player->post_delay_counter == 0 &&
8245         FrameCounter >= player->frame_counter_sleeping)
8246       player->is_sleeping = TRUE;
8247     else if (game.player_boring_delay_fixed +
8248              game.player_boring_delay_random > 0 &&
8249              FrameCounter >= player->frame_counter_bored)
8250       player->is_bored = TRUE;
8251
8252     player->action_waiting = (player->is_sleeping ? ACTION_SLEEPING :
8253                               player->is_bored ? ACTION_BORING :
8254                               ACTION_WAITING);
8255
8256     if (player->is_sleeping)
8257     {
8258       if (player->num_special_action_sleeping > 0)
8259       {
8260         if (player->anim_delay_counter == 0 && player->post_delay_counter == 0)
8261         {
8262           int last_special_action = player->special_action_sleeping;
8263           int num_special_action = player->num_special_action_sleeping;
8264           int special_action =
8265             (last_special_action == ACTION_DEFAULT ? ACTION_SLEEPING_1 :
8266              last_special_action == ACTION_SLEEPING ? ACTION_SLEEPING :
8267              last_special_action < ACTION_SLEEPING_1 + num_special_action - 1 ?
8268              last_special_action + 1 : ACTION_SLEEPING);
8269           int special_graphic =
8270             el_act_dir2img(player->element_nr, special_action, move_dir);
8271
8272           player->anim_delay_counter =
8273             graphic_info[special_graphic].anim_delay_fixed +
8274             SimpleRND(graphic_info[special_graphic].anim_delay_random);
8275           player->post_delay_counter =
8276             graphic_info[special_graphic].post_delay_fixed +
8277             SimpleRND(graphic_info[special_graphic].post_delay_random);
8278
8279           player->special_action_sleeping = special_action;
8280         }
8281
8282         if (player->anim_delay_counter > 0)
8283         {
8284           player->action_waiting = player->special_action_sleeping;
8285           player->anim_delay_counter--;
8286         }
8287         else if (player->post_delay_counter > 0)
8288         {
8289           player->post_delay_counter--;
8290         }
8291       }
8292     }
8293     else if (player->is_bored)
8294     {
8295       if (player->num_special_action_bored > 0)
8296       {
8297         if (player->anim_delay_counter == 0 && player->post_delay_counter == 0)
8298         {
8299           int special_action =
8300             ACTION_BORING_1 + SimpleRND(player->num_special_action_bored);
8301           int special_graphic =
8302             el_act_dir2img(player->element_nr, special_action, move_dir);
8303
8304           player->anim_delay_counter =
8305             graphic_info[special_graphic].anim_delay_fixed +
8306             SimpleRND(graphic_info[special_graphic].anim_delay_random);
8307           player->post_delay_counter =
8308             graphic_info[special_graphic].post_delay_fixed +
8309             SimpleRND(graphic_info[special_graphic].post_delay_random);
8310
8311           player->special_action_bored = special_action;
8312         }
8313
8314         if (player->anim_delay_counter > 0)
8315         {
8316           player->action_waiting = player->special_action_bored;
8317           player->anim_delay_counter--;
8318         }
8319         else if (player->post_delay_counter > 0)
8320         {
8321           player->post_delay_counter--;
8322         }
8323       }
8324     }
8325   }
8326   else if (last_waiting)        /* waiting -> not waiting */
8327   {
8328     player->is_waiting = FALSE;
8329     player->is_bored = FALSE;
8330     player->is_sleeping = FALSE;
8331
8332     player->frame_counter_bored = -1;
8333     player->frame_counter_sleeping = -1;
8334
8335     player->anim_delay_counter = 0;
8336     player->post_delay_counter = 0;
8337
8338     player->action_waiting = ACTION_DEFAULT;
8339
8340     player->special_action_bored = ACTION_DEFAULT;
8341     player->special_action_sleeping = ACTION_DEFAULT;
8342   }
8343 }
8344
8345 #if 1
8346 static byte PlayerActions(struct PlayerInfo *player, byte player_action)
8347 {
8348 #if 0
8349   static byte stored_player_action[MAX_PLAYERS];
8350   static int num_stored_actions = 0;
8351 #endif
8352   boolean moved = FALSE, snapped = FALSE, dropped = FALSE;
8353   int left      = player_action & JOY_LEFT;
8354   int right     = player_action & JOY_RIGHT;
8355   int up        = player_action & JOY_UP;
8356   int down      = player_action & JOY_DOWN;
8357   int button1   = player_action & JOY_BUTTON_1;
8358   int button2   = player_action & JOY_BUTTON_2;
8359   int dx        = (left ? -1    : right ? 1     : 0);
8360   int dy        = (up   ? -1    : down  ? 1     : 0);
8361
8362 #if 0
8363   stored_player_action[player->index_nr] = 0;
8364   num_stored_actions++;
8365 #endif
8366
8367 #if 0
8368   printf("::: player %d [%d]\n", player->index_nr, FrameCounter);
8369 #endif
8370
8371   if (!player->active || tape.pausing)
8372     return 0;
8373
8374 #if 0
8375   printf("::: [%d %d %d %d] [%d %d]\n",
8376          left, right, up, down, button1, button2);
8377 #endif
8378
8379   if (player_action)
8380   {
8381 #if 0
8382     printf("::: player %d acts [%d]\n", player->index_nr, FrameCounter);
8383 #endif
8384
8385 #if 0
8386     /* !!! TEST !!! */
8387     if (player->MovPos == 0)
8388       CheckGravityMovement(player);
8389 #endif
8390     if (button1)
8391       snapped = SnapField(player, dx, dy);
8392     else
8393     {
8394       if (button2)
8395         dropped = DropElement(player);
8396
8397       moved = MovePlayer(player, dx, dy);
8398     }
8399
8400     if (tape.single_step && tape.recording && !tape.pausing)
8401     {
8402       if (button1 || (dropped && !moved))
8403       {
8404         TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8405         SnapField(player, 0, 0);                /* stop snapping */
8406       }
8407     }
8408
8409     SetPlayerWaiting(player, FALSE);
8410
8411 #if 1
8412     return player_action;
8413 #else
8414     stored_player_action[player->index_nr] = player_action;
8415 #endif
8416   }
8417   else
8418   {
8419 #if 0
8420     printf("::: player %d waits [%d]\n", player->index_nr, FrameCounter);
8421 #endif
8422
8423     /* no actions for this player (no input at player's configured device) */
8424
8425     DigField(player, 0, 0, 0, 0, 0, 0, DF_NO_PUSH);
8426     SnapField(player, 0, 0);
8427     CheckGravityMovementWhenNotMoving(player);
8428
8429     if (player->MovPos == 0)
8430       SetPlayerWaiting(player, TRUE);
8431
8432     if (player->MovPos == 0)    /* needed for tape.playing */
8433       player->is_moving = FALSE;
8434
8435     player->is_dropping = FALSE;
8436
8437     return 0;
8438   }
8439
8440 #if 0
8441   if (tape.recording && num_stored_actions >= MAX_PLAYERS)
8442   {
8443     printf("::: player %d recorded [%d]\n", player->index_nr, FrameCounter);
8444
8445     TapeRecordAction(stored_player_action);
8446     num_stored_actions = 0;
8447   }
8448 #endif
8449 }
8450
8451 #else
8452
8453 static void PlayerActions(struct PlayerInfo *player, byte player_action)
8454 {
8455   static byte stored_player_action[MAX_PLAYERS];
8456   static int num_stored_actions = 0;
8457   boolean moved = FALSE, snapped = FALSE, dropped = FALSE;
8458   int left      = player_action & JOY_LEFT;
8459   int right     = player_action & JOY_RIGHT;
8460   int up        = player_action & JOY_UP;
8461   int down      = player_action & JOY_DOWN;
8462   int button1   = player_action & JOY_BUTTON_1;
8463   int button2   = player_action & JOY_BUTTON_2;
8464   int dx        = (left ? -1    : right ? 1     : 0);
8465   int dy        = (up   ? -1    : down  ? 1     : 0);
8466
8467   stored_player_action[player->index_nr] = 0;
8468   num_stored_actions++;
8469
8470   printf("::: player %d [%d]\n", player->index_nr, FrameCounter);
8471
8472   if (!player->active || tape.pausing)
8473     return;
8474
8475   if (player_action)
8476   {
8477     printf("::: player %d acts [%d]\n", player->index_nr, FrameCounter);
8478
8479     if (button1)
8480       snapped = SnapField(player, dx, dy);
8481     else
8482     {
8483       if (button2)
8484         dropped = DropElement(player);
8485
8486       moved = MovePlayer(player, dx, dy);
8487     }
8488
8489     if (tape.single_step && tape.recording && !tape.pausing)
8490     {
8491       if (button1 || (dropped && !moved))
8492       {
8493         TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8494         SnapField(player, 0, 0);                /* stop snapping */
8495       }
8496     }
8497
8498     stored_player_action[player->index_nr] = player_action;
8499   }
8500   else
8501   {
8502     printf("::: player %d waits [%d]\n", player->index_nr, FrameCounter);
8503
8504     /* no actions for this player (no input at player's configured device) */
8505
8506     DigField(player, 0, 0, 0, 0, 0, 0, DF_NO_PUSH);
8507     SnapField(player, 0, 0);
8508     CheckGravityMovementWhenNotMoving(player);
8509
8510     if (player->MovPos == 0)
8511       InitPlayerGfxAnimation(player, ACTION_DEFAULT, player->MovDir);
8512
8513     if (player->MovPos == 0)    /* needed for tape.playing */
8514       player->is_moving = FALSE;
8515   }
8516
8517   if (tape.recording && num_stored_actions >= MAX_PLAYERS)
8518   {
8519     printf("::: player %d recorded [%d]\n", player->index_nr, FrameCounter);
8520
8521     TapeRecordAction(stored_player_action);
8522     num_stored_actions = 0;
8523   }
8524 }
8525 #endif
8526
8527 void AdvanceFrameAndPlayerCounters(int player_nr)
8528 {
8529   int i;
8530
8531   /* advance frame counters (global frame counter and time frame counter) */
8532   FrameCounter++;
8533   TimeFrames++;
8534
8535   /* advance player counters (counters for move delay, move animation etc.) */
8536   for (i = 0; i < MAX_PLAYERS; i++)
8537   {
8538     boolean advance_player_counters = (player_nr == -1 || player_nr == i);
8539     int move_frames =
8540       MOVE_DELAY_NORMAL_SPEED /  stored_player[i].move_delay_value;
8541
8542     if (!advance_player_counters)       /* not all players may be affected */
8543       continue;
8544
8545     stored_player[i].Frame += move_frames;
8546
8547     if (stored_player[i].MovPos != 0)
8548       stored_player[i].StepFrame += move_frames;
8549
8550 #if USE_NEW_MOVE_DELAY
8551     if (stored_player[i].move_delay > 0)
8552       stored_player[i].move_delay--;
8553 #endif
8554
8555 #if USE_NEW_PUSH_DELAY
8556     /* due to bugs in previous versions, counter must count up, not down */
8557     if (stored_player[i].push_delay != -1)
8558       stored_player[i].push_delay++;
8559 #endif
8560
8561     if (stored_player[i].drop_delay > 0)
8562       stored_player[i].drop_delay--;
8563   }
8564 }
8565
8566 void GameActions()
8567 {
8568   static unsigned long game_frame_delay = 0;
8569   unsigned long game_frame_delay_value;
8570   int magic_wall_x = 0, magic_wall_y = 0;
8571   int i, x, y, element, graphic;
8572   byte *recorded_player_action;
8573   byte summarized_player_action = 0;
8574 #if 1
8575   byte tape_action[MAX_PLAYERS];
8576 #endif
8577
8578   if (game_status != GAME_MODE_PLAYING)
8579     return;
8580
8581   game_frame_delay_value =
8582     (tape.playing && tape.fast_forward ? FfwdFrameDelay : GameFrameDelay);
8583
8584   if (tape.playing && tape.warp_forward && !tape.pausing)
8585     game_frame_delay_value = 0;
8586
8587   /* ---------- main game synchronization point ---------- */
8588
8589   WaitUntilDelayReached(&game_frame_delay, game_frame_delay_value);
8590
8591   if (network_playing && !network_player_action_received)
8592   {
8593     /*
8594 #ifdef DEBUG
8595     printf("DEBUG: try to get network player actions in time\n");
8596 #endif
8597     */
8598
8599 #if defined(NETWORK_AVALIABLE)
8600     /* last chance to get network player actions without main loop delay */
8601     HandleNetworking();
8602 #endif
8603
8604     if (game_status != GAME_MODE_PLAYING)
8605       return;
8606
8607     if (!network_player_action_received)
8608     {
8609       /*
8610 #ifdef DEBUG
8611       printf("DEBUG: failed to get network player actions in time\n");
8612 #endif
8613       */
8614       return;
8615     }
8616   }
8617
8618   if (tape.pausing)
8619     return;
8620
8621 #if 0
8622   printf("::: getting new tape action [%d]\n", FrameCounter);
8623 #endif
8624
8625   recorded_player_action = (tape.playing ? TapePlayAction() : NULL);
8626
8627 #if 1
8628   /* !!! CHECK THIS (tape.pausing is always FALSE here!) !!! */
8629   if (recorded_player_action == NULL && tape.pausing)
8630     return;
8631 #endif
8632
8633 #if 0
8634   printf("::: %d\n", stored_player[0].action);
8635 #endif
8636
8637 #if 0
8638   if (recorded_player_action != NULL)
8639     for (i = 0; i < MAX_PLAYERS; i++)
8640       stored_player[i].action = recorded_player_action[i];
8641 #endif
8642
8643   for (i = 0; i < MAX_PLAYERS; i++)
8644   {
8645     summarized_player_action |= stored_player[i].action;
8646
8647     if (!network_playing)
8648       stored_player[i].effective_action = stored_player[i].action;
8649   }
8650
8651 #if defined(NETWORK_AVALIABLE)
8652   if (network_playing)
8653     SendToServer_MovePlayer(summarized_player_action);
8654 #endif
8655
8656   if (!options.network && !setup.team_mode)
8657     local_player->effective_action = summarized_player_action;
8658
8659 #if 1
8660   if (recorded_player_action != NULL)
8661     for (i = 0; i < MAX_PLAYERS; i++)
8662       stored_player[i].effective_action = recorded_player_action[i];
8663 #endif
8664
8665 #if 1
8666   for (i = 0; i < MAX_PLAYERS; i++)
8667   {
8668     tape_action[i] = stored_player[i].effective_action;
8669
8670     if (tape.recording && tape_action[i] && !tape.player_participates[i])
8671       tape.player_participates[i] = TRUE;    /* player just appeared from CE */
8672   }
8673
8674   /* only save actions from input devices, but not programmed actions */
8675   if (tape.recording)
8676     TapeRecordAction(tape_action);
8677 #endif
8678
8679   for (i = 0; i < MAX_PLAYERS; i++)
8680   {
8681     int actual_player_action = stored_player[i].effective_action;
8682
8683 #if 1
8684     /* !!! THIS BREAKS THE FOLLOWING TAPES: !!!
8685        - rnd_equinox_tetrachloride 048
8686        - rnd_equinox_tetrachloride_ii 096
8687        - rnd_emanuel_schmieg 002
8688        - doctor_sloan_ww 001, 020
8689     */
8690     if (stored_player[i].MovPos == 0)
8691       CheckGravityMovement(&stored_player[i]);
8692 #endif
8693
8694 #if 1
8695     /* overwrite programmed action with tape action */
8696     if (stored_player[i].programmed_action)
8697       actual_player_action = stored_player[i].programmed_action;
8698 #endif
8699
8700 #if 0
8701     if (stored_player[i].programmed_action)
8702       printf("::: %d\n", stored_player[i].programmed_action);
8703 #endif
8704
8705     if (recorded_player_action)
8706     {
8707 #if 0
8708       if (stored_player[i].programmed_action &&
8709           stored_player[i].programmed_action != recorded_player_action[i])
8710         printf("::: %d: %d <-> %d\n", i,
8711                stored_player[i].programmed_action, recorded_player_action[i]);
8712 #endif
8713
8714 #if 0
8715       actual_player_action = recorded_player_action[i];
8716 #endif
8717     }
8718
8719 #if 0
8720     /* overwrite tape action with programmed action */
8721     if (stored_player[i].programmed_action)
8722       actual_player_action = stored_player[i].programmed_action;
8723 #endif
8724
8725 #if 0
8726     if (i == 0)
8727       printf("::: action: %d: %x [%d]\n",
8728              stored_player[i].MovPos, actual_player_action, FrameCounter);
8729 #endif
8730
8731 #if 1
8732     PlayerActions(&stored_player[i], actual_player_action);
8733 #else
8734     tape_action[i] = PlayerActions(&stored_player[i], actual_player_action);
8735
8736     if (tape.recording && tape_action[i] && !tape.player_participates[i])
8737       tape.player_participates[i] = TRUE;    /* player just appeared from CE */
8738 #endif
8739
8740     ScrollPlayer(&stored_player[i], SCROLL_GO_ON);
8741   }
8742
8743 #if 0
8744   if (tape.recording)
8745     TapeRecordAction(tape_action);
8746 #endif
8747
8748   network_player_action_received = FALSE;
8749
8750   ScrollScreen(NULL, SCROLL_GO_ON);
8751
8752 #if 0
8753   FrameCounter++;
8754   TimeFrames++;
8755
8756   for (i = 0; i < MAX_PLAYERS; i++)
8757     stored_player[i].Frame++;
8758 #endif
8759
8760 #if 1
8761   /* for backwards compatibility, the following code emulates a fixed bug that
8762      occured when pushing elements (causing elements that just made their last
8763      pushing step to already (if possible) make their first falling step in the
8764      same game frame, which is bad); this code is also needed to use the famous
8765      "spring push bug" which is used in older levels and might be wanted to be
8766      used also in newer levels, but in this case the buggy pushing code is only
8767      affecting the "spring" element and no other elements */
8768
8769 #if 1
8770   if (game.engine_version < VERSION_IDENT(2,2,0,7) || level.use_spring_bug)
8771 #else
8772   if (game.engine_version < VERSION_IDENT(2,2,0,7))
8773 #endif
8774   {
8775     for (i = 0; i < MAX_PLAYERS; i++)
8776     {
8777       struct PlayerInfo *player = &stored_player[i];
8778       int x = player->jx;
8779       int y = player->jy;
8780
8781 #if 1
8782       if (player->active && player->is_pushing && player->is_moving &&
8783           IS_MOVING(x, y) &&
8784           (game.engine_version < VERSION_IDENT(2,2,0,7) ||
8785            Feld[x][y] == EL_SPRING))
8786 #else
8787       if (player->active && player->is_pushing && player->is_moving &&
8788           IS_MOVING(x, y))
8789 #endif
8790       {
8791         ContinueMoving(x, y);
8792
8793         /* continue moving after pushing (this is actually a bug) */
8794         if (!IS_MOVING(x, y))
8795         {
8796           Stop[x][y] = FALSE;
8797         }
8798       }
8799     }
8800   }
8801 #endif
8802
8803   for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
8804   {
8805     Changed[x][y] = CE_BITMASK_DEFAULT;
8806     ChangeEvent[x][y] = CE_BITMASK_DEFAULT;
8807
8808 #if USE_NEW_BLOCK_STYLE
8809     /* this must be handled before main playfield loop */
8810     if (Feld[x][y] == EL_PLAYER_IS_LEAVING)
8811     {
8812       MovDelay[x][y]--;
8813       if (MovDelay[x][y] <= 0)
8814         RemoveField(x, y);
8815     }
8816 #endif
8817
8818 #if DEBUG
8819     if (ChangePage[x][y] != -1 && ChangeDelay[x][y] != 1)
8820     {
8821       printf("GameActions(): x = %d, y = %d: ChangePage != -1\n", x, y);
8822       printf("GameActions(): This should never happen!\n");
8823
8824       ChangePage[x][y] = -1;
8825     }
8826 #endif
8827
8828     Stop[x][y] = FALSE;
8829     if (WasJustMoving[x][y] > 0)
8830       WasJustMoving[x][y]--;
8831     if (WasJustFalling[x][y] > 0)
8832       WasJustFalling[x][y]--;
8833     if (CheckCollision[x][y] > 0)
8834       CheckCollision[x][y]--;
8835
8836     GfxFrame[x][y]++;
8837
8838 #if 1
8839     /* reset finished pushing action (not done in ContinueMoving() to allow
8840        continous pushing animation for elements with zero push delay) */
8841     if (GfxAction[x][y] == ACTION_PUSHING && !IS_MOVING(x, y))
8842     {
8843       ResetGfxAnimation(x, y);
8844       DrawLevelField(x, y);
8845     }
8846 #endif
8847
8848 #if DEBUG
8849     if (IS_BLOCKED(x, y))
8850     {
8851       int oldx, oldy;
8852
8853       Blocked2Moving(x, y, &oldx, &oldy);
8854       if (!IS_MOVING(oldx, oldy))
8855       {
8856         printf("GameActions(): (BLOCKED => MOVING) context corrupted!\n");
8857         printf("GameActions(): BLOCKED: x = %d, y = %d\n", x, y);
8858         printf("GameActions(): !MOVING: oldx = %d, oldy = %d\n", oldx, oldy);
8859         printf("GameActions(): This should never happen!\n");
8860       }
8861     }
8862 #endif
8863   }
8864
8865   for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
8866   {
8867     element = Feld[x][y];
8868 #if 1
8869     graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
8870 #else
8871     graphic = el2img(element);
8872 #endif
8873
8874 #if 0
8875     if (element == -1)
8876     {
8877       printf("::: %d,%d: %d [%d]\n", x, y, element, FrameCounter);
8878
8879       element = graphic = 0;
8880     }
8881 #endif
8882
8883     if (graphic_info[graphic].anim_global_sync)
8884       GfxFrame[x][y] = FrameCounter;
8885
8886     if (ANIM_MODE(graphic) == ANIM_RANDOM &&
8887         IS_NEXT_FRAME(GfxFrame[x][y], graphic))
8888       ResetRandomAnimationValue(x, y);
8889
8890     SetRandomAnimationValue(x, y);
8891
8892 #if 1
8893     PlayLevelSoundActionIfLoop(x, y, GfxAction[x][y]);
8894 #endif
8895
8896     if (IS_INACTIVE(element))
8897     {
8898       if (IS_ANIMATED(graphic))
8899         DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
8900
8901       continue;
8902     }
8903
8904 #if 1
8905     /* this may take place after moving, so 'element' may have changed */
8906 #if 0
8907     if (IS_CHANGING(x, y))
8908 #else
8909     if (IS_CHANGING(x, y) &&
8910         (game.engine_version < VERSION_IDENT(3,0,7,1) || !Stop[x][y]))
8911 #endif
8912     {
8913 #if 0
8914       ChangeElement(x, y, ChangePage[x][y] != -1 ? ChangePage[x][y] :
8915                     element_info[element].event_page_nr[CE_DELAY]);
8916 #else
8917       ChangeElement(x, y, element_info[element].event_page_nr[CE_DELAY]);
8918 #endif
8919
8920       element = Feld[x][y];
8921       graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
8922     }
8923 #endif
8924
8925     if (!IS_MOVING(x, y) && (CAN_FALL(element) || CAN_MOVE(element)))
8926     {
8927       StartMoving(x, y);
8928
8929 #if 1
8930       element = Feld[x][y];
8931       graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
8932 #if 0
8933       if (element == EL_MOLE)
8934         printf("::: %d, %d, %d [%d]\n",
8935                IS_ANIMATED(graphic), IS_MOVING(x, y), Stop[x][y],
8936                GfxAction[x][y]);
8937 #endif
8938 #if 0
8939       if (element == EL_YAMYAM)
8940         printf("::: %d, %d, %d\n",
8941                IS_ANIMATED(graphic), IS_MOVING(x, y), Stop[x][y]);
8942 #endif
8943 #endif
8944
8945       if (IS_ANIMATED(graphic) &&
8946           !IS_MOVING(x, y) &&
8947           !Stop[x][y])
8948       {
8949         DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
8950
8951 #if 0
8952         if (element == EL_BUG)
8953           printf("::: %d, %d\n", graphic, GfxFrame[x][y]);
8954 #endif
8955
8956 #if 0
8957         if (element == EL_MOLE)
8958           printf("::: %d, %d\n", graphic, GfxFrame[x][y]);
8959 #endif
8960       }
8961
8962       if (IS_GEM(element) || element == EL_SP_INFOTRON)
8963         EdelsteinFunkeln(x, y);
8964     }
8965     else if ((element == EL_ACID ||
8966               element == EL_EXIT_OPEN ||
8967               element == EL_SP_EXIT_OPEN ||
8968               element == EL_SP_TERMINAL ||
8969               element == EL_SP_TERMINAL_ACTIVE ||
8970               element == EL_EXTRA_TIME ||
8971               element == EL_SHIELD_NORMAL ||
8972               element == EL_SHIELD_DEADLY) &&
8973              IS_ANIMATED(graphic))
8974       DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
8975     else if (IS_MOVING(x, y))
8976       ContinueMoving(x, y);
8977     else if (IS_ACTIVE_BOMB(element))
8978       CheckDynamite(x, y);
8979 #if 0
8980     else if (element == EL_EXPLOSION && !game.explosions_delayed)
8981       Explode(x, y, ExplodePhase[x][y], EX_TYPE_NORMAL);
8982 #endif
8983     else if (element == EL_AMOEBA_GROWING)
8984       AmoebeWaechst(x, y);
8985     else if (element == EL_AMOEBA_SHRINKING)
8986       AmoebaDisappearing(x, y);
8987
8988 #if !USE_NEW_AMOEBA_CODE
8989     else if (IS_AMOEBALIVE(element))
8990       AmoebeAbleger(x, y);
8991 #endif
8992
8993     else if (element == EL_GAME_OF_LIFE || element == EL_BIOMAZE)
8994       Life(x, y);
8995     else if (element == EL_EXIT_CLOSED)
8996       CheckExit(x, y);
8997     else if (element == EL_SP_EXIT_CLOSED)
8998       CheckExitSP(x, y);
8999     else if (element == EL_EXPANDABLE_WALL_GROWING)
9000       MauerWaechst(x, y);
9001     else if (element == EL_EXPANDABLE_WALL ||
9002              element == EL_EXPANDABLE_WALL_HORIZONTAL ||
9003              element == EL_EXPANDABLE_WALL_VERTICAL ||
9004              element == EL_EXPANDABLE_WALL_ANY)
9005       MauerAbleger(x, y);
9006     else if (element == EL_FLAMES)
9007       CheckForDragon(x, y);
9008 #if 0
9009     else if (IS_AUTO_CHANGING(element))
9010       ChangeElement(x, y);
9011 #endif
9012     else if (element == EL_EXPLOSION)
9013       ; /* drawing of correct explosion animation is handled separately */
9014     else if (IS_ANIMATED(graphic) && !IS_CHANGING(x, y))
9015       DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
9016
9017 #if 0
9018     /* this may take place after moving, so 'element' may have changed */
9019     if (IS_AUTO_CHANGING(Feld[x][y]))
9020       ChangeElement(x, y);
9021 #endif
9022
9023     if (IS_BELT_ACTIVE(element))
9024       PlayLevelSoundAction(x, y, ACTION_ACTIVE);
9025
9026     if (game.magic_wall_active)
9027     {
9028       int jx = local_player->jx, jy = local_player->jy;
9029
9030       /* play the element sound at the position nearest to the player */
9031       if ((element == EL_MAGIC_WALL_FULL ||
9032            element == EL_MAGIC_WALL_ACTIVE ||
9033            element == EL_MAGIC_WALL_EMPTYING ||
9034            element == EL_BD_MAGIC_WALL_FULL ||
9035            element == EL_BD_MAGIC_WALL_ACTIVE ||
9036            element == EL_BD_MAGIC_WALL_EMPTYING) &&
9037           ABS(x-jx) + ABS(y-jy) < ABS(magic_wall_x-jx) + ABS(magic_wall_y-jy))
9038       {
9039         magic_wall_x = x;
9040         magic_wall_y = y;
9041       }
9042     }
9043   }
9044
9045 #if USE_NEW_AMOEBA_CODE
9046   /* new experimental amoeba growth stuff */
9047 #if 1
9048   if (!(FrameCounter % 8))
9049 #endif
9050   {
9051     static unsigned long random = 1684108901;
9052
9053     for (i = 0; i < level.amoeba_speed * 28 / 8; i++)
9054     {
9055 #if 0
9056       x = (random >> 10) % lev_fieldx;
9057       y = (random >> 20) % lev_fieldy;
9058 #else
9059       x = RND(lev_fieldx);
9060       y = RND(lev_fieldy);
9061 #endif
9062       element = Feld[x][y];
9063
9064 #if 1
9065       if (!IS_PLAYER(x,y) &&
9066           (element == EL_EMPTY ||
9067            CAN_GROW_INTO(element) ||
9068            element == EL_QUICKSAND_EMPTY ||
9069            element == EL_ACID_SPLASH_LEFT ||
9070            element == EL_ACID_SPLASH_RIGHT))
9071       {
9072         if ((IN_LEV_FIELD(x, y-1) && Feld[x][y-1] == EL_AMOEBA_WET) ||
9073             (IN_LEV_FIELD(x-1, y) && Feld[x-1][y] == EL_AMOEBA_WET) ||
9074             (IN_LEV_FIELD(x+1, y) && Feld[x+1][y] == EL_AMOEBA_WET) ||
9075             (IN_LEV_FIELD(x, y+1) && Feld[x][y+1] == EL_AMOEBA_WET))
9076           Feld[x][y] = EL_AMOEBA_DROP;
9077       }
9078 #else
9079       /* !!! extend EL_SAND to anything diggable (but maybe not SP_BASE) !!! */
9080       if (!IS_PLAYER(x,y) &&
9081           (element == EL_EMPTY ||
9082            element == EL_SAND ||
9083            element == EL_QUICKSAND_EMPTY ||
9084            element == EL_ACID_SPLASH_LEFT ||
9085            element == EL_ACID_SPLASH_RIGHT))
9086       {
9087         if ((IN_LEV_FIELD(x, y-1) && Feld[x][y-1] == EL_AMOEBA_WET) ||
9088             (IN_LEV_FIELD(x-1, y) && Feld[x-1][y] == EL_AMOEBA_WET) ||
9089             (IN_LEV_FIELD(x+1, y) && Feld[x+1][y] == EL_AMOEBA_WET) ||
9090             (IN_LEV_FIELD(x, y+1) && Feld[x][y+1] == EL_AMOEBA_WET))
9091           Feld[x][y] = EL_AMOEBA_DROP;
9092       }
9093 #endif
9094
9095       random = random * 129 + 1;
9096     }
9097   }
9098 #endif
9099
9100 #if 0
9101   if (game.explosions_delayed)
9102 #endif
9103   {
9104     game.explosions_delayed = FALSE;
9105
9106     for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
9107     {
9108       element = Feld[x][y];
9109
9110       if (ExplodeField[x][y])
9111         Explode(x, y, EX_PHASE_START, ExplodeField[x][y]);
9112       else if (element == EL_EXPLOSION)
9113         Explode(x, y, ExplodePhase[x][y], EX_TYPE_NORMAL);
9114
9115       ExplodeField[x][y] = EX_TYPE_NONE;
9116     }
9117
9118     game.explosions_delayed = TRUE;
9119   }
9120
9121   if (game.magic_wall_active)
9122   {
9123     if (!(game.magic_wall_time_left % 4))
9124     {
9125       int element = Feld[magic_wall_x][magic_wall_y];
9126
9127       if (element == EL_BD_MAGIC_WALL_FULL ||
9128           element == EL_BD_MAGIC_WALL_ACTIVE ||
9129           element == EL_BD_MAGIC_WALL_EMPTYING)
9130         PlayLevelSound(magic_wall_x, magic_wall_y, SND_BD_MAGIC_WALL_ACTIVE);
9131       else
9132         PlayLevelSound(magic_wall_x, magic_wall_y, SND_MAGIC_WALL_ACTIVE);
9133     }
9134
9135     if (game.magic_wall_time_left > 0)
9136     {
9137       game.magic_wall_time_left--;
9138       if (!game.magic_wall_time_left)
9139       {
9140         for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
9141         {
9142           element = Feld[x][y];
9143
9144           if (element == EL_MAGIC_WALL_ACTIVE ||
9145               element == EL_MAGIC_WALL_FULL)
9146           {
9147             Feld[x][y] = EL_MAGIC_WALL_DEAD;
9148             DrawLevelField(x, y);
9149           }
9150           else if (element == EL_BD_MAGIC_WALL_ACTIVE ||
9151                    element == EL_BD_MAGIC_WALL_FULL)
9152           {
9153             Feld[x][y] = EL_BD_MAGIC_WALL_DEAD;
9154             DrawLevelField(x, y);
9155           }
9156         }
9157
9158         game.magic_wall_active = FALSE;
9159       }
9160     }
9161   }
9162
9163   if (game.light_time_left > 0)
9164   {
9165     game.light_time_left--;
9166
9167     if (game.light_time_left == 0)
9168       RedrawAllLightSwitchesAndInvisibleElements();
9169   }
9170
9171   if (game.timegate_time_left > 0)
9172   {
9173     game.timegate_time_left--;
9174
9175     if (game.timegate_time_left == 0)
9176       CloseAllOpenTimegates();
9177   }
9178
9179   for (i = 0; i < MAX_PLAYERS; i++)
9180   {
9181     struct PlayerInfo *player = &stored_player[i];
9182
9183     if (SHIELD_ON(player))
9184     {
9185       if (player->shield_deadly_time_left)
9186         PlayLevelSound(player->jx, player->jy, SND_SHIELD_DEADLY_ACTIVE);
9187       else if (player->shield_normal_time_left)
9188         PlayLevelSound(player->jx, player->jy, SND_SHIELD_NORMAL_ACTIVE);
9189     }
9190   }
9191
9192   if (TimeFrames >= FRAMES_PER_SECOND)
9193   {
9194     TimeFrames = 0;
9195     TapeTime++;
9196
9197     for (i = 0; i < MAX_PLAYERS; i++)
9198     {
9199       struct PlayerInfo *player = &stored_player[i];
9200
9201       if (SHIELD_ON(player))
9202       {
9203         player->shield_normal_time_left--;
9204
9205         if (player->shield_deadly_time_left > 0)
9206           player->shield_deadly_time_left--;
9207       }
9208     }
9209
9210     if (!level.use_step_counter)
9211     {
9212       TimePlayed++;
9213
9214       if (TimeLeft > 0)
9215       {
9216         TimeLeft--;
9217
9218         if (TimeLeft <= 10 && setup.time_limit)
9219           PlaySoundStereo(SND_GAME_RUNNING_OUT_OF_TIME, SOUND_MIDDLE);
9220
9221         DrawGameValue_Time(TimeLeft);
9222
9223         if (!TimeLeft && setup.time_limit)
9224           for (i = 0; i < MAX_PLAYERS; i++)
9225             KillHero(&stored_player[i]);
9226       }
9227       else if (level.time == 0 && !AllPlayersGone) /* level w/o time limit */
9228         DrawGameValue_Time(TimePlayed);
9229     }
9230
9231     if (tape.recording || tape.playing)
9232       DrawVideoDisplay(VIDEO_STATE_TIME_ON, TapeTime);
9233   }
9234
9235   DrawAllPlayers();
9236   PlayAllPlayersSound();
9237
9238   if (options.debug)                    /* calculate frames per second */
9239   {
9240     static unsigned long fps_counter = 0;
9241     static int fps_frames = 0;
9242     unsigned long fps_delay_ms = Counter() - fps_counter;
9243
9244     fps_frames++;
9245
9246     if (fps_delay_ms >= 500)    /* calculate fps every 0.5 seconds */
9247     {
9248       global.frames_per_second = 1000 * (float)fps_frames / fps_delay_ms;
9249
9250       fps_frames = 0;
9251       fps_counter = Counter();
9252     }
9253
9254     redraw_mask |= REDRAW_FPS;
9255   }
9256
9257 #if 0
9258   if (stored_player[0].jx != stored_player[0].last_jx ||
9259       stored_player[0].jy != stored_player[0].last_jy)
9260     printf("::: %d, %d, %d, %d, %d\n",
9261            stored_player[0].MovDir,
9262            stored_player[0].MovPos,
9263            stored_player[0].GfxPos,
9264            stored_player[0].Frame,
9265            stored_player[0].StepFrame);
9266 #endif
9267
9268 #if USE_NEW_MOVE_DELAY
9269   AdvanceFrameAndPlayerCounters(-1);    /* advance counters for all players */
9270 #else
9271   FrameCounter++;
9272   TimeFrames++;
9273
9274   for (i = 0; i < MAX_PLAYERS; i++)
9275   {
9276     int move_frames =
9277       MOVE_DELAY_NORMAL_SPEED /  stored_player[i].move_delay_value;
9278
9279     stored_player[i].Frame += move_frames;
9280
9281     if (stored_player[i].MovPos != 0)
9282       stored_player[i].StepFrame += move_frames;
9283
9284 #if USE_NEW_MOVE_DELAY
9285     if (stored_player[i].move_delay > 0)
9286       stored_player[i].move_delay--;
9287 #endif
9288
9289     if (stored_player[i].drop_delay > 0)
9290       stored_player[i].drop_delay--;
9291   }
9292 #endif
9293
9294 #if 1
9295   if (local_player->show_envelope != 0 && local_player->MovPos == 0)
9296   {
9297     ShowEnvelope(local_player->show_envelope - EL_ENVELOPE_1);
9298
9299     local_player->show_envelope = 0;
9300   }
9301 #endif
9302
9303 #if USE_NEW_RANDOMIZE
9304   /* use random number generator in every frame to make it less predictable */
9305   if (game.engine_version >= VERSION_IDENT(3,1,1,0))
9306     RND(1);
9307 #endif
9308 }
9309
9310 static boolean AllPlayersInSight(struct PlayerInfo *player, int x, int y)
9311 {
9312   int min_x = x, min_y = y, max_x = x, max_y = y;
9313   int i;
9314
9315   for (i = 0; i < MAX_PLAYERS; i++)
9316   {
9317     int jx = stored_player[i].jx, jy = stored_player[i].jy;
9318
9319     if (!stored_player[i].active || &stored_player[i] == player)
9320       continue;
9321
9322     min_x = MIN(min_x, jx);
9323     min_y = MIN(min_y, jy);
9324     max_x = MAX(max_x, jx);
9325     max_y = MAX(max_y, jy);
9326   }
9327
9328   return (max_x - min_x < SCR_FIELDX && max_y - min_y < SCR_FIELDY);
9329 }
9330
9331 static boolean AllPlayersInVisibleScreen()
9332 {
9333   int i;
9334
9335   for (i = 0; i < MAX_PLAYERS; i++)
9336   {
9337     int jx = stored_player[i].jx, jy = stored_player[i].jy;
9338
9339     if (!stored_player[i].active)
9340       continue;
9341
9342     if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
9343       return FALSE;
9344   }
9345
9346   return TRUE;
9347 }
9348
9349 void ScrollLevel(int dx, int dy)
9350 {
9351   int softscroll_offset = (setup.soft_scrolling ? TILEX : 0);
9352   int x, y;
9353
9354   BlitBitmap(drawto_field, drawto_field,
9355              FX + TILEX * (dx == -1) - softscroll_offset,
9356              FY + TILEY * (dy == -1) - softscroll_offset,
9357              SXSIZE - TILEX * (dx!=0) + 2 * softscroll_offset,
9358              SYSIZE - TILEY * (dy!=0) + 2 * softscroll_offset,
9359              FX + TILEX * (dx == 1) - softscroll_offset,
9360              FY + TILEY * (dy == 1) - softscroll_offset);
9361
9362   if (dx)
9363   {
9364     x = (dx == 1 ? BX1 : BX2);
9365     for (y = BY1; y <= BY2; y++)
9366       DrawScreenField(x, y);
9367   }
9368
9369   if (dy)
9370   {
9371     y = (dy == 1 ? BY1 : BY2);
9372     for (x = BX1; x <= BX2; x++)
9373       DrawScreenField(x, y);
9374   }
9375
9376   redraw_mask |= REDRAW_FIELD;
9377 }
9378
9379 #if 0
9380 static boolean canEnterSupaplexPort(int x, int y, int dx, int dy)
9381 {
9382   int nextx = x + dx, nexty = y + dy;
9383   int element = Feld[x][y];
9384
9385   if ((dx == -1 &&
9386        element != EL_SP_PORT_LEFT &&
9387        element != EL_SP_GRAVITY_PORT_LEFT &&
9388        element != EL_SP_PORT_HORIZONTAL &&
9389        element != EL_SP_PORT_ANY) ||
9390       (dx == +1 &&
9391        element != EL_SP_PORT_RIGHT &&
9392        element != EL_SP_GRAVITY_PORT_RIGHT &&
9393        element != EL_SP_PORT_HORIZONTAL &&
9394        element != EL_SP_PORT_ANY) ||
9395       (dy == -1 &&
9396        element != EL_SP_PORT_UP &&
9397        element != EL_SP_GRAVITY_PORT_UP &&
9398        element != EL_SP_PORT_VERTICAL &&
9399        element != EL_SP_PORT_ANY) ||
9400       (dy == +1 &&
9401        element != EL_SP_PORT_DOWN &&
9402        element != EL_SP_GRAVITY_PORT_DOWN &&
9403        element != EL_SP_PORT_VERTICAL &&
9404        element != EL_SP_PORT_ANY) ||
9405       !IN_LEV_FIELD(nextx, nexty) ||
9406       !IS_FREE(nextx, nexty))
9407     return FALSE;
9408
9409   return TRUE;
9410 }
9411 #endif
9412
9413 static boolean canFallDown(struct PlayerInfo *player)
9414 {
9415   int jx = player->jx, jy = player->jy;
9416
9417   return (IN_LEV_FIELD(jx, jy + 1) &&
9418           (IS_FREE(jx, jy + 1) ||
9419            (Feld[jx][jy + 1] == EL_ACID && player->can_fall_into_acid)) &&
9420           IS_WALKABLE_FROM(Feld[jx][jy], MV_DOWN) &&
9421           !IS_WALKABLE_INSIDE(Feld[jx][jy]));
9422 }
9423
9424 static boolean canPassField(int x, int y, int move_dir)
9425 {
9426   int opposite_dir = MV_DIR_OPPOSITE(move_dir);
9427   int dx = (move_dir & MV_LEFT ? -1 : move_dir & MV_RIGHT ? +1 : 0);
9428   int dy = (move_dir & MV_UP   ? -1 : move_dir & MV_DOWN  ? +1 : 0);
9429   int nextx = x + dx;
9430   int nexty = y + dy;
9431   int element = Feld[x][y];
9432
9433   return (IS_PASSABLE_FROM(element, opposite_dir) &&
9434           !CAN_MOVE(element) &&
9435           IN_LEV_FIELD(nextx, nexty) && !IS_PLAYER(nextx, nexty) &&
9436           IS_WALKABLE_FROM(Feld[nextx][nexty], move_dir) &&
9437           (level.can_pass_to_walkable || IS_FREE(nextx, nexty)));
9438 }
9439
9440 static boolean canMoveToValidFieldWithGravity(int x, int y, int move_dir)
9441 {
9442   int opposite_dir = MV_DIR_OPPOSITE(move_dir);
9443   int dx = (move_dir & MV_LEFT ? -1 : move_dir & MV_RIGHT ? +1 : 0);
9444   int dy = (move_dir & MV_UP   ? -1 : move_dir & MV_DOWN  ? +1 : 0);
9445   int newx = x + dx;
9446   int newy = y + dy;
9447 #if 0
9448   int nextx = newx + dx;
9449   int nexty = newy + dy;
9450 #endif
9451
9452 #if 1
9453   return (IN_LEV_FIELD(newx, newy) && !IS_FREE_OR_PLAYER(newx, newy) &&
9454           IS_GRAVITY_REACHABLE(Feld[newx][newy]) &&
9455 #if 0
9456           (!IS_SP_PORT(Feld[newx][newy]) || move_dir == MV_UP) &&
9457 #endif
9458           (IS_DIGGABLE(Feld[newx][newy]) ||
9459            IS_WALKABLE_FROM(Feld[newx][newy], opposite_dir) ||
9460            canPassField(newx, newy, move_dir)));
9461 #else
9462 #if 1
9463   return (IN_LEV_FIELD(newx, newy) && !IS_FREE_OR_PLAYER(newx, newy) &&
9464           IS_GRAVITY_REACHABLE(Feld[newx][newy]) &&
9465           (IS_DIGGABLE(Feld[newx][newy]) ||
9466            IS_WALKABLE_FROM(Feld[newx][newy], opposite_dir) ||
9467            canPassField(newx, newy, move_dir)));
9468 #else
9469 #if 1
9470   return (IN_LEV_FIELD(newx, newy) && !IS_FREE_OR_PLAYER(newx, newy) &&
9471           (IS_DIGGABLE_WITH_GRAVITY(Feld[newx][newy]) ||
9472            IS_WALKABLE_FROM(Feld[newx][newy], opposite_dir) ||
9473            canPassField(newx, newy, move_dir)));
9474 #else
9475   return (IN_LEV_FIELD(newx, newy) && !IS_FREE_OR_PLAYER(newx, newy) &&
9476           (IS_DIGGABLE(Feld[newx][newy]) ||
9477            IS_WALKABLE_FROM(Feld[newx][newy], opposite_dir) ||
9478            (IS_PASSABLE_FROM(Feld[newx][newy], opposite_dir) &&
9479             !CAN_MOVE(Feld[newx][newy]) &&
9480             IN_LEV_FIELD(nextx, nexty) && !IS_PLAYER(nextx, nexty) &&
9481             IS_WALKABLE_FROM(Feld[nextx][nexty], move_dir) &&
9482             (level.can_pass_to_walkable || IS_FREE(nextx, nexty)))));
9483 #endif
9484 #endif
9485 #endif
9486 }
9487
9488 static void CheckGravityMovement(struct PlayerInfo *player)
9489 {
9490   if (game.gravity && !player->programmed_action)
9491   {
9492 #if 1
9493     int move_dir_horizontal = player->effective_action & MV_HORIZONTAL;
9494     int move_dir_vertical   = player->effective_action & MV_VERTICAL;
9495 #else
9496     int move_dir_horizontal = player->action & MV_HORIZONTAL;
9497     int move_dir_vertical   = player->action & MV_VERTICAL;
9498 #endif
9499
9500 #if 1
9501     boolean player_is_snapping = player->effective_action & JOY_BUTTON_1;
9502 #else
9503     boolean player_is_snapping = player->action & JOY_BUTTON_1;
9504 #endif
9505
9506     int jx = player->jx, jy = player->jy;
9507
9508     boolean player_is_moving_to_valid_field =
9509       (!player_is_snapping &&
9510        (canMoveToValidFieldWithGravity(jx, jy, move_dir_horizontal) ||
9511         canMoveToValidFieldWithGravity(jx, jy, move_dir_vertical)));
9512
9513 #if 0
9514     int move_dir =
9515       (player->last_move_dir & MV_HORIZONTAL ?
9516        (move_dir_vertical ? move_dir_vertical : move_dir_horizontal) :
9517        (move_dir_horizontal ? move_dir_horizontal : move_dir_vertical));
9518 #endif
9519
9520 #if 0
9521     int opposite_dir = MV_DIR_OPPOSITE(move_dir);
9522     int dx = (move_dir & MV_LEFT ? -1 : move_dir & MV_RIGHT ? +1 : 0);
9523     int dy = (move_dir & MV_UP ? -1 : move_dir & MV_DOWN ? +1 : 0);
9524     int new_jx = jx + dx, new_jy = jy + dy;
9525     int nextx = new_jx + dx, nexty = new_jy + dy;
9526 #endif
9527
9528 #if 1
9529
9530 #if 1
9531     boolean player_can_fall_down = canFallDown(player);
9532 #else
9533     boolean player_can_fall_down =
9534       (IN_LEV_FIELD(jx, jy + 1) &&
9535        (IS_FREE(jx, jy + 1) ||
9536         (Feld[jx][jy + 1] == EL_ACID && player->can_fall_into_acid)));
9537 #endif
9538
9539 #else
9540     boolean player_can_fall_down =
9541       (IN_LEV_FIELD(jx, jy + 1) &&
9542        (IS_FREE(jx, jy + 1)));
9543 #endif
9544
9545 #if 0
9546     boolean player_is_moving_to_valid_field =
9547       (
9548 #if 1
9549        !player_is_snapping &&
9550 #endif
9551
9552 #if 1
9553        IN_LEV_FIELD(new_jx, new_jy) &&
9554        (IS_DIGGABLE(Feld[new_jx][new_jy]) ||
9555         (IS_SP_PORT(Feld[new_jx][new_jy]) &&
9556          element_info[Feld[new_jx][new_jy]].access_direction & opposite_dir &&
9557          IN_LEV_FIELD(nextx, nexty) &&
9558          element_info[Feld[nextx][nexty]].access_direction & move_dir))
9559 #else
9560        IN_LEV_FIELD(new_jx, new_jy) &&
9561        (Feld[new_jx][new_jy] == EL_SP_BASE ||
9562         Feld[new_jx][new_jy] == EL_SAND ||
9563         (IS_SP_PORT(Feld[new_jx][new_jy]) &&
9564          canEnterSupaplexPort(new_jx, new_jy, dx, dy)))
9565     /* !!! extend EL_SAND to anything diggable !!! */
9566 #endif
9567        );
9568 #endif
9569
9570 #if 0
9571     boolean player_is_standing_on_valid_field =
9572       (IS_WALKABLE_INSIDE(Feld[jx][jy]) ||
9573        (IS_WALKABLE(Feld[jx][jy]) && !ACCESS_FROM(Feld[jx][jy], MV_DOWN)));
9574 #endif
9575
9576 #if 0
9577     printf("::: checking gravity NOW [%d, %d, %d] [%d] [%d / %d] ...\n",
9578            player_can_fall_down,
9579            player_is_standing_on_valid_field,
9580            player_is_moving_to_valid_field,
9581            (player_is_moving_to_valid_field ? Feld[new_jx][new_jy] : -1),
9582            player->effective_action,
9583            player->can_fall_into_acid);
9584 #endif
9585
9586     if (player_can_fall_down &&
9587 #if 0
9588         !player_is_standing_on_valid_field &&
9589 #endif
9590         !player_is_moving_to_valid_field)
9591     {
9592 #if 0
9593       printf("::: setting programmed_action to MV_DOWN [%d,%d - %d] ...\n",
9594              jx, jy, FrameCounter);
9595 #endif
9596
9597       player->programmed_action = MV_DOWN;
9598     }
9599   }
9600 }
9601
9602 static void CheckGravityMovementWhenNotMoving(struct PlayerInfo *player)
9603 {
9604 #if 1
9605   return CheckGravityMovement(player);
9606 #endif
9607
9608   if (game.gravity && !player->programmed_action)
9609   {
9610     int jx = player->jx, jy = player->jy;
9611     boolean field_under_player_is_free =
9612       (IN_LEV_FIELD(jx, jy + 1) && IS_FREE(jx, jy + 1));
9613     boolean player_is_standing_on_valid_field =
9614       (IS_WALKABLE_INSIDE(Feld[jx][jy]) ||
9615        (IS_WALKABLE(Feld[jx][jy]) &&
9616         !(element_info[Feld[jx][jy]].access_direction & MV_DOWN)));
9617
9618     if (field_under_player_is_free && !player_is_standing_on_valid_field)
9619       player->programmed_action = MV_DOWN;
9620   }
9621 }
9622
9623 /*
9624   MovePlayerOneStep()
9625   -----------------------------------------------------------------------------
9626   dx, dy:               direction (non-diagonal) to try to move the player to
9627   real_dx, real_dy:     direction as read from input device (can be diagonal)
9628 */
9629
9630 boolean MovePlayerOneStep(struct PlayerInfo *player,
9631                           int dx, int dy, int real_dx, int real_dy)
9632 {
9633 #if 0
9634   static int trigger_sides[4][2] =
9635   {
9636     /* enter side        leave side */
9637     { CH_SIDE_RIGHT,    CH_SIDE_LEFT    },      /* moving left  */
9638     { CH_SIDE_LEFT,     CH_SIDE_RIGHT   },      /* moving right */
9639     { CH_SIDE_BOTTOM,   CH_SIDE_TOP     },      /* moving up    */
9640     { CH_SIDE_TOP,      CH_SIDE_BOTTOM  }       /* moving down  */
9641   };
9642   int move_direction = (dx == -1 ? MV_LEFT :
9643                         dx == +1 ? MV_RIGHT :
9644                         dy == -1 ? MV_UP :
9645                         dy == +1 ? MV_DOWN : MV_NO_MOVING);
9646   int enter_side = trigger_sides[MV_DIR_BIT(move_direction)][0];
9647   int leave_side = trigger_sides[MV_DIR_BIT(move_direction)][1];
9648 #endif
9649   int jx = player->jx, jy = player->jy;
9650   int new_jx = jx + dx, new_jy = jy + dy;
9651   int element;
9652   int can_move;
9653
9654   if (!player->active || (!dx && !dy))
9655     return MF_NO_ACTION;
9656
9657   player->MovDir = (dx < 0 ? MV_LEFT :
9658                     dx > 0 ? MV_RIGHT :
9659                     dy < 0 ? MV_UP :
9660                     dy > 0 ? MV_DOWN :  MV_NO_MOVING);
9661
9662   if (!IN_LEV_FIELD(new_jx, new_jy))
9663     return MF_NO_ACTION;
9664
9665   if (!options.network && !AllPlayersInSight(player, new_jx, new_jy))
9666     return MF_NO_ACTION;
9667
9668 #if 0
9669   element = MovingOrBlocked2Element(new_jx, new_jy);
9670 #else
9671   element = MovingOrBlocked2ElementIfNotLeaving(new_jx, new_jy);
9672 #endif
9673
9674   if (DONT_RUN_INTO(element))
9675   {
9676     if (element == EL_ACID && dx == 0 && dy == 1)
9677     {
9678       SplashAcid(new_jx, new_jy);
9679       Feld[jx][jy] = EL_PLAYER_1;
9680       InitMovingField(jx, jy, MV_DOWN);
9681       Store[jx][jy] = EL_ACID;
9682       ContinueMoving(jx, jy);
9683       BuryHero(player);
9684     }
9685     else
9686       TestIfHeroRunsIntoBadThing(jx, jy, player->MovDir);
9687
9688     return MF_MOVING;
9689   }
9690
9691   can_move = DigField(player, jx, jy, new_jx, new_jy, real_dx,real_dy, DF_DIG);
9692   if (can_move != MF_MOVING)
9693     return can_move;
9694
9695   /* check if DigField() has caused relocation of the player */
9696   if (player->jx != jx || player->jy != jy)
9697     return MF_NO_ACTION;
9698
9699   StorePlayer[jx][jy] = 0;
9700   player->last_jx = jx;
9701   player->last_jy = jy;
9702   player->jx = new_jx;
9703   player->jy = new_jy;
9704   StorePlayer[new_jx][new_jy] = player->element_nr;
9705
9706   player->MovPos =
9707     (dx > 0 || dy > 0 ? -1 : 1) * (TILEX - TILEX / player->move_delay_value);
9708
9709   player->step_counter++;
9710
9711 #if 0
9712   player->drop_delay = 0;
9713 #endif
9714
9715   PlayerVisit[jx][jy] = FrameCounter;
9716
9717   ScrollPlayer(player, SCROLL_INIT);
9718
9719 #if 0
9720   if (IS_CUSTOM_ELEMENT(Feld[jx][jy]))
9721   {
9722     CheckTriggeredElementChangeBySide(jx, jy, Feld[jx][jy], CE_OTHER_GETS_LEFT,
9723                                       leave_side);
9724     CheckElementChangeBySide(jx,jy, Feld[jx][jy],CE_LEFT_BY_PLAYER,leave_side);
9725   }
9726
9727   if (IS_CUSTOM_ELEMENT(Feld[new_jx][new_jy]))
9728   {
9729     CheckTriggeredElementChangeBySide(new_jx, new_jy, Feld[new_jx][new_jy],
9730                                       CE_OTHER_GETS_ENTERED, enter_side);
9731     CheckElementChangeBySide(new_jx, new_jy, Feld[new_jx][new_jy],
9732                              CE_ENTERED_BY_PLAYER, enter_side);
9733   }
9734 #endif
9735
9736   return MF_MOVING;
9737 }
9738
9739 boolean MovePlayer(struct PlayerInfo *player, int dx, int dy)
9740 {
9741   int jx = player->jx, jy = player->jy;
9742   int old_jx = jx, old_jy = jy;
9743   int moved = MF_NO_ACTION;
9744
9745 #if 1
9746   if (!player->active)
9747     return FALSE;
9748
9749   if (!dx && !dy)
9750   {
9751     if (player->MovPos == 0)
9752     {
9753       player->is_moving = FALSE;
9754       player->is_digging = FALSE;
9755       player->is_collecting = FALSE;
9756       player->is_snapping = FALSE;
9757       player->is_pushing = FALSE;
9758     }
9759
9760     return FALSE;
9761   }
9762 #else
9763   if (!player->active || (!dx && !dy))
9764     return FALSE;
9765 #endif
9766
9767 #if 0
9768   if (!FrameReached(&player->move_delay, player->move_delay_value) &&
9769       !tape.playing)
9770     return FALSE;
9771 #else
9772
9773 #if 1
9774
9775 #if 0
9776   printf("::: %d <= %d < %d ?\n", player->move_delay, FrameCounter,
9777          player->move_delay + player->move_delay_value);
9778 #endif
9779
9780 #if USE_NEW_MOVE_DELAY
9781   if (player->move_delay > 0)
9782 #else
9783   if (!FrameReached(&player->move_delay, player->move_delay_value))
9784 #endif
9785   {
9786 #if 0
9787     printf("::: can NOT move\n");
9788 #endif
9789
9790     return FALSE;
9791   }
9792 #else
9793   if (!FrameReached(&player->move_delay, player->move_delay_value) &&
9794       !(tape.playing && tape.file_version < FILE_VERSION_2_0))
9795     return FALSE;
9796 #endif
9797
9798 #endif
9799
9800 #if 0
9801   printf("::: COULD move now\n");
9802 #endif
9803
9804 #if USE_NEW_MOVE_DELAY
9805   player->move_delay = -1;              /* set to "uninitialized" value */
9806 #endif
9807
9808   /* store if player is automatically moved to next field */
9809   player->is_auto_moving = (player->programmed_action != MV_NO_MOVING);
9810
9811   /* remove the last programmed player action */
9812   player->programmed_action = 0;
9813
9814   if (player->MovPos)
9815   {
9816     /* should only happen if pre-1.2 tape recordings are played */
9817     /* this is only for backward compatibility */
9818
9819     int original_move_delay_value = player->move_delay_value;
9820
9821 #if DEBUG
9822     printf("THIS SHOULD ONLY HAPPEN WITH PRE-1.2 LEVEL TAPES. [%ld]\n",
9823            tape.counter);
9824 #endif
9825
9826     /* scroll remaining steps with finest movement resolution */
9827     player->move_delay_value = MOVE_DELAY_NORMAL_SPEED;
9828
9829     while (player->MovPos)
9830     {
9831       ScrollPlayer(player, SCROLL_GO_ON);
9832       ScrollScreen(NULL, SCROLL_GO_ON);
9833
9834 #if USE_NEW_MOVE_DELAY
9835       AdvanceFrameAndPlayerCounters(player->index_nr);
9836 #else
9837       FrameCounter++;
9838 #endif
9839
9840       DrawAllPlayers();
9841       BackToFront();
9842     }
9843
9844     player->move_delay_value = original_move_delay_value;
9845   }
9846
9847   if (player->last_move_dir & MV_HORIZONTAL)
9848   {
9849     if (!(moved |= MovePlayerOneStep(player, 0, dy, dx, dy)))
9850       moved |= MovePlayerOneStep(player, dx, 0, dx, dy);
9851   }
9852   else
9853   {
9854     if (!(moved |= MovePlayerOneStep(player, dx, 0, dx, dy)))
9855       moved |= MovePlayerOneStep(player, 0, dy, dx, dy);
9856   }
9857
9858   jx = player->jx;
9859   jy = player->jy;
9860
9861   if (moved & MF_MOVING && !ScreenMovPos &&
9862       (player == local_player || !options.network))
9863   {
9864     int old_scroll_x = scroll_x, old_scroll_y = scroll_y;
9865     int offset = (setup.scroll_delay ? 3 : 0);
9866
9867     if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
9868     {
9869       /* actual player has left the screen -- scroll in that direction */
9870       if (jx != old_jx)         /* player has moved horizontally */
9871         scroll_x += (jx - old_jx);
9872       else                      /* player has moved vertically */
9873         scroll_y += (jy - old_jy);
9874     }
9875     else
9876     {
9877       if (jx != old_jx)         /* player has moved horizontally */
9878       {
9879         if ((player->MovDir == MV_LEFT  && scroll_x > jx - MIDPOSX + offset) ||
9880             (player->MovDir == MV_RIGHT && scroll_x < jx - MIDPOSX - offset))
9881           scroll_x = jx-MIDPOSX + (scroll_x < jx-MIDPOSX ? -offset : +offset);
9882
9883         /* don't scroll over playfield boundaries */
9884         if (scroll_x < SBX_Left || scroll_x > SBX_Right)
9885           scroll_x = (scroll_x < SBX_Left ? SBX_Left : SBX_Right);
9886
9887         /* don't scroll more than one field at a time */
9888         scroll_x = old_scroll_x + SIGN(scroll_x - old_scroll_x);
9889
9890         /* don't scroll against the player's moving direction */
9891         if ((player->MovDir == MV_LEFT  && scroll_x > old_scroll_x) ||
9892             (player->MovDir == MV_RIGHT && scroll_x < old_scroll_x))
9893           scroll_x = old_scroll_x;
9894       }
9895       else                      /* player has moved vertically */
9896       {
9897         if ((player->MovDir == MV_UP   && scroll_y > jy - MIDPOSY + offset) ||
9898             (player->MovDir == MV_DOWN && scroll_y < jy - MIDPOSY - offset))
9899           scroll_y = jy-MIDPOSY + (scroll_y < jy-MIDPOSY ? -offset : +offset);
9900
9901         /* don't scroll over playfield boundaries */
9902         if (scroll_y < SBY_Upper || scroll_y > SBY_Lower)
9903           scroll_y = (scroll_y < SBY_Upper ? SBY_Upper : SBY_Lower);
9904
9905         /* don't scroll more than one field at a time */
9906         scroll_y = old_scroll_y + SIGN(scroll_y - old_scroll_y);
9907
9908         /* don't scroll against the player's moving direction */
9909         if ((player->MovDir == MV_UP   && scroll_y > old_scroll_y) ||
9910             (player->MovDir == MV_DOWN && scroll_y < old_scroll_y))
9911           scroll_y = old_scroll_y;
9912       }
9913     }
9914
9915     if (scroll_x != old_scroll_x || scroll_y != old_scroll_y)
9916     {
9917       if (!options.network && !AllPlayersInVisibleScreen())
9918       {
9919         scroll_x = old_scroll_x;
9920         scroll_y = old_scroll_y;
9921       }
9922       else
9923       {
9924         ScrollScreen(player, SCROLL_INIT);
9925         ScrollLevel(old_scroll_x - scroll_x, old_scroll_y - scroll_y);
9926       }
9927     }
9928   }
9929
9930 #if 0
9931 #if 1
9932   InitPlayerGfxAnimation(player, ACTION_DEFAULT);
9933 #else
9934   if (!(moved & MF_MOVING) && !player->is_pushing)
9935     player->Frame = 0;
9936 #endif
9937 #endif
9938
9939   player->StepFrame = 0;
9940
9941   if (moved & MF_MOVING)
9942   {
9943 #if 0
9944     printf("::: REALLY moves now\n");
9945 #endif
9946
9947     if (old_jx != jx && old_jy == jy)
9948       player->MovDir = (old_jx < jx ? MV_RIGHT : MV_LEFT);
9949     else if (old_jx == jx && old_jy != jy)
9950       player->MovDir = (old_jy < jy ? MV_DOWN : MV_UP);
9951
9952     DrawLevelField(jx, jy);     /* for "crumbled sand" */
9953
9954     player->last_move_dir = player->MovDir;
9955     player->is_moving = TRUE;
9956 #if 1
9957     player->is_snapping = FALSE;
9958 #endif
9959
9960 #if 1
9961     player->is_switching = FALSE;
9962 #endif
9963
9964     player->is_dropping = FALSE;
9965
9966
9967 #if 0
9968     /* !!! ENABLE THIS FOR OLD VERSIONS !!! */
9969
9970 #if 1
9971     if (game.engine_version < VERSION_IDENT(3,1,0,0))
9972 #endif
9973     {
9974       int move_direction = player->MovDir;
9975 #if 1
9976       int enter_side = MV_DIR_OPPOSITE(move_direction);
9977       int leave_side = move_direction;
9978 #else
9979       static int trigger_sides[4][2] =
9980       {
9981         /* enter side           leave side */
9982         { CH_SIDE_RIGHT,        CH_SIDE_LEFT    },      /* moving left  */
9983         { CH_SIDE_LEFT,         CH_SIDE_RIGHT   },      /* moving right */
9984         { CH_SIDE_BOTTOM,       CH_SIDE_TOP     },      /* moving up    */
9985         { CH_SIDE_TOP,          CH_SIDE_BOTTOM  }       /* moving down  */
9986       };
9987       int enter_side = trigger_sides[MV_DIR_BIT(move_direction)][0];
9988       int leave_side = trigger_sides[MV_DIR_BIT(move_direction)][1];
9989 #endif
9990       int old_element = Feld[old_jx][old_jy];
9991       int new_element = Feld[jx][jy];
9992
9993 #if 1
9994       /* !!! TEST ONLY !!! */
9995       if (IS_CUSTOM_ELEMENT(old_element))
9996         CheckElementChangeByPlayer(old_jx, old_jy, old_element,
9997                                    CE_LEFT_BY_PLAYER,
9998                                    player->index_bit, leave_side);
9999
10000       CheckTriggeredElementChangeByPlayer(old_jx, old_jy, old_element,
10001                                           CE_OTHER_GETS_LEFT,
10002                                           player->index_bit, leave_side);
10003
10004       if (IS_CUSTOM_ELEMENT(new_element))
10005         CheckElementChangeByPlayer(jx, jy, new_element, CE_ENTERED_BY_PLAYER,
10006                                    player->index_bit, enter_side);
10007
10008       CheckTriggeredElementChangeByPlayer(jx, jy, new_element,
10009                                           CE_OTHER_GETS_ENTERED,
10010                                           player->index_bit, enter_side);
10011 #endif
10012
10013     }
10014 #endif
10015
10016
10017   }
10018   else
10019   {
10020     CheckGravityMovementWhenNotMoving(player);
10021
10022     /*
10023     player->last_move_dir = MV_NO_MOVING;
10024     */
10025     player->is_moving = FALSE;
10026
10027 #if USE_NEW_MOVE_STYLE
10028     /* player is ALLOWED to move, but CANNOT move (something blocks his way) */
10029     /* ensure that the player is also allowed to move in the next frame */
10030     /* (currently, the player is forced to wait eight frames before he can try
10031        again!!!) */
10032
10033     if (game.engine_version >= VERSION_IDENT(3,1,1,0))
10034       player->move_delay = 0;   /* allow direct movement in the next frame */
10035 #endif
10036   }
10037
10038 #if USE_NEW_MOVE_DELAY
10039   if (player->move_delay == -1)         /* not yet initialized by DigField() */
10040     player->move_delay = player->move_delay_value;
10041 #endif
10042
10043   if (game.engine_version < VERSION_IDENT(3,0,7,0))
10044   {
10045     TestIfHeroTouchesBadThing(jx, jy);
10046     TestIfPlayerTouchesCustomElement(jx, jy);
10047   }
10048
10049   if (!player->active)
10050     RemoveHero(player);
10051
10052   return moved;
10053 }
10054
10055 void ScrollPlayer(struct PlayerInfo *player, int mode)
10056 {
10057   int jx = player->jx, jy = player->jy;
10058   int last_jx = player->last_jx, last_jy = player->last_jy;
10059   int move_stepsize = TILEX / player->move_delay_value;
10060
10061   if (!player->active || !player->MovPos)
10062     return;
10063
10064   if (mode == SCROLL_INIT)
10065   {
10066     player->actual_frame_counter = FrameCounter;
10067     player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
10068
10069 #if 0
10070     printf("::: %06d: %d,%d: %d (%d) [%d]\n",
10071            FrameCounter,
10072            last_jx, last_jy, Feld[last_jx][last_jy], EL_EXPLOSION,
10073            player->block_delay);
10074 #endif
10075
10076 #if USE_NEW_BLOCK_STYLE
10077
10078 #if 0
10079     if (player->block_delay <= 0)
10080       printf("::: ALERT! block_delay == %d\n", player->block_delay);
10081 #endif
10082
10083     if (player->block_delay > 0 &&
10084         Feld[last_jx][last_jy] == EL_EMPTY)
10085     {
10086       Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING;
10087       MovDelay[last_jx][last_jy] = player->block_delay + 1;
10088     }
10089 #else
10090 #if USE_NEW_MOVE_STYLE
10091     if ((game.engine_version < VERSION_IDENT(3,1,1,0) ||
10092          player->block_last_field) &&
10093         Feld[last_jx][last_jy] == EL_EMPTY)
10094       Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING;
10095 #else
10096     if (Feld[last_jx][last_jy] == EL_EMPTY)
10097       Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING;
10098 #endif
10099 #endif
10100
10101 #if 0
10102     DrawPlayer(player);
10103 #endif
10104
10105     return;
10106   }
10107   else if (!FrameReached(&player->actual_frame_counter, 1))
10108     return;
10109
10110   player->MovPos += (player->MovPos > 0 ? -1 : 1) * move_stepsize;
10111   player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
10112
10113 #if USE_NEW_BLOCK_STYLE
10114 #else
10115   if (!player->block_last_field &&
10116       Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING)
10117 #if 1
10118     RemoveField(last_jx, last_jy);
10119 #else
10120     Feld[last_jx][last_jy] = EL_EMPTY;
10121 #endif
10122 #endif
10123
10124   /* before DrawPlayer() to draw correct player graphic for this case */
10125   if (player->MovPos == 0)
10126     CheckGravityMovement(player);
10127
10128 #if 0
10129   DrawPlayer(player);   /* needed here only to cleanup last field */
10130 #endif
10131
10132   if (player->MovPos == 0)      /* player reached destination field */
10133   {
10134 #if 1
10135     if (player->move_delay_reset_counter > 0)
10136     {
10137       player->move_delay_reset_counter--;
10138
10139       if (player->move_delay_reset_counter == 0)
10140       {
10141         /* continue with normal speed after quickly moving through gate */
10142         HALVE_PLAYER_SPEED(player);
10143
10144         /* be able to make the next move without delay */
10145         player->move_delay = 0;
10146       }
10147     }
10148 #else
10149     if (IS_PASSABLE(Feld[last_jx][last_jy]))
10150     {
10151       /* continue with normal speed after quickly moving through gate */
10152       HALVE_PLAYER_SPEED(player);
10153
10154       /* be able to make the next move without delay */
10155       player->move_delay = 0;
10156     }
10157 #endif
10158
10159 #if USE_NEW_BLOCK_STYLE
10160 #else
10161     if (player->block_last_field &&
10162         Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING)
10163 #if 1
10164       RemoveField(last_jx, last_jy);
10165 #else
10166       Feld[last_jx][last_jy] = EL_EMPTY;
10167 #endif
10168 #endif
10169
10170     player->last_jx = jx;
10171     player->last_jy = jy;
10172
10173     if (Feld[jx][jy] == EL_EXIT_OPEN ||
10174         Feld[jx][jy] == EL_SP_EXIT_OPEN ||
10175         Feld[jx][jy] == EL_SP_EXIT_OPENING)     /* <-- special case */
10176     {
10177       DrawPlayer(player);       /* needed here only to cleanup last field */
10178       RemoveHero(player);
10179
10180       if (local_player->friends_still_needed == 0 ||
10181           IS_SP_ELEMENT(Feld[jx][jy]))
10182         player->LevelSolved = player->GameOver = TRUE;
10183     }
10184
10185 #if 1
10186     /* !!! ENABLE THIS FOR NEW VERSIONS !!! */
10187     /* this breaks one level: "machine", level 000 */
10188 #if 0
10189     if (game.engine_version >= VERSION_IDENT(3,1,0,0))
10190 #endif
10191     {
10192       int move_direction = player->MovDir;
10193 #if 1
10194       int enter_side = MV_DIR_OPPOSITE(move_direction);
10195       int leave_side = move_direction;
10196 #else
10197       static int trigger_sides[4][2] =
10198       {
10199         /* enter side           leave side */
10200         { CH_SIDE_RIGHT,        CH_SIDE_LEFT    },      /* moving left  */
10201         { CH_SIDE_LEFT,         CH_SIDE_RIGHT   },      /* moving right */
10202         { CH_SIDE_BOTTOM,       CH_SIDE_TOP     },      /* moving up    */
10203         { CH_SIDE_TOP,          CH_SIDE_BOTTOM  }       /* moving down  */
10204       };
10205       int enter_side = trigger_sides[MV_DIR_BIT(move_direction)][0];
10206       int leave_side = trigger_sides[MV_DIR_BIT(move_direction)][1];
10207 #endif
10208       int old_jx = last_jx;
10209       int old_jy = last_jy;
10210       int old_element = Feld[old_jx][old_jy];
10211       int new_element = Feld[jx][jy];
10212
10213 #if 1
10214       /* !!! TEST ONLY !!! */
10215       if (IS_CUSTOM_ELEMENT(old_element))
10216         CheckElementChangeByPlayer(old_jx, old_jy, old_element,
10217                                    CE_LEFT_BY_PLAYER,
10218                                    player->index_bit, leave_side);
10219
10220       CheckTriggeredElementChangeByPlayer(old_jx, old_jy, old_element,
10221                                           CE_OTHER_GETS_LEFT,
10222                                           player->index_bit, leave_side);
10223
10224       if (IS_CUSTOM_ELEMENT(new_element))
10225         CheckElementChangeByPlayer(jx, jy, new_element, CE_ENTERED_BY_PLAYER,
10226                                    player->index_bit, enter_side);
10227
10228       CheckTriggeredElementChangeByPlayer(jx, jy, new_element,
10229                                           CE_OTHER_GETS_ENTERED,
10230                                           player->index_bit, enter_side);
10231 #endif
10232
10233     }
10234 #endif
10235
10236     if (game.engine_version >= VERSION_IDENT(3,0,7,0))
10237     {
10238       TestIfHeroTouchesBadThing(jx, jy);
10239       TestIfPlayerTouchesCustomElement(jx, jy);
10240 #if 1
10241 #if 1
10242       /* needed because pushed element has not yet reached its destination,
10243          so it would trigger a change event at its previous field location */
10244       if (!player->is_pushing)
10245 #endif
10246         TestIfElementTouchesCustomElement(jx, jy);      /* for empty space */
10247 #endif
10248
10249       if (!player->active)
10250         RemoveHero(player);
10251     }
10252
10253     if (level.use_step_counter)
10254     {
10255       int i;
10256
10257       TimePlayed++;
10258
10259       if (TimeLeft > 0)
10260       {
10261         TimeLeft--;
10262
10263         if (TimeLeft <= 10 && setup.time_limit)
10264           PlaySoundStereo(SND_GAME_RUNNING_OUT_OF_TIME, SOUND_MIDDLE);
10265
10266         DrawGameValue_Time(TimeLeft);
10267
10268         if (!TimeLeft && setup.time_limit)
10269           for (i = 0; i < MAX_PLAYERS; i++)
10270             KillHero(&stored_player[i]);
10271       }
10272       else if (level.time == 0 && !AllPlayersGone) /* level w/o time limit */
10273         DrawGameValue_Time(TimePlayed);
10274     }
10275
10276     if (tape.single_step && tape.recording && !tape.pausing &&
10277         !player->programmed_action)
10278       TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
10279   }
10280 }
10281
10282 void ScrollScreen(struct PlayerInfo *player, int mode)
10283 {
10284   static unsigned long screen_frame_counter = 0;
10285
10286   if (mode == SCROLL_INIT)
10287   {
10288     /* set scrolling step size according to actual player's moving speed */
10289     ScrollStepSize = TILEX / player->move_delay_value;
10290
10291     screen_frame_counter = FrameCounter;
10292     ScreenMovDir = player->MovDir;
10293     ScreenMovPos = player->MovPos;
10294     ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
10295     return;
10296   }
10297   else if (!FrameReached(&screen_frame_counter, 1))
10298     return;
10299
10300   if (ScreenMovPos)
10301   {
10302     ScreenMovPos += (ScreenMovPos > 0 ? -1 : 1) * ScrollStepSize;
10303     ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
10304     redraw_mask |= REDRAW_FIELD;
10305   }
10306   else
10307     ScreenMovDir = MV_NO_MOVING;
10308 }
10309
10310 void TestIfPlayerTouchesCustomElement(int x, int y)
10311 {
10312   static int xy[4][2] =
10313   {
10314     { 0, -1 },
10315     { -1, 0 },
10316     { +1, 0 },
10317     { 0, +1 }
10318   };
10319   static int trigger_sides[4][2] =
10320   {
10321     /* center side       border side */
10322     { CH_SIDE_TOP,      CH_SIDE_BOTTOM  },      /* check top    */
10323     { CH_SIDE_LEFT,     CH_SIDE_RIGHT   },      /* check left   */
10324     { CH_SIDE_RIGHT,    CH_SIDE_LEFT    },      /* check right  */
10325     { CH_SIDE_BOTTOM,   CH_SIDE_TOP     }       /* check bottom */
10326   };
10327   static int touch_dir[4] =
10328   {
10329     MV_LEFT | MV_RIGHT,
10330     MV_UP   | MV_DOWN,
10331     MV_UP   | MV_DOWN,
10332     MV_LEFT | MV_RIGHT
10333   };
10334   int center_element = Feld[x][y];      /* should always be non-moving! */
10335   int i;
10336
10337   for (i = 0; i < NUM_DIRECTIONS; i++)
10338   {
10339     int xx = x + xy[i][0];
10340     int yy = y + xy[i][1];
10341     int center_side = trigger_sides[i][0];
10342     int border_side = trigger_sides[i][1];
10343     int border_element;
10344
10345     if (!IN_LEV_FIELD(xx, yy))
10346       continue;
10347
10348     if (IS_PLAYER(x, y))
10349     {
10350       struct PlayerInfo *player = PLAYERINFO(x, y);
10351
10352       if (game.engine_version < VERSION_IDENT(3,0,7,0))
10353         border_element = Feld[xx][yy];          /* may be moving! */
10354       else if (!IS_MOVING(xx, yy) && !IS_BLOCKED(xx, yy))
10355         border_element = Feld[xx][yy];
10356       else if (MovDir[xx][yy] & touch_dir[i])   /* elements are touching */
10357         border_element = MovingOrBlocked2Element(xx, yy);
10358       else
10359         continue;               /* center and border element do not touch */
10360
10361 #if 1
10362       /* !!! TEST ONLY !!! */
10363       CheckElementChangeByPlayer(xx, yy, border_element, CE_TOUCHED_BY_PLAYER,
10364                                  player->index_bit, border_side);
10365       CheckTriggeredElementChangeByPlayer(xx, yy, border_element,
10366                                           CE_OTHER_GETS_TOUCHED,
10367                                           player->index_bit, border_side);
10368 #else
10369       CheckTriggeredElementChangeByPlayer(xx, yy, border_element,
10370                                           CE_OTHER_GETS_TOUCHED,
10371                                           player->index_bit, border_side);
10372       CheckElementChangeByPlayer(xx, yy, border_element, CE_TOUCHED_BY_PLAYER,
10373                                  player->index_bit, border_side);
10374 #endif
10375     }
10376     else if (IS_PLAYER(xx, yy))
10377     {
10378       struct PlayerInfo *player = PLAYERINFO(xx, yy);
10379
10380       if (game.engine_version >= VERSION_IDENT(3,0,7,0))
10381       {
10382         if (player->MovPos != 0 && !(player->MovDir & touch_dir[i]))
10383           continue;             /* center and border element do not touch */
10384       }
10385
10386 #if 1
10387       /* !!! TEST ONLY !!! */
10388       CheckElementChangeByPlayer(x, y, center_element, CE_TOUCHED_BY_PLAYER,
10389                                  player->index_bit, center_side);
10390       CheckTriggeredElementChangeByPlayer(x, y, center_element,
10391                                           CE_OTHER_GETS_TOUCHED,
10392                                           player->index_bit, center_side);
10393 #else
10394       CheckTriggeredElementChangeByPlayer(x, y, center_element,
10395                                           CE_OTHER_GETS_TOUCHED,
10396                                           player->index_bit, center_side);
10397       CheckElementChangeByPlayer(x, y, center_element, CE_TOUCHED_BY_PLAYER,
10398                                  player->index_bit, center_side);
10399 #endif
10400
10401       break;
10402     }
10403   }
10404 }
10405
10406 void TestIfElementTouchesCustomElement(int x, int y)
10407 {
10408   static int xy[4][2] =
10409   {
10410     { 0, -1 },
10411     { -1, 0 },
10412     { +1, 0 },
10413     { 0, +1 }
10414   };
10415   static int trigger_sides[4][2] =
10416   {
10417     /* center side      border side */
10418     { CH_SIDE_TOP,      CH_SIDE_BOTTOM  },      /* check top    */
10419     { CH_SIDE_LEFT,     CH_SIDE_RIGHT   },      /* check left   */
10420     { CH_SIDE_RIGHT,    CH_SIDE_LEFT    },      /* check right  */
10421     { CH_SIDE_BOTTOM,   CH_SIDE_TOP     }       /* check bottom */
10422   };
10423   static int touch_dir[4] =
10424   {
10425     MV_LEFT | MV_RIGHT,
10426     MV_UP   | MV_DOWN,
10427     MV_UP   | MV_DOWN,
10428     MV_LEFT | MV_RIGHT
10429   };
10430   boolean change_center_element = FALSE;
10431   int center_element_change_page = 0;
10432   int center_element = Feld[x][y];      /* should always be non-moving! */
10433   int border_trigger_element = EL_UNDEFINED;
10434   int i, j;
10435
10436   for (i = 0; i < NUM_DIRECTIONS; i++)
10437   {
10438     int xx = x + xy[i][0];
10439     int yy = y + xy[i][1];
10440     int center_side = trigger_sides[i][0];
10441     int border_side = trigger_sides[i][1];
10442     int border_element;
10443
10444     if (!IN_LEV_FIELD(xx, yy))
10445       continue;
10446
10447     if (game.engine_version < VERSION_IDENT(3,0,7,0))
10448       border_element = Feld[xx][yy];    /* may be moving! */
10449     else if (!IS_MOVING(xx, yy) && !IS_BLOCKED(xx, yy))
10450       border_element = Feld[xx][yy];
10451     else if (MovDir[xx][yy] & touch_dir[i])     /* elements are touching */
10452       border_element = MovingOrBlocked2Element(xx, yy);
10453     else
10454       continue;                 /* center and border element do not touch */
10455
10456     /* check for change of center element (but change it only once) */
10457     if (IS_CUSTOM_ELEMENT(center_element) &&
10458         HAS_ANY_CHANGE_EVENT(center_element, CE_OTHER_IS_TOUCHING) &&
10459         !change_center_element)
10460     {
10461       for (j = 0; j < element_info[center_element].num_change_pages; j++)
10462       {
10463         struct ElementChangeInfo *change =
10464           &element_info[center_element].change_page[j];
10465
10466         if (change->can_change &&
10467             change->events & CH_EVENT_BIT(CE_OTHER_IS_TOUCHING) &&
10468             change->trigger_side & border_side &&
10469 #if 1
10470             IS_EQUAL_OR_IN_GROUP(border_element, change->trigger_element)
10471 #else
10472             change->trigger_element == border_element
10473 #endif
10474             )
10475         {
10476           change_center_element = TRUE;
10477           center_element_change_page = j;
10478           border_trigger_element = border_element;
10479
10480           break;
10481         }
10482       }
10483     }
10484
10485     /* check for change of border element */
10486     if (IS_CUSTOM_ELEMENT(border_element) &&
10487         HAS_ANY_CHANGE_EVENT(border_element, CE_OTHER_IS_TOUCHING))
10488     {
10489       for (j = 0; j < element_info[border_element].num_change_pages; j++)
10490       {
10491         struct ElementChangeInfo *change =
10492           &element_info[border_element].change_page[j];
10493
10494         if (change->can_change &&
10495             change->events & CH_EVENT_BIT(CE_OTHER_IS_TOUCHING) &&
10496             change->trigger_side & center_side &&
10497 #if 1
10498             IS_EQUAL_OR_IN_GROUP(center_element, change->trigger_element)
10499 #else
10500             change->trigger_element == center_element
10501 #endif
10502             )
10503         {
10504 #if 0
10505           printf("::: border_element %d, %d\n", x, y);
10506 #endif
10507
10508           CheckElementChangeByPage(xx, yy, border_element, center_element,
10509                                    CE_OTHER_IS_TOUCHING, j);
10510           break;
10511         }
10512       }
10513     }
10514   }
10515
10516   if (change_center_element)
10517   {
10518 #if 0
10519     printf("::: center_element %d, %d\n", x, y);
10520 #endif
10521
10522     CheckElementChangeByPage(x, y, center_element, border_trigger_element,
10523                              CE_OTHER_IS_TOUCHING, center_element_change_page);
10524   }
10525 }
10526
10527 void TestIfElementHitsCustomElement(int x, int y, int direction)
10528 {
10529   int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
10530   int dy = (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
10531   int hitx = x + dx, hity = y + dy;
10532   int hitting_element = Feld[x][y];
10533   int touched_element;
10534 #if 0
10535   boolean object_hit = (IN_LEV_FIELD(hitx, hity) &&
10536                         !IS_FREE(hitx, hity) &&
10537                         (!IS_MOVING(hitx, hity) ||
10538                          MovDir[hitx][hity] != direction ||
10539                          ABS(MovPos[hitx][hity]) <= TILEY / 2));
10540 #endif
10541
10542   if (IN_LEV_FIELD(hitx, hity) && IS_FREE(hitx, hity))
10543     return;
10544
10545 #if 0
10546   if (IN_LEV_FIELD(hitx, hity) && !object_hit)
10547     return;
10548 #endif
10549
10550   touched_element = (IN_LEV_FIELD(hitx, hity) ?
10551                      MovingOrBlocked2Element(hitx, hity) : EL_STEELWALL);
10552
10553   CheckElementChangeBySide(x, y, hitting_element, touched_element,
10554                            CE_HITTING_SOMETHING, direction);
10555
10556   if (IN_LEV_FIELD(hitx, hity))
10557   {
10558     int opposite_direction = MV_DIR_OPPOSITE(direction);
10559     int hitting_side = direction;
10560     int touched_side = opposite_direction;
10561 #if 0
10562     int touched_element = MovingOrBlocked2Element(hitx, hity);
10563 #endif
10564 #if 1
10565     boolean object_hit = (!IS_MOVING(hitx, hity) ||
10566                           MovDir[hitx][hity] != direction ||
10567                           ABS(MovPos[hitx][hity]) <= TILEY / 2);
10568
10569     object_hit = TRUE;
10570 #endif
10571
10572     if (object_hit)
10573     {
10574       int i;
10575
10576       CheckElementChangeBySide(hitx, hity, touched_element, hitting_element,
10577                                CE_HIT_BY_SOMETHING, opposite_direction);
10578
10579       if (IS_CUSTOM_ELEMENT(hitting_element) &&
10580           HAS_ANY_CHANGE_EVENT(hitting_element, CE_OTHER_IS_HITTING))
10581       {
10582         for (i = 0; i < element_info[hitting_element].num_change_pages; i++)
10583         {
10584           struct ElementChangeInfo *change =
10585             &element_info[hitting_element].change_page[i];
10586
10587           if (change->can_change &&
10588               change->events & CH_EVENT_BIT(CE_OTHER_IS_HITTING) &&
10589               change->trigger_side & touched_side &&
10590           
10591 #if 1
10592               IS_EQUAL_OR_IN_GROUP(touched_element, change->trigger_element)
10593 #else
10594               change->trigger_element == touched_element
10595 #endif
10596               )
10597           {
10598             CheckElementChangeByPage(x, y, hitting_element, touched_element,
10599                                      CE_OTHER_IS_HITTING, i);
10600             break;
10601           }
10602         }
10603       }
10604
10605       if (IS_CUSTOM_ELEMENT(touched_element) &&
10606           HAS_ANY_CHANGE_EVENT(touched_element, CE_OTHER_GETS_HIT))
10607       {
10608         for (i = 0; i < element_info[touched_element].num_change_pages; i++)
10609         {
10610           struct ElementChangeInfo *change =
10611             &element_info[touched_element].change_page[i];
10612
10613           if (change->can_change &&
10614               change->events & CH_EVENT_BIT(CE_OTHER_GETS_HIT) &&
10615               change->trigger_side & hitting_side &&
10616 #if 1
10617               IS_EQUAL_OR_IN_GROUP(hitting_element, change->trigger_element)
10618 #else
10619               change->trigger_element == hitting_element
10620 #endif
10621               )
10622           {
10623             CheckElementChangeByPage(hitx, hity, touched_element,
10624                                      hitting_element, CE_OTHER_GETS_HIT, i);
10625             break;
10626           }
10627         }
10628       }
10629     }
10630   }
10631 }
10632
10633 #if 0
10634 void TestIfElementSmashesCustomElement(int x, int y, int direction)
10635 {
10636   int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
10637   int dy = (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
10638   int hitx = x + dx, hity = y + dy;
10639   int hitting_element = Feld[x][y];
10640   int touched_element;
10641 #if 0
10642   boolean object_hit = (IN_LEV_FIELD(hitx, hity) &&
10643                         !IS_FREE(hitx, hity) &&
10644                         (!IS_MOVING(hitx, hity) ||
10645                          MovDir[hitx][hity] != direction ||
10646                          ABS(MovPos[hitx][hity]) <= TILEY / 2));
10647 #endif
10648
10649   if (IN_LEV_FIELD(hitx, hity) && IS_FREE(hitx, hity))
10650     return;
10651
10652 #if 0
10653   if (IN_LEV_FIELD(hitx, hity) && !object_hit)
10654     return;
10655 #endif
10656
10657   touched_element = (IN_LEV_FIELD(hitx, hity) ?
10658                      MovingOrBlocked2Element(hitx, hity) : EL_STEELWALL);
10659
10660   CheckElementChangeBySide(x, y, hitting_element, touched_element,
10661                            EP_CAN_SMASH_EVERYTHING, direction);
10662
10663   if (IN_LEV_FIELD(hitx, hity))
10664   {
10665     int opposite_direction = MV_DIR_OPPOSITE(direction);
10666     int hitting_side = direction;
10667     int touched_side = opposite_direction;
10668 #if 0
10669     int touched_element = MovingOrBlocked2Element(hitx, hity);
10670 #endif
10671 #if 1
10672     boolean object_hit = (!IS_MOVING(hitx, hity) ||
10673                           MovDir[hitx][hity] != direction ||
10674                           ABS(MovPos[hitx][hity]) <= TILEY / 2);
10675
10676     object_hit = TRUE;
10677 #endif
10678
10679     if (object_hit)
10680     {
10681       int i;
10682
10683       CheckElementChangeBySide(hitx, hity, touched_element, hitting_element,
10684                                CE_SMASHED_BY_SOMETHING, opposite_direction);
10685
10686       if (IS_CUSTOM_ELEMENT(hitting_element) &&
10687           HAS_ANY_CHANGE_EVENT(hitting_element, CE_OTHER_IS_SMASHING))
10688       {
10689         for (i = 0; i < element_info[hitting_element].num_change_pages; i++)
10690         {
10691           struct ElementChangeInfo *change =
10692             &element_info[hitting_element].change_page[i];
10693
10694           if (change->can_change &&
10695               change->events & CH_EVENT_BIT(CE_OTHER_IS_SMASHING) &&
10696               change->trigger_side & touched_side &&
10697           
10698 #if 1
10699               IS_EQUAL_OR_IN_GROUP(touched_element, change->trigger_element)
10700 #else
10701               change->trigger_element == touched_element
10702 #endif
10703               )
10704           {
10705             CheckElementChangeByPage(x, y, hitting_element, touched_element,
10706                                      CE_OTHER_IS_SMASHING, i);
10707             break;
10708           }
10709         }
10710       }
10711
10712       if (IS_CUSTOM_ELEMENT(touched_element) &&
10713           HAS_ANY_CHANGE_EVENT(touched_element, CE_OTHER_GETS_SMASHED))
10714       {
10715         for (i = 0; i < element_info[touched_element].num_change_pages; i++)
10716         {
10717           struct ElementChangeInfo *change =
10718             &element_info[touched_element].change_page[i];
10719
10720           if (change->can_change &&
10721               change->events & CH_EVENT_BIT(CE_OTHER_GETS_SMASHED) &&
10722               change->trigger_side & hitting_side &&
10723 #if 1
10724               IS_EQUAL_OR_IN_GROUP(hitting_element, change->trigger_element)
10725 #else
10726               change->trigger_element == hitting_element
10727 #endif
10728               )
10729           {
10730             CheckElementChangeByPage(hitx, hity, touched_element,
10731                                      hitting_element, CE_OTHER_GETS_SMASHED,i);
10732             break;
10733           }
10734         }
10735       }
10736     }
10737   }
10738 }
10739 #endif
10740
10741 void TestIfGoodThingHitsBadThing(int good_x, int good_y, int good_move_dir)
10742 {
10743   int i, kill_x = -1, kill_y = -1;
10744   int bad_element = -1;
10745   static int test_xy[4][2] =
10746   {
10747     { 0, -1 },
10748     { -1, 0 },
10749     { +1, 0 },
10750     { 0, +1 }
10751   };
10752   static int test_dir[4] =
10753   {
10754     MV_UP,
10755     MV_LEFT,
10756     MV_RIGHT,
10757     MV_DOWN
10758   };
10759
10760   for (i = 0; i < NUM_DIRECTIONS; i++)
10761   {
10762     int test_x, test_y, test_move_dir, test_element;
10763
10764     test_x = good_x + test_xy[i][0];
10765     test_y = good_y + test_xy[i][1];
10766
10767     if (!IN_LEV_FIELD(test_x, test_y))
10768       continue;
10769
10770     test_move_dir =
10771       (IS_MOVING(test_x, test_y) ? MovDir[test_x][test_y] : MV_NO_MOVING);
10772
10773 #if 0
10774     test_element = Feld[test_x][test_y];
10775 #else
10776     test_element = MovingOrBlocked2ElementIfNotLeaving(test_x, test_y);
10777 #endif
10778
10779     /* 1st case: good thing is moving towards DONT_RUN_INTO style bad thing;
10780        2nd case: DONT_TOUCH style bad thing does not move away from good thing
10781     */
10782     if ((DONT_RUN_INTO(test_element) && good_move_dir == test_dir[i]) ||
10783         (DONT_TOUCH(test_element)    && test_move_dir != test_dir[i]))
10784     {
10785       kill_x = test_x;
10786       kill_y = test_y;
10787       bad_element = test_element;
10788
10789       break;
10790     }
10791   }
10792
10793   if (kill_x != -1 || kill_y != -1)
10794   {
10795     if (IS_PLAYER(good_x, good_y))
10796     {
10797       struct PlayerInfo *player = PLAYERINFO(good_x, good_y);
10798
10799 #if 1
10800       if (player->shield_deadly_time_left > 0 &&
10801           !IS_INDESTRUCTIBLE(bad_element))
10802         Bang(kill_x, kill_y);
10803       else if (!PLAYER_ENEMY_PROTECTED(good_x, good_y))
10804         KillHero(player);
10805 #else
10806       if (player->shield_deadly_time_left > 0)
10807         Bang(kill_x, kill_y);
10808       else if (!PLAYER_ENEMY_PROTECTED(good_x, good_y))
10809         KillHero(player);
10810 #endif
10811     }
10812     else
10813       Bang(good_x, good_y);
10814   }
10815 }
10816
10817 void TestIfBadThingHitsGoodThing(int bad_x, int bad_y, int bad_move_dir)
10818 {
10819   int i, kill_x = -1, kill_y = -1;
10820   int bad_element = Feld[bad_x][bad_y];
10821   static int test_xy[4][2] =
10822   {
10823     { 0, -1 },
10824     { -1, 0 },
10825     { +1, 0 },
10826     { 0, +1 }
10827   };
10828   static int touch_dir[4] =
10829   {
10830     MV_LEFT | MV_RIGHT,
10831     MV_UP   | MV_DOWN,
10832     MV_UP   | MV_DOWN,
10833     MV_LEFT | MV_RIGHT
10834   };
10835   static int test_dir[4] =
10836   {
10837     MV_UP,
10838     MV_LEFT,
10839     MV_RIGHT,
10840     MV_DOWN
10841   };
10842
10843   if (bad_element == EL_EXPLOSION)      /* skip just exploding bad things */
10844     return;
10845
10846   for (i = 0; i < NUM_DIRECTIONS; i++)
10847   {
10848     int test_x, test_y, test_move_dir, test_element;
10849
10850     test_x = bad_x + test_xy[i][0];
10851     test_y = bad_y + test_xy[i][1];
10852     if (!IN_LEV_FIELD(test_x, test_y))
10853       continue;
10854
10855     test_move_dir =
10856       (IS_MOVING(test_x, test_y) ? MovDir[test_x][test_y] : MV_NO_MOVING);
10857
10858     test_element = Feld[test_x][test_y];
10859
10860     /* 1st case: good thing is moving towards DONT_RUN_INTO style bad thing;
10861        2nd case: DONT_TOUCH style bad thing does not move away from good thing
10862     */
10863     if ((DONT_RUN_INTO(bad_element) &&  bad_move_dir == test_dir[i]) ||
10864         (DONT_TOUCH(bad_element)    && test_move_dir != test_dir[i]))
10865     {
10866       /* good thing is player or penguin that does not move away */
10867       if (IS_PLAYER(test_x, test_y))
10868       {
10869         struct PlayerInfo *player = PLAYERINFO(test_x, test_y);
10870
10871         if (bad_element == EL_ROBOT && player->is_moving)
10872           continue;     /* robot does not kill player if he is moving */
10873
10874         if (game.engine_version >= VERSION_IDENT(3,0,7,0))
10875         {
10876           if (player->MovPos != 0 && !(player->MovDir & touch_dir[i]))
10877             continue;           /* center and border element do not touch */
10878         }
10879
10880         kill_x = test_x;
10881         kill_y = test_y;
10882         break;
10883       }
10884       else if (test_element == EL_PENGUIN)
10885       {
10886         kill_x = test_x;
10887         kill_y = test_y;
10888         break;
10889       }
10890     }
10891   }
10892
10893   if (kill_x != -1 || kill_y != -1)
10894   {
10895     if (IS_PLAYER(kill_x, kill_y))
10896     {
10897       struct PlayerInfo *player = PLAYERINFO(kill_x, kill_y);
10898
10899 #if 1
10900       if (player->shield_deadly_time_left > 0 &&
10901           !IS_INDESTRUCTIBLE(bad_element))
10902         Bang(bad_x, bad_y);
10903       else if (!PLAYER_ENEMY_PROTECTED(kill_x, kill_y))
10904         KillHero(player);
10905 #else
10906       if (player->shield_deadly_time_left > 0)
10907         Bang(bad_x, bad_y);
10908       else if (!PLAYER_ENEMY_PROTECTED(kill_x, kill_y))
10909         KillHero(player);
10910 #endif
10911     }
10912     else
10913       Bang(kill_x, kill_y);
10914   }
10915 }
10916
10917 void TestIfHeroTouchesBadThing(int x, int y)
10918 {
10919   TestIfGoodThingHitsBadThing(x, y, MV_NO_MOVING);
10920 }
10921
10922 void TestIfHeroRunsIntoBadThing(int x, int y, int move_dir)
10923 {
10924   TestIfGoodThingHitsBadThing(x, y, move_dir);
10925 }
10926
10927 void TestIfBadThingTouchesHero(int x, int y)
10928 {
10929   TestIfBadThingHitsGoodThing(x, y, MV_NO_MOVING);
10930 }
10931
10932 void TestIfBadThingRunsIntoHero(int x, int y, int move_dir)
10933 {
10934   TestIfBadThingHitsGoodThing(x, y, move_dir);
10935 }
10936
10937 void TestIfFriendTouchesBadThing(int x, int y)
10938 {
10939   TestIfGoodThingHitsBadThing(x, y, MV_NO_MOVING);
10940 }
10941
10942 void TestIfBadThingTouchesFriend(int x, int y)
10943 {
10944   TestIfBadThingHitsGoodThing(x, y, MV_NO_MOVING);
10945 }
10946
10947 void TestIfBadThingTouchesOtherBadThing(int bad_x, int bad_y)
10948 {
10949   int i, kill_x = bad_x, kill_y = bad_y;
10950   static int xy[4][2] =
10951   {
10952     { 0, -1 },
10953     { -1, 0 },
10954     { +1, 0 },
10955     { 0, +1 }
10956   };
10957
10958   for (i = 0; i < NUM_DIRECTIONS; i++)
10959   {
10960     int x, y, element;
10961
10962     x = bad_x + xy[i][0];
10963     y = bad_y + xy[i][1];
10964     if (!IN_LEV_FIELD(x, y))
10965       continue;
10966
10967     element = Feld[x][y];
10968     if (IS_AMOEBOID(element) || element == EL_GAME_OF_LIFE ||
10969         element == EL_AMOEBA_GROWING || element == EL_AMOEBA_DROP)
10970     {
10971       kill_x = x;
10972       kill_y = y;
10973       break;
10974     }
10975   }
10976
10977   if (kill_x != bad_x || kill_y != bad_y)
10978     Bang(bad_x, bad_y);
10979 }
10980
10981 void KillHero(struct PlayerInfo *player)
10982 {
10983   int jx = player->jx, jy = player->jy;
10984
10985   if (!player->active)
10986     return;
10987
10988   /* remove accessible field at the player's position */
10989   Feld[jx][jy] = EL_EMPTY;
10990
10991   /* deactivate shield (else Bang()/Explode() would not work right) */
10992   player->shield_normal_time_left = 0;
10993   player->shield_deadly_time_left = 0;
10994
10995   Bang(jx, jy);
10996   BuryHero(player);
10997 }
10998
10999 static void KillHeroUnlessEnemyProtected(int x, int y)
11000 {
11001   if (!PLAYER_ENEMY_PROTECTED(x, y))
11002     KillHero(PLAYERINFO(x, y));
11003 }
11004
11005 static void KillHeroUnlessExplosionProtected(int x, int y)
11006 {
11007   if (!PLAYER_EXPLOSION_PROTECTED(x, y))
11008     KillHero(PLAYERINFO(x, y));
11009 }
11010
11011 void BuryHero(struct PlayerInfo *player)
11012 {
11013   int jx = player->jx, jy = player->jy;
11014
11015   if (!player->active)
11016     return;
11017
11018 #if 1
11019   PlayLevelSoundElementAction(jx, jy, player->element_nr, ACTION_DYING);
11020 #else
11021   PlayLevelSound(jx, jy, SND_CLASS_PLAYER_DYING);
11022 #endif
11023   PlayLevelSound(jx, jy, SND_GAME_LOSING);
11024
11025   player->GameOver = TRUE;
11026   RemoveHero(player);
11027 }
11028
11029 void RemoveHero(struct PlayerInfo *player)
11030 {
11031   int jx = player->jx, jy = player->jy;
11032   int i, found = FALSE;
11033
11034   player->present = FALSE;
11035   player->active = FALSE;
11036
11037   if (!ExplodeField[jx][jy])
11038     StorePlayer[jx][jy] = 0;
11039
11040   for (i = 0; i < MAX_PLAYERS; i++)
11041     if (stored_player[i].active)
11042       found = TRUE;
11043
11044   if (!found)
11045     AllPlayersGone = TRUE;
11046
11047   ExitX = ZX = jx;
11048   ExitY = ZY = jy;
11049 }
11050
11051 /*
11052   =============================================================================
11053   checkDiagonalPushing()
11054   -----------------------------------------------------------------------------
11055   check if diagonal input device direction results in pushing of object
11056   (by checking if the alternative direction is walkable, diggable, ...)
11057   =============================================================================
11058 */
11059
11060 static boolean checkDiagonalPushing(struct PlayerInfo *player,
11061                                     int x, int y, int real_dx, int real_dy)
11062 {
11063   int jx, jy, dx, dy, xx, yy;
11064
11065   if (real_dx == 0 || real_dy == 0)     /* no diagonal direction => push */
11066     return TRUE;
11067
11068   /* diagonal direction: check alternative direction */
11069   jx = player->jx;
11070   jy = player->jy;
11071   dx = x - jx;
11072   dy = y - jy;
11073   xx = jx + (dx == 0 ? real_dx : 0);
11074   yy = jy + (dy == 0 ? real_dy : 0);
11075
11076   return (!IN_LEV_FIELD(xx, yy) || IS_SOLID_FOR_PUSHING(Feld[xx][yy]));
11077 }
11078
11079 /*
11080   =============================================================================
11081   DigField()
11082   -----------------------------------------------------------------------------
11083   x, y:                 field next to player (non-diagonal) to try to dig to
11084   real_dx, real_dy:     direction as read from input device (can be diagonal)
11085   =============================================================================
11086 */
11087
11088 int DigField(struct PlayerInfo *player,
11089              int oldx, int oldy, int x, int y,
11090              int real_dx, int real_dy, int mode)
11091 {
11092 #if 0
11093   boolean use_spring_bug = (game.engine_version < VERSION_IDENT(2,2,0,0));
11094 #endif
11095   boolean is_player = (IS_PLAYER(oldx, oldy) || mode != DF_DIG);
11096   boolean player_was_pushing = player->is_pushing;
11097   int jx = oldx, jy = oldy;
11098   int dx = x - jx, dy = y - jy;
11099   int nextx = x + dx, nexty = y + dy;
11100   int move_direction = (dx == -1 ? MV_LEFT :
11101                         dx == +1 ? MV_RIGHT :
11102                         dy == -1 ? MV_UP :
11103                         dy == +1 ? MV_DOWN : MV_NO_MOVING);
11104   int opposite_direction = MV_DIR_OPPOSITE(move_direction);
11105 #if 1
11106   int dig_side = MV_DIR_OPPOSITE(move_direction);
11107 #else
11108   static int trigger_sides[4] =
11109   {
11110     CH_SIDE_RIGHT,      /* moving left  */
11111     CH_SIDE_LEFT,       /* moving right */
11112     CH_SIDE_BOTTOM,     /* moving up    */
11113     CH_SIDE_TOP,        /* moving down  */
11114   };
11115   int dig_side = trigger_sides[MV_DIR_BIT(move_direction)];
11116 #endif
11117   int old_element = Feld[jx][jy];
11118   int element;
11119
11120   if (is_player)                /* function can also be called by EL_PENGUIN */
11121   {
11122     if (player->MovPos == 0)
11123     {
11124       player->is_digging = FALSE;
11125       player->is_collecting = FALSE;
11126     }
11127
11128     if (player->MovPos == 0)    /* last pushing move finished */
11129       player->is_pushing = FALSE;
11130
11131     if (mode == DF_NO_PUSH)     /* player just stopped pushing */
11132     {
11133       player->is_switching = FALSE;
11134 #if USE_NEW_PUSH_DELAY
11135       player->push_delay = -1;
11136 #else
11137       player->push_delay = 0;
11138 #endif
11139
11140       return MF_NO_ACTION;
11141     }
11142   }
11143
11144   if (IS_MOVING(x, y) || IS_PLAYER(x, y))
11145     return MF_NO_ACTION;
11146
11147 #if 0
11148
11149 #if 0
11150   if (IS_TUBE(Feld[jx][jy]) || IS_TUBE(Back[jx][jy]))
11151 #else
11152   if (IS_TUBE(Feld[jx][jy]) ||
11153       (IS_TUBE(Back[jx][jy]) && game.engine_version >= VERSION_IDENT(2,2,0,0)))
11154 #endif
11155   {
11156     int i = 0;
11157     int tube_element = (IS_TUBE(Feld[jx][jy]) ? Feld[jx][jy] : Back[jx][jy]);
11158     int tube_leave_directions[][2] =
11159     {
11160       { EL_TUBE_ANY,                    MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN },
11161       { EL_TUBE_VERTICAL,                                    MV_UP | MV_DOWN },
11162       { EL_TUBE_HORIZONTAL,             MV_LEFT | MV_RIGHT                   },
11163       { EL_TUBE_VERTICAL_LEFT,          MV_LEFT |            MV_UP | MV_DOWN },
11164       { EL_TUBE_VERTICAL_RIGHT,                   MV_RIGHT | MV_UP | MV_DOWN },
11165       { EL_TUBE_HORIZONTAL_UP,          MV_LEFT | MV_RIGHT | MV_UP           },
11166       { EL_TUBE_HORIZONTAL_DOWN,        MV_LEFT | MV_RIGHT |         MV_DOWN },
11167       { EL_TUBE_LEFT_UP,                MV_LEFT |            MV_UP           },
11168       { EL_TUBE_LEFT_DOWN,              MV_LEFT |                    MV_DOWN },
11169       { EL_TUBE_RIGHT_UP,                         MV_RIGHT | MV_UP           },
11170       { EL_TUBE_RIGHT_DOWN,                       MV_RIGHT |         MV_DOWN },
11171       { -1,                             MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN }
11172     };
11173
11174     while (tube_leave_directions[i][0] != tube_element)
11175     {
11176       i++;
11177       if (tube_leave_directions[i][0] == -1)    /* should not happen */
11178         break;
11179     }
11180
11181     if (!(tube_leave_directions[i][1] & move_direction))
11182       return MF_NO_ACTION;      /* tube has no opening in this direction */
11183   }
11184
11185 #else
11186
11187   if (IS_TUBE(Back[jx][jy]) && game.engine_version >= VERSION_IDENT(2,2,0,0))
11188     old_element = Back[jx][jy];
11189
11190 #endif
11191
11192   if (IS_WALKABLE(old_element) && !ACCESS_FROM(old_element, move_direction))
11193     return MF_NO_ACTION;        /* field has no opening in this direction */
11194
11195   if (IS_PASSABLE(old_element) && !ACCESS_FROM(old_element,opposite_direction))
11196     return MF_NO_ACTION;        /* field has no opening in this direction */
11197
11198   element = Feld[x][y];
11199
11200   if (!is_player && !IS_COLLECTIBLE(element))   /* penguin cannot collect it */
11201     return MF_NO_ACTION;
11202
11203   if (mode == DF_SNAP && !IS_SNAPPABLE(element) &&
11204       game.engine_version >= VERSION_IDENT(2,2,0,0))
11205     return MF_NO_ACTION;
11206
11207 #if 1
11208   if (game.gravity && is_player && !player->is_auto_moving &&
11209       canFallDown(player) && move_direction != MV_DOWN &&
11210       !canMoveToValidFieldWithGravity(jx, jy, move_direction))
11211     return MF_NO_ACTION;        /* player cannot walk here due to gravity */
11212 #endif
11213
11214 #if 0
11215   if (element == EL_EMPTY_SPACE &&
11216       game.gravity && !player->is_auto_moving &&
11217       canFallDown(player) && move_direction != MV_DOWN)
11218     return MF_NO_ACTION;        /* player cannot walk here due to gravity */
11219 #endif
11220
11221   switch (element)
11222   {
11223 #if 0
11224     case EL_SP_PORT_LEFT:
11225     case EL_SP_PORT_RIGHT:
11226     case EL_SP_PORT_UP:
11227     case EL_SP_PORT_DOWN:
11228     case EL_SP_PORT_HORIZONTAL:
11229     case EL_SP_PORT_VERTICAL:
11230     case EL_SP_PORT_ANY:
11231     case EL_SP_GRAVITY_PORT_LEFT:
11232     case EL_SP_GRAVITY_PORT_RIGHT:
11233     case EL_SP_GRAVITY_PORT_UP:
11234     case EL_SP_GRAVITY_PORT_DOWN:
11235 #if 1
11236       if (!canEnterSupaplexPort(x, y, dx, dy))
11237         return MF_NO_ACTION;
11238 #else
11239       if ((dx == -1 &&
11240            element != EL_SP_PORT_LEFT &&
11241            element != EL_SP_GRAVITY_PORT_LEFT &&
11242            element != EL_SP_PORT_HORIZONTAL &&
11243            element != EL_SP_PORT_ANY) ||
11244           (dx == +1 &&
11245            element != EL_SP_PORT_RIGHT &&
11246            element != EL_SP_GRAVITY_PORT_RIGHT &&
11247            element != EL_SP_PORT_HORIZONTAL &&
11248            element != EL_SP_PORT_ANY) ||
11249           (dy == -1 &&
11250            element != EL_SP_PORT_UP &&
11251            element != EL_SP_GRAVITY_PORT_UP &&
11252            element != EL_SP_PORT_VERTICAL &&
11253            element != EL_SP_PORT_ANY) ||
11254           (dy == +1 &&
11255            element != EL_SP_PORT_DOWN &&
11256            element != EL_SP_GRAVITY_PORT_DOWN &&
11257            element != EL_SP_PORT_VERTICAL &&
11258            element != EL_SP_PORT_ANY) ||
11259           !IN_LEV_FIELD(nextx, nexty) ||
11260           !IS_FREE(nextx, nexty))
11261         return MF_NO_ACTION;
11262 #endif
11263
11264       if (element == EL_SP_GRAVITY_PORT_LEFT ||
11265           element == EL_SP_GRAVITY_PORT_RIGHT ||
11266           element == EL_SP_GRAVITY_PORT_UP ||
11267           element == EL_SP_GRAVITY_PORT_DOWN)
11268         game.gravity = !game.gravity;
11269
11270       /* automatically move to the next field with double speed */
11271       player->programmed_action = move_direction;
11272 #if 1
11273       if (player->move_delay_reset_counter == 0)
11274       {
11275         player->move_delay_reset_counter = 2;   /* two double speed steps */
11276
11277         DOUBLE_PLAYER_SPEED(player);
11278       }
11279 #else
11280       player->move_delay_reset_counter = 2;
11281
11282       DOUBLE_PLAYER_SPEED(player);
11283 #endif
11284
11285 #if 0
11286       printf("::: passing port %d,%d [%d]\n", x, y, FrameCounter);
11287 #endif
11288
11289       PlayLevelSound(x, y, SND_CLASS_SP_PORT_PASSING);
11290       break;
11291 #endif
11292
11293 #if 0
11294     case EL_TUBE_ANY:
11295     case EL_TUBE_VERTICAL:
11296     case EL_TUBE_HORIZONTAL:
11297     case EL_TUBE_VERTICAL_LEFT:
11298     case EL_TUBE_VERTICAL_RIGHT:
11299     case EL_TUBE_HORIZONTAL_UP:
11300     case EL_TUBE_HORIZONTAL_DOWN:
11301     case EL_TUBE_LEFT_UP:
11302     case EL_TUBE_LEFT_DOWN:
11303     case EL_TUBE_RIGHT_UP:
11304     case EL_TUBE_RIGHT_DOWN:
11305       {
11306         int i = 0;
11307         int tube_enter_directions[][2] =
11308         {
11309           { EL_TUBE_ANY,                MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN },
11310           { EL_TUBE_VERTICAL,                                MV_UP | MV_DOWN },
11311           { EL_TUBE_HORIZONTAL,         MV_LEFT | MV_RIGHT                   },
11312           { EL_TUBE_VERTICAL_LEFT,                MV_RIGHT | MV_UP | MV_DOWN },
11313           { EL_TUBE_VERTICAL_RIGHT,     MV_LEFT            | MV_UP | MV_DOWN },
11314           { EL_TUBE_HORIZONTAL_UP,      MV_LEFT | MV_RIGHT |         MV_DOWN },
11315           { EL_TUBE_HORIZONTAL_DOWN,    MV_LEFT | MV_RIGHT | MV_UP           },
11316           { EL_TUBE_LEFT_UP,                      MV_RIGHT |         MV_DOWN },
11317           { EL_TUBE_LEFT_DOWN,                    MV_RIGHT | MV_UP           },
11318           { EL_TUBE_RIGHT_UP,           MV_LEFT |                    MV_DOWN },
11319           { EL_TUBE_RIGHT_DOWN,         MV_LEFT |            MV_UP           },
11320           { -1,                         MV_NO_MOVING                         }
11321         };
11322
11323         while (tube_enter_directions[i][0] != element)
11324         {
11325           i++;
11326           if (tube_enter_directions[i][0] == -1)        /* should not happen */
11327             break;
11328         }
11329
11330         if (!(tube_enter_directions[i][1] & move_direction))
11331           return MF_NO_ACTION;  /* tube has no opening in this direction */
11332
11333         PlayLevelSound(x, y, SND_CLASS_TUBE_WALKING);
11334       }
11335       break;
11336 #endif
11337
11338     default:
11339
11340 #if 1
11341       if (IS_WALKABLE(element) && ACCESS_FROM(element, opposite_direction))
11342 #else
11343       if (IS_WALKABLE(element))
11344 #endif
11345       {
11346         int sound_element = SND_ELEMENT(element);
11347         int sound_action = ACTION_WALKING;
11348
11349 #if 0
11350         if (!ACCESS_FROM(element, opposite_direction))
11351           return MF_NO_ACTION;  /* field not accessible from this direction */
11352 #endif
11353
11354 #if 0
11355         if (element == EL_EMPTY_SPACE &&
11356             game.gravity && !player->is_auto_moving &&
11357             canFallDown(player) && move_direction != MV_DOWN)
11358           return MF_NO_ACTION;  /* player cannot walk here due to gravity */
11359 #endif
11360
11361         if (IS_GATE(element))
11362         {
11363           if (!player->key[element - EL_GATE_1])
11364             return MF_NO_ACTION;
11365         }
11366         else if (IS_GATE_GRAY(element))
11367         {
11368           if (!player->key[element - EL_GATE_1_GRAY])
11369             return MF_NO_ACTION;
11370         }
11371         else if (element == EL_EXIT_OPEN ||
11372                  element == EL_SP_EXIT_OPEN ||
11373                  element == EL_SP_EXIT_OPENING)
11374         {
11375           sound_action = ACTION_PASSING;        /* player is passing exit */
11376         }
11377         else if (element == EL_EMPTY)
11378         {
11379           sound_action = ACTION_MOVING;         /* nothing to walk on */
11380         }
11381
11382         /* play sound from background or player, whatever is available */
11383         if (element_info[sound_element].sound[sound_action] != SND_UNDEFINED)
11384           PlayLevelSoundElementAction(x, y, sound_element, sound_action);
11385         else
11386           PlayLevelSoundElementAction(x, y, player->element_nr, sound_action);
11387
11388         break;
11389       }
11390 #if 1
11391       else if (IS_PASSABLE(element) && canPassField(x, y, move_direction))
11392 #else
11393       else if (IS_PASSABLE(element))
11394 #endif
11395       {
11396 #if 0
11397         if (!canPassField(x, y, move_direction))
11398           return MF_NO_ACTION;
11399 #else
11400
11401 #if 0
11402 #if 1
11403         if (!IN_LEV_FIELD(nextx, nexty) || IS_PLAYER(nextx, nexty) ||
11404             !IS_WALKABLE_FROM(Feld[nextx][nexty], move_direction) ||
11405             (!level.can_pass_to_walkable && !IS_FREE(nextx, nexty)))
11406           return MF_NO_ACTION;
11407 #else
11408         if (!IN_LEV_FIELD(nextx, nexty) || !IS_FREE(nextx, nexty))
11409           return MF_NO_ACTION;
11410 #endif
11411 #endif
11412
11413 #if 1
11414         if (!ACCESS_FROM(element, opposite_direction))
11415           return MF_NO_ACTION;  /* field not accessible from this direction */
11416 #else
11417         if (IS_CUSTOM_ELEMENT(element) &&
11418             !ACCESS_FROM(element, opposite_direction))
11419           return MF_NO_ACTION;  /* field not accessible from this direction */
11420 #endif
11421
11422 #if 1
11423         if (CAN_MOVE(element))  /* only fixed elements can be passed! */
11424           return MF_NO_ACTION;
11425 #endif
11426
11427 #endif
11428
11429         if (IS_EM_GATE(element))
11430         {
11431           if (!player->key[element - EL_EM_GATE_1])
11432             return MF_NO_ACTION;
11433         }
11434         else if (IS_EM_GATE_GRAY(element))
11435         {
11436           if (!player->key[element - EL_EM_GATE_1_GRAY])
11437             return MF_NO_ACTION;
11438         }
11439         else if (IS_SP_PORT(element))
11440         {
11441           if (element == EL_SP_GRAVITY_PORT_LEFT ||
11442               element == EL_SP_GRAVITY_PORT_RIGHT ||
11443               element == EL_SP_GRAVITY_PORT_UP ||
11444               element == EL_SP_GRAVITY_PORT_DOWN)
11445             game.gravity = !game.gravity;
11446           else if (element == EL_SP_GRAVITY_ON_PORT_LEFT ||
11447                    element == EL_SP_GRAVITY_ON_PORT_RIGHT ||
11448                    element == EL_SP_GRAVITY_ON_PORT_UP ||
11449                    element == EL_SP_GRAVITY_ON_PORT_DOWN)
11450             game.gravity = TRUE;
11451           else if (element == EL_SP_GRAVITY_OFF_PORT_LEFT ||
11452                    element == EL_SP_GRAVITY_OFF_PORT_RIGHT ||
11453                    element == EL_SP_GRAVITY_OFF_PORT_UP ||
11454                    element == EL_SP_GRAVITY_OFF_PORT_DOWN)
11455             game.gravity = FALSE;
11456         }
11457
11458         /* automatically move to the next field with double speed */
11459         player->programmed_action = move_direction;
11460 #if 1
11461         if (player->move_delay_reset_counter == 0)
11462         {
11463           player->move_delay_reset_counter = 2; /* two double speed steps */
11464
11465           DOUBLE_PLAYER_SPEED(player);
11466         }
11467 #else
11468         player->move_delay_reset_counter = 2;
11469
11470         DOUBLE_PLAYER_SPEED(player);
11471 #endif
11472
11473         PlayLevelSoundAction(x, y, ACTION_PASSING);
11474
11475         break;
11476       }
11477       else if (IS_DIGGABLE(element))
11478       {
11479         RemoveField(x, y);
11480
11481         if (mode != DF_SNAP)
11482         {
11483 #if 1
11484           GfxElement[x][y] = GFX_ELEMENT(element);
11485 #else
11486           GfxElement[x][y] =
11487             (GFX_CRUMBLED(element) ? EL_SAND : GFX_ELEMENT(element));
11488 #endif
11489           player->is_digging = TRUE;
11490         }
11491
11492         PlayLevelSoundElementAction(x, y, element, ACTION_DIGGING);
11493
11494         CheckTriggeredElementChangeByPlayer(x, y, element,CE_OTHER_GETS_DIGGED,
11495                                             player->index_bit, dig_side);
11496
11497 #if 1
11498         if (mode == DF_SNAP)
11499           TestIfElementTouchesCustomElement(x, y);      /* for empty space */
11500 #endif
11501
11502         break;
11503       }
11504       else if (IS_COLLECTIBLE(element))
11505       {
11506         RemoveField(x, y);
11507
11508         if (is_player && mode != DF_SNAP)
11509         {
11510           GfxElement[x][y] = element;
11511           player->is_collecting = TRUE;
11512         }
11513
11514         if (element == EL_SPEED_PILL)
11515           player->move_delay_value = MOVE_DELAY_HIGH_SPEED;
11516         else if (element == EL_EXTRA_TIME && level.time > 0)
11517         {
11518           TimeLeft += 10;
11519           DrawGameValue_Time(TimeLeft);
11520         }
11521         else if (element == EL_SHIELD_NORMAL || element == EL_SHIELD_DEADLY)
11522         {
11523           player->shield_normal_time_left += 10;
11524           if (element == EL_SHIELD_DEADLY)
11525             player->shield_deadly_time_left += 10;
11526         }
11527         else if (element == EL_DYNAMITE || element == EL_SP_DISK_RED)
11528         {
11529           if (player->inventory_size < MAX_INVENTORY_SIZE)
11530             player->inventory_element[player->inventory_size++] = element;
11531
11532           DrawGameValue_Dynamite(local_player->inventory_size);
11533         }
11534         else if (element == EL_DYNABOMB_INCREASE_NUMBER)
11535         {
11536           player->dynabomb_count++;
11537           player->dynabombs_left++;
11538         }
11539         else if (element == EL_DYNABOMB_INCREASE_SIZE)
11540         {
11541           player->dynabomb_size++;
11542         }
11543         else if (element == EL_DYNABOMB_INCREASE_POWER)
11544         {
11545           player->dynabomb_xl = TRUE;
11546         }
11547         else if ((element >= EL_KEY_1 && element <= EL_KEY_4) ||
11548                  (element >= EL_EM_KEY_1 && element <= EL_EM_KEY_4))
11549         {
11550           int key_nr = (element >= EL_KEY_1 && element <= EL_KEY_4 ?
11551                         element - EL_KEY_1 : element - EL_EM_KEY_1);
11552
11553           player->key[key_nr] = TRUE;
11554
11555           DrawGameValue_Keys(player->key);
11556
11557           redraw_mask |= REDRAW_DOOR_1;
11558         }
11559         else if (IS_ENVELOPE(element))
11560         {
11561 #if 1
11562           player->show_envelope = element;
11563 #else
11564           ShowEnvelope(element - EL_ENVELOPE_1);
11565 #endif
11566         }
11567         else if (IS_DROPPABLE(element) ||
11568                  IS_THROWABLE(element)) /* can be collected and dropped */
11569         {
11570           int i;
11571
11572           if (element_info[element].collect_count == 0)
11573             player->inventory_infinite_element = element;
11574           else
11575             for (i = 0; i < element_info[element].collect_count; i++)
11576               if (player->inventory_size < MAX_INVENTORY_SIZE)
11577                 player->inventory_element[player->inventory_size++] = element;
11578
11579           DrawGameValue_Dynamite(local_player->inventory_size);
11580         }
11581         else if (element_info[element].collect_count > 0)
11582         {
11583           local_player->gems_still_needed -=
11584             element_info[element].collect_count;
11585           if (local_player->gems_still_needed < 0)
11586             local_player->gems_still_needed = 0;
11587
11588           DrawGameValue_Emeralds(local_player->gems_still_needed);
11589         }
11590
11591         RaiseScoreElement(element);
11592         PlayLevelSoundElementAction(x, y, element, ACTION_COLLECTING);
11593
11594         if (is_player)
11595           CheckTriggeredElementChangeByPlayer(x, y, element,
11596                                               CE_OTHER_GETS_COLLECTED,
11597                                               player->index_bit, dig_side);
11598
11599 #if 1
11600         if (mode == DF_SNAP)
11601           TestIfElementTouchesCustomElement(x, y);      /* for empty space */
11602 #endif
11603
11604         break;
11605       }
11606       else if (IS_PUSHABLE(element))
11607       {
11608         if (mode == DF_SNAP && element != EL_BD_ROCK)
11609           return MF_NO_ACTION;
11610
11611         if (CAN_FALL(element) && dy)
11612           return MF_NO_ACTION;
11613
11614         if (CAN_FALL(element) && IN_LEV_FIELD(x, y + 1) && IS_FREE(x, y + 1) &&
11615             !(element == EL_SPRING && level.use_spring_bug))
11616           return MF_NO_ACTION;
11617
11618 #if 1
11619         if (CAN_MOVE(element) && GET_MAX_MOVE_DELAY(element) == 0 &&
11620             ((move_direction & MV_VERTICAL &&
11621               ((element_info[element].move_pattern & MV_LEFT &&
11622                 IN_LEV_FIELD(x - 1, y) && IS_FREE(x - 1, y)) ||
11623                (element_info[element].move_pattern & MV_RIGHT &&
11624                 IN_LEV_FIELD(x + 1, y) && IS_FREE(x + 1, y)))) ||
11625              (move_direction & MV_HORIZONTAL &&
11626               ((element_info[element].move_pattern & MV_UP &&
11627                 IN_LEV_FIELD(x, y - 1) && IS_FREE(x, y - 1)) ||
11628                (element_info[element].move_pattern & MV_DOWN &&
11629                 IN_LEV_FIELD(x, y + 1) && IS_FREE(x, y + 1))))))
11630           return MF_NO_ACTION;
11631 #endif
11632
11633 #if 1
11634         /* do not push elements already moving away faster than player */
11635         if (CAN_MOVE(element) && MovDir[x][y] == move_direction &&
11636             ABS(getElementMoveStepsize(x, y)) > MOVE_STEPSIZE_NORMAL)
11637           return MF_NO_ACTION;
11638 #else
11639         if (element == EL_SPRING && MovDir[x][y] != MV_NO_MOVING)
11640           return MF_NO_ACTION;
11641 #endif
11642
11643 #if 1
11644
11645 #if 1
11646         if (game.engine_version >= VERSION_IDENT(3,1,0,0))
11647         {
11648           if (player->push_delay_value == -1 || !player_was_pushing)
11649             player->push_delay_value = GET_NEW_PUSH_DELAY(element);
11650         }
11651         else if (game.engine_version >= VERSION_IDENT(3,0,7,1))
11652         {
11653           if (player->push_delay_value == -1)
11654             player->push_delay_value = GET_NEW_PUSH_DELAY(element);
11655         }
11656 #else
11657         if (game.engine_version >= VERSION_IDENT(3,0,7,1))
11658         {
11659           if (player->push_delay_value == -1 || !player_was_pushing)
11660             player->push_delay_value = GET_NEW_PUSH_DELAY(element);
11661         }
11662 #endif
11663         else if (game.engine_version >= VERSION_IDENT(2,2,0,7))
11664         {
11665           if (!player->is_pushing)
11666             player->push_delay_value = GET_NEW_PUSH_DELAY(element);
11667         }
11668
11669         /*
11670         if (game.engine_version >= VERSION_IDENT(2,2,0,7) &&
11671             (game.engine_version < VERSION_IDENT(3,0,7,1) ||
11672              !player_is_pushing))
11673           player->push_delay_value = GET_NEW_PUSH_DELAY(element);
11674         */
11675 #else
11676         if (!player->is_pushing &&
11677             game.engine_version >= VERSION_IDENT(2,2,0,7))
11678           player->push_delay_value = GET_NEW_PUSH_DELAY(element);
11679 #endif
11680
11681 #if 0
11682         printf("::: push delay: %ld -> %ld [%d, %d] [%d / %d] [%d '%s': %d]\n",
11683                player->push_delay, player->push_delay_value,
11684                FrameCounter, game.engine_version,
11685                player_was_pushing, player->is_pushing,
11686                element, element_info[element].token_name,
11687                GET_NEW_PUSH_DELAY(element));
11688 #endif
11689
11690         player->is_pushing = TRUE;
11691
11692         if (!(IN_LEV_FIELD(nextx, nexty) &&
11693               (IS_FREE(nextx, nexty) ||
11694                (Feld[nextx][nexty] == EL_SOKOBAN_FIELD_EMPTY &&
11695                 IS_SB_ELEMENT(element)))))
11696           return MF_NO_ACTION;
11697
11698         if (!checkDiagonalPushing(player, x, y, real_dx, real_dy))
11699           return MF_NO_ACTION;
11700
11701 #if USE_NEW_PUSH_DELAY
11702
11703 #if 0
11704         if ( (player->push_delay == -1) != (player->push_delay2 == 0) )
11705           printf("::: ALERT: %d, %d [%d / %d]\n",
11706                  player->push_delay, player->push_delay2,
11707                  FrameCounter, FrameCounter / 50);
11708 #endif
11709
11710         if (player->push_delay == -1)   /* new pushing; restart delay */
11711           player->push_delay = 0;
11712 #else
11713         if (player->push_delay == 0)    /* new pushing; restart delay */
11714           player->push_delay = FrameCounter;
11715 #endif
11716
11717 #if USE_NEW_PUSH_DELAY
11718 #if 0
11719         if ( (player->push_delay > 0) != (!xxx_fr) )
11720           printf("::: PUSH BUG! %d, (%d -> %d) %d [%d / %d]\n",
11721                  player->push_delay,
11722                  xxx_pdv2, player->push_delay2, player->push_delay_value,
11723                  FrameCounter, FrameCounter / 50);
11724 #endif
11725
11726 #if 0
11727         if (player->push_delay > 0 &&
11728             !(tape.playing && tape.file_version < FILE_VERSION_2_0) &&
11729             element != EL_SPRING && element != EL_BALLOON)
11730 #else
11731         /* !!! */
11732         if (player->push_delay < player->push_delay_value &&
11733             !(tape.playing && tape.file_version < FILE_VERSION_2_0) &&
11734             element != EL_SPRING && element != EL_BALLOON)
11735 #endif
11736
11737 #else
11738         if (!FrameReached(&player->push_delay, player->push_delay_value) &&
11739             !(tape.playing && tape.file_version < FILE_VERSION_2_0) &&
11740             element != EL_SPRING && element != EL_BALLOON)
11741 #endif
11742         {
11743           /* make sure that there is no move delay before next try to push */
11744 #if USE_NEW_MOVE_DELAY
11745           if (game.engine_version >= VERSION_IDENT(3,0,7,1))
11746             player->move_delay = 0;
11747 #else
11748           if (game.engine_version >= VERSION_IDENT(3,0,7,1))
11749             player->move_delay = INITIAL_MOVE_DELAY_OFF;
11750 #endif
11751
11752           return MF_NO_ACTION;
11753         }
11754
11755 #if 0
11756         printf("::: NOW PUSHING... [%d]\n", FrameCounter);
11757 #endif
11758
11759         if (IS_SB_ELEMENT(element))
11760         {
11761           if (element == EL_SOKOBAN_FIELD_FULL)
11762           {
11763             Back[x][y] = EL_SOKOBAN_FIELD_EMPTY;
11764             local_player->sokobanfields_still_needed++;
11765           }
11766
11767           if (Feld[nextx][nexty] == EL_SOKOBAN_FIELD_EMPTY)
11768           {
11769             Back[nextx][nexty] = EL_SOKOBAN_FIELD_EMPTY;
11770             local_player->sokobanfields_still_needed--;
11771           }
11772
11773           Feld[x][y] = EL_SOKOBAN_OBJECT;
11774
11775           if (Back[x][y] == Back[nextx][nexty])
11776             PlayLevelSoundAction(x, y, ACTION_PUSHING);
11777           else if (Back[x][y] != 0)
11778             PlayLevelSoundElementAction(x, y, EL_SOKOBAN_FIELD_FULL,
11779                                         ACTION_EMPTYING);
11780           else
11781             PlayLevelSoundElementAction(nextx, nexty, EL_SOKOBAN_FIELD_EMPTY,
11782                                         ACTION_FILLING);
11783
11784           if (local_player->sokobanfields_still_needed == 0 &&
11785               game.emulation == EMU_SOKOBAN)
11786           {
11787             player->LevelSolved = player->GameOver = TRUE;
11788             PlayLevelSound(x, y, SND_GAME_SOKOBAN_SOLVING);
11789           }
11790         }
11791         else
11792           PlayLevelSoundElementAction(x, y, element, ACTION_PUSHING);
11793
11794         InitMovingField(x, y, move_direction);
11795         GfxAction[x][y] = ACTION_PUSHING;
11796
11797         if (mode == DF_SNAP)
11798           ContinueMoving(x, y);
11799         else
11800           MovPos[x][y] = (dx != 0 ? dx : dy);
11801
11802         Pushed[x][y] = TRUE;
11803         Pushed[nextx][nexty] = TRUE;
11804
11805         if (game.engine_version < VERSION_IDENT(2,2,0,7))
11806           player->push_delay_value = GET_NEW_PUSH_DELAY(element);
11807         else
11808           player->push_delay_value = -1;        /* get new value later */
11809
11810 #if USE_PUSH_BUGFIX
11811         /* now: check for element change _after_ element has been pushed! */
11812 #if 1
11813         if (game.use_bug_change_when_pushing)
11814 #else
11815         if (game.engine_version < VERSION_IDENT(3,1,0,0))
11816 #endif
11817         {
11818           CheckElementChangeByPlayer(x, y, element, CE_PUSHED_BY_PLAYER,
11819                                      player->index_bit, dig_side);
11820           CheckTriggeredElementChangeByPlayer(x,y,element,CE_OTHER_GETS_PUSHED,
11821                                               player->index_bit, dig_side);
11822         }
11823
11824 #else
11825
11826 #if 1
11827         /* check for element change _after_ element has been pushed! */
11828 #else
11829
11830 #if 1
11831         /* !!! TEST ONLY !!! */
11832         CheckElementChangeByPlayer(x, y, element, CE_PUSHED_BY_PLAYER,
11833                                    player->index_bit, dig_side);
11834         CheckTriggeredElementChangeByPlayer(x, y, element,CE_OTHER_GETS_PUSHED,
11835                                             player->index_bit, dig_side);
11836 #else
11837         CheckTriggeredElementChangeByPlayer(x, y, element,CE_OTHER_GETS_PUSHED,
11838                                             player->index_bit, dig_side);
11839         CheckElementChangeByPlayer(x, y, element, CE_PUSHED_BY_PLAYER,
11840                                    player->index_bit, dig_side);
11841 #endif
11842 #endif
11843
11844 #endif
11845
11846         break;
11847       }
11848       else if (IS_SWITCHABLE(element))
11849       {
11850         if (PLAYER_SWITCHING(player, x, y))
11851         {
11852           CheckTriggeredElementChangeByPlayer(x,y, element,
11853                                               CE_OTHER_GETS_PRESSED,
11854                                               player->index_bit, dig_side);
11855
11856           return MF_ACTION;
11857         }
11858
11859         player->is_switching = TRUE;
11860         player->switch_x = x;
11861         player->switch_y = y;
11862
11863         PlayLevelSoundElementAction(x, y, element, ACTION_ACTIVATING);
11864
11865         if (element == EL_ROBOT_WHEEL)
11866         {
11867           Feld[x][y] = EL_ROBOT_WHEEL_ACTIVE;
11868           ZX = x;
11869           ZY = y;
11870
11871           DrawLevelField(x, y);
11872         }
11873         else if (element == EL_SP_TERMINAL)
11874         {
11875           int xx, yy;
11876
11877           for (yy = 0; yy < lev_fieldy; yy++) for (xx=0; xx < lev_fieldx; xx++)
11878           {
11879             if (Feld[xx][yy] == EL_SP_DISK_YELLOW)
11880               Bang(xx, yy);
11881             else if (Feld[xx][yy] == EL_SP_TERMINAL)
11882               Feld[xx][yy] = EL_SP_TERMINAL_ACTIVE;
11883           }
11884         }
11885         else if (IS_BELT_SWITCH(element))
11886         {
11887           ToggleBeltSwitch(x, y);
11888         }
11889         else if (element == EL_SWITCHGATE_SWITCH_UP ||
11890                  element == EL_SWITCHGATE_SWITCH_DOWN)
11891         {
11892           ToggleSwitchgateSwitch(x, y);
11893         }
11894         else if (element == EL_LIGHT_SWITCH ||
11895                  element == EL_LIGHT_SWITCH_ACTIVE)
11896         {
11897           ToggleLightSwitch(x, y);
11898
11899 #if 0
11900           PlayLevelSound(x, y, element == EL_LIGHT_SWITCH ?
11901                          SND_LIGHT_SWITCH_ACTIVATING :
11902                          SND_LIGHT_SWITCH_DEACTIVATING);
11903 #endif
11904         }
11905         else if (element == EL_TIMEGATE_SWITCH)
11906         {
11907           ActivateTimegateSwitch(x, y);
11908         }
11909         else if (element == EL_BALLOON_SWITCH_LEFT ||
11910                  element == EL_BALLOON_SWITCH_RIGHT ||
11911                  element == EL_BALLOON_SWITCH_UP ||
11912                  element == EL_BALLOON_SWITCH_DOWN ||
11913                  element == EL_BALLOON_SWITCH_ANY)
11914         {
11915           if (element == EL_BALLOON_SWITCH_ANY)
11916             game.balloon_dir = move_direction;
11917           else
11918             game.balloon_dir = (element == EL_BALLOON_SWITCH_LEFT  ? MV_LEFT :
11919                                 element == EL_BALLOON_SWITCH_RIGHT ? MV_RIGHT :
11920                                 element == EL_BALLOON_SWITCH_UP    ? MV_UP :
11921                                 element == EL_BALLOON_SWITCH_DOWN  ? MV_DOWN :
11922                                 MV_NO_MOVING);
11923         }
11924         else if (element == EL_LAMP)
11925         {
11926           Feld[x][y] = EL_LAMP_ACTIVE;
11927           local_player->lights_still_needed--;
11928
11929           DrawLevelField(x, y);
11930         }
11931         else if (element == EL_TIME_ORB_FULL)
11932         {
11933           Feld[x][y] = EL_TIME_ORB_EMPTY;
11934           TimeLeft += 10;
11935           DrawGameValue_Time(TimeLeft);
11936
11937           DrawLevelField(x, y);
11938
11939 #if 0
11940           PlaySoundStereo(SND_TIME_ORB_FULL_COLLECTING, SOUND_MIDDLE);
11941 #endif
11942         }
11943
11944         CheckTriggeredElementChangeByPlayer(x, y, element,
11945                                             CE_OTHER_IS_SWITCHING,
11946                                             player->index_bit, dig_side);
11947
11948         CheckTriggeredElementChangeByPlayer(x,y, element,CE_OTHER_GETS_PRESSED,
11949                                             player->index_bit, dig_side);
11950
11951         return MF_ACTION;
11952       }
11953       else
11954       {
11955         if (!PLAYER_SWITCHING(player, x, y))
11956         {
11957           player->is_switching = TRUE;
11958           player->switch_x = x;
11959           player->switch_y = y;
11960
11961 #if 1
11962           /* !!! TEST ONLY !!! */
11963           CheckElementChangeByPlayer(x, y, element, CE_SWITCHED,
11964                                      player->index_bit, dig_side);
11965           CheckTriggeredElementChangeByPlayer(x, y, element,
11966                                               CE_OTHER_IS_SWITCHING,
11967                                               player->index_bit, dig_side);
11968 #else
11969           CheckTriggeredElementChangeByPlayer(x, y, element,
11970                                               CE_OTHER_IS_SWITCHING,
11971                                               player->index_bit, dig_side);
11972           CheckElementChangeByPlayer(x, y, element, CE_SWITCHED,
11973                                      player->index_bit, dig_side);
11974 #endif
11975         }
11976
11977 #if 1
11978         /* !!! TEST ONLY !!! (this breaks "machine", level 000) */
11979         CheckElementChangeByPlayer(x, y, element, CE_PRESSED_BY_PLAYER,
11980                                    player->index_bit, dig_side);
11981         CheckTriggeredElementChangeByPlayer(x,y, element,CE_OTHER_GETS_PRESSED,
11982                                             player->index_bit, dig_side);
11983 #else
11984         CheckTriggeredElementChangeByPlayer(x,y, element,CE_OTHER_GETS_PRESSED,
11985                                             player->index_bit, dig_side);
11986         CheckElementChangeByPlayer(x, y, element, CE_PRESSED_BY_PLAYER,
11987                                    player->index_bit, dig_side);
11988 #endif
11989       }
11990
11991       return MF_NO_ACTION;
11992   }
11993
11994 #if USE_NEW_PUSH_DELAY
11995   player->push_delay = -1;
11996 #else
11997   player->push_delay = 0;
11998 #endif
11999
12000   if (Feld[x][y] != element)            /* really digged/collected something */
12001     player->is_collecting = !player->is_digging;
12002
12003   return MF_MOVING;
12004 }
12005
12006 boolean SnapField(struct PlayerInfo *player, int dx, int dy)
12007 {
12008   int jx = player->jx, jy = player->jy;
12009   int x = jx + dx, y = jy + dy;
12010   int snap_direction = (dx == -1 ? MV_LEFT :
12011                         dx == +1 ? MV_RIGHT :
12012                         dy == -1 ? MV_UP :
12013                         dy == +1 ? MV_DOWN : MV_NO_MOVING);
12014
12015 #if 0
12016   if (player->MovPos != 0)
12017     return FALSE;
12018 #else
12019   if (player->MovPos != 0 && game.engine_version >= VERSION_IDENT(2,2,0,0))
12020     return FALSE;
12021 #endif
12022
12023   if (!player->active || !IN_LEV_FIELD(x, y))
12024     return FALSE;
12025
12026   if (dx && dy)
12027     return FALSE;
12028
12029   if (!dx && !dy)
12030   {
12031     if (player->MovPos == 0)
12032       player->is_pushing = FALSE;
12033
12034     player->is_snapping = FALSE;
12035
12036     if (player->MovPos == 0)
12037     {
12038       player->is_moving = FALSE;
12039       player->is_digging = FALSE;
12040       player->is_collecting = FALSE;
12041     }
12042
12043     return FALSE;
12044   }
12045
12046   if (player->is_snapping)
12047     return FALSE;
12048
12049   player->MovDir = snap_direction;
12050
12051 #if 1
12052   if (player->MovPos == 0)
12053 #endif
12054   {
12055     player->is_moving = FALSE;
12056     player->is_digging = FALSE;
12057     player->is_collecting = FALSE;
12058   }
12059
12060   player->is_dropping = FALSE;
12061
12062   if (DigField(player, jx, jy, x, y, 0, 0, DF_SNAP) == MF_NO_ACTION)
12063     return FALSE;
12064
12065   player->is_snapping = TRUE;
12066
12067 #if 1
12068   if (player->MovPos == 0)
12069 #endif
12070   {
12071     player->is_moving = FALSE;
12072     player->is_digging = FALSE;
12073     player->is_collecting = FALSE;
12074   }
12075
12076 #if 1
12077   if (player->MovPos != 0)      /* prevent graphic bugs in versions < 2.2.0 */
12078     DrawLevelField(player->last_jx, player->last_jy);
12079 #endif
12080
12081   DrawLevelField(x, y);
12082
12083 #if 0
12084   BackToFront();
12085 #endif
12086
12087   return TRUE;
12088 }
12089
12090 boolean DropElement(struct PlayerInfo *player)
12091 {
12092   int old_element, new_element;
12093   int dropx = player->jx, dropy = player->jy;
12094   int drop_direction = player->MovDir;
12095 #if 1
12096   int drop_side = drop_direction;
12097 #else
12098   static int trigger_sides[4] =
12099   {
12100     CH_SIDE_LEFT,       /* dropping left  */
12101     CH_SIDE_RIGHT,      /* dropping right */
12102     CH_SIDE_TOP,        /* dropping up    */
12103     CH_SIDE_BOTTOM,     /* dropping down  */
12104   };
12105   int drop_side = trigger_sides[MV_DIR_BIT(drop_direction)];
12106 #endif
12107   int drop_element = (player->inventory_size > 0 ?
12108                       player->inventory_element[player->inventory_size - 1] :
12109                       player->inventory_infinite_element != EL_UNDEFINED ?
12110                       player->inventory_infinite_element :
12111                       player->dynabombs_left > 0 ?
12112                       EL_DYNABOMB_PLAYER_1_ACTIVE + player->index_nr :
12113                       EL_UNDEFINED);
12114
12115   if (IS_THROWABLE(drop_element))
12116   {
12117     dropx += GET_DX_FROM_DIR(drop_direction);
12118     dropy += GET_DY_FROM_DIR(drop_direction);
12119
12120     if (!IN_LEV_FIELD(dropx, dropy))
12121       return FALSE;
12122   }
12123
12124   old_element = Feld[dropx][dropy];     /* old element at dropping position */
12125   new_element = drop_element;           /* default: no change when dropping */
12126
12127   /* check if player is active, not moving and ready to drop */
12128   if (!player->active || player->MovPos || player->drop_delay > 0)
12129     return FALSE;
12130
12131   /* check if player has anything that can be dropped */
12132 #if 1
12133   if (new_element == EL_UNDEFINED)
12134     return FALSE;
12135 #else
12136   if (player->inventory_size == 0 &&
12137       player->inventory_infinite_element == EL_UNDEFINED &&
12138       player->dynabombs_left == 0)
12139     return FALSE;
12140 #endif
12141
12142   /* check if anything can be dropped at the current position */
12143   if (IS_ACTIVE_BOMB(old_element) || old_element == EL_EXPLOSION)
12144     return FALSE;
12145
12146   /* collected custom elements can only be dropped on empty fields */
12147 #if 1
12148   if (IS_CUSTOM_ELEMENT(new_element) && old_element != EL_EMPTY)
12149     return FALSE;
12150 #else
12151   if (player->inventory_size > 0 &&
12152       IS_CUSTOM_ELEMENT(player->inventory_element[player->inventory_size - 1])
12153       && old_element != EL_EMPTY)
12154     return FALSE;
12155 #endif
12156
12157   if (old_element != EL_EMPTY)
12158     Back[dropx][dropy] = old_element;   /* store old element on this field */
12159
12160   ResetGfxAnimation(dropx, dropy);
12161   ResetRandomAnimationValue(dropx, dropy);
12162
12163   if (player->inventory_size > 0 ||
12164       player->inventory_infinite_element != EL_UNDEFINED)
12165   {
12166     if (player->inventory_size > 0)
12167     {
12168       player->inventory_size--;
12169
12170 #if 0
12171       new_element = player->inventory_element[player->inventory_size];
12172 #endif
12173
12174       DrawGameValue_Dynamite(local_player->inventory_size);
12175
12176       if (new_element == EL_DYNAMITE)
12177         new_element = EL_DYNAMITE_ACTIVE;
12178       else if (new_element == EL_SP_DISK_RED)
12179         new_element = EL_SP_DISK_RED_ACTIVE;
12180     }
12181
12182     Feld[dropx][dropy] = new_element;
12183
12184     if (IN_SCR_FIELD(SCREENX(dropx), SCREENY(dropy)))
12185       DrawGraphicThruMask(SCREENX(dropx), SCREENY(dropy),
12186                           el2img(Feld[dropx][dropy]), 0);
12187
12188     PlayLevelSoundAction(dropx, dropy, ACTION_DROPPING);
12189
12190 #if 1
12191     /* needed if previous element just changed to "empty" in the last frame */
12192     Changed[dropx][dropy] = 0;          /* allow another change */
12193 #endif
12194
12195 #if 1
12196     /* !!! TEST ONLY !!! */
12197     CheckElementChangeByPlayer(dropx, dropy, new_element, CE_DROPPED_BY_PLAYER,
12198                                player->index_bit, drop_side);
12199     CheckTriggeredElementChangeByPlayer(dropx, dropy, new_element,
12200                                         CE_OTHER_GETS_DROPPED,
12201                                         player->index_bit, drop_side);
12202 #else
12203     CheckTriggeredElementChangeByPlayer(dropx, dropy, new_element,
12204                                         CE_OTHER_GETS_DROPPED,
12205                                         player->index_bit, drop_side);
12206     CheckElementChangeByPlayer(dropx, dropy, new_element, CE_DROPPED_BY_PLAYER,
12207                                player->index_bit, drop_side);
12208 #endif
12209
12210     TestIfElementTouchesCustomElement(dropx, dropy);
12211   }
12212   else          /* player is dropping a dyna bomb */
12213   {
12214     player->dynabombs_left--;
12215
12216 #if 0
12217     new_element = EL_DYNABOMB_PLAYER_1_ACTIVE + player->index_nr;
12218 #endif
12219
12220     Feld[dropx][dropy] = new_element;
12221
12222     if (IN_SCR_FIELD(SCREENX(dropx), SCREENY(dropy)))
12223       DrawGraphicThruMask(SCREENX(dropx), SCREENY(dropy),
12224                           el2img(Feld[dropx][dropy]), 0);
12225
12226     PlayLevelSoundAction(dropx, dropy, ACTION_DROPPING);
12227   }
12228
12229
12230
12231 #if 1
12232
12233   if (Feld[dropx][dropy] == new_element) /* uninitialized unless CE change */
12234   {
12235 #if 1
12236     InitField_WithBug1(dropx, dropy, FALSE);
12237 #else
12238     InitField(dropx, dropy, FALSE);
12239     if (CAN_MOVE(Feld[dropx][dropy]))
12240       InitMovDir(dropx, dropy);
12241 #endif
12242   }
12243
12244   new_element = Feld[dropx][dropy];     /* element might have changed */
12245
12246   if (IS_CUSTOM_ELEMENT(new_element) && CAN_MOVE(new_element) &&
12247       element_info[new_element].move_pattern == MV_WHEN_DROPPED)
12248   {
12249 #if 0
12250     int move_stepsize = element_info[new_element].move_stepsize;
12251 #endif
12252     int move_direction, nextx, nexty;
12253
12254     if (element_info[new_element].move_direction_initial == MV_START_AUTOMATIC)
12255       MovDir[dropx][dropy] = drop_direction;
12256
12257     move_direction = MovDir[dropx][dropy];
12258     nextx = dropx + GET_DX_FROM_DIR(move_direction);
12259     nexty = dropy + GET_DY_FROM_DIR(move_direction);
12260
12261 #if 1
12262     Changed[dropx][dropy] = 0;          /* allow another change */
12263     CheckCollision[dropx][dropy] = 2;
12264 #else
12265
12266     if (IN_LEV_FIELD_AND_IS_FREE(nextx, nexty))
12267     {
12268 #if 0
12269       WasJustMoving[dropx][dropy] = 3;
12270 #else
12271 #if 1
12272       InitMovingField(dropx, dropy, move_direction);
12273       ContinueMoving(dropx, dropy);
12274 #endif
12275 #endif
12276     }
12277 #if 0
12278     /* !!! commented out from 3.1.0-4 to 3.1.0-5 !!! */
12279     else
12280     {
12281       Changed[dropx][dropy] = 0;        /* allow another change */
12282
12283 #if 1
12284       TestIfElementHitsCustomElement(dropx, dropy, move_direction);
12285 #else
12286       CheckElementChangeBySide(dropx, dropy, new_element, touched_element,
12287                                CE_HITTING_SOMETHING, move_direction);
12288 #endif
12289     }
12290 #endif
12291
12292 #endif
12293
12294 #if 0
12295     player->drop_delay = 2 * TILEX / move_stepsize + 1;
12296 #endif
12297   }
12298
12299 #if 0
12300   player->drop_delay = 8 + 8 + 8;
12301 #endif
12302
12303 #if 1
12304   player->drop_delay = GET_NEW_DROP_DELAY(drop_element);
12305 #endif
12306
12307 #endif
12308
12309   player->is_dropping = TRUE;
12310
12311
12312   return TRUE;
12313 }
12314
12315 /* ------------------------------------------------------------------------- */
12316 /* game sound playing functions                                              */
12317 /* ------------------------------------------------------------------------- */
12318
12319 static int *loop_sound_frame = NULL;
12320 static int *loop_sound_volume = NULL;
12321
12322 void InitPlayLevelSound()
12323 {
12324   int num_sounds = getSoundListSize();
12325
12326   checked_free(loop_sound_frame);
12327   checked_free(loop_sound_volume);
12328
12329   loop_sound_frame  = checked_calloc(num_sounds * sizeof(int));
12330   loop_sound_volume = checked_calloc(num_sounds * sizeof(int));
12331 }
12332
12333 static void PlayLevelSound(int x, int y, int nr)
12334 {
12335   int sx = SCREENX(x), sy = SCREENY(y);
12336   int volume, stereo_position;
12337   int max_distance = 8;
12338   int type = (IS_LOOP_SOUND(nr) ? SND_CTRL_PLAY_LOOP : SND_CTRL_PLAY_SOUND);
12339
12340   if ((!setup.sound_simple && !IS_LOOP_SOUND(nr)) ||
12341       (!setup.sound_loops && IS_LOOP_SOUND(nr)))
12342     return;
12343
12344   if (!IN_LEV_FIELD(x, y) ||
12345       sx < -max_distance || sx >= SCR_FIELDX + max_distance ||
12346       sy < -max_distance || sy >= SCR_FIELDY + max_distance)
12347     return;
12348
12349   volume = SOUND_MAX_VOLUME;
12350
12351   if (!IN_SCR_FIELD(sx, sy))
12352   {
12353     int dx = ABS(sx - SCR_FIELDX / 2) - SCR_FIELDX / 2;
12354     int dy = ABS(sy - SCR_FIELDY / 2) - SCR_FIELDY / 2;
12355
12356     volume -= volume * (dx > dy ? dx : dy) / max_distance;
12357   }
12358
12359   stereo_position = (SOUND_MAX_LEFT +
12360                      (sx + max_distance) * SOUND_MAX_LEFT2RIGHT /
12361                      (SCR_FIELDX + 2 * max_distance));
12362
12363   if (IS_LOOP_SOUND(nr))
12364   {
12365     /* This assures that quieter loop sounds do not overwrite louder ones,
12366        while restarting sound volume comparison with each new game frame. */
12367
12368     if (loop_sound_volume[nr] > volume && loop_sound_frame[nr] == FrameCounter)
12369       return;
12370
12371     loop_sound_volume[nr] = volume;
12372     loop_sound_frame[nr] = FrameCounter;
12373   }
12374
12375   PlaySoundExt(nr, volume, stereo_position, type);
12376 }
12377
12378 static void PlayLevelSoundNearest(int x, int y, int sound_action)
12379 {
12380   PlayLevelSound(x < LEVELX(BX1) ? LEVELX(BX1) :
12381                  x > LEVELX(BX2) ? LEVELX(BX2) : x,
12382                  y < LEVELY(BY1) ? LEVELY(BY1) :
12383                  y > LEVELY(BY2) ? LEVELY(BY2) : y,
12384                  sound_action);
12385 }
12386
12387 static void PlayLevelSoundAction(int x, int y, int action)
12388 {
12389   PlayLevelSoundElementAction(x, y, Feld[x][y], action);
12390 }
12391
12392 static void PlayLevelSoundElementAction(int x, int y, int element, int action)
12393 {
12394   int sound_effect = element_info[SND_ELEMENT(element)].sound[action];
12395
12396   if (sound_effect != SND_UNDEFINED)
12397     PlayLevelSound(x, y, sound_effect);
12398 }
12399
12400 static void PlayLevelSoundElementActionIfLoop(int x, int y, int element,
12401                                               int action)
12402 {
12403   int sound_effect = element_info[SND_ELEMENT(element)].sound[action];
12404
12405   if (sound_effect != SND_UNDEFINED && IS_LOOP_SOUND(sound_effect))
12406     PlayLevelSound(x, y, sound_effect);
12407 }
12408
12409 static void PlayLevelSoundActionIfLoop(int x, int y, int action)
12410 {
12411   int sound_effect = element_info[SND_ELEMENT(Feld[x][y])].sound[action];
12412
12413   if (sound_effect != SND_UNDEFINED && IS_LOOP_SOUND(sound_effect))
12414     PlayLevelSound(x, y, sound_effect);
12415 }
12416
12417 static void StopLevelSoundActionIfLoop(int x, int y, int action)
12418 {
12419   int sound_effect = element_info[SND_ELEMENT(Feld[x][y])].sound[action];
12420
12421   if (sound_effect != SND_UNDEFINED && IS_LOOP_SOUND(sound_effect))
12422     StopSound(sound_effect);
12423 }
12424
12425 static void PlayLevelMusic()
12426 {
12427   if (levelset.music[level_nr] != MUS_UNDEFINED)
12428     PlayMusic(levelset.music[level_nr]);        /* from config file */
12429   else
12430     PlayMusic(MAP_NOCONF_MUSIC(level_nr));      /* from music dir */
12431 }
12432
12433 void PlayLevelSound_EM(int x, int y, int element_em, int sample)
12434 {
12435   int element = (element_em > -1 ? map_element_EM_to_RND(element_em) : 0);
12436
12437 #if 0
12438   if (sample == SAMPLE_bug)
12439     printf("::: PlayLevelSound_EM: %d, %d: %d\n", x, y, sample);
12440 #endif
12441
12442   switch (sample)
12443   {
12444     case SAMPLE_blank:
12445       PlayLevelSoundElementAction(x, y, element, ACTION_WALKING);
12446       break;
12447
12448     case SAMPLE_roll:
12449       PlayLevelSoundElementAction(x, y, element, ACTION_PUSHING);
12450       break;
12451
12452     case SAMPLE_stone:
12453       PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT);
12454       break;
12455
12456     case SAMPLE_nut:
12457       PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT);
12458       break;
12459
12460     case SAMPLE_crack:
12461       PlayLevelSoundElementAction(x, y, element, ACTION_BREAKING);
12462       break;
12463
12464     case SAMPLE_bug:
12465       PlayLevelSoundElementAction(x, y, EL_BUG, ACTION_MOVING);
12466       break;
12467
12468     case SAMPLE_tank:
12469       PlayLevelSoundElementAction(x, y, EL_SPACESHIP, ACTION_MOVING);
12470       break;
12471
12472     case SAMPLE_android:
12473       PlayLevelSoundElementAction(x, y, element, ACTION_DROPPING);
12474       break;
12475
12476     case SAMPLE_spring:
12477       PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT);
12478       break;
12479
12480     case SAMPLE_slurp:
12481       PlayLevelSoundElementAction(x, y, element, ACTION_SLURPED_BY_SPRING);
12482       break;
12483
12484     case SAMPLE_eater:
12485       PlayLevelSoundElementAction(x, y, EL_YAMYAM, ACTION_WAITING);
12486       break;
12487
12488     case SAMPLE_alien:
12489       PlayLevelSoundElementAction(x, y, element, ACTION_MOVING);
12490       break;
12491
12492     case SAMPLE_collect:
12493       PlayLevelSoundElementAction(x, y, element, ACTION_COLLECTING);
12494       break;
12495
12496     case SAMPLE_diamond:
12497       PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT);
12498       break;
12499
12500     case SAMPLE_squash:
12501       PlayLevelSoundElementAction(x, y, element, ACTION_SMASHED_BY_ROCK);
12502       break;
12503
12504     case SAMPLE_wonderfall:
12505       PlayLevelSoundElementAction(x, y, EL_MAGIC_WALL, ACTION_FILLING);
12506       break;
12507
12508     case SAMPLE_drip:
12509       PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT);
12510       break;
12511
12512     case SAMPLE_push:
12513       PlayLevelSoundElementAction(x, y, element, ACTION_PUSHING);
12514       break;
12515
12516     case SAMPLE_dirt:
12517       PlayLevelSoundElementAction(x, y, element, ACTION_DIGGING);
12518       break;
12519
12520     case SAMPLE_acid:
12521       PlayLevelSound(x, y, SND_ACID_SPLASHING);
12522       break;
12523
12524     case SAMPLE_ball:
12525       PlayLevelSoundElementAction(x, y, element, ACTION_DROPPING);
12526       break;
12527
12528     case SAMPLE_grow:
12529       PlayLevelSoundElementAction(x, y, element, ACTION_GROWING);
12530       break;
12531
12532     case SAMPLE_wonder:
12533       PlayLevelSoundElementAction(x, y, element, ACTION_ACTIVE);
12534       break;
12535
12536     case SAMPLE_door:
12537       PlayLevelSoundElementAction(x, y, element, ACTION_PASSING);
12538       break;
12539
12540     case SAMPLE_exit:
12541       PlayLevelSoundElementAction(x, y, element, ACTION_PASSING);
12542       break;
12543
12544     case SAMPLE_dynamite:
12545       PlayLevelSoundElementAction(x, y, element, ACTION_DROPPING);
12546       break;
12547
12548     case SAMPLE_tick:
12549       PlayLevelSoundElementAction(x, y, element, ACTION_ACTIVE);
12550       break;
12551
12552     case SAMPLE_press:
12553       PlayLevelSoundElementAction(x, y, element, ACTION_ACTIVATING);
12554       break;
12555
12556     case SAMPLE_wheel:
12557       PlayLevelSound(x, y, SND_ROBOT_WHEEL_ACTIVE);
12558       break;
12559
12560     case SAMPLE_boom:
12561       PlayLevelSoundElementAction(x, y, element, ACTION_EXPLODING);
12562       break;
12563
12564     case SAMPLE_time:
12565       PlaySoundStereo(SND_GAME_RUNNING_OUT_OF_TIME, SOUND_MIDDLE);
12566       break;
12567
12568     case SAMPLE_die:
12569       PlayLevelSoundElementAction(x, y, element, ACTION_DYING);
12570       break;
12571
12572     default:
12573       PlayLevelSoundElementAction(x, y, element, ACTION_DEFAULT);
12574       break;
12575   }
12576 }
12577
12578 void RaiseScore(int value)
12579 {
12580   local_player->score += value;
12581
12582   DrawGameValue_Score(local_player->score);
12583 }
12584
12585 void RaiseScoreElement(int element)
12586 {
12587   switch(element)
12588   {
12589     case EL_EMERALD:
12590     case EL_BD_DIAMOND:
12591     case EL_EMERALD_YELLOW:
12592     case EL_EMERALD_RED:
12593     case EL_EMERALD_PURPLE:
12594     case EL_SP_INFOTRON:
12595       RaiseScore(level.score[SC_EMERALD]);
12596       break;
12597     case EL_DIAMOND:
12598       RaiseScore(level.score[SC_DIAMOND]);
12599       break;
12600     case EL_CRYSTAL:
12601       RaiseScore(level.score[SC_CRYSTAL]);
12602       break;
12603     case EL_PEARL:
12604       RaiseScore(level.score[SC_PEARL]);
12605       break;
12606     case EL_BUG:
12607     case EL_BD_BUTTERFLY:
12608     case EL_SP_ELECTRON:
12609       RaiseScore(level.score[SC_BUG]);
12610       break;
12611     case EL_SPACESHIP:
12612     case EL_BD_FIREFLY:
12613     case EL_SP_SNIKSNAK:
12614       RaiseScore(level.score[SC_SPACESHIP]);
12615       break;
12616     case EL_YAMYAM:
12617     case EL_DARK_YAMYAM:
12618       RaiseScore(level.score[SC_YAMYAM]);
12619       break;
12620     case EL_ROBOT:
12621       RaiseScore(level.score[SC_ROBOT]);
12622       break;
12623     case EL_PACMAN:
12624       RaiseScore(level.score[SC_PACMAN]);
12625       break;
12626     case EL_NUT:
12627       RaiseScore(level.score[SC_NUT]);
12628       break;
12629     case EL_DYNAMITE:
12630     case EL_SP_DISK_RED:
12631     case EL_DYNABOMB_INCREASE_NUMBER:
12632     case EL_DYNABOMB_INCREASE_SIZE:
12633     case EL_DYNABOMB_INCREASE_POWER:
12634       RaiseScore(level.score[SC_DYNAMITE]);
12635       break;
12636     case EL_SHIELD_NORMAL:
12637     case EL_SHIELD_DEADLY:
12638       RaiseScore(level.score[SC_SHIELD]);
12639       break;
12640     case EL_EXTRA_TIME:
12641       RaiseScore(level.score[SC_TIME_BONUS]);
12642       break;
12643     case EL_KEY_1:
12644     case EL_KEY_2:
12645     case EL_KEY_3:
12646     case EL_KEY_4:
12647       RaiseScore(level.score[SC_KEY]);
12648       break;
12649     default:
12650       RaiseScore(element_info[element].collect_score);
12651       break;
12652   }
12653 }
12654
12655 void RequestQuitGame(boolean ask_if_really_quit)
12656 {
12657   if (AllPlayersGone ||
12658       !ask_if_really_quit ||
12659       level_editor_test_game ||
12660       Request("Do you really want to quit the game ?",
12661               REQ_ASK | REQ_STAY_CLOSED))
12662   {
12663 #if defined(NETWORK_AVALIABLE)
12664     if (options.network)
12665       SendToServer_StopPlaying();
12666     else
12667 #endif
12668     {
12669       game_status = GAME_MODE_MAIN;
12670       DrawMainMenu();
12671     }
12672   }
12673   else
12674   {
12675
12676 #if 1
12677     if (tape.playing && tape.deactivate_display)
12678       TapeDeactivateDisplayOff(TRUE);
12679 #endif
12680
12681     OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
12682
12683 #if 1
12684     if (tape.playing && tape.deactivate_display)
12685       TapeDeactivateDisplayOn();
12686 #endif
12687
12688   }
12689 }
12690
12691
12692 /* ---------- new game button stuff ---------------------------------------- */
12693
12694 /* graphic position values for game buttons */
12695 #define GAME_BUTTON_XSIZE       30
12696 #define GAME_BUTTON_YSIZE       30
12697 #define GAME_BUTTON_XPOS        5
12698 #define GAME_BUTTON_YPOS        215
12699 #define SOUND_BUTTON_XPOS       5
12700 #define SOUND_BUTTON_YPOS       (GAME_BUTTON_YPOS + GAME_BUTTON_YSIZE)
12701
12702 #define GAME_BUTTON_STOP_XPOS   (GAME_BUTTON_XPOS + 0 * GAME_BUTTON_XSIZE)
12703 #define GAME_BUTTON_PAUSE_XPOS  (GAME_BUTTON_XPOS + 1 * GAME_BUTTON_XSIZE)
12704 #define GAME_BUTTON_PLAY_XPOS   (GAME_BUTTON_XPOS + 2 * GAME_BUTTON_XSIZE)
12705 #define SOUND_BUTTON_MUSIC_XPOS (SOUND_BUTTON_XPOS + 0 * GAME_BUTTON_XSIZE)
12706 #define SOUND_BUTTON_LOOPS_XPOS (SOUND_BUTTON_XPOS + 1 * GAME_BUTTON_XSIZE)
12707 #define SOUND_BUTTON_SIMPLE_XPOS (SOUND_BUTTON_XPOS + 2 * GAME_BUTTON_XSIZE)
12708
12709 static struct
12710 {
12711   int x, y;
12712   int gadget_id;
12713   char *infotext;
12714 } gamebutton_info[NUM_GAME_BUTTONS] =
12715 {
12716   {
12717     GAME_BUTTON_STOP_XPOS,      GAME_BUTTON_YPOS,
12718     GAME_CTRL_ID_STOP,
12719     "stop game"
12720   },
12721   {
12722     GAME_BUTTON_PAUSE_XPOS,     GAME_BUTTON_YPOS,
12723     GAME_CTRL_ID_PAUSE,
12724     "pause game"
12725   },
12726   {
12727     GAME_BUTTON_PLAY_XPOS,      GAME_BUTTON_YPOS,
12728     GAME_CTRL_ID_PLAY,
12729     "play game"
12730   },
12731   {
12732     SOUND_BUTTON_MUSIC_XPOS,    SOUND_BUTTON_YPOS,
12733     SOUND_CTRL_ID_MUSIC,
12734     "background music on/off"
12735   },
12736   {
12737     SOUND_BUTTON_LOOPS_XPOS,    SOUND_BUTTON_YPOS,
12738     SOUND_CTRL_ID_LOOPS,
12739     "sound loops on/off"
12740   },
12741   {
12742     SOUND_BUTTON_SIMPLE_XPOS,   SOUND_BUTTON_YPOS,
12743     SOUND_CTRL_ID_SIMPLE,
12744     "normal sounds on/off"
12745   }
12746 };
12747
12748 void CreateGameButtons()
12749 {
12750   int i;
12751
12752   for (i = 0; i < NUM_GAME_BUTTONS; i++)
12753   {
12754     Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
12755     struct GadgetInfo *gi;
12756     int button_type;
12757     boolean checked;
12758     unsigned long event_mask;
12759     int gd_xoffset, gd_yoffset;
12760     int gd_x1, gd_x2, gd_y1, gd_y2;
12761     int id = i;
12762
12763     gd_xoffset = gamebutton_info[i].x;
12764     gd_yoffset = gamebutton_info[i].y;
12765     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
12766     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
12767
12768     if (id == GAME_CTRL_ID_STOP ||
12769         id == GAME_CTRL_ID_PAUSE ||
12770         id == GAME_CTRL_ID_PLAY)
12771     {
12772       button_type = GD_TYPE_NORMAL_BUTTON;
12773       checked = FALSE;
12774       event_mask = GD_EVENT_RELEASED;
12775       gd_y1  = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
12776       gd_y2  = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
12777     }
12778     else
12779     {
12780       button_type = GD_TYPE_CHECK_BUTTON;
12781       checked =
12782         ((id == SOUND_CTRL_ID_MUSIC && setup.sound_music) ||
12783          (id == SOUND_CTRL_ID_LOOPS && setup.sound_loops) ||
12784          (id == SOUND_CTRL_ID_SIMPLE && setup.sound_simple) ? TRUE : FALSE);
12785       event_mask = GD_EVENT_PRESSED;
12786       gd_y1  = DOOR_GFX_PAGEY1 + gd_yoffset;
12787       gd_y2  = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
12788     }
12789
12790     gi = CreateGadget(GDI_CUSTOM_ID, id,
12791                       GDI_INFO_TEXT, gamebutton_info[i].infotext,
12792                       GDI_X, DX + gd_xoffset,
12793                       GDI_Y, DY + gd_yoffset,
12794                       GDI_WIDTH, GAME_BUTTON_XSIZE,
12795                       GDI_HEIGHT, GAME_BUTTON_YSIZE,
12796                       GDI_TYPE, button_type,
12797                       GDI_STATE, GD_BUTTON_UNPRESSED,
12798                       GDI_CHECKED, checked,
12799                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
12800                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y1,
12801                       GDI_ALT_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y2,
12802                       GDI_ALT_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
12803                       GDI_EVENT_MASK, event_mask,
12804                       GDI_CALLBACK_ACTION, HandleGameButtons,
12805                       GDI_END);
12806
12807     if (gi == NULL)
12808       Error(ERR_EXIT, "cannot create gadget");
12809
12810     game_gadget[id] = gi;
12811   }
12812 }
12813
12814 void FreeGameButtons()
12815 {
12816   int i;
12817
12818   for (i = 0; i < NUM_GAME_BUTTONS; i++)
12819     FreeGadget(game_gadget[i]);
12820 }
12821
12822 static void MapGameButtons()
12823 {
12824   int i;
12825
12826   for (i = 0; i < NUM_GAME_BUTTONS; i++)
12827     MapGadget(game_gadget[i]);
12828 }
12829
12830 void UnmapGameButtons()
12831 {
12832   int i;
12833
12834   for (i = 0; i < NUM_GAME_BUTTONS; i++)
12835     UnmapGadget(game_gadget[i]);
12836 }
12837
12838 static void HandleGameButtons(struct GadgetInfo *gi)
12839 {
12840   int id = gi->custom_id;
12841
12842   if (game_status != GAME_MODE_PLAYING)
12843     return;
12844
12845   switch (id)
12846   {
12847     case GAME_CTRL_ID_STOP:
12848       RequestQuitGame(TRUE);
12849       break;
12850
12851     case GAME_CTRL_ID_PAUSE:
12852       if (options.network)
12853       {
12854 #if defined(NETWORK_AVALIABLE)
12855         if (tape.pausing)
12856           SendToServer_ContinuePlaying();
12857         else
12858           SendToServer_PausePlaying();
12859 #endif
12860       }
12861       else
12862         TapeTogglePause(TAPE_TOGGLE_MANUAL);
12863       break;
12864
12865     case GAME_CTRL_ID_PLAY:
12866       if (tape.pausing)
12867       {
12868 #if defined(NETWORK_AVALIABLE)
12869         if (options.network)
12870           SendToServer_ContinuePlaying();
12871         else
12872 #endif
12873         {
12874           tape.pausing = FALSE;
12875           DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0);
12876         }
12877       }
12878       break;
12879
12880     case SOUND_CTRL_ID_MUSIC:
12881       if (setup.sound_music)
12882       { 
12883         setup.sound_music = FALSE;
12884         FadeMusic();
12885       }
12886       else if (audio.music_available)
12887       { 
12888         setup.sound = setup.sound_music = TRUE;
12889
12890         SetAudioMode(setup.sound);
12891
12892         PlayLevelMusic();
12893       }
12894       break;
12895
12896     case SOUND_CTRL_ID_LOOPS:
12897       if (setup.sound_loops)
12898         setup.sound_loops = FALSE;
12899       else if (audio.loops_available)
12900       {
12901         setup.sound = setup.sound_loops = TRUE;
12902         SetAudioMode(setup.sound);
12903       }
12904       break;
12905
12906     case SOUND_CTRL_ID_SIMPLE:
12907       if (setup.sound_simple)
12908         setup.sound_simple = FALSE;
12909       else if (audio.sound_available)
12910       {
12911         setup.sound = setup.sound_simple = TRUE;
12912         SetAudioMode(setup.sound);
12913       }
12914       break;
12915
12916     default:
12917       break;
12918   }
12919 }