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