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