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