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