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