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