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