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