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