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