rnd-20030119-1-src
[rocksndiamonds.git] / src / game.c
1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * game.c                                                   *
12 ***********************************************************/
13
14 #include "libgame/libgame.h"
15
16 #include "game.h"
17 #include "tools.h"
18 #include "screens.h"
19 #include "init.h"
20 #include "files.h"
21 #include "tape.h"
22 #include "network.h"
23
24 /* this switch controls how rocks move horizontally */
25 #define OLD_GAME_BEHAVIOUR      FALSE
26
27 /* EXPERIMENTAL STUFF */
28 #define USE_NEW_AMOEBA_CODE     FALSE
29
30 /* for DigField() */
31 #define DF_NO_PUSH              0
32 #define DF_DIG                  1
33 #define DF_SNAP                 2
34
35 /* for MoveFigure() */
36 #define MF_NO_ACTION            0
37 #define MF_MOVING               1
38 #define MF_ACTION               2
39
40 /* for ScrollFigure() */
41 #define SCROLL_INIT             0
42 #define SCROLL_GO_ON            1
43
44 /* for Explode() */
45 #define EX_PHASE_START          0
46 #define EX_NO_EXPLOSION         0
47 #define EX_NORMAL               1
48 #define EX_CENTER               2
49 #define EX_BORDER               3
50
51 /* special positions in the game control window (relative to control window) */
52 #define XX_LEVEL                37
53 #define YY_LEVEL                20
54 #define XX_EMERALDS             29
55 #define YY_EMERALDS             54
56 #define XX_DYNAMITE             29
57 #define YY_DYNAMITE             89
58 #define XX_KEYS                 18
59 #define YY_KEYS                 123
60 #define XX_SCORE                15
61 #define YY_SCORE                159
62 #define XX_TIME                 29
63 #define YY_TIME                 194
64
65 /* special positions in the game control window (relative to main window) */
66 #define DX_LEVEL                (DX + XX_LEVEL)
67 #define DY_LEVEL                (DY + YY_LEVEL)
68 #define DX_EMERALDS             (DX + XX_EMERALDS)
69 #define DY_EMERALDS             (DY + YY_EMERALDS)
70 #define DX_DYNAMITE             (DX + XX_DYNAMITE)
71 #define DY_DYNAMITE             (DY + YY_DYNAMITE)
72 #define DX_KEYS                 (DX + XX_KEYS)
73 #define DY_KEYS                 (DY + YY_KEYS)
74 #define DX_SCORE                (DX + XX_SCORE)
75 #define DY_SCORE                (DY + YY_SCORE)
76 #define DX_TIME                 (DX + XX_TIME)
77 #define DY_TIME                 (DY + YY_TIME)
78
79 /* values for initial player move delay (initial delay counter value) */
80 #define INITIAL_MOVE_DELAY_OFF  -1
81 #define INITIAL_MOVE_DELAY_ON   0
82
83 /* values for player movement speed (which is in fact a delay value) */
84 #define MOVE_DELAY_NORMAL_SPEED 8
85 #define MOVE_DELAY_HIGH_SPEED   4
86
87 #define DOUBLE_MOVE_DELAY(x)    (x = (x <= MOVE_DELAY_HIGH_SPEED ? x * 2 : x))
88 #define HALVE_MOVE_DELAY(x)     (x = (x >= MOVE_DELAY_HIGH_SPEED ? x / 2 : x))
89 #define DOUBLE_PLAYER_SPEED(p)  (HALVE_MOVE_DELAY((p)->move_delay_value))
90 #define HALVE_PLAYER_SPEED(p)   (DOUBLE_MOVE_DELAY((p)->move_delay_value))
91
92 /* game button identifiers */
93 #define GAME_CTRL_ID_STOP               0
94 #define GAME_CTRL_ID_PAUSE              1
95 #define GAME_CTRL_ID_PLAY               2
96 #define SOUND_CTRL_ID_MUSIC             3
97 #define SOUND_CTRL_ID_LOOPS             4
98 #define SOUND_CTRL_ID_SIMPLE            5
99
100 #define NUM_GAME_BUTTONS                6
101
102 /* forward declaration for internal use */
103 static void InitBeltMovement(void);
104 static void CloseAllOpenTimegates(void);
105 static void CheckGravityMovement(struct PlayerInfo *);
106 static void KillHeroUnlessProtected(int, int);
107
108 static void PlaySoundLevel(int, int, int);
109 static void PlaySoundLevelNearest(int, int, int);
110 static void PlaySoundLevelAction(int, int, int);
111 static void PlaySoundLevelElementAction(int, int, int, int);
112
113 static void MapGameButtons();
114 static void HandleGameButtons(struct GadgetInfo *);
115
116 static struct GadgetInfo *game_gadget[NUM_GAME_BUTTONS];
117
118 #define IS_ANIMATED(g)          (graphic_info[g].anim_frames > 1)
119 #define IS_LOOP_SOUND(s)        (sound_info[s].loop)
120
121
122 /* -------------------------------------------------------------------------
123    definition of elements that automatically change to other elements after
124    a specified time, eventually calling a function when changing
125    ------------------------------------------------------------------------- */
126
127 /* forward declaration for changer functions */
128 static void InitBuggyBase(int x, int y);
129 static void WarnBuggyBase(int x, int y);
130
131 static void InitTrap(int x, int y);
132 static void ActivateTrap(int x, int y);
133 static void ChangeActiveTrap(int x, int y);
134
135 static void InitRobotWheel(int x, int y);
136 static void RunRobotWheel(int x, int y);
137 static void StopRobotWheel(int x, int y);
138
139 static void InitTimegateWheel(int x, int y);
140 static void RunTimegateWheel(int x, int y);
141
142 struct ChangingElementInfo
143 {
144   int base_element;
145   int next_element;
146   int change_delay;
147   void (*pre_change_function)(int x, int y);
148   void (*change_function)(int x, int y);
149   void (*post_change_function)(int x, int y);
150 };
151
152 static struct ChangingElementInfo changing_element_list[] =
153 {
154   { EL_NUT_CRACKING,            EL_EMERALD,              6, NULL, NULL, NULL },
155   { EL_PEARL_BREAKING,          EL_EMPTY,                8, NULL, NULL, NULL },
156   { EL_EXIT_OPENING,            EL_EXIT_OPEN,           29, NULL, NULL, NULL },
157
158   { EL_SWITCHGATE_OPENING,      EL_SWITCHGATE_OPEN,     29, NULL, NULL, NULL },
159   { EL_SWITCHGATE_CLOSING,      EL_SWITCHGATE_CLOSED,   29, NULL, NULL, NULL },
160
161   { EL_TIMEGATE_OPENING,        EL_TIMEGATE_OPEN,       29, NULL, NULL, NULL },
162   { EL_TIMEGATE_CLOSING,        EL_TIMEGATE_CLOSED,     29, NULL, NULL, NULL },
163
164   { EL_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 ||
2211          smashed == EL_BD_MAGIC_WALL))
2212     {
2213       int xx, yy;
2214       int activated_magic_wall =
2215         (smashed == EL_MAGIC_WALL ? EL_MAGIC_WALL_ACTIVE :
2216          EL_BD_MAGIC_WALL_ACTIVE);
2217
2218       /* activate magic wall / mill */
2219       for (yy=0; yy<lev_fieldy; yy++)
2220         for (xx=0; xx<lev_fieldx; xx++)
2221           if (Feld[xx][yy] == smashed)
2222             Feld[xx][yy] = activated_magic_wall;
2223
2224       game.magic_wall_time_left = level.time_magic_wall * FRAMES_PER_SECOND;
2225       game.magic_wall_active = TRUE;
2226
2227       PlaySoundLevel(x, y, (smashed == EL_MAGIC_WALL ?
2228                             SND_MAGIC_WALL_ACTIVATING :
2229                             SND_BD_MAGIC_WALL_ACTIVATING));
2230     }
2231
2232     if (IS_PLAYER(x, y + 1))
2233     {
2234       KillHeroUnlessProtected(x, y+1);
2235       return;
2236     }
2237     else if (smashed == EL_PENGUIN)
2238     {
2239       Bang(x, y + 1);
2240       return;
2241     }
2242     else if (element == EL_BD_DIAMOND)
2243     {
2244       if (IS_ENEMY(smashed) && IS_BD_ELEMENT(smashed))
2245       {
2246         Bang(x, y + 1);
2247         return;
2248       }
2249     }
2250     else if ((element == EL_SP_INFOTRON ||
2251               element == EL_SP_ZONK) &&
2252              (smashed == EL_SP_SNIKSNAK ||
2253               smashed == EL_SP_ELECTRON ||
2254               smashed == EL_SP_DISK_ORANGE))
2255     {
2256       Bang(x, y + 1);
2257       return;
2258     }
2259     else if (element == EL_ROCK ||
2260              element == EL_SP_ZONK ||
2261              element == EL_BD_ROCK)
2262     {
2263       if (IS_ENEMY(smashed) ||
2264           smashed == EL_BOMB ||
2265           smashed == EL_SP_DISK_ORANGE ||
2266           smashed == EL_DX_SUPABOMB ||
2267           smashed == EL_SATELLITE ||
2268           smashed == EL_PIG ||
2269           smashed == EL_DRAGON ||
2270           smashed == EL_MOLE)
2271       {
2272         Bang(x, y + 1);
2273         return;
2274       }
2275       else if (!IS_MOVING(x, y + 1))
2276       {
2277         if (smashed == EL_LAMP ||
2278             smashed == EL_LAMP_ACTIVE)
2279         {
2280           Bang(x, y + 1);
2281           return;
2282         }
2283         else if (smashed == EL_NUT)
2284         {
2285           Feld[x][y+1] = EL_NUT_CRACKING;
2286           PlaySoundLevel(x, y, SND_NUT_CRACKING);
2287           RaiseScoreElement(EL_NUT);
2288           return;
2289         }
2290         else if (smashed == EL_PEARL)
2291         {
2292           Feld[x][y+1] = EL_PEARL_BREAKING;
2293           PlaySoundLevel(x, y, SND_PEARL_BREAKING);
2294           return;
2295         }
2296         else if (smashed == EL_DIAMOND)
2297         {
2298           Feld[x][y+1] = EL_EMPTY;
2299           PlaySoundLevel(x, y, SND_DIAMOND_BREAKING);
2300           return;
2301         }
2302         else if (IS_BELT_SWITCH(smashed))
2303         {
2304           ToggleBeltSwitch(x, y+1);
2305         }
2306         else if (smashed == EL_SWITCHGATE_SWITCH_UP ||
2307                  smashed == EL_SWITCHGATE_SWITCH_DOWN)
2308         {
2309           ToggleSwitchgateSwitch(x, y+1);
2310         }
2311         else if (smashed == EL_LIGHT_SWITCH ||
2312                  smashed == EL_LIGHT_SWITCH_ACTIVE)
2313         {
2314           ToggleLightSwitch(x, y+1);
2315         }
2316       }
2317     }
2318   }
2319
2320   /* play sound of magic wall / mill */
2321   if (!lastline &&
2322       (Feld[x][y+1] == EL_MAGIC_WALL_ACTIVE ||
2323        Feld[x][y+1] == EL_BD_MAGIC_WALL_ACTIVE))
2324   {
2325     if (Feld[x][y+1] == EL_MAGIC_WALL_ACTIVE)
2326       PlaySoundLevel(x, y, SND_MAGIC_WALL_CHANGING);
2327     else if (Feld[x][y+1] == EL_BD_MAGIC_WALL_ACTIVE)
2328       PlaySoundLevel(x, y, SND_BD_MAGIC_WALL_CHANGING);
2329
2330     return;
2331   }
2332
2333   /* play sound of object that hits the ground */
2334   if (lastline || object_hit)
2335     PlaySoundLevelElementAction(x, y, element, ACTION_IMPACT);
2336 }
2337
2338 void TurnRound(int x, int y)
2339 {
2340   static struct
2341   {
2342     int x, y;
2343   } move_xy[] =
2344   {
2345     { 0, 0 },
2346     {-1, 0 },
2347     {+1, 0 },
2348     { 0, 0 },
2349     { 0, -1 },
2350     { 0, 0 }, { 0, 0 }, { 0, 0 },
2351     { 0, +1 }
2352   };
2353   static struct
2354   {
2355     int left, right, back;
2356   } turn[] =
2357   {
2358     { 0,        0,              0 },
2359     { MV_DOWN,  MV_UP,          MV_RIGHT },
2360     { MV_UP,    MV_DOWN,        MV_LEFT },
2361     { 0,        0,              0 },
2362     { MV_LEFT,  MV_RIGHT,       MV_DOWN },
2363     { 0,0,0 },  { 0,0,0 },      { 0,0,0 },
2364     { MV_RIGHT, MV_LEFT,        MV_UP }
2365   };
2366
2367   int element = Feld[x][y];
2368   int old_move_dir = MovDir[x][y];
2369   int left_dir  = turn[old_move_dir].left;
2370   int right_dir = turn[old_move_dir].right;
2371   int back_dir  = turn[old_move_dir].back;
2372
2373   int left_dx  = move_xy[left_dir].x,     left_dy  = move_xy[left_dir].y;
2374   int right_dx = move_xy[right_dir].x,    right_dy = move_xy[right_dir].y;
2375   int move_dx  = move_xy[old_move_dir].x, move_dy  = move_xy[old_move_dir].y;
2376   int back_dx  = move_xy[back_dir].x,     back_dy  = move_xy[back_dir].y;
2377
2378   int left_x  = x + left_dx,  left_y  = y + left_dy;
2379   int right_x = x + right_dx, right_y = y + right_dy;
2380   int move_x  = x + move_dx,  move_y  = y + move_dy;
2381
2382   if (element == EL_BUG || element == EL_BD_BUTTERFLY)
2383   {
2384     TestIfBadThingTouchesOtherBadThing(x, y);
2385
2386     if (IN_LEV_FIELD(right_x, right_y) &&
2387         IS_FREE(right_x, right_y))
2388       MovDir[x][y] = right_dir;
2389     else if (!IN_LEV_FIELD(move_x, move_y) ||
2390              !IS_FREE(move_x, move_y))
2391       MovDir[x][y] = left_dir;
2392
2393     if (element == EL_BUG && MovDir[x][y] != old_move_dir)
2394       MovDelay[x][y] = 9;
2395     else if (element == EL_BD_BUTTERFLY)     /* && MovDir[x][y] == left_dir) */
2396       MovDelay[x][y] = 1;
2397   }
2398   else if (element == EL_SPACESHIP || element == EL_BD_FIREFLY ||
2399            element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
2400   {
2401     TestIfBadThingTouchesOtherBadThing(x, y);
2402
2403     if (IN_LEV_FIELD(left_x, left_y) &&
2404         IS_FREE(left_x, left_y))
2405       MovDir[x][y] = left_dir;
2406     else if (!IN_LEV_FIELD(move_x, move_y) ||
2407              !IS_FREE(move_x, move_y))
2408       MovDir[x][y] = right_dir;
2409
2410     if ((element == EL_SPACESHIP ||
2411          element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
2412         && MovDir[x][y] != old_move_dir)
2413       MovDelay[x][y] = 9;
2414     else if (element == EL_BD_FIREFLY)      /* && MovDir[x][y] == right_dir) */
2415       MovDelay[x][y] = 1;
2416   }
2417   else if (element == EL_YAMYAM)
2418   {
2419     boolean can_turn_left = FALSE, can_turn_right = FALSE;
2420
2421     if (IN_LEV_FIELD(left_x, left_y) &&
2422         (IS_FREE_OR_PLAYER(left_x, left_y) ||
2423          Feld[left_x][left_y] == EL_DIAMOND))
2424       can_turn_left = TRUE;
2425     if (IN_LEV_FIELD(right_x, right_y) &&
2426         (IS_FREE_OR_PLAYER(right_x, right_y) ||
2427          Feld[right_x][right_y] == EL_DIAMOND))
2428       can_turn_right = TRUE;
2429
2430     if (can_turn_left && can_turn_right)
2431       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
2432     else if (can_turn_left)
2433       MovDir[x][y] = (RND(2) ? left_dir : back_dir);
2434     else if (can_turn_right)
2435       MovDir[x][y] = (RND(2) ? right_dir : back_dir);
2436     else
2437       MovDir[x][y] = back_dir;
2438
2439     MovDelay[x][y] = 16+16*RND(3);
2440   }
2441   else if (element == EL_DARK_YAMYAM)
2442   {
2443     boolean can_turn_left = FALSE, can_turn_right = FALSE;
2444
2445     if (IN_LEV_FIELD(left_x, left_y) &&
2446         (IS_FREE_OR_PLAYER(left_x, left_y) ||
2447          IS_MAMPF2(Feld[left_x][left_y])))
2448       can_turn_left = TRUE;
2449     if (IN_LEV_FIELD(right_x, right_y) &&
2450         (IS_FREE_OR_PLAYER(right_x, right_y) ||
2451          IS_MAMPF2(Feld[right_x][right_y])))
2452       can_turn_right = TRUE;
2453
2454     if (can_turn_left && can_turn_right)
2455       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
2456     else if (can_turn_left)
2457       MovDir[x][y] = (RND(2) ? left_dir : back_dir);
2458     else if (can_turn_right)
2459       MovDir[x][y] = (RND(2) ? right_dir : back_dir);
2460     else
2461       MovDir[x][y] = back_dir;
2462
2463     MovDelay[x][y] = 16+16*RND(3);
2464   }
2465   else if (element == EL_PACMAN)
2466   {
2467     boolean can_turn_left = FALSE, can_turn_right = FALSE;
2468
2469     if (IN_LEV_FIELD(left_x, left_y) &&
2470         (IS_FREE_OR_PLAYER(left_x, left_y) ||
2471          IS_AMOEBOID(Feld[left_x][left_y])))
2472       can_turn_left = TRUE;
2473     if (IN_LEV_FIELD(right_x, right_y) &&
2474         (IS_FREE_OR_PLAYER(right_x, right_y) ||
2475          IS_AMOEBOID(Feld[right_x][right_y])))
2476       can_turn_right = TRUE;
2477
2478     if (can_turn_left && can_turn_right)
2479       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
2480     else if (can_turn_left)
2481       MovDir[x][y] = (RND(2) ? left_dir : back_dir);
2482     else if (can_turn_right)
2483       MovDir[x][y] = (RND(2) ? right_dir : back_dir);
2484     else
2485       MovDir[x][y] = back_dir;
2486
2487     MovDelay[x][y] = 6+RND(40);
2488   }
2489   else if (element == EL_PIG)
2490   {
2491     boolean can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE;
2492     boolean should_turn_left = FALSE, should_turn_right = FALSE;
2493     boolean should_move_on = FALSE;
2494     int rnd_value = 24;
2495     int rnd = RND(rnd_value);
2496
2497     if (IN_LEV_FIELD(left_x, left_y) &&
2498         (IS_FREE(left_x, left_y) || IS_GEM(Feld[left_x][left_y])))
2499       can_turn_left = TRUE;
2500     if (IN_LEV_FIELD(right_x, right_y) &&
2501         (IS_FREE(right_x, right_y) || IS_GEM(Feld[right_x][right_y])))
2502       can_turn_right = TRUE;
2503     if (IN_LEV_FIELD(move_x, move_y) &&
2504         (IS_FREE(move_x, move_y) || IS_GEM(Feld[move_x][move_y])))
2505       can_move_on = TRUE;
2506
2507     if (can_turn_left &&
2508         (!can_move_on ||
2509          (IN_LEV_FIELD(x+back_dx+left_dx, y+back_dy+left_dy) &&
2510           !IS_FREE(x+back_dx+left_dx, y+back_dy+left_dy))))
2511       should_turn_left = TRUE;
2512     if (can_turn_right &&
2513         (!can_move_on ||
2514          (IN_LEV_FIELD(x+back_dx+right_dx, y+back_dy+right_dy) &&
2515           !IS_FREE(x+back_dx+right_dx, y+back_dy+right_dy))))
2516       should_turn_right = TRUE;
2517     if (can_move_on &&
2518         (!can_turn_left || !can_turn_right ||
2519          (IN_LEV_FIELD(x+move_dx+left_dx, y+move_dy+left_dy) &&
2520           !IS_FREE(x+move_dx+left_dx, y+move_dy+left_dy)) ||
2521          (IN_LEV_FIELD(x+move_dx+right_dx, y+move_dy+right_dy) &&
2522           !IS_FREE(x+move_dx+right_dx, y+move_dy+right_dy))))
2523       should_move_on = TRUE;
2524
2525     if (should_turn_left || should_turn_right || should_move_on)
2526     {
2527       if (should_turn_left && should_turn_right && should_move_on)
2528         MovDir[x][y] = (rnd < rnd_value/3 ? left_dir :
2529                         rnd < 2*rnd_value/3 ? right_dir :
2530                         old_move_dir);
2531       else if (should_turn_left && should_turn_right)
2532         MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
2533       else if (should_turn_left && should_move_on)
2534         MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : old_move_dir);
2535       else if (should_turn_right && should_move_on)
2536         MovDir[x][y] = (rnd < rnd_value/2 ? right_dir : old_move_dir);
2537       else if (should_turn_left)
2538         MovDir[x][y] = left_dir;
2539       else if (should_turn_right)
2540         MovDir[x][y] = right_dir;
2541       else if (should_move_on)
2542         MovDir[x][y] = old_move_dir;
2543     }
2544     else if (can_move_on && rnd > rnd_value/8)
2545       MovDir[x][y] = old_move_dir;
2546     else if (can_turn_left && can_turn_right)
2547       MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
2548     else if (can_turn_left && rnd > rnd_value/8)
2549       MovDir[x][y] = left_dir;
2550     else if (can_turn_right && rnd > rnd_value/8)
2551       MovDir[x][y] = right_dir;
2552     else
2553       MovDir[x][y] = back_dir;
2554
2555     if (!IS_FREE(x+move_xy[MovDir[x][y]].x, y+move_xy[MovDir[x][y]].y) &&
2556         !IS_GEM(Feld[x+move_xy[MovDir[x][y]].x][y+move_xy[MovDir[x][y]].y]))
2557       MovDir[x][y] = old_move_dir;
2558
2559     MovDelay[x][y] = 0;
2560   }
2561   else if (element == EL_DRAGON)
2562   {
2563     boolean can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE;
2564     int rnd_value = 24;
2565     int rnd = RND(rnd_value);
2566
2567     if (IN_LEV_FIELD(left_x, left_y) && IS_FREE(left_x, left_y))
2568       can_turn_left = TRUE;
2569     if (IN_LEV_FIELD(right_x, right_y) && IS_FREE(right_x, right_y))
2570       can_turn_right = TRUE;
2571     if (IN_LEV_FIELD(move_x, move_y) && IS_FREE(move_x, move_y))
2572       can_move_on = TRUE;
2573
2574     if (can_move_on && rnd > rnd_value/8)
2575       MovDir[x][y] = old_move_dir;
2576     else if (can_turn_left && can_turn_right)
2577       MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
2578     else if (can_turn_left && rnd > rnd_value/8)
2579       MovDir[x][y] = left_dir;
2580     else if (can_turn_right && rnd > rnd_value/8)
2581       MovDir[x][y] = right_dir;
2582     else
2583       MovDir[x][y] = back_dir;
2584
2585     if (!IS_FREE(x+move_xy[MovDir[x][y]].x, y+move_xy[MovDir[x][y]].y))
2586       MovDir[x][y] = old_move_dir;
2587
2588     MovDelay[x][y] = 0;
2589   }
2590   else if (element == EL_MOLE)
2591   {
2592     boolean can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE;
2593
2594     if (IN_LEV_FIELD(move_x, move_y) &&
2595         (IS_FREE(move_x, move_y) || IS_AMOEBOID(Feld[move_x][move_y]) ||
2596          Feld[move_x][move_y] == EL_AMOEBA_SHRINKING))
2597       can_move_on = TRUE;
2598
2599     if (!can_move_on)
2600     {
2601       if (IN_LEV_FIELD(left_x, left_y) &&
2602           (IS_FREE(left_x, left_y) || IS_AMOEBOID(Feld[left_x][left_y])))
2603         can_turn_left = TRUE;
2604       if (IN_LEV_FIELD(right_x, right_y) &&
2605           (IS_FREE(right_x, right_y) || IS_AMOEBOID(Feld[right_x][right_y])))
2606         can_turn_right = TRUE;
2607
2608       if (can_turn_left && can_turn_right)
2609         MovDir[x][y] = (RND(2) ? left_dir : right_dir);
2610       else if (can_turn_left)
2611         MovDir[x][y] = left_dir;
2612       else
2613         MovDir[x][y] = right_dir;
2614     }
2615
2616     if (MovDir[x][y] != old_move_dir)
2617       MovDelay[x][y] = 9;
2618   }
2619   else if (element == EL_BALLOON)
2620   {
2621     MovDir[x][y] = game.balloon_dir;
2622     MovDelay[x][y] = 0;
2623   }
2624   else if (element == EL_SPRING)
2625   {
2626     if ((MovDir[x][y] == MV_LEFT || MovDir[x][y] == MV_RIGHT) &&
2627         (!IN_LEV_FIELD(move_x, move_y) || !IS_FREE(move_x, move_y) ||
2628          (IN_LEV_FIELD(x, y + 1) && IS_FREE(x, y + 1))))
2629       MovDir[x][y] = MV_NO_MOVING;
2630
2631     MovDelay[x][y] = 0;
2632   }
2633   else if (element == EL_ROBOT ||
2634            element == EL_SATELLITE ||
2635            element == EL_PENGUIN)
2636   {
2637     int attr_x = -1, attr_y = -1;
2638
2639     if (AllPlayersGone)
2640     {
2641       attr_x = ExitX;
2642       attr_y = ExitY;
2643     }
2644     else
2645     {
2646       int i;
2647
2648       for (i=0; i<MAX_PLAYERS; i++)
2649       {
2650         struct PlayerInfo *player = &stored_player[i];
2651         int jx = player->jx, jy = player->jy;
2652
2653         if (!player->active)
2654           continue;
2655
2656         if (attr_x == -1 || ABS(jx-x)+ABS(jy-y) < ABS(attr_x-x)+ABS(attr_y-y))
2657         {
2658           attr_x = jx;
2659           attr_y = jy;
2660         }
2661       }
2662     }
2663
2664     if (element == EL_ROBOT && ZX >= 0 && ZY >= 0)
2665     {
2666       attr_x = ZX;
2667       attr_y = ZY;
2668     }
2669
2670     if (element == EL_PENGUIN)
2671     {
2672       int i;
2673       static int xy[4][2] =
2674       {
2675         { 0, -1 },
2676         { -1, 0 },
2677         { +1, 0 },
2678         { 0, +1 }
2679       };
2680
2681       for (i=0; i<4; i++)
2682       {
2683         int ex = x + xy[i%4][0];
2684         int ey = y + xy[i%4][1];
2685
2686         if (IN_LEV_FIELD(ex, ey) && Feld[ex][ey] == EL_EXIT_OPEN)
2687         {
2688           attr_x = ex;
2689           attr_y = ey;
2690           break;
2691         }
2692       }
2693     }
2694
2695     MovDir[x][y] = MV_NO_MOVING;
2696     if (attr_x<x)
2697       MovDir[x][y] |= (AllPlayersGone ? MV_RIGHT : MV_LEFT);
2698     else if (attr_x>x)
2699       MovDir[x][y] |= (AllPlayersGone ? MV_LEFT : MV_RIGHT);
2700     if (attr_y<y)
2701       MovDir[x][y] |= (AllPlayersGone ? MV_DOWN : MV_UP);
2702     else if (attr_y>y)
2703       MovDir[x][y] |= (AllPlayersGone ? MV_UP : MV_DOWN);
2704
2705     if (element == EL_ROBOT)
2706     {
2707       int newx, newy;
2708
2709       if ((MovDir[x][y]&(MV_LEFT|MV_RIGHT)) && (MovDir[x][y]&(MV_UP|MV_DOWN)))
2710         MovDir[x][y] &= (RND(2) ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
2711       Moving2Blocked(x, y, &newx, &newy);
2712
2713       if (IN_LEV_FIELD(newx, newy) && IS_FREE_OR_PLAYER(newx, newy))
2714         MovDelay[x][y] = 8+8*!RND(3);
2715       else
2716         MovDelay[x][y] = 16;
2717     }
2718     else
2719     {
2720       int newx, newy;
2721
2722       MovDelay[x][y] = 1;
2723
2724       if ((MovDir[x][y]&(MV_LEFT|MV_RIGHT)) && (MovDir[x][y]&(MV_UP|MV_DOWN)))
2725       {
2726         boolean first_horiz = RND(2);
2727         int new_move_dir = MovDir[x][y];
2728
2729         MovDir[x][y] =
2730           new_move_dir & (first_horiz ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
2731         Moving2Blocked(x, y, &newx, &newy);
2732
2733         if (IN_LEV_FIELD(newx, newy) &&
2734             (IS_FREE(newx, newy) ||
2735              Feld[newx][newy] == EL_ACID ||
2736              (element == EL_PENGUIN &&
2737               (Feld[newx][newy] == EL_EXIT_OPEN ||
2738                IS_MAMPF3(Feld[newx][newy])))))
2739           return;
2740
2741         MovDir[x][y] =
2742           new_move_dir & (!first_horiz ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
2743         Moving2Blocked(x, y, &newx, &newy);
2744
2745         if (IN_LEV_FIELD(newx, newy) &&
2746             (IS_FREE(newx, newy) ||
2747              Feld[newx][newy] == EL_ACID ||
2748              (element == EL_PENGUIN &&
2749               (Feld[newx][newy] == EL_EXIT_OPEN ||
2750                IS_MAMPF3(Feld[newx][newy])))))
2751           return;
2752
2753         MovDir[x][y] = old_move_dir;
2754         return;
2755       }
2756     }
2757   }
2758 }
2759
2760 static boolean JustBeingPushed(int x, int y)
2761 {
2762   int i;
2763
2764   for (i=0; i<MAX_PLAYERS; i++)
2765   {
2766     struct PlayerInfo *player = &stored_player[i];
2767
2768     if (player->active && player->Pushing && player->MovPos)
2769     {
2770       int next_jx = player->jx + (player->jx - player->last_jx);
2771       int next_jy = player->jy + (player->jy - player->last_jy);
2772
2773       if (x == next_jx && y == next_jy)
2774         return TRUE;
2775     }
2776   }
2777
2778   return FALSE;
2779 }
2780
2781 void StartMoving(int x, int y)
2782 {
2783   static boolean use_spring_bug = TRUE;
2784   boolean started_moving = FALSE;       /* some elements can fall _and_ move */
2785   int element = Feld[x][y];
2786
2787   if (Stop[x][y])
2788     return;
2789
2790   GfxAction[x][y] = ACTION_DEFAULT;
2791
2792   if (CAN_FALL(element) && y < lev_fieldy - 1)
2793   {
2794     if ((x>0 && IS_PLAYER(x-1, y)) || (x<lev_fieldx-1 && IS_PLAYER(x+1, y)))
2795       if (JustBeingPushed(x, y))
2796         return;
2797
2798     if (element == EL_QUICKSAND_FULL)
2799     {
2800       if (IS_FREE(x, y+1))
2801       {
2802         InitMovingField(x, y, MV_DOWN);
2803         started_moving = TRUE;
2804
2805         Feld[x][y] = EL_QUICKSAND_EMPTYING;
2806         Store[x][y] = EL_ROCK;
2807         PlaySoundLevel(x, y, SND_QUICKSAND_EMPTYING);
2808       }
2809       else if (Feld[x][y+1] == EL_QUICKSAND_EMPTY)
2810       {
2811         if (!MovDelay[x][y])
2812           MovDelay[x][y] = TILEY + 1;
2813
2814         if (MovDelay[x][y])
2815         {
2816           MovDelay[x][y]--;
2817           if (MovDelay[x][y])
2818             return;
2819         }
2820
2821         Feld[x][y] = EL_QUICKSAND_EMPTY;
2822         Feld[x][y+1] = EL_QUICKSAND_FULL;
2823         Store[x][y+1] = Store[x][y];
2824         Store[x][y] = 0;
2825         PlaySoundLevel(x, y, SND_QUICKSAND_SLIPPING);
2826       }
2827     }
2828     else if ((element == EL_ROCK || element == EL_BD_ROCK) &&
2829              Feld[x][y+1] == EL_QUICKSAND_EMPTY)
2830     {
2831       InitMovingField(x, y, MV_DOWN);
2832       started_moving = TRUE;
2833
2834       Feld[x][y] = EL_QUICKSAND_FILLING;
2835       Store[x][y] = element;
2836       PlaySoundLevel(x, y, SND_QUICKSAND_FILLING);
2837     }
2838     else if (element == EL_MAGIC_WALL_FULL)
2839     {
2840       if (IS_FREE(x, y+1))
2841       {
2842         InitMovingField(x, y, MV_DOWN);
2843         started_moving = TRUE;
2844
2845         Feld[x][y] = EL_MAGIC_WALL_EMPTYING;
2846         Store[x][y] = EL_CHANGED(Store[x][y]);
2847       }
2848       else if (Feld[x][y+1] == EL_MAGIC_WALL_ACTIVE)
2849       {
2850         if (!MovDelay[x][y])
2851           MovDelay[x][y] = TILEY/4 + 1;
2852
2853         if (MovDelay[x][y])
2854         {
2855           MovDelay[x][y]--;
2856           if (MovDelay[x][y])
2857             return;
2858         }
2859
2860         Feld[x][y] = EL_MAGIC_WALL_ACTIVE;
2861         Feld[x][y+1] = EL_MAGIC_WALL_FULL;
2862         Store[x][y+1] = EL_CHANGED(Store[x][y]);
2863         Store[x][y] = 0;
2864       }
2865     }
2866     else if (element == EL_BD_MAGIC_WALL_FULL)
2867     {
2868       if (IS_FREE(x, y+1))
2869       {
2870         InitMovingField(x, y, MV_DOWN);
2871         started_moving = TRUE;
2872
2873         Feld[x][y] = EL_BD_MAGIC_WALL_EMPTYING;
2874         Store[x][y] = EL_CHANGED2(Store[x][y]);
2875       }
2876       else if (Feld[x][y+1] == EL_BD_MAGIC_WALL_ACTIVE)
2877       {
2878         if (!MovDelay[x][y])
2879           MovDelay[x][y] = TILEY/4 + 1;
2880
2881         if (MovDelay[x][y])
2882         {
2883           MovDelay[x][y]--;
2884           if (MovDelay[x][y])
2885             return;
2886         }
2887
2888         Feld[x][y] = EL_BD_MAGIC_WALL_ACTIVE;
2889         Feld[x][y+1] = EL_BD_MAGIC_WALL_FULL;
2890         Store[x][y+1] = EL_CHANGED2(Store[x][y]);
2891         Store[x][y] = 0;
2892       }
2893     }
2894     else if (CAN_CHANGE(element) &&
2895              (Feld[x][y+1] == EL_MAGIC_WALL_ACTIVE ||
2896               Feld[x][y+1] == EL_BD_MAGIC_WALL_ACTIVE))
2897     {
2898       InitMovingField(x, y, MV_DOWN);
2899       started_moving = TRUE;
2900
2901       Feld[x][y] =
2902         (Feld[x][y+1] == EL_MAGIC_WALL_ACTIVE ? EL_MAGIC_WALL_FILLING :
2903          EL_BD_MAGIC_WALL_FILLING);
2904       Store[x][y] = element;
2905     }
2906     else if (CAN_SMASH(element) && Feld[x][y+1] == EL_ACID)
2907     {
2908       Blurb(x, y);
2909
2910       InitMovingField(x, y, MV_DOWN);
2911       started_moving = TRUE;
2912
2913       Store[x][y] = EL_ACID;
2914     }
2915     else if (CAN_SMASH(element) && Feld[x][y+1] == EL_BLOCKED &&
2916              JustStopped[x][y])
2917     {
2918       Impact(x, y);
2919     }
2920     else if (IS_FREE(x, y+1) && element == EL_SPRING && use_spring_bug)
2921     {
2922       if (MovDir[x][y] == MV_NO_MOVING)
2923       {
2924         InitMovingField(x, y, MV_DOWN);
2925         started_moving = TRUE;
2926       }
2927     }
2928     else if (IS_FREE(x, y+1))
2929     {
2930       InitMovingField(x, y, MV_DOWN);
2931       started_moving = TRUE;
2932     }
2933     else if (element == EL_AMOEBA_DROP)
2934     {
2935       Feld[x][y] = EL_AMOEBA_CREATING;
2936       Store[x][y] = EL_AMOEBA_WET;
2937     }
2938     /* Store[x][y+1] must be zero, because:
2939        (EL_QUICKSAND_FULL -> EL_ROCK): Store[x][y+1] == EL_QUICKSAND_EMPTY
2940     */
2941 #if 0
2942 #if OLD_GAME_BEHAVIOUR
2943     else if (IS_SLIPPERY(Feld[x][y+1]) && !Store[x][y+1])
2944 #else
2945     else if (IS_SLIPPERY(Feld[x][y+1]) && !Store[x][y+1] &&
2946              !IS_FALLING(x, y+1) && !JustStopped[x][y+1] &&
2947              element != EL_DX_SUPABOMB)
2948 #endif
2949 #else
2950     else if ((IS_SLIPPERY(Feld[x][y+1]) ||
2951               (IS_EM_SLIPPERY_WALL(Feld[x][y+1]) && IS_GEM(element))) &&
2952              !IS_FALLING(x, y+1) && !JustStopped[x][y+1] &&
2953              element != EL_DX_SUPABOMB && element != EL_SP_DISK_ORANGE)
2954 #endif
2955     {
2956       boolean left  = (x>0 && IS_FREE(x-1, y) &&
2957                        (IS_FREE(x-1, y+1) || Feld[x-1][y+1] == EL_ACID));
2958       boolean right = (x<lev_fieldx-1 && IS_FREE(x+1, y) &&
2959                        (IS_FREE(x+1, y+1) || Feld[x+1][y+1] == EL_ACID));
2960
2961       if (left || right)
2962       {
2963         if (left && right &&
2964             (game.emulation != EMU_BOULDERDASH &&
2965              element != EL_BD_ROCK && element != EL_BD_DIAMOND))
2966           left = !(right = RND(2));
2967
2968         InitMovingField(x, y, left ? MV_LEFT : MV_RIGHT);
2969         started_moving = TRUE;
2970       }
2971     }
2972     else if (IS_BELT_ACTIVE(Feld[x][y+1]))
2973     {
2974       boolean left_is_free  = (x>0 && IS_FREE(x-1, y));
2975       boolean right_is_free = (x<lev_fieldx-1 && IS_FREE(x+1, y));
2976       int belt_nr = getBeltNrFromBeltActiveElement(Feld[x][y+1]);
2977       int belt_dir = game.belt_dir[belt_nr];
2978
2979       if ((belt_dir == MV_LEFT  && left_is_free) ||
2980           (belt_dir == MV_RIGHT && right_is_free))
2981       {
2982         InitMovingField(x, y, belt_dir);
2983         started_moving = TRUE;
2984
2985         GfxAction[x][y] = ACTION_DEFAULT;
2986       }
2987     }
2988   }
2989
2990   /* not "else if" because of EL_SPRING */
2991   if (CAN_MOVE(element) && !started_moving)
2992   {
2993     int newx, newy;
2994
2995     if ((element == EL_SATELLITE ||
2996          element == EL_BALLOON ||
2997          element == EL_SPRING)
2998         && JustBeingPushed(x, y))
2999       return;
3000
3001 #if 0
3002 #if 0
3003     if (element == EL_SPRING && MovDir[x][y] == MV_DOWN)
3004       Feld[x][y + 1] = EL_EMPTY;        /* was set to EL_BLOCKED above */
3005 #else
3006     if (element == EL_SPRING && MovDir[x][y] != MV_NO_MOVING)
3007     {
3008       Moving2Blocked(x, y, &newx, &newy);
3009       if (Feld[newx][newy] == EL_BLOCKED)
3010         Feld[newx][newy] = EL_EMPTY;    /* was set to EL_BLOCKED above */
3011     }
3012 #endif
3013 #endif
3014
3015     if (!MovDelay[x][y])        /* start new movement phase */
3016     {
3017       /* all objects that can change their move direction after each step */
3018       /* (MAMPFER, MAMPFER2 and PACMAN go straight until they hit a wall  */
3019
3020       if (element != EL_YAMYAM &&
3021           element != EL_DARK_YAMYAM &&
3022           element != EL_PACMAN)
3023       {
3024 #if 0
3025   if (element == EL_SPRING)
3026     printf("1--> %d\n", MovDir[x][y]);
3027 #endif
3028         TurnRound(x, y);
3029 #if 0
3030   if (element == EL_SPRING)
3031     printf("2--> %d\n", MovDir[x][y]);
3032 #endif
3033         if (MovDelay[x][y] && (element == EL_BUG ||
3034                                element == EL_SPACESHIP ||
3035                                element == EL_SP_SNIKSNAK ||
3036                                element == EL_SP_ELECTRON ||
3037                                element == EL_MOLE))
3038           DrawLevelField(x, y);
3039       }
3040     }
3041
3042     if (MovDelay[x][y])         /* wait some time before next movement */
3043     {
3044       MovDelay[x][y]--;
3045
3046       if (element == EL_ROBOT ||
3047           element == EL_YAMYAM || element == EL_DARK_YAMYAM)
3048       {
3049         if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3050         {
3051           int graphic = el2img(element);
3052           int frame = getGraphicAnimationFrame(graphic, MovDelay[x][y] % 8);
3053
3054           DrawGraphic(SCREENX(x), SCREENY(y), graphic, frame);
3055         }
3056
3057         if (MovDelay[x][y] % 4 == 3)
3058         {
3059           if (element == EL_YAMYAM)
3060             PlaySoundLevel(x, y, SND_YAMYAM_WAITING);
3061           else if (element == EL_DARK_YAMYAM)
3062             PlaySoundLevel(x, y, SND_DARK_YAMYAM_WAITING);
3063         }
3064       }
3065       else if (element == EL_SP_ELECTRON)
3066         DrawLevelElementAnimation(x, y, element);
3067       else if (element == EL_DRAGON)
3068       {
3069         int i;
3070         int dir = MovDir[x][y];
3071         int dx = (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
3072         int dy = (dir == MV_UP   ? -1 : dir == MV_DOWN  ? +1 : 0);
3073         int graphic = (dir == MV_LEFT   ? IMG_FLAMES_LEFT1 :
3074                        dir == MV_RIGHT  ? IMG_FLAMES_RIGHT1 :
3075                        dir == MV_UP     ? IMG_FLAMES_UP1 :
3076                        dir == MV_DOWN   ? IMG_FLAMES_DOWN1 : IMG_EMPTY);
3077         int frame = getGraphicAnimationFrame(graphic, -1);
3078
3079         for (i=1; i<=3; i++)
3080         {
3081           int xx = x + i*dx, yy = y + i*dy;
3082           int sx = SCREENX(xx), sy = SCREENY(yy);
3083           int flame_graphic = graphic + (i - 1);
3084
3085           if (!IN_LEV_FIELD(xx, yy) ||
3086               IS_SOLID(Feld[xx][yy]) || Feld[xx][yy] == EL_EXPLOSION)
3087             break;
3088
3089           if (MovDelay[x][y])
3090           {
3091             int flamed = MovingOrBlocked2Element(xx, yy);
3092
3093             if (IS_ENEMY(flamed) || IS_EXPLOSIVE(flamed))
3094               Bang(xx, yy);
3095             else
3096               RemoveMovingField(xx, yy);
3097
3098             Feld[xx][yy] = EL_FLAMES;
3099             if (IN_SCR_FIELD(sx, sy))
3100               DrawGraphic(sx, sy, flame_graphic, frame);
3101           }
3102           else
3103           {
3104             if (Feld[xx][yy] == EL_FLAMES)
3105               Feld[xx][yy] = EL_EMPTY;
3106             DrawLevelField(xx, yy);
3107           }
3108         }
3109       }
3110
3111       if (MovDelay[x][y])       /* element still has to wait some time */
3112       {
3113         PlaySoundLevelAction(x, y, ACTION_WAITING);
3114
3115         return;
3116       }
3117     }
3118
3119     /* now make next step */
3120
3121     Moving2Blocked(x, y, &newx, &newy); /* get next screen position */
3122
3123     if (IS_ENEMY(element) && IS_PLAYER(newx, newy) &&
3124         !PLAYER_PROTECTED(newx, newy))
3125     {
3126
3127 #if 1
3128       TestIfBadThingRunsIntoHero(x, y, MovDir[x][y]);
3129       return;
3130 #else
3131       /* enemy got the player */
3132       MovDir[x][y] = 0;
3133       KillHero(PLAYERINFO(newx, newy));
3134       return;
3135 #endif
3136
3137     }
3138     else if ((element == EL_PENGUIN || element == EL_ROBOT ||
3139               element == EL_SATELLITE || element == EL_BALLOON) &&
3140              IN_LEV_FIELD(newx, newy) &&
3141              MovDir[x][y] == MV_DOWN && Feld[newx][newy] == EL_ACID)
3142     {
3143       Blurb(x, y);
3144       Store[x][y] = EL_ACID;
3145     }
3146     else if (element == EL_PENGUIN && IN_LEV_FIELD(newx, newy))
3147     {
3148       if (Feld[newx][newy] == EL_EXIT_OPEN)
3149       {
3150         Feld[x][y] = EL_EMPTY;
3151         DrawLevelField(x, y);
3152
3153         PlaySoundLevel(newx, newy, SND_PENGUIN_PASSING_EXIT);
3154         if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
3155           DrawGraphicThruMask(SCREENX(newx),SCREENY(newy), el2img(element), 0);
3156
3157         local_player->friends_still_needed--;
3158         if (!local_player->friends_still_needed &&
3159             !local_player->GameOver && AllPlayersGone)
3160           local_player->LevelSolved = local_player->GameOver = TRUE;
3161
3162         return;
3163       }
3164       else if (IS_MAMPF3(Feld[newx][newy]))
3165       {
3166         if (DigField(local_player, newx, newy, 0, 0, DF_DIG) == MF_MOVING)
3167           DrawLevelField(newx, newy);
3168         else
3169           MovDir[x][y] = MV_NO_MOVING;
3170       }
3171       else if (!IS_FREE(newx, newy))
3172       {
3173         if (IS_PLAYER(x, y))
3174           DrawPlayerField(x, y);
3175         else
3176           DrawLevelField(x, y);
3177         return;
3178       }
3179     }
3180     else if (element == EL_PIG && IN_LEV_FIELD(newx, newy))
3181     {
3182       if (IS_GEM(Feld[newx][newy]))
3183       {
3184         if (IS_MOVING(newx, newy))
3185           RemoveMovingField(newx, newy);
3186         else
3187         {
3188           Feld[newx][newy] = EL_EMPTY;
3189           DrawLevelField(newx, newy);
3190         }
3191
3192         PlaySoundLevel(x, y, SND_PIG_EATING);
3193       }
3194       else if (!IS_FREE(newx, newy))
3195       {
3196         if (IS_PLAYER(x, y))
3197           DrawPlayerField(x, y);
3198         else
3199           DrawLevelField(x, y);
3200         return;
3201       }
3202     }
3203     else if (element == EL_DRAGON && IN_LEV_FIELD(newx, newy))
3204     {
3205       if (!IS_FREE(newx, newy))
3206       {
3207         if (IS_PLAYER(x, y))
3208           DrawPlayerField(x, y);
3209         else
3210           DrawLevelField(x, y);
3211         return;
3212       }
3213       else
3214       {
3215         boolean wanna_flame = !RND(10);
3216         int dx = newx - x, dy = newy - y;
3217         int newx1 = newx+1*dx, newy1 = newy+1*dy;
3218         int newx2 = newx+2*dx, newy2 = newy+2*dy;
3219         int element1 = (IN_LEV_FIELD(newx1, newy1) ?
3220                         MovingOrBlocked2Element(newx1, newy1) : EL_STEELWALL);
3221         int element2 = (IN_LEV_FIELD(newx2, newy2) ?
3222                         MovingOrBlocked2Element(newx2, newy2) : EL_STEELWALL);
3223
3224         if ((wanna_flame || IS_ENEMY(element1) || IS_ENEMY(element2)) &&
3225             element1 != EL_DRAGON && element2 != EL_DRAGON &&
3226             element1 != EL_FLAMES && element2 != EL_FLAMES)
3227         {
3228           if (IS_PLAYER(x, y))
3229             DrawPlayerField(x, y);
3230           else
3231             DrawLevelField(x, y);
3232
3233           PlaySoundLevel(x, y, SND_DRAGON_ATTACKING);
3234
3235           MovDelay[x][y] = 50;
3236           Feld[newx][newy] = EL_FLAMES;
3237           if (IN_LEV_FIELD(newx1, newy1) && Feld[newx1][newy1] == EL_EMPTY)
3238             Feld[newx1][newy1] = EL_FLAMES;
3239           if (IN_LEV_FIELD(newx2, newy2) && Feld[newx2][newy2] == EL_EMPTY)
3240             Feld[newx2][newy2] = EL_FLAMES;
3241           return;
3242         }
3243       }
3244     }
3245     else if (element == EL_YAMYAM && IN_LEV_FIELD(newx, newy) &&
3246              Feld[newx][newy] == EL_DIAMOND)
3247     {
3248       if (IS_MOVING(newx, newy))
3249         RemoveMovingField(newx, newy);
3250       else
3251       {
3252         Feld[newx][newy] = EL_EMPTY;
3253         DrawLevelField(newx, newy);
3254       }
3255
3256       PlaySoundLevel(x, y, SND_YAMYAM_EATING);
3257     }
3258     else if (element == EL_DARK_YAMYAM && IN_LEV_FIELD(newx, newy) &&
3259              IS_MAMPF2(Feld[newx][newy]))
3260     {
3261       if (AmoebaNr[newx][newy])
3262       {
3263         AmoebaCnt2[AmoebaNr[newx][newy]]--;
3264         if (Feld[newx][newy] == EL_AMOEBA_FULL ||
3265             Feld[newx][newy] == EL_BD_AMOEBA)
3266           AmoebaCnt[AmoebaNr[newx][newy]]--;
3267       }
3268
3269       if (IS_MOVING(newx, newy))
3270         RemoveMovingField(newx, newy);
3271       else
3272       {
3273         Feld[newx][newy] = EL_EMPTY;
3274         DrawLevelField(newx, newy);
3275       }
3276
3277       PlaySoundLevel(x, y, SND_DARK_YAMYAM_EATING);
3278     }
3279     else if ((element == EL_PACMAN || element == EL_MOLE)
3280              && IN_LEV_FIELD(newx, newy) && IS_AMOEBOID(Feld[newx][newy]))
3281     {
3282       if (AmoebaNr[newx][newy])
3283       {
3284         AmoebaCnt2[AmoebaNr[newx][newy]]--;
3285         if (Feld[newx][newy] == EL_AMOEBA_FULL ||
3286             Feld[newx][newy] == EL_BD_AMOEBA)
3287           AmoebaCnt[AmoebaNr[newx][newy]]--;
3288       }
3289
3290       if (element == EL_MOLE)
3291       {
3292         Feld[newx][newy] = EL_AMOEBA_SHRINKING;
3293         PlaySoundLevel(x, y, SND_MOLE_EATING);
3294         MovDelay[newx][newy] = 0;       /* start amoeba shrinking delay */
3295         return;                         /* wait for shrinking amoeba */
3296       }
3297       else      /* element == EL_PACMAN */
3298       {
3299         Feld[newx][newy] = EL_EMPTY;
3300         DrawLevelField(newx, newy);
3301         PlaySoundLevel(x, y, SND_PACMAN_EATING);
3302       }
3303     }
3304     else if (element == EL_MOLE && IN_LEV_FIELD(newx, newy) &&
3305              (Feld[newx][newy] == EL_AMOEBA_SHRINKING ||
3306               (Feld[newx][newy] == EL_EMPTY && Stop[newx][newy])))
3307     {
3308       /* wait for shrinking amoeba to completely disappear */
3309       return;
3310     }
3311     else if (!IN_LEV_FIELD(newx, newy) || !IS_FREE(newx, newy))
3312     {
3313       /* object was running against a wall */
3314
3315       TurnRound(x, y);
3316
3317       if (element == EL_BUG || element == EL_SPACESHIP ||
3318           element == EL_SP_SNIKSNAK)
3319         DrawLevelField(x, y);
3320       else if (element == EL_BUG || element == EL_SPACESHIP ||
3321                element == EL_SP_SNIKSNAK || element == EL_MOLE)
3322         DrawLevelField(x, y);
3323       else if (element == EL_BD_BUTTERFLY || element == EL_BD_FIREFLY)
3324         DrawLevelElementAnimation(x, y, element);
3325       else if (element == EL_SATELLITE)
3326         DrawLevelElementAnimation(x, y, element);
3327       else if (element == EL_SP_ELECTRON)
3328         DrawLevelElementAnimation(x, y, element);
3329
3330       if (DONT_TOUCH(element))
3331         TestIfBadThingTouchesHero(x, y);
3332
3333       PlaySoundLevelAction(x, y, ACTION_WAITING);
3334
3335       return;
3336     }
3337
3338     InitMovingField(x, y, MovDir[x][y]);
3339
3340     PlaySoundLevelAction(x, y, ACTION_MOVING);
3341   }
3342
3343   if (MovDir[x][y])
3344     ContinueMoving(x, y);
3345 }
3346
3347 void ContinueMoving(int x, int y)
3348 {
3349   int element = Feld[x][y];
3350   int direction = MovDir[x][y];
3351   int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
3352   int dy = (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
3353   int horiz_move = (dx != 0);
3354   int newx = x + dx, newy = y + dy;
3355   int step = (horiz_move ? dx : dy) * TILEX / 8;
3356
3357   if (element == EL_AMOEBA_DROP || element == EL_AMOEBA_DRIPPING)
3358     step /= 2;
3359   else if (element == EL_QUICKSAND_FILLING ||
3360            element == EL_QUICKSAND_EMPTYING)
3361     step /= 4;
3362   else if (element == EL_MAGIC_WALL_FILLING ||
3363            element == EL_BD_MAGIC_WALL_FILLING ||
3364            element == EL_MAGIC_WALL_EMPTYING ||
3365            element == EL_BD_MAGIC_WALL_EMPTYING)
3366     step /= 2;
3367   else if (CAN_FALL(element) && horiz_move &&
3368            y < lev_fieldy-1 && IS_BELT_ACTIVE(Feld[x][y+1]))
3369     step /= 2;
3370   else if (element == EL_SPRING && horiz_move)
3371     step *= 2;
3372
3373 #if OLD_GAME_BEHAVIOUR
3374   else if (CAN_FALL(element) && horiz_move && !IS_SP_ELEMENT(element))
3375     step*=2;
3376 #endif
3377
3378   MovPos[x][y] += step;
3379
3380   if (ABS(MovPos[x][y]) >= TILEX)       /* object reached its destination */
3381   {
3382     Feld[x][y] = EL_EMPTY;
3383     Feld[newx][newy] = element;
3384
3385     if (element == EL_MOLE)
3386     {
3387       int i;
3388       static int xy[4][2] =
3389       {
3390         { 0, -1 },
3391         { -1, 0 },
3392         { +1, 0 },
3393         { 0, +1 }
3394       };
3395
3396       Feld[x][y] = EL_SAND;
3397       DrawLevelField(x, y);
3398
3399       for(i=0; i<4; i++)
3400       {
3401         int xx, yy;
3402
3403         xx = x + xy[i][0];
3404         yy = y + xy[i][1];
3405
3406         if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == EL_SAND)
3407           DrawLevelField(xx, yy);       /* for "DrawCrumbledSand()" */
3408       }
3409     }
3410
3411     if (element == EL_QUICKSAND_FILLING)
3412     {
3413       element = Feld[newx][newy] = get_next_element(element);
3414       Store[newx][newy] = Store[x][y];
3415     }
3416     else if (element == EL_QUICKSAND_EMPTYING)
3417     {
3418       Feld[x][y] = get_next_element(element);
3419       element = Feld[newx][newy] = Store[x][y];
3420     }
3421     else if (element == EL_MAGIC_WALL_FILLING)
3422     {
3423       element = Feld[newx][newy] = get_next_element(element);
3424       if (!game.magic_wall_active)
3425         element = Feld[newx][newy] = EL_MAGIC_WALL_DEAD;
3426       Store[newx][newy] = Store[x][y];
3427     }
3428     else if (element == EL_MAGIC_WALL_EMPTYING)
3429     {
3430       Feld[x][y] = get_next_element(element);
3431       if (!game.magic_wall_active)
3432         Feld[x][y] = EL_MAGIC_WALL_DEAD;
3433       element = Feld[newx][newy] = Store[x][y];
3434     }
3435     else if (element == EL_BD_MAGIC_WALL_FILLING)
3436     {
3437       element = Feld[newx][newy] = get_next_element(element);
3438       if (!game.magic_wall_active)
3439         element = Feld[newx][newy] = EL_BD_MAGIC_WALL_DEAD;
3440       Store[newx][newy] = Store[x][y];
3441     }
3442     else if (element == EL_BD_MAGIC_WALL_EMPTYING)
3443     {
3444       Feld[x][y] = get_next_element(element);
3445       if (!game.magic_wall_active)
3446         Feld[x][y] = EL_BD_MAGIC_WALL_DEAD;
3447       element = Feld[newx][newy] = Store[x][y];
3448     }
3449     else if (element == EL_AMOEBA_DRIPPING)
3450     {
3451       Feld[x][y] = get_next_element(element);
3452       element = Feld[newx][newy] = Store[x][y];
3453     }
3454     else if (Store[x][y] == EL_ACID)
3455     {
3456       element = Feld[newx][newy] = EL_ACID;
3457     }
3458
3459     Store[x][y] = 0;
3460     MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
3461     MovDelay[newx][newy] = 0;
3462
3463     GfxAction[newx][newy] = GfxAction[x][y];    /* keep action one frame */
3464     GfxAction[x][y] = ACTION_DEFAULT;
3465
3466 #if 0
3467     if (!CAN_MOVE(element))
3468       MovDir[newx][newy] = 0;
3469 #else
3470     /*
3471     if (CAN_FALL(element) && MovDir[newx][newy] == MV_DOWN)
3472       MovDir[newx][newy] = 0;
3473     */
3474
3475     if (!CAN_MOVE(element) ||
3476         (element == EL_SPRING && MovDir[newx][newy] == MV_DOWN))
3477       MovDir[newx][newy] = 0;
3478 #endif
3479
3480     DrawLevelField(x, y);
3481     DrawLevelField(newx, newy);
3482
3483     Stop[newx][newy] = TRUE;
3484     JustStopped[newx][newy] = 3;
3485
3486     if (DONT_TOUCH(element))    /* object may be nasty to player or others */
3487     {
3488       TestIfBadThingTouchesHero(newx, newy);
3489       TestIfBadThingTouchesFriend(newx, newy);
3490       TestIfBadThingTouchesOtherBadThing(newx, newy);
3491     }
3492     else if (element == EL_PENGUIN)
3493       TestIfFriendTouchesBadThing(newx, newy);
3494
3495     if (CAN_SMASH(element) && direction == MV_DOWN &&
3496         (newy == lev_fieldy-1 || !IS_FREE(x, newy+1)))
3497       Impact(x, newy);
3498   }
3499   else                          /* still moving on */
3500   {
3501 #if 0
3502     if (GfxAction[x][y] == ACTION_DEFAULT)
3503     {
3504       printf("reset GfxAction...\n");
3505
3506       GfxAction[x][y] = ACTION_MOVING;
3507     }
3508 #endif
3509
3510     DrawLevelField(x, y);
3511   }
3512 }
3513
3514 int AmoebeNachbarNr(int ax, int ay)
3515 {
3516   int i;
3517   int element = Feld[ax][ay];
3518   int group_nr = 0;
3519   static int xy[4][2] =
3520   {
3521     { 0, -1 },
3522     { -1, 0 },
3523     { +1, 0 },
3524     { 0, +1 }
3525   };
3526
3527   for (i=0; i<4; i++)
3528   {
3529     int x = ax + xy[i][0];
3530     int y = ay + xy[i][1];
3531
3532     if (!IN_LEV_FIELD(x, y))
3533       continue;
3534
3535     if (Feld[x][y] == element && AmoebaNr[x][y] > 0)
3536       group_nr = AmoebaNr[x][y];
3537   }
3538
3539   return group_nr;
3540 }
3541
3542 void AmoebenVereinigen(int ax, int ay)
3543 {
3544   int i, x, y, xx, yy;
3545   int new_group_nr = AmoebaNr[ax][ay];
3546   static int xy[4][2] =
3547   {
3548     { 0, -1 },
3549     { -1, 0 },
3550     { +1, 0 },
3551     { 0, +1 }
3552   };
3553
3554   if (new_group_nr == 0)
3555     return;
3556
3557   for (i=0; i<4; i++)
3558   {
3559     x = ax + xy[i][0];
3560     y = ay + xy[i][1];
3561
3562     if (!IN_LEV_FIELD(x, y))
3563       continue;
3564
3565     if ((Feld[x][y] == EL_AMOEBA_FULL ||
3566          Feld[x][y] == EL_BD_AMOEBA ||
3567          Feld[x][y] == EL_AMOEBA_DEAD) &&
3568         AmoebaNr[x][y] != new_group_nr)
3569     {
3570       int old_group_nr = AmoebaNr[x][y];
3571
3572       if (old_group_nr == 0)
3573         return;
3574
3575       AmoebaCnt[new_group_nr] += AmoebaCnt[old_group_nr];
3576       AmoebaCnt[old_group_nr] = 0;
3577       AmoebaCnt2[new_group_nr] += AmoebaCnt2[old_group_nr];
3578       AmoebaCnt2[old_group_nr] = 0;
3579
3580       for (yy=0; yy<lev_fieldy; yy++)
3581       {
3582         for (xx=0; xx<lev_fieldx; xx++)
3583         {
3584           if (AmoebaNr[xx][yy] == old_group_nr)
3585             AmoebaNr[xx][yy] = new_group_nr;
3586         }
3587       }
3588     }
3589   }
3590 }
3591
3592 void AmoebeUmwandeln(int ax, int ay)
3593 {
3594   int i, x, y;
3595
3596   if (Feld[ax][ay] == EL_AMOEBA_DEAD)
3597   {
3598     int group_nr = AmoebaNr[ax][ay];
3599
3600 #ifdef DEBUG
3601     if (group_nr == 0)
3602     {
3603       printf("AmoebeUmwandeln(): ax = %d, ay = %d\n", ax, ay);
3604       printf("AmoebeUmwandeln(): This should never happen!\n");
3605       return;
3606     }
3607 #endif
3608
3609     for (y=0; y<lev_fieldy; y++)
3610     {
3611       for (x=0; x<lev_fieldx; x++)
3612       {
3613         if (Feld[x][y] == EL_AMOEBA_DEAD && AmoebaNr[x][y] == group_nr)
3614         {
3615           AmoebaNr[x][y] = 0;
3616           Feld[x][y] = EL_AMOEBA_TO_DIAMOND;
3617         }
3618       }
3619     }
3620     PlaySoundLevel(ax, ay, (IS_GEM(level.amoeba_content) ?
3621                             SND_AMOEBA_TURNING_TO_GEM :
3622                             SND_AMOEBA_TURNING_TO_ROCK));
3623     Bang(ax, ay);
3624   }
3625   else
3626   {
3627     static int xy[4][2] =
3628     {
3629       { 0, -1 },
3630       { -1, 0 },
3631       { +1, 0 },
3632       { 0, +1 }
3633     };
3634
3635     for (i=0; i<4; i++)
3636     {
3637       x = ax + xy[i][0];
3638       y = ay + xy[i][1];
3639
3640       if (!IN_LEV_FIELD(x, y))
3641         continue;
3642
3643       if (Feld[x][y] == EL_AMOEBA_TO_DIAMOND)
3644       {
3645         PlaySoundLevel(x, y, (IS_GEM(level.amoeba_content) ?
3646                               SND_AMOEBA_TURNING_TO_GEM :
3647                               SND_AMOEBA_TURNING_TO_ROCK));
3648         Bang(x, y);
3649       }
3650     }
3651   }
3652 }
3653
3654 void AmoebeUmwandelnBD(int ax, int ay, int new_element)
3655 {
3656   int x, y;
3657   int group_nr = AmoebaNr[ax][ay];
3658   boolean done = FALSE;
3659
3660 #ifdef DEBUG
3661   if (group_nr == 0)
3662   {
3663     printf("AmoebeUmwandelnBD(): ax = %d, ay = %d\n", ax, ay);
3664     printf("AmoebeUmwandelnBD(): This should never happen!\n");
3665     return;
3666   }
3667 #endif
3668
3669   for (y=0; y<lev_fieldy; y++)
3670   {
3671     for (x=0; x<lev_fieldx; x++)
3672     {
3673       if (AmoebaNr[x][y] == group_nr &&
3674           (Feld[x][y] == EL_AMOEBA_DEAD ||
3675            Feld[x][y] == EL_BD_AMOEBA ||
3676            Feld[x][y] == EL_AMOEBA_CREATING))
3677       {
3678         AmoebaNr[x][y] = 0;
3679         Feld[x][y] = new_element;
3680         InitField(x, y, FALSE);
3681         DrawLevelField(x, y);
3682         done = TRUE;
3683       }
3684     }
3685   }
3686
3687   if (done)
3688     PlaySoundLevel(ax, ay, (new_element == EL_BD_ROCK ?
3689                             SND_BD_AMOEBA_TURNING_TO_ROCK :
3690                             SND_BD_AMOEBA_TURNING_TO_GEM));
3691 }
3692
3693 void AmoebeWaechst(int x, int y)
3694 {
3695   static unsigned long sound_delay = 0;
3696   static unsigned long sound_delay_value = 0;
3697
3698   if (!MovDelay[x][y])          /* start new growing cycle */
3699   {
3700     MovDelay[x][y] = 7;
3701
3702     if (DelayReached(&sound_delay, sound_delay_value))
3703     {
3704       if (Store[x][y] == EL_BD_AMOEBA)
3705         PlaySoundLevel(x, y, SND_BD_AMOEBA_CREATING);
3706       else
3707         PlaySoundLevel(x, y, SND_AMOEBA_CREATING);
3708       sound_delay_value = 30;
3709     }
3710   }
3711
3712   if (MovDelay[x][y])           /* wait some time before growing bigger */
3713   {
3714     MovDelay[x][y]--;
3715     if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3716     {
3717       int frame = getGraphicAnimationFrame(IMG_AMOEBA_CREATING,
3718                                            6 - MovDelay[x][y]);
3719
3720       DrawGraphic(SCREENX(x), SCREENY(y), IMG_AMOEBA_CREATING, frame);
3721     }
3722
3723     if (!MovDelay[x][y])
3724     {
3725       Feld[x][y] = Store[x][y];
3726       Store[x][y] = 0;
3727       DrawLevelField(x, y);
3728     }
3729   }
3730 }
3731
3732 void AmoebaDisappearing(int x, int y)
3733 {
3734   static unsigned long sound_delay = 0;
3735   static unsigned long sound_delay_value = 0;
3736
3737   if (!MovDelay[x][y])          /* start new shrinking cycle */
3738   {
3739     MovDelay[x][y] = 7;
3740
3741     if (DelayReached(&sound_delay, sound_delay_value))
3742       sound_delay_value = 30;
3743   }
3744
3745   if (MovDelay[x][y])           /* wait some time before shrinking */
3746   {
3747     MovDelay[x][y]--;
3748     if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3749     {
3750       int frame = getGraphicAnimationFrame(IMG_AMOEBA_SHRINKING,
3751                                            6 - MovDelay[x][y]);
3752
3753       DrawGraphic(SCREENX(x), SCREENY(y), IMG_AMOEBA_SHRINKING, frame);
3754     }
3755
3756     if (!MovDelay[x][y])
3757     {
3758       Feld[x][y] = EL_EMPTY;
3759       DrawLevelField(x, y);
3760
3761       /* don't let mole enter this field in this cycle;
3762          (give priority to objects falling to this field from above) */
3763       Stop[x][y] = TRUE;
3764     }
3765   }
3766 }
3767
3768 void AmoebeAbleger(int ax, int ay)
3769 {
3770   int i;
3771   int element = Feld[ax][ay];
3772   int newax = ax, neway = ay;
3773   static int xy[4][2] =
3774   {
3775     { 0, -1 },
3776     { -1, 0 },
3777     { +1, 0 },
3778     { 0, +1 }
3779   };
3780
3781   if (!level.amoeba_speed)
3782   {
3783     Feld[ax][ay] = EL_AMOEBA_DEAD;
3784     DrawLevelField(ax, ay);
3785     return;
3786   }
3787
3788   if (!MovDelay[ax][ay])        /* start making new amoeba field */
3789     MovDelay[ax][ay] = RND(FRAMES_PER_SECOND * 25 / (1 + level.amoeba_speed));
3790
3791   if (MovDelay[ax][ay])         /* wait some time before making new amoeba */
3792   {
3793     MovDelay[ax][ay]--;
3794     if (MovDelay[ax][ay])
3795       return;
3796   }
3797
3798   if (element == EL_AMOEBA_WET) /* object is an acid / amoeba drop */
3799   {
3800     int start = RND(4);
3801     int x = ax + xy[start][0];
3802     int y = ay + xy[start][1];
3803
3804     if (!IN_LEV_FIELD(x, y))
3805       return;
3806
3807     if (IS_FREE(x, y) ||
3808         Feld[x][y] == EL_SAND || Feld[x][y] == EL_QUICKSAND_EMPTY)
3809     {
3810       newax = x;
3811       neway = y;
3812     }
3813
3814     if (newax == ax && neway == ay)
3815       return;
3816   }
3817   else                          /* normal or "filled" (BD style) amoeba */
3818   {
3819     int start = RND(4);
3820     boolean waiting_for_player = FALSE;
3821
3822     for (i=0; i<4; i++)
3823     {
3824       int j = (start + i) % 4;
3825       int x = ax + xy[j][0];
3826       int y = ay + xy[j][1];
3827
3828       if (!IN_LEV_FIELD(x, y))
3829         continue;
3830
3831       if (IS_FREE(x, y) ||
3832           Feld[x][y] == EL_SAND || Feld[x][y] == EL_QUICKSAND_EMPTY)
3833       {
3834         newax = x;
3835         neway = y;
3836         break;
3837       }
3838       else if (IS_PLAYER(x, y))
3839         waiting_for_player = TRUE;
3840     }
3841
3842     if (newax == ax && neway == ay)             /* amoeba cannot grow */
3843     {
3844       if (i == 4 && (!waiting_for_player || game.emulation == EMU_BOULDERDASH))
3845       {
3846         Feld[ax][ay] = EL_AMOEBA_DEAD;
3847         DrawLevelField(ax, ay);
3848         AmoebaCnt[AmoebaNr[ax][ay]]--;
3849
3850         if (AmoebaCnt[AmoebaNr[ax][ay]] <= 0)   /* amoeba is completely dead */
3851         {
3852           if (element == EL_AMOEBA_FULL)
3853             AmoebeUmwandeln(ax, ay);
3854           else if (element == EL_BD_AMOEBA)
3855             AmoebeUmwandelnBD(ax, ay, level.amoeba_content);
3856         }
3857       }
3858       return;
3859     }
3860     else if (element == EL_AMOEBA_FULL || element == EL_BD_AMOEBA)
3861     {
3862       /* amoeba gets larger by growing in some direction */
3863
3864       int new_group_nr = AmoebaNr[ax][ay];
3865
3866 #ifdef DEBUG
3867   if (new_group_nr == 0)
3868   {
3869     printf("AmoebeAbleger(): newax = %d, neway = %d\n", newax, neway);
3870     printf("AmoebeAbleger(): This should never happen!\n");
3871     return;
3872   }
3873 #endif
3874
3875       AmoebaNr[newax][neway] = new_group_nr;
3876       AmoebaCnt[new_group_nr]++;
3877       AmoebaCnt2[new_group_nr]++;
3878
3879       /* if amoeba touches other amoeba(s) after growing, unify them */
3880       AmoebenVereinigen(newax, neway);
3881
3882       if (element == EL_BD_AMOEBA && AmoebaCnt2[new_group_nr] >= 200)
3883       {
3884         AmoebeUmwandelnBD(newax, neway, EL_BD_ROCK);
3885         return;
3886       }
3887     }
3888   }
3889
3890   if (element != EL_AMOEBA_WET || neway < ay || !IS_FREE(newax, neway) ||
3891       (neway == lev_fieldy - 1 && newax != ax))
3892   {
3893     Feld[newax][neway] = EL_AMOEBA_CREATING;    /* creation of new amoeba */
3894     Store[newax][neway] = element;
3895   }
3896   else if (neway == ay)
3897   {
3898     Feld[newax][neway] = EL_AMOEBA_DROP;        /* drop left/right of amoeba */
3899     PlaySoundLevel(newax, neway, SND_AMOEBA_DROP_CREATING);
3900   }
3901   else
3902   {
3903     InitMovingField(ax, ay, MV_DOWN);           /* drop dripping from amoeba */
3904     Feld[ax][ay] = EL_AMOEBA_DRIPPING;
3905     Store[ax][ay] = EL_AMOEBA_DROP;
3906     ContinueMoving(ax, ay);
3907     return;
3908   }
3909
3910   DrawLevelField(newax, neway);
3911 }
3912
3913 void Life(int ax, int ay)
3914 {
3915   int x1, y1, x2, y2;
3916   static int life[4] = { 2, 3, 3, 3 };  /* parameters for "game of life" */
3917   int life_time = 40;
3918   int element = Feld[ax][ay];
3919   boolean changed = FALSE;
3920
3921   if (Stop[ax][ay])
3922     return;
3923
3924   if (!MovDelay[ax][ay])        /* start new "game of life" cycle */
3925     MovDelay[ax][ay] = life_time;
3926
3927   if (MovDelay[ax][ay])         /* wait some time before next cycle */
3928   {
3929     MovDelay[ax][ay]--;
3930     if (MovDelay[ax][ay])
3931       return;
3932   }
3933
3934   for (y1=-1; y1<2; y1++) for(x1=-1; x1<2; x1++)
3935   {
3936     int xx = ax+x1, yy = ay+y1;
3937     int nachbarn = 0;
3938
3939     if (!IN_LEV_FIELD(xx, yy))
3940       continue;
3941
3942     for (y2=-1; y2<2; y2++) for (x2=-1; x2<2; x2++)
3943     {
3944       int x = xx+x2, y = yy+y2;
3945
3946       if (!IN_LEV_FIELD(x, y) || (x == xx && y == yy))
3947         continue;
3948
3949       if (((Feld[x][y] == element ||
3950             (element == EL_GAMEOFLIFE && IS_PLAYER(x, y))) &&
3951            !Stop[x][y]) ||
3952           (IS_FREE(x, y) && Stop[x][y]))
3953         nachbarn++;
3954     }
3955
3956     if (xx == ax && yy == ay)           /* field in the middle */
3957     {
3958       if (nachbarn < life[0] || nachbarn > life[1])
3959       {
3960         Feld[xx][yy] = EL_EMPTY;
3961         if (!Stop[xx][yy])
3962           DrawLevelField(xx, yy);
3963         Stop[xx][yy] = TRUE;
3964         changed = TRUE;
3965       }
3966     }
3967     else if (IS_FREE(xx, yy) || Feld[xx][yy] == EL_SAND)
3968     {                                   /* free border field */
3969       if (nachbarn >= life[2] && nachbarn <= life[3])
3970       {
3971         Feld[xx][yy] = element;
3972         MovDelay[xx][yy] = (element == EL_GAMEOFLIFE ? 0 : life_time-1);
3973         if (!Stop[xx][yy])
3974           DrawLevelField(xx, yy);
3975         Stop[xx][yy] = TRUE;
3976         changed = TRUE;
3977       }
3978     }
3979   }
3980
3981   if (changed)
3982     PlaySoundLevel(ax, ay, element == EL_GAMEOFLIFE ? SND_GAMEOFLIFE_CREATING :
3983                    SND_BIOMAZE_CREATING);
3984 }
3985
3986 static void InitRobotWheel(int x, int y)
3987 {
3988   MovDelay[x][y] = level.time_wheel * FRAMES_PER_SECOND;
3989 }
3990
3991 static void RunRobotWheel(int x, int y)
3992 {
3993   PlaySoundLevel(x, y, SND_ROBOT_WHEEL_ACTIVE);
3994 }
3995
3996 static void StopRobotWheel(int x, int y)
3997 {
3998   if (ZX == x && ZY == y)
3999     ZX = ZY = -1;
4000 }
4001
4002 #if 1
4003 void RobotWheel(int x, int y)
4004 {
4005   if (!MovDelay[x][y])          /* next animation frame */
4006     MovDelay[x][y] = level.time_wheel * FRAMES_PER_SECOND;
4007
4008   if (MovDelay[x][y])           /* wait some time before next frame */
4009   {
4010     MovDelay[x][y]--;
4011     if (MovDelay[x][y])
4012     {
4013       if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
4014       {
4015         int frame = getGraphicAnimationFrame(IMG_ROBOT_WHEEL_ACTIVE, -1);
4016
4017         DrawGraphic(SCREENX(x), SCREENY(y), IMG_ROBOT_WHEEL_ACTIVE, frame);
4018       }
4019
4020       PlaySoundLevel(x, y, SND_ROBOT_WHEEL_ACTIVE);
4021
4022       return;
4023     }
4024   }
4025
4026   Feld[x][y] = EL_ROBOT_WHEEL;
4027   DrawLevelField(x, y);
4028
4029   if (ZX == x && ZY == y)
4030     ZX = ZY = -1;
4031 }
4032 #endif
4033
4034 static void InitTimegateWheel(int x, int y)
4035 {
4036   MovDelay[x][y] = level.time_wheel * FRAMES_PER_SECOND;
4037 }
4038
4039 static void RunTimegateWheel(int x, int y)
4040 {
4041   PlaySoundLevel(x, y, SND_TIMEGATE_SWITCH_ACTIVE);
4042 }
4043
4044 #if 1
4045 void TimegateWheel(int x, int y)
4046 {
4047   if (!MovDelay[x][y])          /* next animation frame */
4048     MovDelay[x][y] = level.time_wheel * FRAMES_PER_SECOND;
4049
4050   if (MovDelay[x][y])           /* wait some time before next frame */
4051   {
4052     MovDelay[x][y]--;
4053     if (MovDelay[x][y])
4054     {
4055       if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
4056       {
4057         int frame = getGraphicAnimationFrame(IMG_TIMEGATE_SWITCH_ACTIVE, -1);
4058
4059         DrawGraphic(SCREENX(x), SCREENY(y), IMG_TIMEGATE_SWITCH_ACTIVE, frame);
4060       }
4061
4062       PlaySoundLevel(x, y, SND_TIMEGATE_SWITCH_ACTIVE);
4063
4064       return;
4065     }
4066   }
4067
4068   Feld[x][y] = EL_TIMEGATE_SWITCH;
4069   DrawLevelField(x, y);
4070
4071   /* THIS HAS NO EFFECT AT ALL! */
4072 #if 1
4073   /* !!! THIS LOOKS WRONG !!! */
4074   if (ZX == x && ZY == y)
4075     ZX = ZY = -1;
4076 #endif
4077
4078 }
4079 #endif
4080
4081 #if 1
4082 void NussKnacken(int x, int y)
4083 {
4084   if (!MovDelay[x][y])          /* next animation frame */
4085     MovDelay[x][y] = 7;
4086
4087   if (MovDelay[x][y])           /* wait some time before next frame */
4088   {
4089     MovDelay[x][y]--;
4090     if (MovDelay[x][y])
4091     {
4092       if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
4093       {
4094         int frame = getGraphicAnimationFrame(IMG_NUT_CRACKING,
4095                                              6 - MovDelay[x][y]);
4096
4097         DrawGraphic(SCREENX(x), SCREENY(y), IMG_NUT_CRACKING, frame);
4098       }
4099
4100       return;
4101     }
4102   }
4103
4104   Feld[x][y] = EL_EMERALD;
4105   DrawLevelField(x, y);
4106 }
4107 #endif
4108
4109 #if 1
4110 void BreakingPearl(int x, int y)
4111 {
4112   if (!MovDelay[x][y])          /* next animation frame */
4113     MovDelay[x][y] = 9;
4114
4115   if (MovDelay[x][y])           /* wait some time before next frame */
4116   {
4117     MovDelay[x][y]--;
4118     if (MovDelay[x][y])
4119     {
4120       if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
4121       {
4122         int frame = getGraphicAnimationFrame(IMG_PEARL_BREAKING,
4123                                              8 - MovDelay[x][y]);
4124
4125         DrawGraphic(SCREENX(x), SCREENY(y), IMG_PEARL_BREAKING, frame);
4126       }
4127
4128       return;
4129     }
4130   }
4131
4132   Feld[x][y] = EL_EMPTY;
4133   DrawLevelField(x, y);
4134 }
4135 #endif
4136
4137 void SiebAktivieren(int x, int y, int type)
4138 {
4139   int graphic = (type == 1 ? IMG_MAGIC_WALL_FULL : IMG_BD_MAGIC_WALL_FULL);
4140
4141   DrawLevelGraphicAnimation(x, y, graphic);
4142 }
4143
4144 void CheckExit(int x, int y)
4145 {
4146   if (local_player->gems_still_needed > 0 ||
4147       local_player->sokobanfields_still_needed > 0 ||
4148       local_player->lights_still_needed > 0)
4149     return;
4150
4151   Feld[x][y] = EL_EXIT_OPENING;
4152
4153   PlaySoundLevelNearest(x, y, SND_EXIT_OPENING);
4154 }
4155
4156 void CheckExitSP(int x, int y)
4157 {
4158   if (local_player->gems_still_needed > 0)
4159     return;
4160
4161   Feld[x][y] = EL_SP_EXIT_OPEN;
4162
4163   PlaySoundLevelNearest(x, y, SND_SP_EXIT_OPENING);
4164 }
4165
4166 #if 1
4167 void AusgangstuerOeffnen(int x, int y)
4168 {
4169   int delay = 6;
4170
4171   if (!MovDelay[x][y])          /* next animation frame */
4172     MovDelay[x][y] = 5 * delay;
4173
4174   if (MovDelay[x][y])           /* wait some time before next frame */
4175   {
4176     int tuer;
4177
4178     MovDelay[x][y]--;
4179     tuer = MovDelay[x][y] / delay;
4180
4181     if (!(MovDelay[x][y] % delay))
4182     {
4183       if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
4184       {
4185         int frame = getGraphicAnimationFrame(IMG_EXIT_OPENING,
4186                                              29 - MovDelay[x][y]);
4187
4188         DrawGraphic(SCREENX(x), SCREENY(y), IMG_EXIT_OPENING, frame);
4189       }
4190     }
4191
4192     if (MovDelay[x][y])
4193       return;
4194   }
4195
4196   Feld[x][y] = EL_EXIT_OPEN;
4197   DrawLevelField(x, y);
4198 }
4199 #endif
4200
4201 #if 1
4202 void OpenSwitchgate(int x, int y)
4203 {
4204   int delay = 6;
4205
4206   if (!MovDelay[x][y])          /* next animation frame */
4207     MovDelay[x][y] = 5 * delay;
4208
4209   if (MovDelay[x][y])           /* wait some time before next frame */
4210   {
4211     MovDelay[x][y]--;
4212
4213     if (!(MovDelay[x][y] % delay))
4214     {
4215       if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
4216       {
4217         int frame = getGraphicAnimationFrame(IMG_SWITCHGATE_OPENING,
4218                                              29 - MovDelay[x][y]);
4219
4220         DrawGraphic(SCREENX(x), SCREENY(y), IMG_SWITCHGATE_OPENING, frame);
4221       }
4222     }
4223
4224     if (MovDelay[x][y])
4225       return;
4226   }
4227
4228   Feld[x][y] = EL_SWITCHGATE_OPEN;
4229   DrawLevelField(x, y);
4230 }
4231 #endif
4232
4233 #if 1
4234 void CloseSwitchgate(int x, int y)
4235 {
4236   int delay = 6;
4237
4238   if (!MovDelay[x][y])          /* next animation frame */
4239     MovDelay[x][y] = 5 * delay;
4240
4241   if (MovDelay[x][y])           /* wait some time before next frame */
4242   {
4243     MovDelay[x][y]--;
4244
4245     if (!(MovDelay[x][y] % delay))
4246     {
4247       if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
4248       {
4249         int frame = getGraphicAnimationFrame(IMG_SWITCHGATE_CLOSING,
4250                                              29 - MovDelay[x][y]);
4251
4252         DrawGraphic(SCREENX(x), SCREENY(y), IMG_SWITCHGATE_CLOSING, frame);
4253       }
4254     }
4255
4256     if (MovDelay[x][y])
4257       return;
4258   }
4259
4260   Feld[x][y] = EL_SWITCHGATE_CLOSED;
4261   DrawLevelField(x, y);
4262 }
4263 #endif
4264
4265 #if 1
4266 void OpenTimegate(int x, int y)
4267 {
4268   int delay = 6;
4269
4270   if (!MovDelay[x][y])          /* next animation frame */
4271     MovDelay[x][y] = 5 * delay;
4272
4273   if (MovDelay[x][y])           /* wait some time before next frame */
4274   {
4275     MovDelay[x][y]--;
4276
4277     if (!(MovDelay[x][y] % delay))
4278     {
4279       if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
4280       {
4281         int frame = getGraphicAnimationFrame(IMG_TIMEGATE_OPENING,
4282                                              29 - MovDelay[x][y]);
4283
4284         DrawGraphic(SCREENX(x), SCREENY(y), IMG_TIMEGATE_OPENING, frame);
4285       }
4286     }
4287
4288     if (MovDelay[x][y])
4289       return;
4290   }
4291
4292   Feld[x][y] = EL_TIMEGATE_OPEN;
4293   DrawLevelField(x, y);
4294 }
4295 #endif
4296
4297 #if 1
4298 void CloseTimegate(int x, int y)
4299 {
4300   int delay = 6;
4301
4302   if (!MovDelay[x][y])          /* next animation frame */
4303     MovDelay[x][y] = 5 * delay;
4304
4305   if (MovDelay[x][y])           /* wait some time before next frame */
4306   {
4307     MovDelay[x][y]--;
4308
4309     if (!(MovDelay[x][y] % delay))
4310     {
4311       if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
4312       {
4313         int frame = getGraphicAnimationFrame(IMG_TIMEGATE_CLOSING,
4314                                              29 - MovDelay[x][y]);
4315
4316         DrawGraphic(SCREENX(x), SCREENY(y), IMG_TIMEGATE_CLOSING, frame);
4317       }
4318     }
4319
4320     if (MovDelay[x][y])
4321       return;
4322   }
4323
4324   Feld[x][y] = EL_TIMEGATE_CLOSED;
4325   DrawLevelField(x, y);
4326 }
4327 #endif
4328
4329 static void CloseAllOpenTimegates()
4330 {
4331   int x, y;
4332
4333   for (y=0; y<lev_fieldy; y++)
4334   {
4335     for (x=0; x<lev_fieldx; x++)
4336     {
4337       int element = Feld[x][y];
4338
4339       if (element == EL_TIMEGATE_OPEN || element == EL_TIMEGATE_OPENING)
4340       {
4341         Feld[x][y] = EL_TIMEGATE_CLOSING;
4342         PlaySoundLevel(x, y, SND_TIMEGATE_CLOSING);
4343       }
4344     }
4345   }
4346 }
4347
4348 void EdelsteinFunkeln(int x, int y)
4349 {
4350   if (!IN_SCR_FIELD(SCREENX(x), SCREENY(y)) || IS_MOVING(x, y))
4351     return;
4352
4353   if (Feld[x][y] == EL_BD_DIAMOND)
4354 #if 0
4355     DrawLevelElementAnimation(x, y, el2img(Feld[x][y]));
4356 #else
4357     return;
4358 #endif
4359   else
4360   {
4361     if (MovDelay[x][y] == 0)    /* next animation frame */
4362       MovDelay[x][y] = 11 * !SimpleRND(500);
4363
4364     if (MovDelay[x][y] != 0)    /* wait some time before next frame */
4365     {
4366       MovDelay[x][y]--;
4367
4368       if (setup.direct_draw && MovDelay[x][y])
4369         SetDrawtoField(DRAW_BUFFERED);
4370
4371 #if 0
4372       DrawGraphic(SCREENX(x), SCREENY(y), el2img(Feld[x][y]), 0);
4373 #else
4374       DrawLevelElementAnimation(x, y, Feld[x][y]);
4375 #endif
4376
4377       if (MovDelay[x][y] != 0)
4378       {
4379         int frame = getGraphicAnimationFrame(IMG_TWINKLE_WHITE,
4380                                              10 - MovDelay[x][y]);
4381
4382         DrawGraphicThruMask(SCREENX(x), SCREENY(y), IMG_TWINKLE_WHITE, frame);
4383
4384         if (setup.direct_draw)
4385         {
4386           int dest_x, dest_y;
4387
4388           dest_x = FX + SCREENX(x) * TILEX;
4389           dest_y = FY + SCREENY(y) * TILEY;
4390
4391           BlitBitmap(drawto_field, window,
4392                      dest_x, dest_y, TILEX, TILEY, dest_x, dest_y);
4393           SetDrawtoField(DRAW_DIRECT);
4394         }
4395       }
4396     }
4397   }
4398 }
4399
4400 void MauerWaechst(int x, int y)
4401 {
4402   int delay = 6;
4403
4404   if (!MovDelay[x][y])          /* next animation frame */
4405     MovDelay[x][y] = 3 * delay;
4406
4407   if (MovDelay[x][y])           /* wait some time before next frame */
4408   {
4409     MovDelay[x][y]--;
4410
4411     if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
4412     {
4413       int graphic = el_dir2img(Feld[x][y], MovDir[x][y]);
4414       int frame = getGraphicAnimationFrame(graphic, 17 - MovDelay[x][y]);
4415
4416       DrawGraphic(SCREENX(x), SCREENY(y), graphic, frame);
4417     }
4418
4419     if (!MovDelay[x][y])
4420     {
4421       if (MovDir[x][y] == MV_LEFT)
4422       {
4423         if (IN_LEV_FIELD(x - 1, y) && IS_MAUER(Feld[x - 1][y]))
4424           DrawLevelField(x - 1, y);
4425       }
4426       else if (MovDir[x][y] == MV_RIGHT)
4427       {
4428         if (IN_LEV_FIELD(x + 1, y) && IS_MAUER(Feld[x + 1][y]))
4429           DrawLevelField(x + 1, y);
4430       }
4431       else if (MovDir[x][y] == MV_UP)
4432       {
4433         if (IN_LEV_FIELD(x, y - 1) && IS_MAUER(Feld[x][y - 1]))
4434           DrawLevelField(x, y - 1);
4435       }
4436       else
4437       {
4438         if (IN_LEV_FIELD(x, y + 1) && IS_MAUER(Feld[x][y + 1]))
4439           DrawLevelField(x, y + 1);
4440       }
4441
4442       Feld[x][y] = Store[x][y];
4443       Store[x][y] = 0;
4444       MovDir[x][y] = MV_NO_MOVING;
4445       DrawLevelField(x, y);
4446     }
4447   }
4448 }
4449
4450 void MauerAbleger(int ax, int ay)
4451 {
4452   int element = Feld[ax][ay];
4453   boolean oben_frei = FALSE, unten_frei = FALSE;
4454   boolean links_frei = FALSE, rechts_frei = FALSE;
4455   boolean oben_massiv = FALSE, unten_massiv = FALSE;
4456   boolean links_massiv = FALSE, rechts_massiv = FALSE;
4457   boolean new_wall = FALSE;
4458
4459   if (!MovDelay[ax][ay])        /* start building new wall */
4460     MovDelay[ax][ay] = 6;
4461
4462   if (MovDelay[ax][ay])         /* wait some time before building new wall */
4463   {
4464     MovDelay[ax][ay]--;
4465     if (MovDelay[ax][ay])
4466       return;
4467   }
4468
4469   if (IN_LEV_FIELD(ax, ay-1) && IS_FREE(ax, ay-1))
4470     oben_frei = TRUE;
4471   if (IN_LEV_FIELD(ax, ay+1) && IS_FREE(ax, ay+1))
4472     unten_frei = TRUE;
4473   if (IN_LEV_FIELD(ax-1, ay) && IS_FREE(ax-1, ay))
4474     links_frei = TRUE;
4475   if (IN_LEV_FIELD(ax+1, ay) && IS_FREE(ax+1, ay))
4476     rechts_frei = TRUE;
4477
4478   if (element == EL_WALL_GROWING_Y || element == EL_WALL_GROWING_XY)
4479   {
4480     if (oben_frei)
4481     {
4482       Feld[ax][ay-1] = EL_WALL_GROWING_ACTIVE;
4483       Store[ax][ay-1] = element;
4484       MovDir[ax][ay-1] = MV_UP;
4485       if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay-1)))
4486         DrawGraphic(SCREENX(ax), SCREENY(ay - 1),
4487                     IMG_WALL_GROWING_ACTIVE_UP, 0);
4488       new_wall = TRUE;
4489     }
4490     if (unten_frei)
4491     {
4492       Feld[ax][ay+1] = EL_WALL_GROWING_ACTIVE;
4493       Store[ax][ay+1] = element;
4494       MovDir[ax][ay+1] = MV_DOWN;
4495       if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay+1)))
4496         DrawGraphic(SCREENX(ax), SCREENY(ay + 1),
4497                     IMG_WALL_GROWING_ACTIVE_DOWN, 0);
4498       new_wall = TRUE;
4499     }
4500   }
4501
4502   if (element == EL_WALL_GROWING_X || element == EL_WALL_GROWING_XY ||
4503       element == EL_WALL_GROWING)
4504   {
4505     if (links_frei)
4506     {
4507       Feld[ax-1][ay] = EL_WALL_GROWING_ACTIVE;
4508       Store[ax-1][ay] = element;
4509       MovDir[ax-1][ay] = MV_LEFT;
4510       if (IN_SCR_FIELD(SCREENX(ax-1), SCREENY(ay)))
4511         DrawGraphic(SCREENX(ax - 1), SCREENY(ay),
4512                     IMG_WALL_GROWING_ACTIVE_LEFT, 0);
4513       new_wall = TRUE;
4514     }
4515
4516     if (rechts_frei)
4517     {
4518       Feld[ax+1][ay] = EL_WALL_GROWING_ACTIVE;
4519       Store[ax+1][ay] = element;
4520       MovDir[ax+1][ay] = MV_RIGHT;
4521       if (IN_SCR_FIELD(SCREENX(ax+1), SCREENY(ay)))
4522         DrawGraphic(SCREENX(ax + 1), SCREENY(ay),
4523                     IMG_WALL_GROWING_ACTIVE_RIGHT, 0);
4524       new_wall = TRUE;
4525     }
4526   }
4527
4528   if (element == EL_WALL_GROWING && (links_frei || rechts_frei))
4529     DrawLevelField(ax, ay);
4530
4531   if (!IN_LEV_FIELD(ax, ay-1) || IS_MAUER(Feld[ax][ay-1]))
4532     oben_massiv = TRUE;
4533   if (!IN_LEV_FIELD(ax, ay+1) || IS_MAUER(Feld[ax][ay+1]))
4534     unten_massiv = TRUE;
4535   if (!IN_LEV_FIELD(ax-1, ay) || IS_MAUER(Feld[ax-1][ay]))
4536     links_massiv = TRUE;
4537   if (!IN_LEV_FIELD(ax+1, ay) || IS_MAUER(Feld[ax+1][ay]))
4538     rechts_massiv = TRUE;
4539
4540   if (((oben_massiv && unten_massiv) ||
4541        element == EL_WALL_GROWING_X || element == EL_WALL_GROWING) &&
4542       ((links_massiv && rechts_massiv) ||
4543        element == EL_WALL_GROWING_Y))
4544     Feld[ax][ay] = EL_WALL;
4545
4546   if (new_wall)
4547     PlaySoundLevel(ax, ay, SND_WALL_GROWING);
4548 }
4549
4550 void CheckForDragon(int x, int y)
4551 {
4552   int i, j;
4553   boolean dragon_found = FALSE;
4554   static int xy[4][2] =
4555   {
4556     { 0, -1 },
4557     { -1, 0 },
4558     { +1, 0 },
4559     { 0, +1 }
4560   };
4561
4562   for (i=0; i<4; i++)
4563   {
4564     for (j=0; j<4; j++)
4565     {
4566       int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
4567
4568       if (IN_LEV_FIELD(xx, yy) &&
4569           (Feld[xx][yy] == EL_FLAMES || Feld[xx][yy] == EL_DRAGON))
4570       {
4571         if (Feld[xx][yy] == EL_DRAGON)
4572           dragon_found = TRUE;
4573       }
4574       else
4575         break;
4576     }
4577   }
4578
4579   if (!dragon_found)
4580   {
4581     for (i=0; i<4; i++)
4582     {
4583       for (j=0; j<3; j++)
4584       {
4585         int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
4586   
4587         if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == EL_FLAMES)
4588         {
4589           Feld[xx][yy] = EL_EMPTY;
4590           DrawLevelField(xx, yy);
4591         }
4592         else
4593           break;
4594       }
4595     }
4596   }
4597 }
4598
4599 static void InitBuggyBase(int x, int y)
4600 {
4601   int element = Feld[x][y];
4602   int activating_delay = FRAMES_PER_SECOND / 4;
4603
4604   MovDelay[x][y] =
4605     (element == EL_SP_BUGGY_BASE ?
4606      2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND) - activating_delay :
4607      element == EL_SP_BUGGY_BASE_ACTIVATING ?
4608      activating_delay :
4609      element == EL_SP_BUGGY_BASE_ACTIVE ?
4610      1 * FRAMES_PER_SECOND + RND(1 * FRAMES_PER_SECOND) : 1);
4611 }
4612
4613 static void WarnBuggyBase(int x, int y)
4614 {
4615   int i;
4616   static int xy[4][2] =
4617   {
4618     { 0, -1 },
4619     { -1, 0 },
4620     { +1, 0 },
4621     { 0, +1 }
4622   };
4623
4624   for (i=0; i<4; i++)
4625   {
4626     int xx = x + xy[i][0], yy = y + xy[i][1];
4627
4628     if (IS_PLAYER(xx, yy))
4629     {
4630       PlaySoundLevel(x, y, SND_SP_BUGGY_BASE_ACTIVE);
4631
4632       break;
4633     }
4634   }
4635 }
4636
4637 #if 1
4638 void CheckBuggyBase(int x, int y)
4639 {
4640   int element = Feld[x][y];
4641
4642   if (element == EL_SP_BUGGY_BASE)
4643   {
4644     if (MovDelay[x][y] == 0)    /* wait some time before activating base */
4645     {
4646       GfxFrame[x][y] = 0;
4647
4648       InitBuggyBase(x, y);
4649     }
4650
4651     MovDelay[x][y]--;
4652
4653     if (MovDelay[x][y] != 0)
4654     {
4655       DrawLevelElementAnimation(x, y, element);
4656     }
4657     else
4658     {
4659       Feld[x][y] = EL_SP_BUGGY_BASE_ACTIVATING;
4660       DrawLevelField(x, y);
4661     }
4662   }
4663   else if (element == EL_SP_BUGGY_BASE_ACTIVATING)
4664   {
4665     if (MovDelay[x][y] == 0)    /* display activation warning of buggy base */
4666     {
4667       GfxFrame[x][y] = 0;
4668
4669       InitBuggyBase(x, y);
4670     }
4671
4672     MovDelay[x][y]--;
4673
4674     if (MovDelay[x][y] != 0)
4675     {
4676       DrawLevelElementAnimation(x, y, element);
4677     }
4678     else
4679     {
4680       Feld[x][y] = EL_SP_BUGGY_BASE_ACTIVE;
4681       DrawLevelField(x, y);
4682     }
4683   }
4684   else if (element == EL_SP_BUGGY_BASE_ACTIVE)
4685   {
4686     if (MovDelay[x][y] == 0)    /* start activating buggy base */
4687     {
4688       GfxFrame[x][y] = 0;
4689
4690       InitBuggyBase(x, y);
4691     }
4692
4693     MovDelay[x][y]--;
4694
4695     if (MovDelay[x][y] != 0)
4696     {
4697       DrawLevelElementAnimation(x, y, element);
4698
4699       WarnBuggyBase(x, y);
4700     }
4701     else
4702     {
4703       Feld[x][y] = EL_SP_BUGGY_BASE;
4704       DrawLevelField(x, y);
4705     }
4706   }
4707 }
4708 #endif
4709
4710 static void InitTrap(int x, int y)
4711 {
4712   MovDelay[x][y] = 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND);
4713 }
4714
4715 static void ActivateTrap(int x, int y)
4716 {
4717   PlaySoundLevel(x, y, SND_TRAP_ACTIVATING);
4718 }
4719
4720 static void ChangeActiveTrap(int x, int y)
4721 {
4722   int graphic = IMG_TRAP_ACTIVE;
4723
4724   /* if animation frame already drawn, correct crumbled sand border */
4725   if (IS_ANIMATED(graphic))
4726     if (checkDrawLevelGraphicAnimation(x, y, graphic))
4727       DrawCrumbledSand(SCREENX(x), SCREENY(y));
4728 }
4729
4730 #if 1
4731 void CheckTrap(int x, int y)
4732 {
4733   int element = Feld[x][y];
4734
4735   if (element == EL_TRAP)
4736   {
4737     if (MovDelay[x][y] == 0)    /* wait some time before activating trap */
4738       MovDelay[x][y] = 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND);
4739
4740     MovDelay[x][y]--;
4741
4742     if (MovDelay[x][y] != 0)
4743     {
4744       /* do nothing while waiting */
4745     }
4746     else
4747     {
4748       Feld[x][y] = EL_TRAP_ACTIVE;
4749       PlaySoundLevel(x, y, SND_TRAP_ACTIVATING);
4750     }
4751   }
4752   else if (element == EL_TRAP_ACTIVE)
4753   {
4754     int delay = 4;
4755     int num_frames = 8;
4756
4757     if (MovDelay[x][y] == 0)    /* start activating trap */
4758     {
4759       MovDelay[x][y] = num_frames * delay;
4760       GfxFrame[x][y] = 0;
4761     }
4762
4763     MovDelay[x][y]--;
4764
4765     if (MovDelay[x][y] != 0)
4766     {
4767       if (DrawLevelElementAnimation(x, y, element))
4768         DrawCrumbledSand(SCREENX(x), SCREENY(y));
4769     }
4770     else
4771     {
4772       Feld[x][y] = EL_TRAP;
4773       DrawLevelField(x, y);
4774     }
4775   }
4776 }
4777 #endif
4778
4779 #if 1
4780 static void DrawBeltAnimation(int x, int y, int element)
4781 {
4782   int belt_nr = getBeltNrFromBeltActiveElement(element);
4783   int belt_dir = game.belt_dir[belt_nr];
4784
4785   if (belt_dir != MV_NO_MOVING)
4786   {
4787     DrawLevelElementAnimation(x, y, element);
4788
4789     if (!(FrameCounter % 2))
4790       PlaySoundLevelAction(x, y, ACTION_ACTIVE);
4791   }
4792 }
4793 #endif
4794
4795 static void ChangeElement(int x, int y)
4796 {
4797   int element = Feld[x][y];
4798
4799   if (MovDelay[x][y] == 0)              /* initialize element change */
4800   {
4801     MovDelay[x][y] = changing_element[element].change_delay + 1;
4802     GfxFrame[x][y] = 0;
4803
4804     if (changing_element[element].pre_change_function)
4805       changing_element[element].pre_change_function(x, y);
4806   }
4807
4808   MovDelay[x][y]--;
4809
4810   if (MovDelay[x][y] != 0)              /* continue element change */
4811   {
4812     if (IS_ANIMATED(el2img(element)))
4813       DrawLevelElementAnimation(x, y, element);
4814
4815     if (changing_element[element].change_function)
4816       changing_element[element].change_function(x, y);
4817   }
4818   else                                  /* finish element change */
4819   {
4820     Feld[x][y] = changing_element[element].next_element;
4821     GfxFrame[x][y] = 0;
4822
4823     DrawLevelField(x, y);
4824
4825     if (changing_element[element].post_change_function)
4826       changing_element[element].post_change_function(x, y);
4827   }
4828 }
4829
4830 static void PlayerActions(struct PlayerInfo *player, byte player_action)
4831 {
4832   static byte stored_player_action[MAX_PLAYERS];
4833   static int num_stored_actions = 0;
4834 #if 0
4835   static boolean save_tape_entry = FALSE;
4836 #endif
4837   boolean moved = FALSE, snapped = FALSE, bombed = FALSE;
4838   int left      = player_action & JOY_LEFT;
4839   int right     = player_action & JOY_RIGHT;
4840   int up        = player_action & JOY_UP;
4841   int down      = player_action & JOY_DOWN;
4842   int button1   = player_action & JOY_BUTTON_1;
4843   int button2   = player_action & JOY_BUTTON_2;
4844   int dx        = (left ? -1    : right ? 1     : 0);
4845   int dy        = (up   ? -1    : down  ? 1     : 0);
4846
4847   stored_player_action[player->index_nr] = 0;
4848   num_stored_actions++;
4849
4850   if (!player->active || tape.pausing)
4851     return;
4852
4853   if (player_action)
4854   {
4855 #if 0
4856     save_tape_entry = TRUE;
4857 #endif
4858     player->frame_reset_delay = 0;
4859
4860     if (button1)
4861       snapped = SnapField(player, dx, dy);
4862     else
4863     {
4864       if (button2)
4865         bombed = PlaceBomb(player);
4866       moved = MoveFigure(player, dx, dy);
4867     }
4868
4869     if (tape.single_step && tape.recording && !tape.pausing)
4870     {
4871       if (button1 || (bombed && !moved))
4872       {
4873         TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
4874         SnapField(player, 0, 0);                /* stop snapping */
4875       }
4876     }
4877
4878 #if 0
4879     if (tape.recording && (moved || snapped || bombed))
4880     {
4881       if (bombed && !moved)
4882         player_action &= JOY_BUTTON;
4883
4884       stored_player_action[player->index_nr] = player_action;
4885       save_tape_entry = TRUE;
4886     }
4887     else if (tape.playing && snapped)
4888       SnapField(player, 0, 0);                  /* stop snapping */
4889 #else
4890     stored_player_action[player->index_nr] = player_action;
4891 #endif
4892   }
4893   else
4894   {
4895     /* no actions for this player (no input at player's configured device) */
4896
4897     DigField(player, 0, 0, 0, 0, DF_NO_PUSH);
4898     SnapField(player, 0, 0);
4899     CheckGravityMovement(player);
4900
4901 #if 1
4902     if (player->MovPos == 0)    /* needed for tape.playing */
4903       player->is_moving = FALSE;
4904 #endif
4905 #if 0
4906     if (player->MovPos == 0)    /* needed for tape.playing */
4907       player->last_move_dir = MV_NO_MOVING;
4908
4909     /* !!! CHECK THIS AGAIN !!!
4910        (Seems to be needed for some EL_ROBOT stuff, but breaks
4911        tapes when walking through pipes!)
4912     */
4913
4914     /* it seems that "player->last_move_dir" is misused as some sort of
4915        "player->is_just_moving_in_this_moment", which is needed for the
4916        robot stuff (robots don't kill players when they are moving)
4917     */
4918 #endif 
4919
4920     /* if the player does not move for some time, reset animation to start */
4921     if (++player->frame_reset_delay > player->move_delay_value)
4922       player->Frame = 0;
4923   }
4924
4925 #if 0
4926   if (tape.recording && num_stored_actions >= MAX_PLAYERS && save_tape_entry)
4927   {
4928     TapeRecordAction(stored_player_action);
4929     num_stored_actions = 0;
4930     save_tape_entry = FALSE;
4931   }
4932 #else
4933   if (tape.recording && num_stored_actions >= MAX_PLAYERS)
4934   {
4935     TapeRecordAction(stored_player_action);
4936     num_stored_actions = 0;
4937   }
4938 #endif
4939
4940 #if 0
4941   if (tape.playing && !tape.pausing && !player_action &&
4942       tape.counter < tape.length)
4943   {
4944     int jx = player->jx, jy = player->jy;
4945     int next_joy =
4946       tape.pos[tape.counter].action[player->index_nr] & (JOY_LEFT|JOY_RIGHT);
4947
4948     if ((next_joy == JOY_LEFT || next_joy == JOY_RIGHT) &&
4949         (player->MovDir != JOY_UP && player->MovDir != JOY_DOWN))
4950     {
4951       int dx = (next_joy == JOY_LEFT ? -1 : +1);
4952
4953       if (IN_LEV_FIELD(jx+dx, jy) && IS_PUSHABLE(Feld[jx+dx][jy]))
4954       {
4955         int el = Feld[jx+dx][jy];
4956         int push_delay = (IS_SB_ELEMENT(el) || el == EL_SATELLITE ? 2 :
4957                           (el == EL_BALLOON || el == EL_SPRING) ? 0 : 10);
4958
4959         if (tape.delay_played + push_delay >= tape.pos[tape.counter].delay)
4960         {
4961           player->MovDir = next_joy;
4962           player->Frame = FrameCounter % 4;
4963           player->Pushing = TRUE;
4964         }
4965       }
4966     }
4967   }
4968 #endif
4969 }
4970
4971 void GameActions()
4972 {
4973   static unsigned long action_delay = 0;
4974   unsigned long action_delay_value;
4975   int sieb_x = 0, sieb_y = 0;
4976   int i, x, y, element, graphic;
4977   byte *recorded_player_action;
4978   byte summarized_player_action = 0;
4979
4980   if (game_status != PLAYING)
4981     return;
4982
4983   action_delay_value =
4984     (tape.playing && tape.fast_forward ? FfwdFrameDelay : GameFrameDelay);
4985
4986   if (tape.playing && tape.index_search && !tape.pausing)
4987     action_delay_value = 0;
4988
4989   /* ---------- main game synchronization point ---------- */
4990
4991   WaitUntilDelayReached(&action_delay, action_delay_value);
4992
4993   if (network_playing && !network_player_action_received)
4994   {
4995     /*
4996 #ifdef DEBUG
4997     printf("DEBUG: try to get network player actions in time\n");
4998 #endif
4999     */
5000
5001 #if defined(PLATFORM_UNIX)
5002     /* last chance to get network player actions without main loop delay */
5003     HandleNetworking();
5004 #endif
5005
5006     if (game_status != PLAYING)
5007       return;
5008
5009     if (!network_player_action_received)
5010     {
5011       /*
5012 #ifdef DEBUG
5013       printf("DEBUG: failed to get network player actions in time\n");
5014 #endif
5015       */
5016       return;
5017     }
5018   }
5019
5020   if (tape.pausing)
5021     return;
5022
5023   recorded_player_action = (tape.playing ? TapePlayAction() : NULL);
5024
5025   for (i=0; i<MAX_PLAYERS; i++)
5026   {
5027     summarized_player_action |= stored_player[i].action;
5028
5029     if (!network_playing)
5030       stored_player[i].effective_action = stored_player[i].action;
5031   }
5032
5033 #if defined(PLATFORM_UNIX)
5034   if (network_playing)
5035     SendToServer_MovePlayer(summarized_player_action);
5036 #endif
5037
5038   if (!options.network && !setup.team_mode)
5039     local_player->effective_action = summarized_player_action;
5040
5041   for (i=0; i<MAX_PLAYERS; i++)
5042   {
5043     int actual_player_action = stored_player[i].effective_action;
5044
5045     if (stored_player[i].programmed_action)
5046       actual_player_action = stored_player[i].programmed_action;
5047
5048     if (recorded_player_action)
5049       actual_player_action = recorded_player_action[i];
5050
5051     PlayerActions(&stored_player[i], actual_player_action);
5052     ScrollFigure(&stored_player[i], SCROLL_GO_ON);
5053   }
5054
5055   network_player_action_received = FALSE;
5056
5057   ScrollScreen(NULL, SCROLL_GO_ON);
5058
5059
5060
5061 #ifdef DEBUG
5062 #if 0
5063   if (TimeFrames == 0 && local_player->active)
5064   {
5065     extern unsigned int last_RND();
5066
5067     printf("DEBUG: %03d last RND was %d \t [state checksum is %d]\n",
5068            TimePlayed, last_RND(), getStateCheckSum(TimePlayed));
5069   }
5070 #endif
5071 #endif
5072
5073 #ifdef DEBUG
5074 #if 0
5075   if (GameFrameDelay >= 500)
5076     printf("FrameCounter == %d\n", FrameCounter);
5077 #endif
5078 #endif
5079
5080   FrameCounter++;
5081   TimeFrames++;
5082
5083   for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
5084   {
5085     Stop[x][y] = FALSE;
5086     if (JustStopped[x][y] > 0)
5087       JustStopped[x][y]--;
5088
5089     GfxFrame[x][y]++;
5090
5091 #if DEBUG
5092     if (IS_BLOCKED(x, y))
5093     {
5094       int oldx, oldy;
5095
5096       Blocked2Moving(x, y, &oldx, &oldy);
5097       if (!IS_MOVING(oldx, oldy))
5098       {
5099         printf("GameActions(): (BLOCKED => MOVING) context corrupted!\n");
5100         printf("GameActions(): BLOCKED: x = %d, y = %d\n", x, y);
5101         printf("GameActions(): !MOVING: oldx = %d, oldy = %d\n", oldx, oldy);
5102         printf("GameActions(): This should never happen!\n");
5103       }
5104     }
5105 #endif
5106   }
5107
5108   for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
5109   {
5110     element = Feld[x][y];
5111     graphic = el2img(element);
5112
5113     if (IS_INACTIVE(element))
5114     {
5115
5116 #if 1
5117       if (IS_ANIMATED(graphic))
5118         DrawLevelGraphicAnimation(x, y, graphic);
5119 #endif
5120
5121       continue;
5122     }
5123
5124     if (!IS_MOVING(x, y) && (CAN_FALL(element) || CAN_MOVE(element)))
5125     {
5126       StartMoving(x, y);
5127
5128 #if 1
5129 #if 0
5130       if (Feld[x][y] == EL_EMERALD &&
5131           IS_ANIMATED(graphic) &&
5132           !IS_MOVING(x, y))
5133         DrawLevelGraphicAnimation(x, y, graphic);
5134 #else
5135       if (IS_ANIMATED(graphic) &&
5136           !IS_MOVING(x, y))
5137         DrawLevelGraphicAnimation(x, y, graphic);
5138 #endif
5139 #endif
5140
5141       if (IS_GEM(element) || element == EL_SP_INFOTRON)
5142         EdelsteinFunkeln(x, y);
5143     }
5144
5145 #if 1
5146     else if ((element == EL_ACID ||
5147               element == EL_EXIT_OPEN ||
5148               element == EL_SP_EXIT_OPEN ||
5149               element == EL_SP_TERMINAL ||
5150               element == EL_SP_TERMINAL_ACTIVE ||
5151               element == EL_EXTRA_TIME ||
5152               element == EL_SHIELD_NORMAL ||
5153               element == EL_SHIELD_DEADLY) &&
5154              IS_ANIMATED(graphic))
5155       DrawLevelGraphicAnimation(x, y, graphic);
5156 #endif
5157
5158     else if (IS_MOVING(x, y))
5159       ContinueMoving(x, y);
5160     else if (IS_ACTIVE_BOMB(element))
5161       CheckDynamite(x, y);
5162 #if 0
5163     else if (element == EL_EXPLOSION && !game.explosions_delayed)
5164       Explode(x, y, ExplodePhase[x][y], EX_NORMAL);
5165 #endif
5166     else if (element == EL_AMOEBA_CREATING)
5167       AmoebeWaechst(x, y);
5168     else if (element == EL_AMOEBA_SHRINKING)
5169       AmoebaDisappearing(x, y);
5170
5171 #if !USE_NEW_AMOEBA_CODE
5172     else if (IS_AMOEBALIVE(element))
5173       AmoebeAbleger(x, y);
5174 #endif
5175
5176     else if (element == EL_GAMEOFLIFE || element == EL_BIOMAZE)
5177       Life(x, y);
5178 #if 0
5179     else if (element == EL_ROBOT_WHEEL_ACTIVE)
5180       RobotWheel(x, y);
5181     else if (element == EL_TIMEGATE_SWITCH_ACTIVE)
5182       TimegateWheel(x, y);
5183 #endif
5184     else if (element == EL_ACID_SPLASH_LEFT ||
5185              element == EL_ACID_SPLASH_RIGHT)
5186       Blurb(x, y);
5187 #if 0
5188     else if (element == EL_NUT_CRACKING)
5189       NussKnacken(x, y);
5190     else if (element == EL_PEARL_BREAKING)
5191       BreakingPearl(x, y);
5192 #endif
5193     else if (element == EL_EXIT_CLOSED)
5194       CheckExit(x, y);
5195     else if (element == EL_SP_EXIT_CLOSED)
5196       CheckExitSP(x, y);
5197 #if 0
5198     else if (element == EL_EXIT_OPENING)
5199       AusgangstuerOeffnen(x, y);
5200 #endif
5201     else if (element == EL_WALL_GROWING_ACTIVE)
5202       MauerWaechst(x, y);
5203     else if (element == EL_WALL_GROWING ||
5204              element == EL_WALL_GROWING_X ||
5205              element == EL_WALL_GROWING_Y ||
5206              element == EL_WALL_GROWING_XY)
5207       MauerAbleger(x, y);
5208     else if (element == EL_FLAMES)
5209       CheckForDragon(x, y);
5210 #if 0
5211     else if (element == EL_SP_BUGGY_BASE ||
5212              element == EL_SP_BUGGY_BASE_ACTIVATING ||
5213              element == EL_SP_BUGGY_BASE_ACTIVE)
5214       CheckBuggyBase(x, y);
5215     else if (element == EL_TRAP ||
5216              element == EL_TRAP_ACTIVE)
5217       CheckTrap(x, y);
5218     else if (IS_BELT_ACTIVE(element))
5219       DrawBeltAnimation(x, y, element);
5220     else if (element == EL_SWITCHGATE_OPENING)
5221       OpenSwitchgate(x, y);
5222     else if (element == EL_SWITCHGATE_CLOSING)
5223       CloseSwitchgate(x, y);
5224     else if (element == EL_TIMEGATE_OPENING)
5225       OpenTimegate(x, y);
5226     else if (element == EL_TIMEGATE_CLOSING)
5227       CloseTimegate(x, y);
5228 #endif
5229
5230     else if (IS_AUTO_CHANGING(element))
5231       ChangeElement(x, y);
5232
5233 #if 1
5234     else if (element == EL_EXPLOSION)
5235       ; /* drawing of correct explosion animation is handled separately */
5236     else if (IS_ANIMATED(graphic))
5237       DrawLevelGraphicAnimation(x, y, graphic);
5238 #endif
5239
5240     if (IS_BELT_ACTIVE(element))
5241       PlaySoundLevelAction(x, y, ACTION_ACTIVE);
5242
5243     if (game.magic_wall_active)
5244     {
5245       boolean sieb = FALSE;
5246       int jx = local_player->jx, jy = local_player->jy;
5247
5248       if (element == EL_MAGIC_WALL_FULL ||
5249           element == EL_MAGIC_WALL_ACTIVE ||
5250           element == EL_MAGIC_WALL_EMPTYING)
5251       {
5252         SiebAktivieren(x, y, 1);
5253         sieb = TRUE;
5254       }
5255       else if (element == EL_BD_MAGIC_WALL_FULL ||
5256                element == EL_BD_MAGIC_WALL_ACTIVE ||
5257                element == EL_BD_MAGIC_WALL_EMPTYING)
5258       {
5259         SiebAktivieren(x, y, 2);
5260         sieb = TRUE;
5261       }
5262
5263       /* play the element sound at the position nearest to the player */
5264       if (sieb && ABS(x-jx)+ABS(y-jy) < ABS(sieb_x-jx)+ABS(sieb_y-jy))
5265       {
5266         sieb_x = x;
5267         sieb_y = y;
5268       }
5269     }
5270   }
5271
5272 #if USE_NEW_AMOEBA_CODE
5273   /* new experimental amoeba growth stuff */
5274 #if 1
5275   if (!(FrameCounter % 8))
5276 #endif
5277   {
5278     static unsigned long random = 1684108901;
5279
5280     for (i = 0; i < level.amoeba_speed * 28 / 8; i++)
5281     {
5282 #if 0
5283       x = (random >> 10) % lev_fieldx;
5284       y = (random >> 20) % lev_fieldy;
5285 #else
5286       x = RND(lev_fieldx);
5287       y = RND(lev_fieldy);
5288 #endif
5289       element = Feld[x][y];
5290
5291       if (!IS_PLAYER(x,y) &&
5292           (element == EL_EMPTY ||
5293            element == EL_SAND ||
5294            element == EL_QUICKSAND_EMPTY ||
5295            element == EL_ACID_SPLASH_LEFT ||
5296            element == EL_ACID_SPLASH_RIGHT))
5297       {
5298         if ((IN_LEV_FIELD(x, y-1) && Feld[x][y-1] == EL_AMOEBA_WET) ||
5299             (IN_LEV_FIELD(x-1, y) && Feld[x-1][y] == EL_AMOEBA_WET) ||
5300             (IN_LEV_FIELD(x+1, y) && Feld[x+1][y] == EL_AMOEBA_WET) ||
5301             (IN_LEV_FIELD(x, y+1) && Feld[x][y+1] == EL_AMOEBA_WET))
5302           Feld[x][y] = EL_AMOEBA_DROP;
5303       }
5304
5305       random = random * 129 + 1;
5306     }
5307   }
5308 #endif
5309
5310 #if 0
5311   if (game.explosions_delayed)
5312 #endif
5313   {
5314     game.explosions_delayed = FALSE;
5315
5316     for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
5317     {
5318       element = Feld[x][y];
5319
5320       if (ExplodeField[x][y])
5321         Explode(x, y, EX_PHASE_START, ExplodeField[x][y]);
5322       else if (element == EL_EXPLOSION)
5323         Explode(x, y, ExplodePhase[x][y], EX_NORMAL);
5324
5325       ExplodeField[x][y] = EX_NO_EXPLOSION;
5326     }
5327
5328     game.explosions_delayed = TRUE;
5329   }
5330
5331   if (game.magic_wall_active)
5332   {
5333     if (!(game.magic_wall_time_left % 4))
5334     {
5335       int element = Feld[sieb_x][sieb_y];
5336
5337       if (element == EL_BD_MAGIC_WALL_FULL ||
5338           element == EL_BD_MAGIC_WALL_ACTIVE ||
5339           element == EL_BD_MAGIC_WALL_EMPTYING)
5340         PlaySoundLevel(sieb_x, sieb_y, SND_BD_MAGIC_WALL_ACTIVE);
5341       else
5342         PlaySoundLevel(sieb_x, sieb_y, SND_MAGIC_WALL_ACTIVE);
5343     }
5344
5345     if (game.magic_wall_time_left > 0)
5346     {
5347       game.magic_wall_time_left--;
5348       if (!game.magic_wall_time_left)
5349       {
5350         for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
5351         {
5352           element = Feld[x][y];
5353
5354           if (element == EL_MAGIC_WALL_ACTIVE ||
5355               element == EL_MAGIC_WALL_FULL)
5356           {
5357             Feld[x][y] = EL_MAGIC_WALL_DEAD;
5358             DrawLevelField(x, y);
5359           }
5360           else if (element == EL_BD_MAGIC_WALL_ACTIVE ||
5361                    element == EL_BD_MAGIC_WALL_FULL)
5362           {
5363             Feld[x][y] = EL_BD_MAGIC_WALL_DEAD;
5364             DrawLevelField(x, y);
5365           }
5366         }
5367
5368         game.magic_wall_active = FALSE;
5369       }
5370     }
5371   }
5372
5373   if (game.light_time_left > 0)
5374   {
5375     game.light_time_left--;
5376
5377     if (game.light_time_left == 0)
5378       RedrawAllLightSwitchesAndInvisibleElements();
5379   }
5380
5381   if (game.timegate_time_left > 0)
5382   {
5383     game.timegate_time_left--;
5384
5385     if (game.timegate_time_left == 0)
5386       CloseAllOpenTimegates();
5387   }
5388
5389   for (i=0; i<MAX_PLAYERS; i++)
5390   {
5391     struct PlayerInfo *player = &stored_player[i];
5392
5393     if (SHIELD_ON(player))
5394     {
5395       if (player->shield_deadly_time_left)
5396         PlaySoundLevel(player->jx, player->jy, SND_SHIELD_DEADLY_ACTIVE);
5397       else if (player->shield_normal_time_left)
5398         PlaySoundLevel(player->jx, player->jy, SND_SHIELD_NORMAL_ACTIVE);
5399     }
5400   }
5401
5402   if (TimeFrames >= (1000 / GameFrameDelay))
5403   {
5404     TimeFrames = 0;
5405     TimePlayed++;
5406
5407     for (i=0; i<MAX_PLAYERS; i++)
5408     {
5409       struct PlayerInfo *player = &stored_player[i];
5410
5411       if (SHIELD_ON(player))
5412       {
5413         player->shield_normal_time_left--;
5414
5415         if (player->shield_deadly_time_left > 0)
5416           player->shield_deadly_time_left--;
5417       }
5418     }
5419
5420     if (tape.recording || tape.playing)
5421       DrawVideoDisplay(VIDEO_STATE_TIME_ON, TimePlayed);
5422
5423     if (TimeLeft > 0)
5424     {
5425       TimeLeft--;
5426
5427       if (TimeLeft <= 10 && setup.time_limit)
5428         PlaySoundStereo(SND_GAME_RUNNING_OUT_OF_TIME, SOUND_MAX_RIGHT);
5429
5430       DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
5431
5432       if (!TimeLeft && setup.time_limit)
5433         for (i=0; i<MAX_PLAYERS; i++)
5434           KillHero(&stored_player[i]);
5435     }
5436     else if (level.time == 0 && !AllPlayersGone) /* level without time limit */
5437       DrawText(DX_TIME, DY_TIME, int2str(TimePlayed, 3), FS_SMALL, FC_YELLOW);
5438   }
5439
5440   DrawAllPlayers();
5441
5442   if (options.debug)                    /* calculate frames per second */
5443   {
5444     static unsigned long fps_counter = 0;
5445     static int fps_frames = 0;
5446     unsigned long fps_delay_ms = Counter() - fps_counter;
5447
5448     fps_frames++;
5449
5450     if (fps_delay_ms >= 500)    /* calculate fps every 0.5 seconds */
5451     {
5452       global.frames_per_second = 1000 * (float)fps_frames / fps_delay_ms;
5453
5454       fps_frames = 0;
5455       fps_counter = Counter();
5456     }
5457
5458     redraw_mask |= REDRAW_FPS;
5459   }
5460 }
5461
5462 static boolean AllPlayersInSight(struct PlayerInfo *player, int x, int y)
5463 {
5464   int min_x = x, min_y = y, max_x = x, max_y = y;
5465   int i;
5466
5467   for (i=0; i<MAX_PLAYERS; i++)
5468   {
5469     int jx = stored_player[i].jx, jy = stored_player[i].jy;
5470
5471     if (!stored_player[i].active || &stored_player[i] == player)
5472       continue;
5473
5474     min_x = MIN(min_x, jx);
5475     min_y = MIN(min_y, jy);
5476     max_x = MAX(max_x, jx);
5477     max_y = MAX(max_y, jy);
5478   }
5479
5480   return (max_x - min_x < SCR_FIELDX && max_y - min_y < SCR_FIELDY);
5481 }
5482
5483 static boolean AllPlayersInVisibleScreen()
5484 {
5485   int i;
5486
5487   for (i=0; i<MAX_PLAYERS; i++)
5488   {
5489     int jx = stored_player[i].jx, jy = stored_player[i].jy;
5490
5491     if (!stored_player[i].active)
5492       continue;
5493
5494     if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
5495       return FALSE;
5496   }
5497
5498   return TRUE;
5499 }
5500
5501 void ScrollLevel(int dx, int dy)
5502 {
5503   int softscroll_offset = (setup.soft_scrolling ? TILEX : 0);
5504   int x, y;
5505
5506   BlitBitmap(drawto_field, drawto_field,
5507              FX + TILEX*(dx == -1) - softscroll_offset,
5508              FY + TILEY*(dy == -1) - softscroll_offset,
5509              SXSIZE - TILEX*(dx!=0) + 2*softscroll_offset,
5510              SYSIZE - TILEY*(dy!=0) + 2*softscroll_offset,
5511              FX + TILEX*(dx == 1) - softscroll_offset,
5512              FY + TILEY*(dy == 1) - softscroll_offset);
5513
5514   if (dx)
5515   {
5516     x = (dx == 1 ? BX1 : BX2);
5517     for (y=BY1; y<=BY2; y++)
5518       DrawScreenField(x, y);
5519   }
5520
5521   if (dy)
5522   {
5523     y = (dy == 1 ? BY1 : BY2);
5524     for (x=BX1; x<=BX2; x++)
5525       DrawScreenField(x, y);
5526   }
5527
5528   redraw_mask |= REDRAW_FIELD;
5529 }
5530
5531 static void CheckGravityMovement(struct PlayerInfo *player)
5532 {
5533   if (level.gravity && !player->programmed_action)
5534   {
5535     int move_dir_vertical = player->action & (MV_UP | MV_DOWN);
5536     int move_dir_horizontal = player->action & (MV_LEFT | MV_RIGHT);
5537     int move_dir =
5538       (player->last_move_dir & (MV_LEFT | MV_RIGHT) ?
5539        (move_dir_vertical ? move_dir_vertical : move_dir_horizontal) :
5540        (move_dir_horizontal ? move_dir_horizontal : move_dir_vertical));
5541     int jx = player->jx, jy = player->jy;
5542     int dx = (move_dir & MV_LEFT ? -1 : move_dir & MV_RIGHT ? +1 : 0);
5543     int dy = (move_dir & MV_UP ? -1 : move_dir & MV_DOWN ? +1 : 0);
5544     int new_jx = jx + dx, new_jy = jy + dy;
5545     boolean field_under_player_is_free =
5546       (IN_LEV_FIELD(jx, jy + 1) && IS_FREE(jx, jy + 1));
5547     boolean player_is_moving_to_valid_field =
5548       (IN_LEV_FIELD(new_jx, new_jy) &&
5549        (Feld[new_jx][new_jy] == EL_SP_BASE ||
5550         Feld[new_jx][new_jy] == EL_SAND));
5551
5552     if (field_under_player_is_free &&
5553         !player_is_moving_to_valid_field &&
5554         !IS_TUBE(Feld[jx][jy]))
5555       player->programmed_action = MV_DOWN;
5556   }
5557 }
5558
5559 boolean MoveFigureOneStep(struct PlayerInfo *player,
5560                           int dx, int dy, int real_dx, int real_dy)
5561 {
5562   int jx = player->jx, jy = player->jy;
5563   int new_jx = jx+dx, new_jy = jy+dy;
5564   int element;
5565   int can_move;
5566
5567   if (!player->active || (!dx && !dy))
5568     return MF_NO_ACTION;
5569
5570   player->MovDir = (dx < 0 ? MV_LEFT :
5571                     dx > 0 ? MV_RIGHT :
5572                     dy < 0 ? MV_UP :
5573                     dy > 0 ? MV_DOWN :  MV_NO_MOVING);
5574
5575   if (!IN_LEV_FIELD(new_jx, new_jy))
5576     return MF_NO_ACTION;
5577
5578   if (!options.network && !AllPlayersInSight(player, new_jx, new_jy))
5579     return MF_NO_ACTION;
5580
5581 #if 0
5582   element = MovingOrBlocked2Element(new_jx, new_jy);
5583 #else
5584   element = MovingOrBlocked2ElementIfNotLeaving(new_jx, new_jy);
5585 #endif
5586
5587   if (DONT_GO_TO(element))
5588   {
5589     if (element == EL_ACID && dx == 0 && dy == 1)
5590     {
5591       Blurb(jx, jy);
5592       Feld[jx][jy] = EL_PLAYER1;
5593       InitMovingField(jx, jy, MV_DOWN);
5594       Store[jx][jy] = EL_ACID;
5595       ContinueMoving(jx, jy);
5596       BuryHero(player);
5597     }
5598     else
5599       TestIfHeroRunsIntoBadThing(jx, jy, player->MovDir);
5600
5601     return MF_MOVING;
5602   }
5603
5604   can_move = DigField(player, new_jx, new_jy, real_dx, real_dy, DF_DIG);
5605   if (can_move != MF_MOVING)
5606     return can_move;
5607
5608   StorePlayer[jx][jy] = 0;
5609   player->last_jx = jx;
5610   player->last_jy = jy;
5611   jx = player->jx = new_jx;
5612   jy = player->jy = new_jy;
5613   StorePlayer[jx][jy] = player->element_nr;
5614
5615   player->MovPos =
5616     (dx > 0 || dy > 0 ? -1 : 1) * (TILEX - TILEX / player->move_delay_value);
5617
5618   ScrollFigure(player, SCROLL_INIT);
5619
5620   return MF_MOVING;
5621 }
5622
5623 boolean MoveFigure(struct PlayerInfo *player, int dx, int dy)
5624 {
5625   int jx = player->jx, jy = player->jy;
5626   int old_jx = jx, old_jy = jy;
5627   int moved = MF_NO_ACTION;
5628
5629   if (!player->active || (!dx && !dy))
5630     return FALSE;
5631
5632 #if 0
5633   if (!FrameReached(&player->move_delay, player->move_delay_value) &&
5634       !tape.playing)
5635     return FALSE;
5636 #else
5637   if (!FrameReached(&player->move_delay, player->move_delay_value) &&
5638       !(tape.playing && tape.file_version < FILE_VERSION_2_0))
5639     return FALSE;
5640 #endif
5641
5642   /* remove the last programmed player action */
5643   player->programmed_action = 0;
5644
5645   if (player->MovPos)
5646   {
5647     /* should only happen if pre-1.2 tape recordings are played */
5648     /* this is only for backward compatibility */
5649
5650     int original_move_delay_value = player->move_delay_value;
5651
5652 #if DEBUG
5653     printf("THIS SHOULD ONLY HAPPEN WITH PRE-1.2 LEVEL TAPES. [%ld]\n",
5654            tape.counter);
5655 #endif
5656
5657     /* scroll remaining steps with finest movement resolution */
5658     player->move_delay_value = MOVE_DELAY_NORMAL_SPEED;
5659
5660     while (player->MovPos)
5661     {
5662       ScrollFigure(player, SCROLL_GO_ON);
5663       ScrollScreen(NULL, SCROLL_GO_ON);
5664       FrameCounter++;
5665       DrawAllPlayers();
5666       BackToFront();
5667     }
5668
5669     player->move_delay_value = original_move_delay_value;
5670   }
5671
5672   if (player->last_move_dir & (MV_LEFT | MV_RIGHT))
5673   {
5674     if (!(moved |= MoveFigureOneStep(player, 0, dy, dx, dy)))
5675       moved |= MoveFigureOneStep(player, dx, 0, dx, dy);
5676   }
5677   else
5678   {
5679     if (!(moved |= MoveFigureOneStep(player, dx, 0, dx, dy)))
5680       moved |= MoveFigureOneStep(player, 0, dy, dx, dy);
5681   }
5682
5683   jx = player->jx;
5684   jy = player->jy;
5685
5686   if (moved & MF_MOVING && !ScreenMovPos &&
5687       (player == local_player || !options.network))
5688   {
5689     int old_scroll_x = scroll_x, old_scroll_y = scroll_y;
5690     int offset = (setup.scroll_delay ? 3 : 0);
5691
5692     if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
5693     {
5694       /* actual player has left the screen -- scroll in that direction */
5695       if (jx != old_jx)         /* player has moved horizontally */
5696         scroll_x += (jx - old_jx);
5697       else                      /* player has moved vertically */
5698         scroll_y += (jy - old_jy);
5699     }
5700     else
5701     {
5702       if (jx != old_jx)         /* player has moved horizontally */
5703       {
5704         if ((player->MovDir == MV_LEFT && scroll_x > jx - MIDPOSX + offset) ||
5705             (player->MovDir == MV_RIGHT && scroll_x < jx - MIDPOSX - offset))
5706           scroll_x = jx-MIDPOSX + (scroll_x < jx-MIDPOSX ? -offset : +offset);
5707
5708         /* don't scroll over playfield boundaries */
5709         if (scroll_x < SBX_Left || scroll_x > SBX_Right)
5710           scroll_x = (scroll_x < SBX_Left ? SBX_Left : SBX_Right);
5711
5712         /* don't scroll more than one field at a time */
5713         scroll_x = old_scroll_x + SIGN(scroll_x - old_scroll_x);
5714
5715         /* don't scroll against the player's moving direction */
5716         if ((player->MovDir == MV_LEFT && scroll_x > old_scroll_x) ||
5717             (player->MovDir == MV_RIGHT && scroll_x < old_scroll_x))
5718           scroll_x = old_scroll_x;
5719       }
5720       else                      /* player has moved vertically */
5721       {
5722         if ((player->MovDir == MV_UP && scroll_y > jy - MIDPOSY + offset) ||
5723             (player->MovDir == MV_DOWN && scroll_y < jy - MIDPOSY - offset))
5724           scroll_y = jy-MIDPOSY + (scroll_y < jy-MIDPOSY ? -offset : +offset);
5725
5726         /* don't scroll over playfield boundaries */
5727         if (scroll_y < SBY_Upper || scroll_y > SBY_Lower)
5728           scroll_y = (scroll_y < SBY_Upper ? SBY_Upper : SBY_Lower);
5729
5730         /* don't scroll more than one field at a time */
5731         scroll_y = old_scroll_y + SIGN(scroll_y - old_scroll_y);
5732
5733         /* don't scroll against the player's moving direction */
5734         if ((player->MovDir == MV_UP && scroll_y > old_scroll_y) ||
5735             (player->MovDir == MV_DOWN && scroll_y < old_scroll_y))
5736           scroll_y = old_scroll_y;
5737       }
5738     }
5739
5740     if (scroll_x != old_scroll_x || scroll_y != old_scroll_y)
5741     {
5742       if (!options.network && !AllPlayersInVisibleScreen())
5743       {
5744         scroll_x = old_scroll_x;
5745         scroll_y = old_scroll_y;
5746       }
5747       else
5748       {
5749         ScrollScreen(player, SCROLL_INIT);
5750         ScrollLevel(old_scroll_x - scroll_x, old_scroll_y - scroll_y);
5751       }
5752     }
5753   }
5754
5755   if (!(moved & MF_MOVING) && !player->Pushing)
5756     player->Frame = 0;
5757   else
5758 #if 0
5759     player->Frame = (player->Frame + 1) % 4;
5760 #else
5761     player->Frame += 1 * 0;
5762 #endif
5763
5764   if (moved & MF_MOVING)
5765   {
5766     if (old_jx != jx && old_jy == jy)
5767       player->MovDir = (old_jx < jx ? MV_RIGHT : MV_LEFT);
5768     else if (old_jx == jx && old_jy != jy)
5769       player->MovDir = (old_jy < jy ? MV_DOWN : MV_UP);
5770
5771     DrawLevelField(jx, jy);     /* for "DrawCrumbledSand()" */
5772
5773     player->last_move_dir = player->MovDir;
5774     player->is_moving = TRUE;
5775   }
5776   else
5777   {
5778     CheckGravityMovement(player);
5779
5780     /*
5781     player->last_move_dir = MV_NO_MOVING;
5782     */
5783     player->is_moving = FALSE;
5784   }
5785
5786   TestIfHeroTouchesBadThing(jx, jy);
5787
5788   if (!player->active)
5789     RemoveHero(player);
5790
5791   return moved;
5792 }
5793
5794 void ScrollFigure(struct PlayerInfo *player, int mode)
5795 {
5796   int jx = player->jx, jy = player->jy;
5797   int last_jx = player->last_jx, last_jy = player->last_jy;
5798   int move_stepsize = TILEX / player->move_delay_value;
5799
5800   if (!player->active || !player->MovPos)
5801     return;
5802
5803   if (mode == SCROLL_INIT)
5804   {
5805     player->actual_frame_counter = FrameCounter;
5806     player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
5807     if (player->Frame)
5808       player->Frame += 1;
5809
5810     if (Feld[last_jx][last_jy] == EL_EMPTY)
5811       Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING;
5812
5813     DrawPlayer(player);
5814     return;
5815   }
5816   else if (!FrameReached(&player->actual_frame_counter, 1))
5817     return;
5818
5819   player->MovPos += (player->MovPos > 0 ? -1 : 1) * move_stepsize;
5820   player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
5821   player->Frame += 1;
5822
5823   if (Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING)
5824     Feld[last_jx][last_jy] = EL_EMPTY;
5825
5826   /* before DrawPlayer() to draw correct player graphic for this case */
5827   if (player->MovPos == 0)
5828     CheckGravityMovement(player);
5829
5830   DrawPlayer(player);
5831
5832   if (player->MovPos == 0)
5833   {
5834     if (IS_QUICK_GATE(Feld[last_jx][last_jy]))
5835     {
5836       /* continue with normal speed after quickly moving through gate */
5837       HALVE_PLAYER_SPEED(player);
5838
5839       /* be able to make the next move without delay */
5840       player->move_delay = 0;
5841     }
5842
5843     player->last_jx = jx;
5844     player->last_jy = jy;
5845
5846     if (Feld[jx][jy] == EL_EXIT_OPEN ||
5847         Feld[jx][jy] == EL_SP_EXIT_OPEN)
5848     {
5849       RemoveHero(player);
5850
5851       if (local_player->friends_still_needed == 0 ||
5852           Feld[jx][jy] == EL_SP_EXIT_OPEN)
5853         player->LevelSolved = player->GameOver = TRUE;
5854     }
5855
5856     if (tape.single_step && tape.recording && !tape.pausing &&
5857         !player->programmed_action)
5858       TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
5859   }
5860 }
5861
5862 void ScrollScreen(struct PlayerInfo *player, int mode)
5863 {
5864   static unsigned long screen_frame_counter = 0;
5865
5866   if (mode == SCROLL_INIT)
5867   {
5868     /* set scrolling step size according to actual player's moving speed */
5869     ScrollStepSize = TILEX / player->move_delay_value;
5870
5871     screen_frame_counter = FrameCounter;
5872     ScreenMovDir = player->MovDir;
5873     ScreenMovPos = player->MovPos;
5874     ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
5875     return;
5876   }
5877   else if (!FrameReached(&screen_frame_counter, 1))
5878     return;
5879
5880   if (ScreenMovPos)
5881   {
5882     ScreenMovPos += (ScreenMovPos > 0 ? -1 : 1) * ScrollStepSize;
5883     ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
5884     redraw_mask |= REDRAW_FIELD;
5885   }
5886   else
5887     ScreenMovDir = MV_NO_MOVING;
5888 }
5889
5890 void TestIfGoodThingHitsBadThing(int good_x, int good_y, int good_move_dir)
5891 {
5892   int i, kill_x = -1, kill_y = -1;
5893   static int test_xy[4][2] =
5894   {
5895     { 0, -1 },
5896     { -1, 0 },
5897     { +1, 0 },
5898     { 0, +1 }
5899   };
5900   static int test_dir[4] =
5901   {
5902     MV_UP,
5903     MV_LEFT,
5904     MV_RIGHT,
5905     MV_DOWN
5906   };
5907
5908   for (i=0; i<4; i++)
5909   {
5910     int test_x, test_y, test_move_dir, test_element;
5911
5912     test_x = good_x + test_xy[i][0];
5913     test_y = good_y + test_xy[i][1];
5914     if (!IN_LEV_FIELD(test_x, test_y))
5915       continue;
5916
5917     test_move_dir =
5918       (IS_MOVING(test_x, test_y) ? MovDir[test_x][test_y] : MV_NO_MOVING);
5919
5920 #if 0
5921     test_element = Feld[test_x][test_y];
5922 #else
5923     test_element = MovingOrBlocked2ElementIfNotLeaving(test_x, test_y);
5924 #endif
5925
5926     /* 1st case: good thing is moving towards DONT_GO_TO style bad thing;
5927        2nd case: DONT_TOUCH style bad thing does not move away from good thing
5928     */
5929     if ((DONT_GO_TO(test_element) && good_move_dir == test_dir[i]) ||
5930         (DONT_TOUCH(test_element) && test_move_dir != test_dir[i]))
5931     {
5932       kill_x = test_x;
5933       kill_y = test_y;
5934       break;
5935     }
5936   }
5937
5938   if (kill_x != -1 || kill_y != -1)
5939   {
5940     if (IS_PLAYER(good_x, good_y))
5941     {
5942       struct PlayerInfo *player = PLAYERINFO(good_x, good_y);
5943
5944       if (player->shield_deadly_time_left > 0)
5945         Bang(kill_x, kill_y);
5946       else if (!PLAYER_PROTECTED(good_x, good_y))
5947         KillHero(player);
5948     }
5949     else
5950       Bang(good_x, good_y);
5951   }
5952 }
5953
5954 void TestIfBadThingHitsGoodThing(int bad_x, int bad_y, int bad_move_dir)
5955 {
5956   int i, kill_x = -1, kill_y = -1;
5957   int bad_element = Feld[bad_x][bad_y];
5958   static int test_xy[4][2] =
5959   {
5960     { 0, -1 },
5961     { -1, 0 },
5962     { +1, 0 },
5963     { 0, +1 }
5964   };
5965   static int test_dir[4] =
5966   {
5967     MV_UP,
5968     MV_LEFT,
5969     MV_RIGHT,
5970     MV_DOWN
5971   };
5972
5973   if (bad_element == EL_EXPLOSION)      /* skip just exploding bad things */
5974     return;
5975
5976   for (i=0; i<4; i++)
5977   {
5978     int test_x, test_y, test_move_dir, test_element;
5979
5980     test_x = bad_x + test_xy[i][0];
5981     test_y = bad_y + test_xy[i][1];
5982     if (!IN_LEV_FIELD(test_x, test_y))
5983       continue;
5984
5985     test_move_dir =
5986       (IS_MOVING(test_x, test_y) ? MovDir[test_x][test_y] : MV_NO_MOVING);
5987
5988     test_element = Feld[test_x][test_y];
5989
5990     /* 1st case: good thing is moving towards DONT_GO_TO style bad thing;
5991        2nd case: DONT_TOUCH style bad thing does not move away from good thing
5992     */
5993     if ((DONT_GO_TO(bad_element) &&  bad_move_dir == test_dir[i]) ||
5994         (DONT_TOUCH(bad_element) && test_move_dir != test_dir[i]))
5995     {
5996       /* good thing is player or penguin that does not move away */
5997       if (IS_PLAYER(test_x, test_y))
5998       {
5999         struct PlayerInfo *player = PLAYERINFO(test_x, test_y);
6000
6001         if (bad_element == EL_ROBOT && player->is_moving)
6002           continue;     /* robot does not kill player if he is moving */
6003
6004         kill_x = test_x;
6005         kill_y = test_y;
6006         break;
6007       }
6008       else if (test_element == EL_PENGUIN)
6009       {
6010         kill_x = test_x;
6011         kill_y = test_y;
6012         break;
6013       }
6014     }
6015   }
6016
6017   if (kill_x != -1 || kill_y != -1)
6018   {
6019     if (IS_PLAYER(kill_x, kill_y))
6020     {
6021       struct PlayerInfo *player = PLAYERINFO(kill_x, kill_y);
6022
6023 #if 0
6024       int dir = player->MovDir;
6025       int newx = player->jx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
6026       int newy = player->jy + (dir == MV_UP   ? -1 : dir == MV_DOWN  ? +1 : 0);
6027
6028       if (Feld[bad_x][bad_y] == EL_ROBOT && player->is_moving &&
6029           newx != bad_x && newy != bad_y)
6030         ;       /* robot does not kill player if he is moving */
6031       else
6032         printf("-> %d\n", player->MovDir);
6033
6034       if (Feld[bad_x][bad_y] == EL_ROBOT && player->is_moving &&
6035           newx != bad_x && newy != bad_y)
6036         ;       /* robot does not kill player if he is moving */
6037       else
6038         ;
6039 #endif
6040
6041       if (player->shield_deadly_time_left > 0)
6042         Bang(bad_x, bad_y);
6043       else if (!PLAYER_PROTECTED(kill_x, kill_y))
6044         KillHero(player);
6045     }
6046     else
6047       Bang(kill_x, kill_y);
6048   }
6049 }
6050
6051 void TestIfHeroTouchesBadThing(int x, int y)
6052 {
6053   TestIfGoodThingHitsBadThing(x, y, MV_NO_MOVING);
6054 }
6055
6056 void TestIfHeroRunsIntoBadThing(int x, int y, int move_dir)
6057 {
6058   TestIfGoodThingHitsBadThing(x, y, move_dir);
6059 }
6060
6061 void TestIfBadThingTouchesHero(int x, int y)
6062 {
6063   TestIfBadThingHitsGoodThing(x, y, MV_NO_MOVING);
6064 }
6065
6066 void TestIfBadThingRunsIntoHero(int x, int y, int move_dir)
6067 {
6068   TestIfBadThingHitsGoodThing(x, y, move_dir);
6069 }
6070
6071 void TestIfFriendTouchesBadThing(int x, int y)
6072 {
6073   TestIfGoodThingHitsBadThing(x, y, MV_NO_MOVING);
6074 }
6075
6076 void TestIfBadThingTouchesFriend(int x, int y)
6077 {
6078   TestIfBadThingHitsGoodThing(x, y, MV_NO_MOVING);
6079 }
6080
6081 void TestIfBadThingTouchesOtherBadThing(int bad_x, int bad_y)
6082 {
6083   int i, kill_x = bad_x, kill_y = bad_y;
6084   static int xy[4][2] =
6085   {
6086     { 0, -1 },
6087     { -1, 0 },
6088     { +1, 0 },
6089     { 0, +1 }
6090   };
6091
6092   for (i=0; i<4; i++)
6093   {
6094     int x, y, element;
6095
6096     x = bad_x + xy[i][0];
6097     y = bad_y + xy[i][1];
6098     if (!IN_LEV_FIELD(x, y))
6099       continue;
6100
6101     element = Feld[x][y];
6102     if (IS_AMOEBOID(element) || element == EL_GAMEOFLIFE ||
6103         element == EL_AMOEBA_CREATING || element == EL_AMOEBA_DROP)
6104     {
6105       kill_x = x;
6106       kill_y = y;
6107       break;
6108     }
6109   }
6110
6111   if (kill_x != bad_x || kill_y != bad_y)
6112     Bang(bad_x, bad_y);
6113 }
6114
6115 void KillHero(struct PlayerInfo *player)
6116 {
6117   int jx = player->jx, jy = player->jy;
6118
6119   if (!player->active)
6120     return;
6121
6122   if (IS_PFORTE(Feld[jx][jy]))
6123     Feld[jx][jy] = EL_EMPTY;
6124
6125   /* deactivate shield (else Bang()/Explode() would not work right) */
6126   player->shield_normal_time_left = 0;
6127   player->shield_deadly_time_left = 0;
6128
6129   Bang(jx, jy);
6130   BuryHero(player);
6131 }
6132
6133 static void KillHeroUnlessProtected(int x, int y)
6134 {
6135   if (!PLAYER_PROTECTED(x, y))
6136     KillHero(PLAYERINFO(x, y));
6137 }
6138
6139 void BuryHero(struct PlayerInfo *player)
6140 {
6141   int jx = player->jx, jy = player->jy;
6142
6143   if (!player->active)
6144     return;
6145
6146   PlaySoundLevel(jx, jy, SND_PLAYER_DYING);
6147   PlaySoundLevel(jx, jy, SND_GAME_LOSING);
6148
6149   player->GameOver = TRUE;
6150   RemoveHero(player);
6151 }
6152
6153 void RemoveHero(struct PlayerInfo *player)
6154 {
6155   int jx = player->jx, jy = player->jy;
6156   int i, found = FALSE;
6157
6158   player->present = FALSE;
6159   player->active = FALSE;
6160
6161   if (!ExplodeField[jx][jy])
6162     StorePlayer[jx][jy] = 0;
6163
6164   for (i=0; i<MAX_PLAYERS; i++)
6165     if (stored_player[i].active)
6166       found = TRUE;
6167
6168   if (!found)
6169     AllPlayersGone = TRUE;
6170
6171   ExitX = ZX = jx;
6172   ExitY = ZY = jy;
6173 }
6174
6175 int DigField(struct PlayerInfo *player,
6176              int x, int y, int real_dx, int real_dy, int mode)
6177 {
6178   int jx = player->jx, jy = player->jy;
6179   int dx = x - jx, dy = y - jy;
6180   int move_direction = (dx == -1 ? MV_LEFT :
6181                         dx == +1 ? MV_RIGHT :
6182                         dy == -1 ? MV_UP :
6183                         dy == +1 ? MV_DOWN : MV_NO_MOVING);
6184   int element;
6185
6186   if (player->MovPos == 0)
6187     player->Pushing = FALSE;
6188
6189   if (mode == DF_NO_PUSH)
6190   {
6191     player->Switching = FALSE;
6192     player->push_delay = 0;
6193     return MF_NO_ACTION;
6194   }
6195
6196   if (IS_MOVING(x, y) || IS_PLAYER(x, y))
6197     return MF_NO_ACTION;
6198
6199   if (IS_TUBE(Feld[jx][jy]))
6200   {
6201     int i = 0;
6202     int tube_leave_directions[][2] =
6203     {
6204       { EL_TUBE_ALL,                    MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN },
6205       { EL_TUBE_VERTICAL,                                    MV_UP | MV_DOWN },
6206       { EL_TUBE_HORIZONTAL,             MV_LEFT | MV_RIGHT                   },
6207       { EL_TUBE_VERTICAL_LEFT,          MV_LEFT |            MV_UP | MV_DOWN },
6208       { EL_TUBE_VERTICAL_RIGHT,                   MV_RIGHT | MV_UP | MV_DOWN },
6209       { EL_TUBE_HORIZONTAL_UP,          MV_LEFT | MV_RIGHT | MV_UP           },
6210       { EL_TUBE_HORIZONTAL_DOWN,        MV_LEFT | MV_RIGHT |         MV_DOWN },
6211       { EL_TUBE_LEFT_UP,                MV_LEFT |            MV_UP           },
6212       { EL_TUBE_LEFT_DOWN,              MV_LEFT |                    MV_DOWN },
6213       { EL_TUBE_RIGHT_UP,                         MV_RIGHT | MV_UP           },
6214       { EL_TUBE_RIGHT_DOWN,                       MV_RIGHT |         MV_DOWN },
6215       { -1,                             MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN }
6216     };
6217
6218     while (tube_leave_directions[i][0] != Feld[jx][jy])
6219     {
6220       i++;
6221       if (tube_leave_directions[i][0] == -1)    /* should not happen */
6222         break;
6223     }
6224
6225     if (!(tube_leave_directions[i][1] & move_direction))
6226       return MF_NO_ACTION;      /* tube has no opening in this direction */
6227   }
6228
6229   element = Feld[x][y];
6230
6231   switch (element)
6232   {
6233     case EL_EMPTY:
6234     case EL_SAND:
6235     case EL_INVISIBLE_SAND:
6236     case EL_INVISIBLE_SAND_ACTIVE:
6237     case EL_TRAP:
6238     case EL_SP_BASE:
6239     case EL_SP_BUGGY_BASE:
6240     case EL_SP_BUGGY_BASE_ACTIVATING:
6241       RemoveField(x, y);
6242       PlaySoundLevelElementAction(x, y, element, ACTION_DIGGING);
6243       break;
6244
6245     case EL_EMERALD:
6246     case EL_BD_DIAMOND:
6247     case EL_EMERALD_YELLOW:
6248     case EL_EMERALD_RED:
6249     case EL_EMERALD_PURPLE:
6250     case EL_DIAMOND:
6251     case EL_SP_INFOTRON:
6252     case EL_PEARL:
6253     case EL_CRYSTAL:
6254       RemoveField(x, y);
6255       local_player->gems_still_needed -= (element == EL_DIAMOND ? 3 :
6256                                           element == EL_PEARL ? 5 :
6257                                           element == EL_CRYSTAL ? 8 : 1);
6258       if (local_player->gems_still_needed < 0)
6259         local_player->gems_still_needed = 0;
6260       RaiseScoreElement(element);
6261       DrawText(DX_EMERALDS, DY_EMERALDS,
6262                int2str(local_player->gems_still_needed, 3),
6263                FS_SMALL, FC_YELLOW);
6264       PlaySoundLevelElementAction(x, y, element, ACTION_COLLECTING);
6265       break;
6266
6267     case EL_SPEED_PILL:
6268       RemoveField(x, y);
6269       player->move_delay_value = MOVE_DELAY_HIGH_SPEED;
6270       PlaySoundLevel(x, y, SND_SPEED_PILL_COLLECTING);
6271       break;
6272
6273     case EL_ENVELOPE:
6274       Feld[x][y] = EL_EMPTY;
6275       PlaySoundLevel(x, y, SND_ENVELOPE_COLLECTING);
6276       break;
6277
6278     case EL_EXTRA_TIME:
6279       RemoveField(x, y);
6280       if (level.time > 0)
6281       {
6282         TimeLeft += 10;
6283         DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
6284       }
6285       PlaySoundStereo(SND_EXTRA_TIME_COLLECTING, SOUND_MAX_RIGHT);
6286       break;
6287
6288     case EL_SHIELD_NORMAL:
6289       RemoveField(x, y);
6290       player->shield_normal_time_left += 10;
6291       PlaySoundLevel(x, y, SND_SHIELD_NORMAL_COLLECTING);
6292       break;
6293
6294     case EL_SHIELD_DEADLY:
6295       RemoveField(x, y);
6296       player->shield_normal_time_left += 10;
6297       player->shield_deadly_time_left += 10;
6298       PlaySoundLevel(x, y, SND_SHIELD_DEADLY_COLLECTING);
6299       break;
6300
6301     case EL_DYNAMITE:
6302     case EL_SP_DISK_RED:
6303       RemoveField(x, y);
6304       player->dynamite++;
6305       RaiseScoreElement(EL_DYNAMITE);
6306       DrawText(DX_DYNAMITE, DY_DYNAMITE,
6307                int2str(local_player->dynamite, 3),
6308                FS_SMALL, FC_YELLOW);
6309       PlaySoundLevelElementAction(x, y, element, ACTION_COLLECTING);
6310       break;
6311
6312     case EL_DYNABOMB_NR:
6313       RemoveField(x, y);
6314       player->dynabomb_count++;
6315       player->dynabombs_left++;
6316       RaiseScoreElement(EL_DYNAMITE);
6317       PlaySoundLevel(x, y, SND_DYNABOMB_NR_COLLECTING);
6318       break;
6319
6320     case EL_DYNABOMB_SZ:
6321       RemoveField(x, y);
6322       player->dynabomb_size++;
6323       RaiseScoreElement(EL_DYNAMITE);
6324       PlaySoundLevel(x, y, SND_DYNABOMB_SZ_COLLECTING);
6325       break;
6326
6327     case EL_DYNABOMB_XL:
6328       RemoveField(x, y);
6329       player->dynabomb_xl = TRUE;
6330       RaiseScoreElement(EL_DYNAMITE);
6331       PlaySoundLevel(x, y, SND_DYNABOMB_XL_COLLECTING);
6332       break;
6333
6334     case EL_KEY1:
6335     case EL_KEY2:
6336     case EL_KEY3:
6337     case EL_KEY4:
6338     {
6339       int key_nr = element - EL_KEY1;
6340
6341       RemoveField(x, y);
6342       player->key[key_nr] = TRUE;
6343       RaiseScoreElement(element);
6344       DrawMiniGraphicExt(drawto, DX_KEYS + key_nr * MINI_TILEX, DY_KEYS,
6345                          IMG_KEY1 + key_nr);
6346       DrawMiniGraphicExt(window, DX_KEYS + key_nr * MINI_TILEX, DY_KEYS,
6347                          IMG_KEY1 + key_nr);
6348       PlaySoundLevel(x, y, SND_KEY_COLLECTING);
6349       break;
6350     }
6351
6352     case EL_EM_KEY1:
6353     case EL_EM_KEY2:
6354     case EL_EM_KEY3:
6355     case EL_EM_KEY4:
6356     {
6357       int key_nr = element - EL_EM_KEY1;
6358
6359       RemoveField(x, y);
6360       player->key[key_nr] = TRUE;
6361       RaiseScoreElement(element);
6362       DrawMiniGraphicExt(drawto, DX_KEYS + key_nr * MINI_TILEX, DY_KEYS,
6363                          IMG_KEY1 + key_nr);
6364       DrawMiniGraphicExt(window, DX_KEYS + key_nr * MINI_TILEX, DY_KEYS,
6365                          IMG_KEY1 + key_nr);
6366       PlaySoundLevel(x, y, SND_KEY_COLLECTING);
6367       break;
6368     }
6369
6370     case EL_ROBOT_WHEEL:
6371       Feld[x][y] = EL_ROBOT_WHEEL_ACTIVE;
6372       ZX = x;
6373       ZY = y;
6374       DrawLevelField(x, y);
6375       PlaySoundLevel(x, y, SND_ROBOT_WHEEL_ACTIVATING);
6376       return MF_ACTION;
6377       break;
6378
6379     case EL_SP_TERMINAL:
6380       {
6381         int xx, yy;
6382
6383         PlaySoundLevel(x, y, SND_SP_TERMINAL_ACTIVATING);
6384
6385         for (yy=0; yy<lev_fieldy; yy++)
6386         {
6387           for (xx=0; xx<lev_fieldx; xx++)
6388           {
6389             if (Feld[xx][yy] == EL_SP_DISK_YELLOW)
6390               Bang(xx, yy);
6391             else if (Feld[xx][yy] == EL_SP_TERMINAL)
6392               Feld[xx][yy] = EL_SP_TERMINAL_ACTIVE;
6393           }
6394         }
6395
6396         return MF_ACTION;
6397       }
6398       break;
6399
6400     case EL_CONVEYOR_BELT1_SWITCH_LEFT:
6401     case EL_CONVEYOR_BELT1_SWITCH_MIDDLE:
6402     case EL_CONVEYOR_BELT1_SWITCH_RIGHT:
6403     case EL_CONVEYOR_BELT2_SWITCH_LEFT:
6404     case EL_CONVEYOR_BELT2_SWITCH_MIDDLE:
6405     case EL_CONVEYOR_BELT2_SWITCH_RIGHT:
6406     case EL_CONVEYOR_BELT3_SWITCH_LEFT:
6407     case EL_CONVEYOR_BELT3_SWITCH_MIDDLE:
6408     case EL_CONVEYOR_BELT3_SWITCH_RIGHT:
6409     case EL_CONVEYOR_BELT4_SWITCH_LEFT:
6410     case EL_CONVEYOR_BELT4_SWITCH_MIDDLE:
6411     case EL_CONVEYOR_BELT4_SWITCH_RIGHT:
6412       if (!player->Switching)
6413       {
6414         player->Switching = TRUE;
6415         ToggleBeltSwitch(x, y);
6416         PlaySoundLevel(x, y, SND_CONVEYOR_BELT_SWITCH_ACTIVATING);
6417       }
6418       return MF_ACTION;
6419       break;
6420
6421     case EL_SWITCHGATE_SWITCH_UP:
6422     case EL_SWITCHGATE_SWITCH_DOWN:
6423       if (!player->Switching)
6424       {
6425         player->Switching = TRUE;
6426         ToggleSwitchgateSwitch(x, y);
6427         PlaySoundLevel(x, y, SND_SWITCHGATE_SWITCH_ACTIVATING);
6428       }
6429       return MF_ACTION;
6430       break;
6431
6432     case EL_LIGHT_SWITCH:
6433     case EL_LIGHT_SWITCH_ACTIVE:
6434       if (!player->Switching)
6435       {
6436         player->Switching = TRUE;
6437         ToggleLightSwitch(x, y);
6438         PlaySoundLevel(x, y, element == EL_LIGHT_SWITCH ?
6439                        SND_LIGHT_SWITCH_ACTIVATING :
6440                        SND_LIGHT_SWITCH_DEACTIVATING);
6441       }
6442       return MF_ACTION;
6443       break;
6444
6445     case EL_TIMEGATE_SWITCH:
6446       ActivateTimegateSwitch(x, y);
6447       PlaySoundLevel(x, y, SND_TIMEGATE_SWITCH_ACTIVATING);
6448
6449       return MF_ACTION;
6450       break;
6451
6452     case EL_BALLOON_SEND_LEFT:
6453     case EL_BALLOON_SEND_RIGHT:
6454     case EL_BALLOON_SEND_UP:
6455     case EL_BALLOON_SEND_DOWN:
6456     case EL_BALLOON_SEND_ANY_DIRECTION:
6457       if (element == EL_BALLOON_SEND_ANY_DIRECTION)
6458         game.balloon_dir = move_direction;
6459       else
6460         game.balloon_dir = (element == EL_BALLOON_SEND_LEFT  ? MV_LEFT :
6461                             element == EL_BALLOON_SEND_RIGHT ? MV_RIGHT :
6462                             element == EL_BALLOON_SEND_UP    ? MV_UP :
6463                             element == EL_BALLOON_SEND_DOWN  ? MV_DOWN :
6464                             MV_NO_MOVING);
6465       PlaySoundLevel(x, y, SND_BALLOON_SWITCH_ACTIVATING);
6466
6467       return MF_ACTION;
6468       break;
6469
6470       /* the following elements cannot be pushed by "snapping" */
6471     case EL_ROCK:
6472     case EL_BOMB:
6473     case EL_DX_SUPABOMB:
6474     case EL_NUT:
6475     case EL_TIME_ORB_EMPTY:
6476     case EL_SP_ZONK:
6477     case EL_SP_DISK_ORANGE:
6478     case EL_SPRING:
6479       if (mode == DF_SNAP)
6480         return MF_NO_ACTION;
6481       /* no "break" -- fall through to next case */
6482       /* the following elements can be pushed by "snapping" */
6483     case EL_BD_ROCK:
6484       if (dy)
6485         return MF_NO_ACTION;
6486
6487       player->Pushing = TRUE;
6488
6489       if (!IN_LEV_FIELD(x+dx, y+dy) || !IS_FREE(x+dx, y+dy))
6490         return MF_NO_ACTION;
6491
6492       if (real_dy)
6493       {
6494         if (IN_LEV_FIELD(jx, jy+real_dy) && !IS_SOLID(Feld[jx][jy+real_dy]))
6495           return MF_NO_ACTION;
6496       }
6497
6498       if (player->push_delay == 0)
6499         player->push_delay = FrameCounter;
6500 #if 0
6501       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
6502           !tape.playing && element != EL_SPRING)
6503         return MF_NO_ACTION;
6504 #else
6505       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
6506           !(tape.playing && tape.file_version < FILE_VERSION_2_0) &&
6507           element != EL_SPRING)
6508         return MF_NO_ACTION;
6509 #endif
6510
6511       if (mode == DF_SNAP)
6512       {
6513         InitMovingField(x, y, move_direction);
6514         ContinueMoving(x, y);
6515       }
6516       else
6517       {
6518         RemoveField(x, y);
6519         Feld[x + dx][y + dy] = element;
6520       }
6521
6522       if (element == EL_SPRING)
6523       {
6524         Feld[x + dx][y + dy] = EL_SPRING;
6525         MovDir[x + dx][y + dy] = move_direction;
6526       }
6527
6528       player->push_delay_value = (element == EL_SPRING ? 0 : 2 + RND(8));
6529
6530       DrawLevelField(x + dx, y + dy);
6531       PlaySoundLevelElementAction(x, y, element, ACTION_PUSHING);
6532       break;
6533
6534     case EL_GATE1:
6535     case EL_GATE2:
6536     case EL_GATE3:
6537     case EL_GATE4:
6538       if (!player->key[element - EL_GATE1])
6539         return MF_NO_ACTION;
6540       break;
6541
6542     case EL_GATE1_GRAY:
6543     case EL_GATE2_GRAY:
6544     case EL_GATE3_GRAY:
6545     case EL_GATE4_GRAY:
6546       if (!player->key[element - EL_GATE1_GRAY])
6547         return MF_NO_ACTION;
6548       break;
6549
6550     case EL_EM_GATE1:
6551     case EL_EM_GATE2:
6552     case EL_EM_GATE3:
6553     case EL_EM_GATE4:
6554       if (!player->key[element - EL_EM_GATE1])
6555         return MF_NO_ACTION;
6556       if (!IN_LEV_FIELD(x + dx, y + dy) || !IS_FREE(x + dx, y + dy))
6557         return MF_NO_ACTION;
6558
6559       /* automatically move to the next field with double speed */
6560       player->programmed_action = move_direction;
6561       DOUBLE_PLAYER_SPEED(player);
6562
6563       PlaySoundLevel(x, y, SND_GATE_PASSING);
6564       break;
6565
6566     case EL_EM_GATE1_GRAY:
6567     case EL_EM_GATE2_GRAY:
6568     case EL_EM_GATE3_GRAY:
6569     case EL_EM_GATE4_GRAY:
6570       if (!player->key[element - EL_EM_GATE1_GRAY])
6571         return MF_NO_ACTION;
6572       if (!IN_LEV_FIELD(x + dx, y + dy) || !IS_FREE(x + dx, y + dy))
6573         return MF_NO_ACTION;
6574
6575       /* automatically move to the next field with double speed */
6576       player->programmed_action = move_direction;
6577       DOUBLE_PLAYER_SPEED(player);
6578
6579       PlaySoundLevel(x, y, SND_GATE_PASSING);
6580       break;
6581
6582     case EL_SWITCHGATE_OPEN:
6583     case EL_TIMEGATE_OPEN:
6584       if (!IN_LEV_FIELD(x + dx, y + dy) || !IS_FREE(x + dx, y + dy))
6585         return MF_NO_ACTION;
6586
6587       /* automatically move to the next field with double speed */
6588       player->programmed_action = move_direction;
6589       DOUBLE_PLAYER_SPEED(player);
6590
6591       PlaySoundLevelElementAction(x, y, element, ACTION_PASSING);
6592       break;
6593
6594     case EL_SP_PORT1_LEFT:
6595     case EL_SP_PORT2_LEFT:
6596     case EL_SP_PORT1_RIGHT:
6597     case EL_SP_PORT2_RIGHT:
6598     case EL_SP_PORT1_UP:
6599     case EL_SP_PORT2_UP:
6600     case EL_SP_PORT1_DOWN:
6601     case EL_SP_PORT2_DOWN:
6602     case EL_SP_PORT_X:
6603     case EL_SP_PORT_Y:
6604     case EL_SP_PORT_XY:
6605       if ((dx == -1 &&
6606            element != EL_SP_PORT1_LEFT &&
6607            element != EL_SP_PORT2_LEFT &&
6608            element != EL_SP_PORT_X &&
6609            element != EL_SP_PORT_XY) ||
6610           (dx == +1 &&
6611            element != EL_SP_PORT1_RIGHT &&
6612            element != EL_SP_PORT2_RIGHT &&
6613            element != EL_SP_PORT_X &&
6614            element != EL_SP_PORT_XY) ||
6615           (dy == -1 &&
6616            element != EL_SP_PORT1_UP &&
6617            element != EL_SP_PORT2_UP &&
6618            element != EL_SP_PORT_Y &&
6619            element != EL_SP_PORT_XY) ||
6620           (dy == +1 &&
6621            element != EL_SP_PORT1_DOWN &&
6622            element != EL_SP_PORT2_DOWN &&
6623            element != EL_SP_PORT_Y &&
6624            element != EL_SP_PORT_XY) ||
6625           !IN_LEV_FIELD(x + dx, y + dy) ||
6626           !IS_FREE(x + dx, y + dy))
6627         return MF_NO_ACTION;
6628
6629       /* automatically move to the next field with double speed */
6630       player->programmed_action = move_direction;
6631       DOUBLE_PLAYER_SPEED(player);
6632
6633       PlaySoundLevel(x, y, SND_SP_PORT_PASSING);
6634       break;
6635
6636     case EL_TUBE_ALL:
6637     case EL_TUBE_VERTICAL:
6638     case EL_TUBE_HORIZONTAL:
6639     case EL_TUBE_VERTICAL_LEFT:
6640     case EL_TUBE_VERTICAL_RIGHT:
6641     case EL_TUBE_HORIZONTAL_UP:
6642     case EL_TUBE_HORIZONTAL_DOWN:
6643     case EL_TUBE_LEFT_UP:
6644     case EL_TUBE_LEFT_DOWN:
6645     case EL_TUBE_RIGHT_UP:
6646     case EL_TUBE_RIGHT_DOWN:
6647       {
6648         int i = 0;
6649         int tube_enter_directions[][2] =
6650         {
6651           { EL_TUBE_ALL,                MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN },
6652           { EL_TUBE_VERTICAL,                                MV_UP | MV_DOWN },
6653           { EL_TUBE_HORIZONTAL,         MV_LEFT | MV_RIGHT                   },
6654           { EL_TUBE_VERTICAL_LEFT,                MV_RIGHT | MV_UP | MV_DOWN },
6655           { EL_TUBE_VERTICAL_RIGHT,     MV_LEFT            | MV_UP | MV_DOWN },
6656           { EL_TUBE_HORIZONTAL_UP,      MV_LEFT | MV_RIGHT |         MV_DOWN },
6657           { EL_TUBE_HORIZONTAL_DOWN,    MV_LEFT | MV_RIGHT | MV_UP           },
6658           { EL_TUBE_LEFT_UP,                      MV_RIGHT |         MV_DOWN },
6659           { EL_TUBE_LEFT_DOWN,                    MV_RIGHT | MV_UP           },
6660           { EL_TUBE_RIGHT_UP,           MV_LEFT |                    MV_DOWN },
6661           { EL_TUBE_RIGHT_DOWN,         MV_LEFT |            MV_UP           },
6662           { -1,                         MV_NO_MOVING                         }
6663         };
6664
6665         while (tube_enter_directions[i][0] != element)
6666         {
6667           i++;
6668           if (tube_enter_directions[i][0] == -1)        /* should not happen */
6669             break;
6670         }
6671
6672         if (!(tube_enter_directions[i][1] & move_direction))
6673           return MF_NO_ACTION;  /* tube has no opening in this direction */
6674
6675         PlaySoundLevel(x, y, SND_TUBE_PASSING);
6676       }
6677       break;
6678
6679     case EL_EXIT_CLOSED:
6680     case EL_SP_EXIT_CLOSED:
6681     case EL_EXIT_OPENING:
6682       return MF_NO_ACTION;
6683       break;
6684
6685     case EL_EXIT_OPEN:
6686     case EL_SP_EXIT_OPEN:
6687       if (mode == DF_SNAP)
6688         return MF_NO_ACTION;
6689
6690       if (element == EL_EXIT_OPEN)
6691         PlaySoundLevel(x, y, SND_EXIT_PASSING);
6692       else
6693         PlaySoundLevel(x, y, SND_SP_EXIT_PASSING);
6694
6695       break;
6696
6697     case EL_LAMP:
6698       Feld[x][y] = EL_LAMP_ACTIVE;
6699       local_player->lights_still_needed--;
6700       DrawLevelField(x, y);
6701       PlaySoundLevel(x, y, SND_LAMP_ACTIVATING);
6702       return MF_ACTION;
6703       break;
6704
6705     case EL_TIME_ORB_FULL:
6706       Feld[x][y] = EL_TIME_ORB_EMPTY;
6707       TimeLeft += 10;
6708       DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
6709       DrawLevelField(x, y);
6710       PlaySoundStereo(SND_TIME_ORB_FULL_COLLECTING, SOUND_MAX_RIGHT);
6711       return MF_ACTION;
6712       break;
6713
6714     case EL_SOKOBAN_FIELD_EMPTY:
6715       break;
6716
6717     case EL_SOKOBAN_OBJECT:
6718     case EL_SOKOBAN_FIELD_FULL:
6719     case EL_SATELLITE:
6720     case EL_SP_DISK_YELLOW:
6721     case EL_BALLOON:
6722       if (mode == DF_SNAP)
6723         return MF_NO_ACTION;
6724
6725       player->Pushing = TRUE;
6726
6727       if (!IN_LEV_FIELD(x+dx, y+dy)
6728           || (!IS_FREE(x+dx, y+dy)
6729               && (Feld[x+dx][y+dy] != EL_SOKOBAN_FIELD_EMPTY
6730                   || !IS_SB_ELEMENT(element))))
6731         return MF_NO_ACTION;
6732
6733       if (dx && real_dy)
6734       {
6735         if (IN_LEV_FIELD(jx, jy+real_dy) && !IS_SOLID(Feld[jx][jy+real_dy]))
6736           return MF_NO_ACTION;
6737       }
6738       else if (dy && real_dx)
6739       {
6740         if (IN_LEV_FIELD(jx+real_dx, jy) && !IS_SOLID(Feld[jx+real_dx][jy]))
6741           return MF_NO_ACTION;
6742       }
6743
6744       if (player->push_delay == 0)
6745         player->push_delay = FrameCounter;
6746 #if 0
6747       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
6748           !tape.playing && element != EL_BALLOON)
6749         return MF_NO_ACTION;
6750 #else
6751       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
6752           !(tape.playing && tape.file_version < FILE_VERSION_2_0) &&
6753           element != EL_BALLOON)
6754         return MF_NO_ACTION;
6755 #endif
6756
6757       if (IS_SB_ELEMENT(element))
6758       {
6759         if (element == EL_SOKOBAN_FIELD_FULL)
6760         {
6761           Feld[x][y] = EL_SOKOBAN_FIELD_EMPTY;
6762           local_player->sokobanfields_still_needed++;
6763         }
6764         else
6765           RemoveField(x, y);
6766
6767         if (Feld[x+dx][y+dy] == EL_SOKOBAN_FIELD_EMPTY)
6768         {
6769           Feld[x+dx][y+dy] = EL_SOKOBAN_FIELD_FULL;
6770           local_player->sokobanfields_still_needed--;
6771           if (element == EL_SOKOBAN_OBJECT)
6772             PlaySoundLevel(x, y, SND_SOKOBAN_FIELD_FILLING);
6773           else
6774             PlaySoundLevel(x, y, SND_SOKOBAN_OBJECT_PUSHING);
6775         }
6776         else
6777         {
6778           Feld[x+dx][y+dy] = EL_SOKOBAN_OBJECT;
6779           if (element == EL_SOKOBAN_FIELD_FULL)
6780             PlaySoundLevel(x, y, SND_SOKOBAN_FIELD_EMPTYING);
6781           else
6782             PlaySoundLevel(x, y, SND_SOKOBAN_OBJECT_PUSHING);
6783         }
6784       }
6785       else
6786       {
6787         RemoveField(x, y);
6788         Feld[x+dx][y+dy] = element;
6789         PlaySoundLevelElementAction(x, y, element, ACTION_PUSHING);
6790       }
6791
6792       player->push_delay_value = (element == EL_BALLOON ? 0 : 2);
6793
6794       DrawLevelField(x, y);
6795       DrawLevelField(x + dx, y + dy);
6796
6797       if (IS_SB_ELEMENT(element) &&
6798           local_player->sokobanfields_still_needed == 0 &&
6799           game.emulation == EMU_SOKOBAN)
6800       {
6801         player->LevelSolved = player->GameOver = TRUE;
6802         PlaySoundLevel(x, y, SND_SOKOBAN_GAME_SOLVING);
6803       }
6804
6805       break;
6806
6807     case EL_PENGUIN:
6808     case EL_PIG:
6809     case EL_DRAGON:
6810       break;
6811
6812     default:
6813       return MF_NO_ACTION;
6814   }
6815
6816   player->push_delay = 0;
6817
6818   return MF_MOVING;
6819 }
6820
6821 boolean SnapField(struct PlayerInfo *player, int dx, int dy)
6822 {
6823   int jx = player->jx, jy = player->jy;
6824   int x = jx + dx, y = jy + dy;
6825
6826   if (!player->active || !IN_LEV_FIELD(x, y))
6827     return FALSE;
6828
6829   if (dx && dy)
6830     return FALSE;
6831
6832   if (!dx && !dy)
6833   {
6834     if (player->MovPos == 0)
6835       player->Pushing = FALSE;
6836
6837     player->snapped = FALSE;
6838     return FALSE;
6839   }
6840
6841   if (player->snapped)
6842     return FALSE;
6843
6844   player->MovDir = (dx < 0 ? MV_LEFT :
6845                     dx > 0 ? MV_RIGHT :
6846                     dy < 0 ? MV_UP :
6847                     dy > 0 ? MV_DOWN :  MV_NO_MOVING);
6848
6849   if (!DigField(player, x, y, 0, 0, DF_SNAP))
6850     return FALSE;
6851
6852   player->snapped = TRUE;
6853   DrawLevelField(x, y);
6854   BackToFront();
6855
6856   return TRUE;
6857 }
6858
6859 boolean PlaceBomb(struct PlayerInfo *player)
6860 {
6861   int jx = player->jx, jy = player->jy;
6862   int element;
6863
6864   if (!player->active || player->MovPos)
6865     return FALSE;
6866
6867   element = Feld[jx][jy];
6868
6869   if ((player->dynamite == 0 && player->dynabombs_left == 0) ||
6870       IS_ACTIVE_BOMB(element) || element == EL_EXPLOSION)
6871     return FALSE;
6872
6873   if (element != EL_EMPTY)
6874     Store[jx][jy] = element;
6875
6876   MovDelay[jx][jy] = 96;
6877   GfxFrame[jx][jy] = 0;
6878
6879   if (player->dynamite)
6880   {
6881     Feld[jx][jy] = EL_DYNAMITE_ACTIVE;
6882     player->dynamite--;
6883
6884     DrawText(DX_DYNAMITE, DY_DYNAMITE, int2str(local_player->dynamite, 3),
6885              FS_SMALL, FC_YELLOW);
6886     if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy)))
6887     {
6888       if (game.emulation == EMU_SUPAPLEX)
6889         DrawGraphic(SCREENX(jx), SCREENY(jy), IMG_SP_DISK_RED, 0);
6890       else
6891         DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), IMG_DYNAMITE_ACTIVE, 0);
6892     }
6893
6894     PlaySoundLevel(jx, jy, SND_DYNAMITE_DROPPING);
6895   }
6896   else
6897   {
6898     Feld[jx][jy] =
6899       EL_DYNABOMB_PLAYER1_ACTIVE + (player->element_nr - EL_PLAYER1);
6900     player->dynabombs_left--;
6901
6902     if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy)))
6903       DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), el2img(Feld[jx][jy]), 0);
6904
6905     PlaySoundLevel(jx, jy, SND_DYNABOMB_DROPPING);
6906   }
6907
6908   return TRUE;
6909 }
6910
6911 static void PlaySoundLevel(int x, int y, int nr)
6912 {
6913   static int loop_sound_frame[NUM_SOUND_FILES];
6914   static int loop_sound_volume[NUM_SOUND_FILES];
6915   int sx = SCREENX(x), sy = SCREENY(y);
6916   int volume, stereo_position;
6917   int max_distance = 8;
6918   int type = (IS_LOOP_SOUND(nr) ? SND_CTRL_PLAY_LOOP : SND_CTRL_PLAY_SOUND);
6919
6920   if ((!setup.sound_simple && !IS_LOOP_SOUND(nr)) ||
6921       (!setup.sound_loops && IS_LOOP_SOUND(nr)))
6922     return;
6923
6924   if (!IN_LEV_FIELD(x, y) ||
6925       sx < -max_distance || sx >= SCR_FIELDX + max_distance ||
6926       sy < -max_distance || sy >= SCR_FIELDY + max_distance)
6927     return;
6928
6929   volume = SOUND_MAX_VOLUME;
6930
6931   if (!IN_SCR_FIELD(sx, sy))
6932   {
6933     int dx = ABS(sx - SCR_FIELDX / 2) - SCR_FIELDX / 2;
6934     int dy = ABS(sy - SCR_FIELDY / 2) - SCR_FIELDY / 2;
6935
6936     volume -= volume * (dx > dy ? dx : dy) / max_distance;
6937   }
6938
6939   stereo_position = (SOUND_MAX_LEFT +
6940                      (sx + max_distance) * SOUND_MAX_LEFT2RIGHT /
6941                      (SCR_FIELDX + 2 * max_distance));
6942
6943   if (IS_LOOP_SOUND(nr))
6944   {
6945     /* This assures that quieter loop sounds do not overwrite louder ones,
6946        while restarting sound volume comparison with each new game frame. */
6947
6948     if (loop_sound_volume[nr] > volume && loop_sound_frame[nr] == FrameCounter)
6949       return;
6950
6951     loop_sound_volume[nr] = volume;
6952     loop_sound_frame[nr] = FrameCounter;
6953   }
6954
6955   PlaySoundExt(nr, volume, stereo_position, type);
6956 }
6957
6958 static void PlaySoundLevelNearest(int x, int y, int sound_action)
6959 {
6960   PlaySoundLevel(x < LEVELX(BX1) ? LEVELX(BX1) :
6961                  x > LEVELX(BX2) ? LEVELX(BX2) : x,
6962                  y < LEVELY(BY1) ? LEVELY(BY1) :
6963                  y > LEVELY(BY2) ? LEVELY(BY2) : y,
6964                  sound_action);
6965 }
6966
6967 static void PlaySoundLevelAction(int x, int y, int sound_action)
6968 {
6969   PlaySoundLevelElementAction(x, y, Feld[x][y], sound_action);
6970 }
6971
6972 static void PlaySoundLevelElementAction(int x, int y, int element,
6973                                         int sound_action)
6974 {
6975   int sound_effect = element_info[element].sound[sound_action];
6976
6977   if (sound_effect != SND_UNDEFINED)
6978     PlaySoundLevel(x, y, sound_effect);
6979 }
6980
6981 void RaiseScore(int value)
6982 {
6983   local_player->score += value;
6984   DrawText(DX_SCORE, DY_SCORE, int2str(local_player->score, 5),
6985            FS_SMALL, FC_YELLOW);
6986 }
6987
6988 void RaiseScoreElement(int element)
6989 {
6990   switch(element)
6991   {
6992     case EL_EMERALD:
6993     case EL_BD_DIAMOND:
6994     case EL_EMERALD_YELLOW:
6995     case EL_EMERALD_RED:
6996     case EL_EMERALD_PURPLE:
6997       RaiseScore(level.score[SC_EDELSTEIN]);
6998       break;
6999     case EL_DIAMOND:
7000       RaiseScore(level.score[SC_DIAMANT]);
7001       break;
7002     case EL_BUG:
7003     case EL_BD_BUTTERFLY:
7004       RaiseScore(level.score[SC_KAEFER]);
7005       break;
7006     case EL_SPACESHIP:
7007     case EL_BD_FIREFLY:
7008       RaiseScore(level.score[SC_FLIEGER]);
7009       break;
7010     case EL_YAMYAM:
7011     case EL_DARK_YAMYAM:
7012       RaiseScore(level.score[SC_MAMPFER]);
7013       break;
7014     case EL_ROBOT:
7015       RaiseScore(level.score[SC_ROBOT]);
7016       break;
7017     case EL_PACMAN:
7018       RaiseScore(level.score[SC_PACMAN]);
7019       break;
7020     case EL_NUT:
7021       RaiseScore(level.score[SC_KOKOSNUSS]);
7022       break;
7023     case EL_DYNAMITE:
7024       RaiseScore(level.score[SC_DYNAMIT]);
7025       break;
7026     case EL_KEY1:
7027     case EL_KEY2:
7028     case EL_KEY3:
7029     case EL_KEY4:
7030       RaiseScore(level.score[SC_SCHLUESSEL]);
7031       break;
7032     default:
7033       break;
7034   }
7035 }
7036
7037 void RequestQuitGame(boolean ask_if_really_quit)
7038 {
7039   if (AllPlayersGone ||
7040       !ask_if_really_quit ||
7041       level_editor_test_game ||
7042       Request("Do you really want to quit the game ?",
7043               REQ_ASK | REQ_STAY_CLOSED))
7044   {
7045 #if defined(PLATFORM_UNIX)
7046     if (options.network)
7047       SendToServer_StopPlaying();
7048     else
7049 #endif
7050     {
7051       game_status = MAINMENU;
7052       DrawMainMenu();
7053     }
7054   }
7055   else
7056   {
7057     OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
7058   }
7059 }
7060
7061
7062 /* ---------- new game button stuff ---------------------------------------- */
7063
7064 /* graphic position values for game buttons */
7065 #define GAME_BUTTON_XSIZE       30
7066 #define GAME_BUTTON_YSIZE       30
7067 #define GAME_BUTTON_XPOS        5
7068 #define GAME_BUTTON_YPOS        215
7069 #define SOUND_BUTTON_XPOS       5
7070 #define SOUND_BUTTON_YPOS       (GAME_BUTTON_YPOS + GAME_BUTTON_YSIZE)
7071
7072 #define GAME_BUTTON_STOP_XPOS   (GAME_BUTTON_XPOS + 0 * GAME_BUTTON_XSIZE)
7073 #define GAME_BUTTON_PAUSE_XPOS  (GAME_BUTTON_XPOS + 1 * GAME_BUTTON_XSIZE)
7074 #define GAME_BUTTON_PLAY_XPOS   (GAME_BUTTON_XPOS + 2 * GAME_BUTTON_XSIZE)
7075 #define SOUND_BUTTON_MUSIC_XPOS (SOUND_BUTTON_XPOS + 0 * GAME_BUTTON_XSIZE)
7076 #define SOUND_BUTTON_LOOPS_XPOS (SOUND_BUTTON_XPOS + 1 * GAME_BUTTON_XSIZE)
7077 #define SOUND_BUTTON_SIMPLE_XPOS (SOUND_BUTTON_XPOS + 2 * GAME_BUTTON_XSIZE)
7078
7079 static struct
7080 {
7081   int x, y;
7082   int gadget_id;
7083   char *infotext;
7084 } gamebutton_info[NUM_GAME_BUTTONS] =
7085 {
7086   {
7087     GAME_BUTTON_STOP_XPOS,      GAME_BUTTON_YPOS,
7088     GAME_CTRL_ID_STOP,
7089     "stop game"
7090   },
7091   {
7092     GAME_BUTTON_PAUSE_XPOS,     GAME_BUTTON_YPOS,
7093     GAME_CTRL_ID_PAUSE,
7094     "pause game"
7095   },
7096   {
7097     GAME_BUTTON_PLAY_XPOS,      GAME_BUTTON_YPOS,
7098     GAME_CTRL_ID_PLAY,
7099     "play game"
7100   },
7101   {
7102     SOUND_BUTTON_MUSIC_XPOS,    SOUND_BUTTON_YPOS,
7103     SOUND_CTRL_ID_MUSIC,
7104     "background music on/off"
7105   },
7106   {
7107     SOUND_BUTTON_LOOPS_XPOS,    SOUND_BUTTON_YPOS,
7108     SOUND_CTRL_ID_LOOPS,
7109     "sound loops on/off"
7110   },
7111   {
7112     SOUND_BUTTON_SIMPLE_XPOS,   SOUND_BUTTON_YPOS,
7113     SOUND_CTRL_ID_SIMPLE,
7114     "normal sounds on/off"
7115   }
7116 };
7117
7118 void CreateGameButtons()
7119 {
7120   int i;
7121
7122   for (i=0; i<NUM_GAME_BUTTONS; i++)
7123   {
7124     Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
7125     struct GadgetInfo *gi;
7126     int button_type;
7127     boolean checked;
7128     unsigned long event_mask;
7129     int gd_xoffset, gd_yoffset;
7130     int gd_x1, gd_x2, gd_y1, gd_y2;
7131     int id = i;
7132
7133     gd_xoffset = gamebutton_info[i].x;
7134     gd_yoffset = gamebutton_info[i].y;
7135     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
7136     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
7137
7138     if (id == GAME_CTRL_ID_STOP ||
7139         id == GAME_CTRL_ID_PAUSE ||
7140         id == GAME_CTRL_ID_PLAY)
7141     {
7142       button_type = GD_TYPE_NORMAL_BUTTON;
7143       checked = FALSE;
7144       event_mask = GD_EVENT_RELEASED;
7145       gd_y1  = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
7146       gd_y2  = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
7147     }
7148     else
7149     {
7150       button_type = GD_TYPE_CHECK_BUTTON;
7151       checked =
7152         ((id == SOUND_CTRL_ID_MUSIC && setup.sound_music) ||
7153          (id == SOUND_CTRL_ID_LOOPS && setup.sound_loops) ||
7154          (id == SOUND_CTRL_ID_SIMPLE && setup.sound_simple) ? TRUE : FALSE);
7155       event_mask = GD_EVENT_PRESSED;
7156       gd_y1  = DOOR_GFX_PAGEY1 + gd_yoffset;
7157       gd_y2  = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
7158     }
7159
7160     gi = CreateGadget(GDI_CUSTOM_ID, id,
7161                       GDI_INFO_TEXT, gamebutton_info[i].infotext,
7162                       GDI_X, DX + gd_xoffset,
7163                       GDI_Y, DY + gd_yoffset,
7164                       GDI_WIDTH, GAME_BUTTON_XSIZE,
7165                       GDI_HEIGHT, GAME_BUTTON_YSIZE,
7166                       GDI_TYPE, button_type,
7167                       GDI_STATE, GD_BUTTON_UNPRESSED,
7168                       GDI_CHECKED, checked,
7169                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
7170                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y1,
7171                       GDI_ALT_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y2,
7172                       GDI_ALT_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
7173                       GDI_EVENT_MASK, event_mask,
7174                       GDI_CALLBACK_ACTION, HandleGameButtons,
7175                       GDI_END);
7176
7177     if (gi == NULL)
7178       Error(ERR_EXIT, "cannot create gadget");
7179
7180     game_gadget[id] = gi;
7181   }
7182 }
7183
7184 void FreeGameButtons()
7185 {
7186   int i;
7187
7188   for (i=0; i<NUM_GAME_BUTTONS; i++)
7189     FreeGadget(game_gadget[i]);
7190 }
7191
7192 static void MapGameButtons()
7193 {
7194   int i;
7195
7196   for (i=0; i<NUM_GAME_BUTTONS; i++)
7197     MapGadget(game_gadget[i]);
7198 }
7199
7200 void UnmapGameButtons()
7201 {
7202   int i;
7203
7204   for (i=0; i<NUM_GAME_BUTTONS; i++)
7205     UnmapGadget(game_gadget[i]);
7206 }
7207
7208 static void HandleGameButtons(struct GadgetInfo *gi)
7209 {
7210   int id = gi->custom_id;
7211
7212   if (game_status != PLAYING)
7213     return;
7214
7215   switch (id)
7216   {
7217     case GAME_CTRL_ID_STOP:
7218       RequestQuitGame(TRUE);
7219       break;
7220
7221     case GAME_CTRL_ID_PAUSE:
7222       if (options.network)
7223       {
7224 #if defined(PLATFORM_UNIX)
7225         if (tape.pausing)
7226           SendToServer_ContinuePlaying();
7227         else
7228           SendToServer_PausePlaying();
7229 #endif
7230       }
7231       else
7232         TapeTogglePause(TAPE_TOGGLE_MANUAL);
7233       break;
7234
7235     case GAME_CTRL_ID_PLAY:
7236       if (tape.pausing)
7237       {
7238 #if defined(PLATFORM_UNIX)
7239         if (options.network)
7240           SendToServer_ContinuePlaying();
7241         else
7242 #endif
7243         {
7244           tape.pausing = FALSE;
7245           DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0);
7246         }
7247       }
7248       break;
7249
7250     case SOUND_CTRL_ID_MUSIC:
7251       if (setup.sound_music)
7252       { 
7253         setup.sound_music = FALSE;
7254         FadeMusic();
7255       }
7256       else if (audio.music_available)
7257       { 
7258         setup.sound = setup.sound_music = TRUE;
7259         PlayMusic(level_nr);
7260       }
7261       break;
7262
7263     case SOUND_CTRL_ID_LOOPS:
7264       if (setup.sound_loops)
7265         setup.sound_loops = FALSE;
7266       else if (audio.loops_available)
7267         setup.sound = setup.sound_loops = TRUE;
7268       break;
7269
7270     case SOUND_CTRL_ID_SIMPLE:
7271       if (setup.sound_simple)
7272         setup.sound_simple = FALSE;
7273       else if (audio.sound_available)
7274         setup.sound = setup.sound_simple = TRUE;
7275       break;
7276
7277     default:
7278       break;
7279   }
7280 }