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