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