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