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