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