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