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