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