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