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