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