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