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