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