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