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