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