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