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