06edf65091e2acd9dac24734fd34eb66e3d3b586
[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(new_graphic_info[IMG_MENU_DOOR].bitmap, 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, bitmap_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
4082     if (MovDelay[x][y])
4083       return;
4084   }
4085
4086   Feld[x][y] = EL_EXIT_OPEN;
4087   DrawLevelField(x, y);
4088 }
4089
4090 void OpenSwitchgate(int x, int y)
4091 {
4092   int delay = 6;
4093
4094   if (!MovDelay[x][y])          /* next animation frame */
4095     MovDelay[x][y] = 5 * delay;
4096
4097   if (MovDelay[x][y])           /* wait some time before next frame */
4098   {
4099     MovDelay[x][y]--;
4100
4101     if (!(MovDelay[x][y] % delay))
4102     {
4103       if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
4104       {
4105         int frame = getGraphicAnimationFrame(IMG_SWITCHGATE_OPENING,
4106                                              29 - MovDelay[x][y]);
4107
4108         DrawGraphic(SCREENX(x), SCREENY(y), IMG_SWITCHGATE_OPENING, frame);
4109       }
4110     }
4111
4112     if (MovDelay[x][y])
4113       return;
4114   }
4115
4116   Feld[x][y] = EL_SWITCHGATE_OPEN;
4117   DrawLevelField(x, y);
4118 }
4119
4120 void CloseSwitchgate(int x, int y)
4121 {
4122   int delay = 6;
4123
4124   if (!MovDelay[x][y])          /* next animation frame */
4125     MovDelay[x][y] = 5 * delay;
4126
4127   if (MovDelay[x][y])           /* wait some time before next frame */
4128   {
4129     MovDelay[x][y]--;
4130
4131     if (!(MovDelay[x][y] % delay))
4132     {
4133       if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
4134       {
4135         int frame = getGraphicAnimationFrame(IMG_SWITCHGATE_CLOSING,
4136                                              29 - MovDelay[x][y]);
4137
4138         DrawGraphic(SCREENX(x), SCREENY(y), IMG_SWITCHGATE_CLOSING, frame);
4139       }
4140     }
4141
4142     if (MovDelay[x][y])
4143       return;
4144   }
4145
4146   Feld[x][y] = EL_SWITCHGATE_CLOSED;
4147   DrawLevelField(x, y);
4148 }
4149
4150 void OpenTimegate(int x, int y)
4151 {
4152   int delay = 6;
4153
4154   if (!MovDelay[x][y])          /* next animation frame */
4155     MovDelay[x][y] = 5 * delay;
4156
4157   if (MovDelay[x][y])           /* wait some time before next frame */
4158   {
4159     MovDelay[x][y]--;
4160
4161     if (!(MovDelay[x][y] % delay))
4162     {
4163       if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
4164       {
4165         int frame = getGraphicAnimationFrame(IMG_TIMEGATE_OPENING,
4166                                              29 - MovDelay[x][y]);
4167
4168         DrawGraphic(SCREENX(x), SCREENY(y), IMG_TIMEGATE_OPENING, frame);
4169       }
4170     }
4171
4172     if (MovDelay[x][y])
4173       return;
4174   }
4175
4176   Feld[x][y] = EL_TIMEGATE_OPEN;
4177   DrawLevelField(x, y);
4178 }
4179
4180 void CloseTimegate(int x, int y)
4181 {
4182   int delay = 6;
4183
4184   if (!MovDelay[x][y])          /* next animation frame */
4185     MovDelay[x][y] = 5 * delay;
4186
4187   if (MovDelay[x][y])           /* wait some time before next frame */
4188   {
4189     MovDelay[x][y]--;
4190
4191     if (!(MovDelay[x][y] % delay))
4192     {
4193       if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
4194       {
4195         int frame = getGraphicAnimationFrame(IMG_TIMEGATE_CLOSING,
4196                                              29 - MovDelay[x][y]);
4197
4198         DrawGraphic(SCREENX(x), SCREENY(y), IMG_TIMEGATE_CLOSING, frame);
4199       }
4200     }
4201
4202     if (MovDelay[x][y])
4203       return;
4204   }
4205
4206   Feld[x][y] = EL_TIMEGATE_CLOSED;
4207   DrawLevelField(x, y);
4208 }
4209
4210 static void CloseAllOpenTimegates()
4211 {
4212   int x, y;
4213
4214   for (y=0; y<lev_fieldy; y++)
4215   {
4216     for (x=0; x<lev_fieldx; x++)
4217     {
4218       int element = Feld[x][y];
4219
4220       if (element == EL_TIMEGATE_OPEN || element == EL_TIMEGATE_OPENING)
4221       {
4222         Feld[x][y] = EL_TIMEGATE_CLOSING;
4223         PlaySoundLevel(x, y, SND_TIMEGATE_CLOSING);
4224       }
4225     }
4226   }
4227 }
4228
4229 void EdelsteinFunkeln(int x, int y)
4230 {
4231   if (!IN_SCR_FIELD(SCREENX(x), SCREENY(y)) || IS_MOVING(x, y))
4232     return;
4233
4234   if (Feld[x][y] == EL_BD_DIAMOND)
4235     DrawGraphicAnimation(SCREENX(x), SCREENY(y), IMG_BD_DIAMOND);
4236   else
4237   {
4238     if (!MovDelay[x][y])        /* next animation frame */
4239       MovDelay[x][y] = 11 * !SimpleRND(500);
4240
4241     if (MovDelay[x][y])         /* wait some time before next frame */
4242     {
4243       MovDelay[x][y]--;
4244
4245       if (setup.direct_draw && MovDelay[x][y])
4246         SetDrawtoField(DRAW_BUFFERED);
4247
4248 #if 0
4249       DrawGraphic(SCREENX(x), SCREENY(y), el2img(Feld[x][y]), 0);
4250 #else
4251       DrawGraphicAnimation(SCREENX(x), SCREENY(y), el2img(Feld[x][y]));
4252 #endif
4253
4254       if (MovDelay[x][y])
4255       {
4256         int frame = getGraphicAnimationFrame(IMG_TWINKLE_WHITE,
4257                                              10 - MovDelay[x][y]);
4258
4259         DrawGraphicThruMask(SCREENX(x), SCREENY(y), IMG_TWINKLE_WHITE, frame);
4260
4261         if (setup.direct_draw)
4262         {
4263           int dest_x, dest_y;
4264
4265           dest_x = FX + SCREENX(x) * TILEX;
4266           dest_y = FY + SCREENY(y) * TILEY;
4267
4268           BlitBitmap(drawto_field, window,
4269                      dest_x, dest_y, TILEX, TILEY, dest_x, dest_y);
4270           SetDrawtoField(DRAW_DIRECT);
4271         }
4272       }
4273     }
4274   }
4275 }
4276
4277 void MauerWaechst(int x, int y)
4278 {
4279   int delay = 6;
4280
4281   if (!MovDelay[x][y])          /* next animation frame */
4282     MovDelay[x][y] = 3 * delay;
4283
4284   if (MovDelay[x][y])           /* wait some time before next frame */
4285   {
4286     MovDelay[x][y]--;
4287
4288     if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
4289     {
4290       int graphic = el_dir2img(Feld[x][y], MovDir[x][y]);
4291       int frame = getGraphicAnimationFrame(graphic, 17 - MovDelay[x][y]);
4292
4293       DrawGraphic(SCREENX(x), SCREENY(y), graphic, frame);
4294     }
4295
4296     if (!MovDelay[x][y])
4297     {
4298       if (MovDir[x][y] == MV_LEFT)
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_RIGHT)
4304       {
4305         if (IN_LEV_FIELD(x + 1, y) && IS_MAUER(Feld[x + 1][y]))
4306           DrawLevelField(x + 1, y);
4307       }
4308       else if (MovDir[x][y] == MV_UP)
4309       {
4310         if (IN_LEV_FIELD(x, y - 1) && IS_MAUER(Feld[x][y - 1]))
4311           DrawLevelField(x, y - 1);
4312       }
4313       else
4314       {
4315         if (IN_LEV_FIELD(x, y + 1) && IS_MAUER(Feld[x][y + 1]))
4316           DrawLevelField(x, y + 1);
4317       }
4318
4319       Feld[x][y] = Store[x][y];
4320       Store[x][y] = 0;
4321       MovDir[x][y] = MV_NO_MOVING;
4322       DrawLevelField(x, y);
4323     }
4324   }
4325 }
4326
4327 void MauerAbleger(int ax, int ay)
4328 {
4329   int element = Feld[ax][ay];
4330   boolean oben_frei = FALSE, unten_frei = FALSE;
4331   boolean links_frei = FALSE, rechts_frei = FALSE;
4332   boolean oben_massiv = FALSE, unten_massiv = FALSE;
4333   boolean links_massiv = FALSE, rechts_massiv = FALSE;
4334   boolean new_wall = FALSE;
4335
4336   if (!MovDelay[ax][ay])        /* start building new wall */
4337     MovDelay[ax][ay] = 6;
4338
4339   if (MovDelay[ax][ay])         /* wait some time before building new wall */
4340   {
4341     MovDelay[ax][ay]--;
4342     if (MovDelay[ax][ay])
4343       return;
4344   }
4345
4346   if (IN_LEV_FIELD(ax, ay-1) && IS_FREE(ax, ay-1))
4347     oben_frei = TRUE;
4348   if (IN_LEV_FIELD(ax, ay+1) && IS_FREE(ax, ay+1))
4349     unten_frei = TRUE;
4350   if (IN_LEV_FIELD(ax-1, ay) && IS_FREE(ax-1, ay))
4351     links_frei = TRUE;
4352   if (IN_LEV_FIELD(ax+1, ay) && IS_FREE(ax+1, ay))
4353     rechts_frei = TRUE;
4354
4355   if (element == EL_WALL_GROWING_Y || element == EL_WALL_GROWING_XY)
4356   {
4357     if (oben_frei)
4358     {
4359       Feld[ax][ay-1] = EL_WALL_GROWING_ACTIVE;
4360       Store[ax][ay-1] = element;
4361       MovDir[ax][ay-1] = MV_UP;
4362       if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay-1)))
4363         DrawGraphic(SCREENX(ax), SCREENY(ay - 1),
4364                     IMG_WALL_GROWING_ACTIVE_UP, 0);
4365       new_wall = TRUE;
4366     }
4367     if (unten_frei)
4368     {
4369       Feld[ax][ay+1] = EL_WALL_GROWING_ACTIVE;
4370       Store[ax][ay+1] = element;
4371       MovDir[ax][ay+1] = MV_DOWN;
4372       if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay+1)))
4373         DrawGraphic(SCREENX(ax), SCREENY(ay + 1),
4374                     IMG_WALL_GROWING_ACTIVE_DOWN, 0);
4375       new_wall = TRUE;
4376     }
4377   }
4378
4379   if (element == EL_WALL_GROWING_X || element == EL_WALL_GROWING_XY ||
4380       element == EL_WALL_GROWING)
4381   {
4382     if (links_frei)
4383     {
4384       Feld[ax-1][ay] = EL_WALL_GROWING_ACTIVE;
4385       Store[ax-1][ay] = element;
4386       MovDir[ax-1][ay] = MV_LEFT;
4387       if (IN_SCR_FIELD(SCREENX(ax-1), SCREENY(ay)))
4388         DrawGraphic(SCREENX(ax - 1), SCREENY(ay),
4389                     IMG_WALL_GROWING_ACTIVE_LEFT, 0);
4390       new_wall = TRUE;
4391     }
4392
4393     if (rechts_frei)
4394     {
4395       Feld[ax+1][ay] = EL_WALL_GROWING_ACTIVE;
4396       Store[ax+1][ay] = element;
4397       MovDir[ax+1][ay] = MV_RIGHT;
4398       if (IN_SCR_FIELD(SCREENX(ax+1), SCREENY(ay)))
4399         DrawGraphic(SCREENX(ax + 1), SCREENY(ay),
4400                     IMG_WALL_GROWING_ACTIVE_RIGHT, 0);
4401       new_wall = TRUE;
4402     }
4403   }
4404
4405   if (element == EL_WALL_GROWING && (links_frei || rechts_frei))
4406     DrawLevelField(ax, ay);
4407
4408   if (!IN_LEV_FIELD(ax, ay-1) || IS_MAUER(Feld[ax][ay-1]))
4409     oben_massiv = TRUE;
4410   if (!IN_LEV_FIELD(ax, ay+1) || IS_MAUER(Feld[ax][ay+1]))
4411     unten_massiv = TRUE;
4412   if (!IN_LEV_FIELD(ax-1, ay) || IS_MAUER(Feld[ax-1][ay]))
4413     links_massiv = TRUE;
4414   if (!IN_LEV_FIELD(ax+1, ay) || IS_MAUER(Feld[ax+1][ay]))
4415     rechts_massiv = TRUE;
4416
4417   if (((oben_massiv && unten_massiv) ||
4418        element == EL_WALL_GROWING_X || element == EL_WALL_GROWING) &&
4419       ((links_massiv && rechts_massiv) ||
4420        element == EL_WALL_GROWING_Y))
4421     Feld[ax][ay] = EL_WALL;
4422
4423   if (new_wall)
4424     PlaySoundLevel(ax, ay, SND_WALL_GROWING);
4425 }
4426
4427 void CheckForDragon(int x, int y)
4428 {
4429   int i, j;
4430   boolean dragon_found = FALSE;
4431   static int xy[4][2] =
4432   {
4433     { 0, -1 },
4434     { -1, 0 },
4435     { +1, 0 },
4436     { 0, +1 }
4437   };
4438
4439   for (i=0; i<4; i++)
4440   {
4441     for (j=0; j<4; j++)
4442     {
4443       int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
4444
4445       if (IN_LEV_FIELD(xx, yy) &&
4446           (Feld[xx][yy] == EL_FLAMES || Feld[xx][yy] == EL_DRAGON))
4447       {
4448         if (Feld[xx][yy] == EL_DRAGON)
4449           dragon_found = TRUE;
4450       }
4451       else
4452         break;
4453     }
4454   }
4455
4456   if (!dragon_found)
4457   {
4458     for (i=0; i<4; i++)
4459     {
4460       for (j=0; j<3; j++)
4461       {
4462         int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
4463   
4464         if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == EL_FLAMES)
4465         {
4466           Feld[xx][yy] = EL_EMPTY;
4467           DrawLevelField(xx, yy);
4468         }
4469         else
4470           break;
4471       }
4472     }
4473   }
4474 }
4475
4476 static void CheckBuggyBase(int x, int y)
4477 {
4478   int element = Feld[x][y];
4479
4480   if (element == EL_SP_BUGGY_BASE)
4481   {
4482     if (!MovDelay[x][y])        /* wait some time before activating base */
4483       MovDelay[x][y] = 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND);
4484
4485     if (MovDelay[x][y])
4486     {
4487       MovDelay[x][y]--;
4488       if (MovDelay[x][y] < 5 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
4489         DrawGraphic(SCREENX(x), SCREENY(y), IMG_SP_BUGGY_BASE, 0);
4490       if (MovDelay[x][y])
4491         return;
4492
4493       Feld[x][y] = EL_SP_BUGGY_BASE_ACTIVE;
4494     }
4495   }
4496   else if (element == EL_SP_BUGGY_BASE_ACTIVE)
4497   {
4498     if (!MovDelay[x][y])        /* start activating buggy base */
4499       MovDelay[x][y] = 1 * FRAMES_PER_SECOND + RND(1 * FRAMES_PER_SECOND);
4500
4501     if (MovDelay[x][y])
4502     {
4503       MovDelay[x][y]--;
4504       if (MovDelay[x][y])
4505       {
4506         int i;
4507         static int xy[4][2] =
4508         {
4509           { 0, -1 },
4510           { -1, 0 },
4511           { +1, 0 },
4512           { 0, +1 }
4513         };
4514
4515         if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
4516         {
4517           int graphic = IMG_SP_BUGGY_BASE_ACTIVE;
4518           int frame = getGraphicAnimationFrame(graphic, SimpleRND(100));
4519
4520           DrawGraphic(SCREENX(x), SCREENY(y), graphic, frame);
4521         }
4522
4523         for (i=0; i<4; i++)
4524         {
4525           int xx = x + xy[i][0], yy = y + xy[i][1];
4526
4527           if (IS_PLAYER(xx, yy))
4528           {
4529             PlaySoundLevel(x, y, SND_SP_BUGGY_BASE_ACTIVE);
4530             break;
4531           }
4532         }
4533
4534         return;
4535       }
4536
4537       Feld[x][y] = EL_SP_BUGGY_BASE;
4538       DrawLevelField(x, y);
4539     }
4540   }
4541 }
4542
4543 static void CheckTrap(int x, int y)
4544 {
4545   int element = Feld[x][y];
4546
4547   if (element == EL_TRAP)
4548   {
4549     if (!MovDelay[x][y])        /* wait some time before activating trap */
4550       MovDelay[x][y] = 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND);
4551
4552     if (MovDelay[x][y])
4553     {
4554       MovDelay[x][y]--;
4555       if (MovDelay[x][y])
4556         return;
4557
4558       Feld[x][y] = EL_TRAP_ACTIVE;
4559       PlaySoundLevel(x, y, SND_TRAP_ACTIVATING);
4560     }
4561   }
4562   else if (element == EL_TRAP_ACTIVE)
4563   {
4564     int delay = 4;
4565     int num_frames = 8;
4566
4567     if (!MovDelay[x][y])        /* start activating trap */
4568       MovDelay[x][y] = num_frames * delay;
4569
4570     if (MovDelay[x][y])
4571     {
4572       MovDelay[x][y]--;
4573
4574       if (MovDelay[x][y])
4575       {
4576         if (!(MovDelay[x][y] % delay))
4577         {
4578           if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
4579           {
4580             int graphic = IMG_TRAP_ACTIVE;
4581             int frame = getGraphicAnimationFrame(graphic, 31 - MovDelay[x][y]);
4582
4583             DrawGraphic(SCREENX(x),SCREENY(y), graphic, frame);
4584             DrawCrumbledSand(SCREENX(x), SCREENY(y));
4585           }
4586         }
4587
4588         return;
4589       }
4590
4591       Feld[x][y] = EL_TRAP;
4592       DrawLevelField(x, y);
4593     }
4594   }
4595 }
4596
4597 static void DrawBeltAnimation(int x, int y, int element)
4598 {
4599   int belt_nr = getBeltNrFromBeltActiveElement(element);
4600   int belt_dir = game.belt_dir[belt_nr];
4601
4602   if (belt_dir != MV_NO_MOVING)
4603   {
4604     int graphic = el2img(element);
4605
4606     DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
4607
4608     if (!(FrameCounter % 2))
4609       PlaySoundLevel(x, y, SND_CONVEYOR_BELT_ACTIVE);
4610   }
4611 }
4612
4613 static void PlayerActions(struct PlayerInfo *player, byte player_action)
4614 {
4615   static byte stored_player_action[MAX_PLAYERS];
4616   static int num_stored_actions = 0;
4617 #if 0
4618   static boolean save_tape_entry = FALSE;
4619 #endif
4620   boolean moved = FALSE, snapped = FALSE, bombed = FALSE;
4621   int left      = player_action & JOY_LEFT;
4622   int right     = player_action & JOY_RIGHT;
4623   int up        = player_action & JOY_UP;
4624   int down      = player_action & JOY_DOWN;
4625   int button1   = player_action & JOY_BUTTON_1;
4626   int button2   = player_action & JOY_BUTTON_2;
4627   int dx        = (left ? -1    : right ? 1     : 0);
4628   int dy        = (up   ? -1    : down  ? 1     : 0);
4629
4630   stored_player_action[player->index_nr] = 0;
4631   num_stored_actions++;
4632
4633   if (!player->active || tape.pausing)
4634     return;
4635
4636   if (player_action)
4637   {
4638 #if 0
4639     save_tape_entry = TRUE;
4640 #endif
4641     player->frame_reset_delay = 0;
4642
4643     if (button1)
4644       snapped = SnapField(player, dx, dy);
4645     else
4646     {
4647       if (button2)
4648         bombed = PlaceBomb(player);
4649       moved = MoveFigure(player, dx, dy);
4650     }
4651
4652     if (tape.single_step && tape.recording && !tape.pausing)
4653     {
4654       if (button1 || (bombed && !moved))
4655       {
4656         TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
4657         SnapField(player, 0, 0);                /* stop snapping */
4658       }
4659     }
4660
4661 #if 0
4662     if (tape.recording && (moved || snapped || bombed))
4663     {
4664       if (bombed && !moved)
4665         player_action &= JOY_BUTTON;
4666
4667       stored_player_action[player->index_nr] = player_action;
4668       save_tape_entry = TRUE;
4669     }
4670     else if (tape.playing && snapped)
4671       SnapField(player, 0, 0);                  /* stop snapping */
4672 #else
4673     stored_player_action[player->index_nr] = player_action;
4674 #endif
4675   }
4676   else
4677   {
4678     /* no actions for this player (no input at player's configured device) */
4679
4680     DigField(player, 0, 0, 0, 0, DF_NO_PUSH);
4681     SnapField(player, 0, 0);
4682     CheckGravityMovement(player);
4683
4684 #if 1
4685     if (player->MovPos == 0)    /* needed for tape.playing */
4686       player->is_moving = FALSE;
4687 #endif
4688 #if 0
4689     if (player->MovPos == 0)    /* needed for tape.playing */
4690       player->last_move_dir = MV_NO_MOVING;
4691
4692     /* !!! CHECK THIS AGAIN !!!
4693        (Seems to be needed for some EL_ROBOT stuff, but breaks
4694        tapes when walking through pipes!)
4695     */
4696
4697     /* it seems that "player->last_move_dir" is misused as some sort of
4698        "player->is_just_moving_in_this_moment", which is needed for the
4699        robot stuff (robots don't kill players when they are moving)
4700     */
4701 #endif 
4702
4703     /* if the player does not move for some time, reset animation to start */
4704     if (++player->frame_reset_delay > player->move_delay_value)
4705       player->Frame = 0;
4706   }
4707
4708 #if 0
4709   if (tape.recording && num_stored_actions >= MAX_PLAYERS && save_tape_entry)
4710   {
4711     TapeRecordAction(stored_player_action);
4712     num_stored_actions = 0;
4713     save_tape_entry = FALSE;
4714   }
4715 #else
4716   if (tape.recording && num_stored_actions >= MAX_PLAYERS)
4717   {
4718     TapeRecordAction(stored_player_action);
4719     num_stored_actions = 0;
4720   }
4721 #endif
4722
4723 #if 0
4724   if (tape.playing && !tape.pausing && !player_action &&
4725       tape.counter < tape.length)
4726   {
4727     int jx = player->jx, jy = player->jy;
4728     int next_joy =
4729       tape.pos[tape.counter].action[player->index_nr] & (JOY_LEFT|JOY_RIGHT);
4730
4731     if ((next_joy == JOY_LEFT || next_joy == JOY_RIGHT) &&
4732         (player->MovDir != JOY_UP && player->MovDir != JOY_DOWN))
4733     {
4734       int dx = (next_joy == JOY_LEFT ? -1 : +1);
4735
4736       if (IN_LEV_FIELD(jx+dx, jy) && IS_PUSHABLE(Feld[jx+dx][jy]))
4737       {
4738         int el = Feld[jx+dx][jy];
4739         int push_delay = (IS_SB_ELEMENT(el) || el == EL_SATELLITE ? 2 :
4740                           (el == EL_BALLOON || el == EL_SPRING) ? 0 : 10);
4741
4742         if (tape.delay_played + push_delay >= tape.pos[tape.counter].delay)
4743         {
4744           player->MovDir = next_joy;
4745           player->Frame = FrameCounter % 4;
4746           player->Pushing = TRUE;
4747         }
4748       }
4749     }
4750   }
4751 #endif
4752 }
4753
4754 void GameActions()
4755 {
4756   static unsigned long action_delay = 0;
4757   unsigned long action_delay_value;
4758   int sieb_x = 0, sieb_y = 0;
4759   int i, x, y, element, graphic;
4760   byte *recorded_player_action;
4761   byte summarized_player_action = 0;
4762
4763   if (game_status != PLAYING)
4764     return;
4765
4766   action_delay_value =
4767     (tape.playing && tape.fast_forward ? FfwdFrameDelay : GameFrameDelay);
4768
4769   if (tape.playing && tape.index_search && !tape.pausing)
4770     action_delay_value = 0;
4771
4772   /* ---------- main game synchronization point ---------- */
4773
4774   WaitUntilDelayReached(&action_delay, action_delay_value);
4775
4776   if (network_playing && !network_player_action_received)
4777   {
4778     /*
4779 #ifdef DEBUG
4780     printf("DEBUG: try to get network player actions in time\n");
4781 #endif
4782     */
4783
4784 #if defined(PLATFORM_UNIX)
4785     /* last chance to get network player actions without main loop delay */
4786     HandleNetworking();
4787 #endif
4788
4789     if (game_status != PLAYING)
4790       return;
4791
4792     if (!network_player_action_received)
4793     {
4794       /*
4795 #ifdef DEBUG
4796       printf("DEBUG: failed to get network player actions in time\n");
4797 #endif
4798       */
4799       return;
4800     }
4801   }
4802
4803   if (tape.pausing)
4804     return;
4805
4806   recorded_player_action = (tape.playing ? TapePlayAction() : NULL);
4807
4808   for (i=0; i<MAX_PLAYERS; i++)
4809   {
4810     summarized_player_action |= stored_player[i].action;
4811
4812     if (!network_playing)
4813       stored_player[i].effective_action = stored_player[i].action;
4814   }
4815
4816 #if defined(PLATFORM_UNIX)
4817   if (network_playing)
4818     SendToServer_MovePlayer(summarized_player_action);
4819 #endif
4820
4821   if (!options.network && !setup.team_mode)
4822     local_player->effective_action = summarized_player_action;
4823
4824   for (i=0; i<MAX_PLAYERS; i++)
4825   {
4826     int actual_player_action = stored_player[i].effective_action;
4827
4828     if (stored_player[i].programmed_action)
4829       actual_player_action = stored_player[i].programmed_action;
4830
4831     if (recorded_player_action)
4832       actual_player_action = recorded_player_action[i];
4833
4834     PlayerActions(&stored_player[i], actual_player_action);
4835     ScrollFigure(&stored_player[i], SCROLL_GO_ON);
4836   }
4837
4838   network_player_action_received = FALSE;
4839
4840   ScrollScreen(NULL, SCROLL_GO_ON);
4841
4842
4843
4844 #ifdef DEBUG
4845 #if 0
4846   if (TimeFrames == 0 && local_player->active)
4847   {
4848     extern unsigned int last_RND();
4849
4850     printf("DEBUG: %03d last RND was %d \t [state checksum is %d]\n",
4851            TimePlayed, last_RND(), getStateCheckSum(TimePlayed));
4852   }
4853 #endif
4854 #endif
4855
4856 #ifdef DEBUG
4857 #if 0
4858   if (GameFrameDelay >= 500)
4859     printf("FrameCounter == %d\n", FrameCounter);
4860 #endif
4861 #endif
4862
4863
4864
4865   FrameCounter++;
4866   TimeFrames++;
4867
4868   for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
4869   {
4870     Stop[x][y] = FALSE;
4871     if (JustStopped[x][y] > 0)
4872       JustStopped[x][y]--;
4873
4874 #if DEBUG
4875     if (IS_BLOCKED(x, y))
4876     {
4877       int oldx, oldy;
4878
4879       Blocked2Moving(x, y, &oldx, &oldy);
4880       if (!IS_MOVING(oldx, oldy))
4881       {
4882         printf("GameActions(): (BLOCKED => MOVING) context corrupted!\n");
4883         printf("GameActions(): BLOCKED: x = %d, y = %d\n", x, y);
4884         printf("GameActions(): !MOVING: oldx = %d, oldy = %d\n", oldx, oldy);
4885         printf("GameActions(): This should never happen!\n");
4886       }
4887     }
4888 #endif
4889   }
4890
4891   for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
4892   {
4893     element = Feld[x][y];
4894     graphic = el2img(element);
4895
4896     if (IS_INACTIVE(element))
4897     {
4898
4899 #if 1
4900       if (new_graphic_info[graphic].anim_frames > 1)
4901         DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
4902 #endif
4903
4904       continue;
4905     }
4906
4907     if (!IS_MOVING(x, y) && (CAN_FALL(element) || CAN_MOVE(element)))
4908     {
4909       StartMoving(x, y);
4910
4911 #if 1
4912       if (Feld[x][y] == EL_EMERALD &&
4913           new_graphic_info[graphic].anim_frames > 1 &&
4914           !IS_MOVING(x, y))
4915         DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
4916 #endif
4917
4918       if (IS_GEM(element) || element == EL_SP_INFOTRON)
4919         EdelsteinFunkeln(x, y);
4920     }
4921
4922 #if 1
4923     else if ((element == EL_ACID ||
4924               element == EL_EXIT_OPEN ||
4925               element == EL_SP_EXIT_OPEN ||
4926               element == EL_SP_TERMINAL ||
4927               element == EL_SP_TERMINAL_ACTIVE ||
4928               element == EL_EXTRA_TIME ||
4929               element == EL_SHIELD_NORMAL ||
4930               element == EL_SHIELD_DEADLY) &&
4931              new_graphic_info[graphic].anim_frames > 1)
4932       DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
4933 #endif
4934
4935     else if (IS_MOVING(x, y))
4936       ContinueMoving(x, y);
4937     else if (IS_ACTIVE_BOMB(element))
4938       CheckDynamite(x, y);
4939 #if 0
4940     else if (element == EL_EXPLOSION && !game.explosions_delayed)
4941       Explode(x, y, Frame[x][y], EX_NORMAL);
4942 #endif
4943     else if (element == EL_AMOEBA_CREATING)
4944       AmoebeWaechst(x, y);
4945     else if (element == EL_AMOEBA_SHRINKING)
4946       AmoebaDisappearing(x, y);
4947
4948 #if !USE_NEW_AMOEBA_CODE
4949     else if (IS_AMOEBALIVE(element))
4950       AmoebeAbleger(x, y);
4951 #endif
4952
4953     else if (element == EL_GAMEOFLIFE || element == EL_BIOMAZE)
4954       Life(x, y);
4955     else if (element == EL_ROBOT_WHEEL_ACTIVE)
4956       RobotWheel(x, y);
4957     else if (element == EL_TIMEGATE_SWITCH_ACTIVE)
4958       TimegateWheel(x, y);
4959     else if (element == EL_ACID_SPLASH_LEFT ||
4960              element == EL_ACID_SPLASH_RIGHT)
4961       Blurb(x, y);
4962     else if (element == EL_NUT_CRACKING)
4963       NussKnacken(x, y);
4964     else if (element == EL_PEARL_BREAKING)
4965       BreakingPearl(x, y);
4966     else if (element == EL_EXIT_CLOSED)
4967       AusgangstuerPruefen(x, y);
4968     else if (element == EL_SP_EXIT_CLOSED)
4969       AusgangstuerPruefen_SP(x, y);
4970     else if (element == EL_EXIT_OPENING)
4971       AusgangstuerOeffnen(x, y);
4972     else if (element == EL_WALL_GROWING_ACTIVE)
4973       MauerWaechst(x, y);
4974     else if (element == EL_WALL_GROWING ||
4975              element == EL_WALL_GROWING_X ||
4976              element == EL_WALL_GROWING_Y ||
4977              element == EL_WALL_GROWING_XY)
4978       MauerAbleger(x, y);
4979     else if (element == EL_FLAMES)
4980       CheckForDragon(x, y);
4981     else if (element == EL_SP_BUGGY_BASE || element == EL_SP_BUGGY_BASE_ACTIVE)
4982       CheckBuggyBase(x, y);
4983     else if (element == EL_TRAP || element == EL_TRAP_ACTIVE)
4984       CheckTrap(x, y);
4985     else if (IS_BELT_ACTIVE(element))
4986       DrawBeltAnimation(x, y, element);
4987     else if (element == EL_SWITCHGATE_OPENING)
4988       OpenSwitchgate(x, y);
4989     else if (element == EL_SWITCHGATE_CLOSING)
4990       CloseSwitchgate(x, y);
4991     else if (element == EL_TIMEGATE_OPENING)
4992       OpenTimegate(x, y);
4993     else if (element == EL_TIMEGATE_CLOSING)
4994       CloseTimegate(x, y);
4995
4996 #if 1
4997     else if (new_graphic_info[graphic].anim_frames > 1)
4998       DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
4999 #endif
5000
5001     if (game.magic_wall_active)
5002     {
5003       boolean sieb = FALSE;
5004       int jx = local_player->jx, jy = local_player->jy;
5005
5006       if (element == EL_MAGIC_WALL_FULL ||
5007           element == EL_MAGIC_WALL_ACTIVE ||
5008           element == EL_MAGIC_WALL_EMPTYING)
5009       {
5010         SiebAktivieren(x, y, 1);
5011         sieb = TRUE;
5012       }
5013       else if (element == EL_BD_MAGIC_WALL_FULL ||
5014                element == EL_BD_MAGIC_WALL_ACTIVE ||
5015                element == EL_BD_MAGIC_WALL_EMPTYING)
5016       {
5017         SiebAktivieren(x, y, 2);
5018         sieb = TRUE;
5019       }
5020
5021       /* play the element sound at the position nearest to the player */
5022       if (sieb && ABS(x-jx)+ABS(y-jy) < ABS(sieb_x-jx)+ABS(sieb_y-jy))
5023       {
5024         sieb_x = x;
5025         sieb_y = y;
5026       }
5027     }
5028   }
5029
5030 #if USE_NEW_AMOEBA_CODE
5031   /* new experimental amoeba growth stuff */
5032 #if 1
5033   if (!(FrameCounter % 8))
5034 #endif
5035   {
5036     static unsigned long random = 1684108901;
5037
5038     for (i = 0; i < level.amoeba_speed * 28 / 8; i++)
5039     {
5040 #if 0
5041       x = (random >> 10) % lev_fieldx;
5042       y = (random >> 20) % lev_fieldy;
5043 #else
5044       x = RND(lev_fieldx);
5045       y = RND(lev_fieldy);
5046 #endif
5047       element = Feld[x][y];
5048
5049       if (!IS_PLAYER(x,y) &&
5050           (element == EL_EMPTY ||
5051            element == EL_SAND ||
5052            element == EL_QUICKSAND_EMPTY ||
5053            element == EL_ACID_SPLASH_LEFT ||
5054            element == EL_ACID_SPLASH_RIGHT))
5055       {
5056         if ((IN_LEV_FIELD(x, y-1) && Feld[x][y-1] == EL_AMOEBA_WET) ||
5057             (IN_LEV_FIELD(x-1, y) && Feld[x-1][y] == EL_AMOEBA_WET) ||
5058             (IN_LEV_FIELD(x+1, y) && Feld[x+1][y] == EL_AMOEBA_WET) ||
5059             (IN_LEV_FIELD(x, y+1) && Feld[x][y+1] == EL_AMOEBA_WET))
5060           Feld[x][y] = EL_AMOEBA_DROP;
5061       }
5062
5063       random = random * 129 + 1;
5064     }
5065   }
5066 #endif
5067
5068 #if 0
5069   if (game.explosions_delayed)
5070 #endif
5071   {
5072     game.explosions_delayed = FALSE;
5073
5074     for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
5075     {
5076       element = Feld[x][y];
5077
5078       if (ExplodeField[x][y])
5079         Explode(x, y, EX_PHASE_START, ExplodeField[x][y]);
5080       else if (element == EL_EXPLOSION)
5081         Explode(x, y, Frame[x][y], EX_NORMAL);
5082
5083       ExplodeField[x][y] = EX_NO_EXPLOSION;
5084     }
5085
5086     game.explosions_delayed = TRUE;
5087   }
5088
5089   if (game.magic_wall_active)
5090   {
5091     if (!(game.magic_wall_time_left % 4))
5092     {
5093       int element = Feld[sieb_x][sieb_y];
5094
5095       if (element == EL_BD_MAGIC_WALL_FULL ||
5096           element == EL_BD_MAGIC_WALL_ACTIVE ||
5097           element == EL_BD_MAGIC_WALL_EMPTYING)
5098         PlaySoundLevel(sieb_x, sieb_y, SND_BD_MAGIC_WALL_ACTIVE);
5099       else
5100         PlaySoundLevel(sieb_x, sieb_y, SND_MAGIC_WALL_ACTIVE);
5101     }
5102
5103     if (game.magic_wall_time_left > 0)
5104     {
5105       game.magic_wall_time_left--;
5106       if (!game.magic_wall_time_left)
5107       {
5108         for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
5109         {
5110           element = Feld[x][y];
5111
5112           if (element == EL_MAGIC_WALL_ACTIVE ||
5113               element == EL_MAGIC_WALL_FULL)
5114           {
5115             Feld[x][y] = EL_MAGIC_WALL_DEAD;
5116             DrawLevelField(x, y);
5117           }
5118           else if (element == EL_BD_MAGIC_WALL_ACTIVE ||
5119                    element == EL_BD_MAGIC_WALL_FULL)
5120           {
5121             Feld[x][y] = EL_BD_MAGIC_WALL_DEAD;
5122             DrawLevelField(x, y);
5123           }
5124         }
5125
5126         game.magic_wall_active = FALSE;
5127       }
5128     }
5129   }
5130
5131   if (game.light_time_left > 0)
5132   {
5133     game.light_time_left--;
5134
5135     if (game.light_time_left == 0)
5136       RedrawAllLightSwitchesAndInvisibleElements();
5137   }
5138
5139   if (game.timegate_time_left > 0)
5140   {
5141     game.timegate_time_left--;
5142
5143     if (game.timegate_time_left == 0)
5144       CloseAllOpenTimegates();
5145   }
5146
5147   for (i=0; i<MAX_PLAYERS; i++)
5148   {
5149     struct PlayerInfo *player = &stored_player[i];
5150
5151     if (SHIELD_ON(player))
5152     {
5153       if (player->shield_deadly_time_left)
5154         PlaySoundLevel(player->jx, player->jy, SND_SHIELD_DEADLY_ACTIVE);
5155       else if (player->shield_normal_time_left)
5156         PlaySoundLevel(player->jx, player->jy, SND_SHIELD_NORMAL_ACTIVE);
5157     }
5158   }
5159
5160   if (TimeFrames >= (1000 / GameFrameDelay))
5161   {
5162     TimeFrames = 0;
5163     TimePlayed++;
5164
5165     for (i=0; i<MAX_PLAYERS; i++)
5166     {
5167       struct PlayerInfo *player = &stored_player[i];
5168
5169       if (SHIELD_ON(player))
5170       {
5171         player->shield_normal_time_left--;
5172
5173         if (player->shield_deadly_time_left > 0)
5174           player->shield_deadly_time_left--;
5175       }
5176     }
5177
5178     if (tape.recording || tape.playing)
5179       DrawVideoDisplay(VIDEO_STATE_TIME_ON, TimePlayed);
5180
5181     if (TimeLeft > 0)
5182     {
5183       TimeLeft--;
5184
5185       if (TimeLeft <= 10 && setup.time_limit)
5186         PlaySoundStereo(SND_GAME_RUNNING_OUT_OF_TIME, SOUND_MAX_RIGHT);
5187
5188       DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
5189
5190       if (!TimeLeft && setup.time_limit)
5191         for (i=0; i<MAX_PLAYERS; i++)
5192           KillHero(&stored_player[i]);
5193     }
5194     else if (level.time == 0 && !AllPlayersGone) /* level without time limit */
5195       DrawText(DX_TIME, DY_TIME, int2str(TimePlayed, 3), FS_SMALL, FC_YELLOW);
5196   }
5197
5198   DrawAllPlayers();
5199
5200   if (options.debug)                    /* calculate frames per second */
5201   {
5202     static unsigned long fps_counter = 0;
5203     static int fps_frames = 0;
5204     unsigned long fps_delay_ms = Counter() - fps_counter;
5205
5206     fps_frames++;
5207
5208     if (fps_delay_ms >= 500)    /* calculate fps every 0.5 seconds */
5209     {
5210       global.frames_per_second = 1000 * (float)fps_frames / fps_delay_ms;
5211
5212       fps_frames = 0;
5213       fps_counter = Counter();
5214     }
5215
5216     redraw_mask |= REDRAW_FPS;
5217   }
5218 }
5219
5220 static boolean AllPlayersInSight(struct PlayerInfo *player, int x, int y)
5221 {
5222   int min_x = x, min_y = y, max_x = x, max_y = y;
5223   int i;
5224
5225   for (i=0; i<MAX_PLAYERS; i++)
5226   {
5227     int jx = stored_player[i].jx, jy = stored_player[i].jy;
5228
5229     if (!stored_player[i].active || &stored_player[i] == player)
5230       continue;
5231
5232     min_x = MIN(min_x, jx);
5233     min_y = MIN(min_y, jy);
5234     max_x = MAX(max_x, jx);
5235     max_y = MAX(max_y, jy);
5236   }
5237
5238   return (max_x - min_x < SCR_FIELDX && max_y - min_y < SCR_FIELDY);
5239 }
5240
5241 static boolean AllPlayersInVisibleScreen()
5242 {
5243   int i;
5244
5245   for (i=0; i<MAX_PLAYERS; i++)
5246   {
5247     int jx = stored_player[i].jx, jy = stored_player[i].jy;
5248
5249     if (!stored_player[i].active)
5250       continue;
5251
5252     if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
5253       return FALSE;
5254   }
5255
5256   return TRUE;
5257 }
5258
5259 void ScrollLevel(int dx, int dy)
5260 {
5261   int softscroll_offset = (setup.soft_scrolling ? TILEX : 0);
5262   int x, y;
5263
5264   BlitBitmap(drawto_field, drawto_field,
5265              FX + TILEX*(dx == -1) - softscroll_offset,
5266              FY + TILEY*(dy == -1) - softscroll_offset,
5267              SXSIZE - TILEX*(dx!=0) + 2*softscroll_offset,
5268              SYSIZE - TILEY*(dy!=0) + 2*softscroll_offset,
5269              FX + TILEX*(dx == 1) - softscroll_offset,
5270              FY + TILEY*(dy == 1) - softscroll_offset);
5271
5272   if (dx)
5273   {
5274     x = (dx == 1 ? BX1 : BX2);
5275     for (y=BY1; y<=BY2; y++)
5276       DrawScreenField(x, y);
5277   }
5278
5279   if (dy)
5280   {
5281     y = (dy == 1 ? BY1 : BY2);
5282     for (x=BX1; x<=BX2; x++)
5283       DrawScreenField(x, y);
5284   }
5285
5286   redraw_mask |= REDRAW_FIELD;
5287 }
5288
5289 static void CheckGravityMovement(struct PlayerInfo *player)
5290 {
5291   if (level.gravity && !player->programmed_action)
5292   {
5293     int move_dir_vertical = player->action & (MV_UP | MV_DOWN);
5294     int move_dir_horizontal = player->action & (MV_LEFT | MV_RIGHT);
5295     int move_dir =
5296       (player->last_move_dir & (MV_LEFT | MV_RIGHT) ?
5297        (move_dir_vertical ? move_dir_vertical : move_dir_horizontal) :
5298        (move_dir_horizontal ? move_dir_horizontal : move_dir_vertical));
5299     int jx = player->jx, jy = player->jy;
5300     int dx = (move_dir & MV_LEFT ? -1 : move_dir & MV_RIGHT ? +1 : 0);
5301     int dy = (move_dir & MV_UP ? -1 : move_dir & MV_DOWN ? +1 : 0);
5302     int new_jx = jx + dx, new_jy = jy + dy;
5303     boolean field_under_player_is_free =
5304       (IN_LEV_FIELD(jx, jy + 1) && IS_FREE(jx, jy + 1));
5305     boolean player_is_moving_to_valid_field =
5306       (IN_LEV_FIELD(new_jx, new_jy) &&
5307        (Feld[new_jx][new_jy] == EL_SP_BASE ||
5308         Feld[new_jx][new_jy] == EL_SAND));
5309
5310     if (field_under_player_is_free &&
5311         !player_is_moving_to_valid_field &&
5312         !IS_TUBE(Feld[jx][jy]))
5313       player->programmed_action = MV_DOWN;
5314   }
5315 }
5316
5317 boolean MoveFigureOneStep(struct PlayerInfo *player,
5318                           int dx, int dy, int real_dx, int real_dy)
5319 {
5320   int jx = player->jx, jy = player->jy;
5321   int new_jx = jx+dx, new_jy = jy+dy;
5322   int element;
5323   int can_move;
5324
5325   if (!player->active || (!dx && !dy))
5326     return MF_NO_ACTION;
5327
5328   player->MovDir = (dx < 0 ? MV_LEFT :
5329                     dx > 0 ? MV_RIGHT :
5330                     dy < 0 ? MV_UP :
5331                     dy > 0 ? MV_DOWN :  MV_NO_MOVING);
5332
5333   if (!IN_LEV_FIELD(new_jx, new_jy))
5334     return MF_NO_ACTION;
5335
5336   if (!options.network && !AllPlayersInSight(player, new_jx, new_jy))
5337     return MF_NO_ACTION;
5338
5339 #if 0
5340   element = MovingOrBlocked2Element(new_jx, new_jy);
5341 #else
5342   element = MovingOrBlocked2ElementIfNotLeaving(new_jx, new_jy);
5343 #endif
5344
5345   if (DONT_GO_TO(element))
5346   {
5347     if (element == EL_ACID && dx == 0 && dy == 1)
5348     {
5349       Blurb(jx, jy);
5350       Feld[jx][jy] = EL_PLAYER1;
5351       InitMovingField(jx, jy, MV_DOWN);
5352       Store[jx][jy] = EL_ACID;
5353       ContinueMoving(jx, jy);
5354       BuryHero(player);
5355     }
5356     else
5357       TestIfHeroRunsIntoBadThing(jx, jy, player->MovDir);
5358
5359     return MF_MOVING;
5360   }
5361
5362   can_move = DigField(player, new_jx, new_jy, real_dx, real_dy, DF_DIG);
5363   if (can_move != MF_MOVING)
5364     return can_move;
5365
5366   StorePlayer[jx][jy] = 0;
5367   player->last_jx = jx;
5368   player->last_jy = jy;
5369   jx = player->jx = new_jx;
5370   jy = player->jy = new_jy;
5371   StorePlayer[jx][jy] = player->element_nr;
5372
5373   player->MovPos =
5374     (dx > 0 || dy > 0 ? -1 : 1) * (TILEX - TILEX / player->move_delay_value);
5375
5376   ScrollFigure(player, SCROLL_INIT);
5377
5378   return MF_MOVING;
5379 }
5380
5381 boolean MoveFigure(struct PlayerInfo *player, int dx, int dy)
5382 {
5383   int jx = player->jx, jy = player->jy;
5384   int old_jx = jx, old_jy = jy;
5385   int moved = MF_NO_ACTION;
5386
5387   if (!player->active || (!dx && !dy))
5388     return FALSE;
5389
5390 #if 0
5391   if (!FrameReached(&player->move_delay, player->move_delay_value) &&
5392       !tape.playing)
5393     return FALSE;
5394 #else
5395   if (!FrameReached(&player->move_delay, player->move_delay_value) &&
5396       !(tape.playing && tape.file_version < FILE_VERSION_2_0))
5397     return FALSE;
5398 #endif
5399
5400   /* remove the last programmed player action */
5401   player->programmed_action = 0;
5402
5403   if (player->MovPos)
5404   {
5405     /* should only happen if pre-1.2 tape recordings are played */
5406     /* this is only for backward compatibility */
5407
5408     int original_move_delay_value = player->move_delay_value;
5409
5410 #if DEBUG
5411     printf("THIS SHOULD ONLY HAPPEN WITH PRE-1.2 LEVEL TAPES.\n");
5412 #endif
5413
5414     /* scroll remaining steps with finest movement resolution */
5415     player->move_delay_value = MOVE_DELAY_NORMAL_SPEED;
5416
5417     while (player->MovPos)
5418     {
5419       ScrollFigure(player, SCROLL_GO_ON);
5420       ScrollScreen(NULL, SCROLL_GO_ON);
5421       FrameCounter++;
5422       DrawAllPlayers();
5423       BackToFront();
5424     }
5425
5426     player->move_delay_value = original_move_delay_value;
5427   }
5428
5429   if (player->last_move_dir & (MV_LEFT | MV_RIGHT))
5430   {
5431     if (!(moved |= MoveFigureOneStep(player, 0, dy, dx, dy)))
5432       moved |= MoveFigureOneStep(player, dx, 0, dx, dy);
5433   }
5434   else
5435   {
5436     if (!(moved |= MoveFigureOneStep(player, dx, 0, dx, dy)))
5437       moved |= MoveFigureOneStep(player, 0, dy, dx, dy);
5438   }
5439
5440   jx = player->jx;
5441   jy = player->jy;
5442
5443   if (moved & MF_MOVING && !ScreenMovPos &&
5444       (player == local_player || !options.network))
5445   {
5446     int old_scroll_x = scroll_x, old_scroll_y = scroll_y;
5447     int offset = (setup.scroll_delay ? 3 : 0);
5448
5449     if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
5450     {
5451       /* actual player has left the screen -- scroll in that direction */
5452       if (jx != old_jx)         /* player has moved horizontally */
5453         scroll_x += (jx - old_jx);
5454       else                      /* player has moved vertically */
5455         scroll_y += (jy - old_jy);
5456     }
5457     else
5458     {
5459       if (jx != old_jx)         /* player has moved horizontally */
5460       {
5461         if ((player->MovDir == MV_LEFT && scroll_x > jx - MIDPOSX + offset) ||
5462             (player->MovDir == MV_RIGHT && scroll_x < jx - MIDPOSX - offset))
5463           scroll_x = jx-MIDPOSX + (scroll_x < jx-MIDPOSX ? -offset : +offset);
5464
5465         /* don't scroll over playfield boundaries */
5466         if (scroll_x < SBX_Left || scroll_x > SBX_Right)
5467           scroll_x = (scroll_x < SBX_Left ? SBX_Left : SBX_Right);
5468
5469         /* don't scroll more than one field at a time */
5470         scroll_x = old_scroll_x + SIGN(scroll_x - old_scroll_x);
5471
5472         /* don't scroll against the player's moving direction */
5473         if ((player->MovDir == MV_LEFT && scroll_x > old_scroll_x) ||
5474             (player->MovDir == MV_RIGHT && scroll_x < old_scroll_x))
5475           scroll_x = old_scroll_x;
5476       }
5477       else                      /* player has moved vertically */
5478       {
5479         if ((player->MovDir == MV_UP && scroll_y > jy - MIDPOSY + offset) ||
5480             (player->MovDir == MV_DOWN && scroll_y < jy - MIDPOSY - offset))
5481           scroll_y = jy-MIDPOSY + (scroll_y < jy-MIDPOSY ? -offset : +offset);
5482
5483         /* don't scroll over playfield boundaries */
5484         if (scroll_y < SBY_Upper || scroll_y > SBY_Lower)
5485           scroll_y = (scroll_y < SBY_Upper ? SBY_Upper : SBY_Lower);
5486
5487         /* don't scroll more than one field at a time */
5488         scroll_y = old_scroll_y + SIGN(scroll_y - old_scroll_y);
5489
5490         /* don't scroll against the player's moving direction */
5491         if ((player->MovDir == MV_UP && scroll_y > old_scroll_y) ||
5492             (player->MovDir == MV_DOWN && scroll_y < old_scroll_y))
5493           scroll_y = old_scroll_y;
5494       }
5495     }
5496
5497     if (scroll_x != old_scroll_x || scroll_y != old_scroll_y)
5498     {
5499       if (!options.network && !AllPlayersInVisibleScreen())
5500       {
5501         scroll_x = old_scroll_x;
5502         scroll_y = old_scroll_y;
5503       }
5504       else
5505       {
5506         ScrollScreen(player, SCROLL_INIT);
5507         ScrollLevel(old_scroll_x - scroll_x, old_scroll_y - scroll_y);
5508       }
5509     }
5510   }
5511
5512   if (!(moved & MF_MOVING) && !player->Pushing)
5513     player->Frame = 0;
5514   else
5515 #if 0
5516     player->Frame = (player->Frame + 1) % 4;
5517 #else
5518     player->Frame += 1 * 0;
5519 #endif
5520
5521   if (moved & MF_MOVING)
5522   {
5523     if (old_jx != jx && old_jy == jy)
5524       player->MovDir = (old_jx < jx ? MV_RIGHT : MV_LEFT);
5525     else if (old_jx == jx && old_jy != jy)
5526       player->MovDir = (old_jy < jy ? MV_DOWN : MV_UP);
5527
5528     DrawLevelField(jx, jy);     /* for "DrawCrumbledSand()" */
5529
5530     player->last_move_dir = player->MovDir;
5531     player->is_moving = TRUE;
5532   }
5533   else
5534   {
5535     CheckGravityMovement(player);
5536
5537     /*
5538     player->last_move_dir = MV_NO_MOVING;
5539     */
5540     player->is_moving = FALSE;
5541   }
5542
5543   TestIfHeroTouchesBadThing(jx, jy);
5544
5545   if (!player->active)
5546     RemoveHero(player);
5547
5548   return moved;
5549 }
5550
5551 void ScrollFigure(struct PlayerInfo *player, int mode)
5552 {
5553   int jx = player->jx, jy = player->jy;
5554   int last_jx = player->last_jx, last_jy = player->last_jy;
5555   int move_stepsize = TILEX / player->move_delay_value;
5556
5557   if (!player->active || !player->MovPos)
5558     return;
5559
5560   if (mode == SCROLL_INIT)
5561   {
5562     player->actual_frame_counter = FrameCounter;
5563     player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
5564     if (player->Frame)
5565       player->Frame += 1;
5566
5567     if (Feld[last_jx][last_jy] == EL_EMPTY)
5568       Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING;
5569
5570     DrawPlayer(player);
5571     return;
5572   }
5573   else if (!FrameReached(&player->actual_frame_counter, 1))
5574     return;
5575
5576   player->MovPos += (player->MovPos > 0 ? -1 : 1) * move_stepsize;
5577   player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
5578   player->Frame += 1;
5579
5580   if (Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING)
5581     Feld[last_jx][last_jy] = EL_EMPTY;
5582
5583   /* before DrawPlayer() to draw correct player graphic for this case */
5584   if (player->MovPos == 0)
5585     CheckGravityMovement(player);
5586
5587   DrawPlayer(player);
5588
5589   if (player->MovPos == 0)
5590   {
5591     if (IS_QUICK_GATE(Feld[last_jx][last_jy]))
5592     {
5593       /* continue with normal speed after quickly moving through gate */
5594       HALVE_PLAYER_SPEED(player);
5595
5596       /* be able to make the next move without delay */
5597       player->move_delay = 0;
5598     }
5599
5600     player->last_jx = jx;
5601     player->last_jy = jy;
5602
5603     if (Feld[jx][jy] == EL_EXIT_OPEN ||
5604         Feld[jx][jy] == EL_SP_EXIT_OPEN)
5605     {
5606       RemoveHero(player);
5607
5608       if (local_player->friends_still_needed == 0 ||
5609           Feld[jx][jy] == EL_SP_EXIT_OPEN)
5610         player->LevelSolved = player->GameOver = TRUE;
5611     }
5612
5613     if (tape.single_step && tape.recording && !tape.pausing &&
5614         !player->programmed_action)
5615       TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
5616   }
5617 }
5618
5619 void ScrollScreen(struct PlayerInfo *player, int mode)
5620 {
5621   static unsigned long screen_frame_counter = 0;
5622
5623   if (mode == SCROLL_INIT)
5624   {
5625     /* set scrolling step size according to actual player's moving speed */
5626     ScrollStepSize = TILEX / player->move_delay_value;
5627
5628     screen_frame_counter = FrameCounter;
5629     ScreenMovDir = player->MovDir;
5630     ScreenMovPos = player->MovPos;
5631     ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
5632     return;
5633   }
5634   else if (!FrameReached(&screen_frame_counter, 1))
5635     return;
5636
5637   if (ScreenMovPos)
5638   {
5639     ScreenMovPos += (ScreenMovPos > 0 ? -1 : 1) * ScrollStepSize;
5640     ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
5641     redraw_mask |= REDRAW_FIELD;
5642   }
5643   else
5644     ScreenMovDir = MV_NO_MOVING;
5645 }
5646
5647 void TestIfGoodThingHitsBadThing(int good_x, int good_y, int good_move_dir)
5648 {
5649   int i, kill_x = -1, kill_y = -1;
5650   static int test_xy[4][2] =
5651   {
5652     { 0, -1 },
5653     { -1, 0 },
5654     { +1, 0 },
5655     { 0, +1 }
5656   };
5657   static int test_dir[4] =
5658   {
5659     MV_UP,
5660     MV_LEFT,
5661     MV_RIGHT,
5662     MV_DOWN
5663   };
5664
5665   for (i=0; i<4; i++)
5666   {
5667     int test_x, test_y, test_move_dir, test_element;
5668
5669     test_x = good_x + test_xy[i][0];
5670     test_y = good_y + test_xy[i][1];
5671     if (!IN_LEV_FIELD(test_x, test_y))
5672       continue;
5673
5674     test_move_dir =
5675       (IS_MOVING(test_x, test_y) ? MovDir[test_x][test_y] : MV_NO_MOVING);
5676
5677 #if 0
5678     test_element = Feld[test_x][test_y];
5679 #else
5680     test_element = MovingOrBlocked2ElementIfNotLeaving(test_x, test_y);
5681 #endif
5682
5683     /* 1st case: good thing is moving towards DONT_GO_TO style bad thing;
5684        2nd case: DONT_TOUCH style bad thing does not move away from good thing
5685     */
5686     if ((DONT_GO_TO(test_element) && good_move_dir == test_dir[i]) ||
5687         (DONT_TOUCH(test_element) && test_move_dir != test_dir[i]))
5688     {
5689       kill_x = test_x;
5690       kill_y = test_y;
5691       break;
5692     }
5693   }
5694
5695   if (kill_x != -1 || kill_y != -1)
5696   {
5697     if (IS_PLAYER(good_x, good_y))
5698     {
5699       struct PlayerInfo *player = PLAYERINFO(good_x, good_y);
5700
5701       if (player->shield_deadly_time_left > 0)
5702         Bang(kill_x, kill_y);
5703       else if (!PLAYER_PROTECTED(good_x, good_y))
5704         KillHero(player);
5705     }
5706     else
5707       Bang(good_x, good_y);
5708   }
5709 }
5710
5711 void TestIfBadThingHitsGoodThing(int bad_x, int bad_y, int bad_move_dir)
5712 {
5713   int i, kill_x = -1, kill_y = -1;
5714   int bad_element = Feld[bad_x][bad_y];
5715   static int test_xy[4][2] =
5716   {
5717     { 0, -1 },
5718     { -1, 0 },
5719     { +1, 0 },
5720     { 0, +1 }
5721   };
5722   static int test_dir[4] =
5723   {
5724     MV_UP,
5725     MV_LEFT,
5726     MV_RIGHT,
5727     MV_DOWN
5728   };
5729
5730   if (bad_element == EL_EXPLOSION)      /* skip just exploding bad things */
5731     return;
5732
5733   for (i=0; i<4; i++)
5734   {
5735     int test_x, test_y, test_move_dir, test_element;
5736
5737     test_x = bad_x + test_xy[i][0];
5738     test_y = bad_y + test_xy[i][1];
5739     if (!IN_LEV_FIELD(test_x, test_y))
5740       continue;
5741
5742     test_move_dir =
5743       (IS_MOVING(test_x, test_y) ? MovDir[test_x][test_y] : MV_NO_MOVING);
5744
5745     test_element = Feld[test_x][test_y];
5746
5747     /* 1st case: good thing is moving towards DONT_GO_TO style bad thing;
5748        2nd case: DONT_TOUCH style bad thing does not move away from good thing
5749     */
5750     if ((DONT_GO_TO(bad_element) &&  bad_move_dir == test_dir[i]) ||
5751         (DONT_TOUCH(bad_element) && test_move_dir != test_dir[i]))
5752     {
5753       /* good thing is player or penguin that does not move away */
5754       if (IS_PLAYER(test_x, test_y))
5755       {
5756         struct PlayerInfo *player = PLAYERINFO(test_x, test_y);
5757
5758         if (bad_element == EL_ROBOT && player->is_moving)
5759           continue;     /* robot does not kill player if he is moving */
5760
5761         kill_x = test_x;
5762         kill_y = test_y;
5763         break;
5764       }
5765       else if (test_element == EL_PENGUIN)
5766       {
5767         kill_x = test_x;
5768         kill_y = test_y;
5769         break;
5770       }
5771     }
5772   }
5773
5774   if (kill_x != -1 || kill_y != -1)
5775   {
5776     if (IS_PLAYER(kill_x, kill_y))
5777     {
5778       struct PlayerInfo *player = PLAYERINFO(kill_x, kill_y);
5779
5780 #if 0
5781       int dir = player->MovDir;
5782       int newx = player->jx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
5783       int newy = player->jy + (dir == MV_UP   ? -1 : dir == MV_DOWN  ? +1 : 0);
5784
5785       if (Feld[bad_x][bad_y] == EL_ROBOT && player->is_moving &&
5786           newx != bad_x && newy != bad_y)
5787         ;       /* robot does not kill player if he is moving */
5788       else
5789         printf("-> %d\n", player->MovDir);
5790
5791       if (Feld[bad_x][bad_y] == EL_ROBOT && player->is_moving &&
5792           newx != bad_x && newy != bad_y)
5793         ;       /* robot does not kill player if he is moving */
5794       else
5795         ;
5796 #endif
5797
5798       if (player->shield_deadly_time_left > 0)
5799         Bang(bad_x, bad_y);
5800       else if (!PLAYER_PROTECTED(kill_x, kill_y))
5801         KillHero(player);
5802     }
5803     else
5804       Bang(kill_x, kill_y);
5805   }
5806 }
5807
5808 void TestIfHeroTouchesBadThing(int x, int y)
5809 {
5810   TestIfGoodThingHitsBadThing(x, y, MV_NO_MOVING);
5811 }
5812
5813 void TestIfHeroRunsIntoBadThing(int x, int y, int move_dir)
5814 {
5815   TestIfGoodThingHitsBadThing(x, y, move_dir);
5816 }
5817
5818 void TestIfBadThingTouchesHero(int x, int y)
5819 {
5820   TestIfBadThingHitsGoodThing(x, y, MV_NO_MOVING);
5821 }
5822
5823 void TestIfBadThingRunsIntoHero(int x, int y, int move_dir)
5824 {
5825   TestIfBadThingHitsGoodThing(x, y, move_dir);
5826 }
5827
5828 void TestIfFriendTouchesBadThing(int x, int y)
5829 {
5830   TestIfGoodThingHitsBadThing(x, y, MV_NO_MOVING);
5831 }
5832
5833 void TestIfBadThingTouchesFriend(int x, int y)
5834 {
5835   TestIfBadThingHitsGoodThing(x, y, MV_NO_MOVING);
5836 }
5837
5838 void TestIfBadThingTouchesOtherBadThing(int bad_x, int bad_y)
5839 {
5840   int i, kill_x = bad_x, kill_y = bad_y;
5841   static int xy[4][2] =
5842   {
5843     { 0, -1 },
5844     { -1, 0 },
5845     { +1, 0 },
5846     { 0, +1 }
5847   };
5848
5849   for (i=0; i<4; i++)
5850   {
5851     int x, y, element;
5852
5853     x = bad_x + xy[i][0];
5854     y = bad_y + xy[i][1];
5855     if (!IN_LEV_FIELD(x, y))
5856       continue;
5857
5858     element = Feld[x][y];
5859     if (IS_AMOEBOID(element) || element == EL_GAMEOFLIFE ||
5860         element == EL_AMOEBA_CREATING || element == EL_AMOEBA_DROP)
5861     {
5862       kill_x = x;
5863       kill_y = y;
5864       break;
5865     }
5866   }
5867
5868   if (kill_x != bad_x || kill_y != bad_y)
5869     Bang(bad_x, bad_y);
5870 }
5871
5872 void KillHero(struct PlayerInfo *player)
5873 {
5874   int jx = player->jx, jy = player->jy;
5875
5876   if (!player->active)
5877     return;
5878
5879   if (IS_PFORTE(Feld[jx][jy]))
5880     Feld[jx][jy] = EL_EMPTY;
5881
5882   /* deactivate shield (else Bang()/Explode() would not work right) */
5883   player->shield_normal_time_left = 0;
5884   player->shield_deadly_time_left = 0;
5885
5886   Bang(jx, jy);
5887   BuryHero(player);
5888 }
5889
5890 static void KillHeroUnlessProtected(int x, int y)
5891 {
5892   if (!PLAYER_PROTECTED(x, y))
5893     KillHero(PLAYERINFO(x, y));
5894 }
5895
5896 void BuryHero(struct PlayerInfo *player)
5897 {
5898   int jx = player->jx, jy = player->jy;
5899
5900   if (!player->active)
5901     return;
5902
5903   PlaySoundLevel(jx, jy, SND_PLAYER_DYING);
5904   PlaySoundLevel(jx, jy, SND_GAME_LOSING);
5905
5906   player->GameOver = TRUE;
5907   RemoveHero(player);
5908 }
5909
5910 void RemoveHero(struct PlayerInfo *player)
5911 {
5912   int jx = player->jx, jy = player->jy;
5913   int i, found = FALSE;
5914
5915   player->present = FALSE;
5916   player->active = FALSE;
5917
5918   if (!ExplodeField[jx][jy])
5919     StorePlayer[jx][jy] = 0;
5920
5921   for (i=0; i<MAX_PLAYERS; i++)
5922     if (stored_player[i].active)
5923       found = TRUE;
5924
5925   if (!found)
5926     AllPlayersGone = TRUE;
5927
5928   ExitX = ZX = jx;
5929   ExitY = ZY = jy;
5930 }
5931
5932 int DigField(struct PlayerInfo *player,
5933              int x, int y, int real_dx, int real_dy, int mode)
5934 {
5935   int jx = player->jx, jy = player->jy;
5936   int dx = x - jx, dy = y - jy;
5937   int move_direction = (dx == -1 ? MV_LEFT :
5938                         dx == +1 ? MV_RIGHT :
5939                         dy == -1 ? MV_UP :
5940                         dy == +1 ? MV_DOWN : MV_NO_MOVING);
5941   int element;
5942
5943   if (player->MovPos == 0)
5944     player->Pushing = FALSE;
5945
5946   if (mode == DF_NO_PUSH)
5947   {
5948     player->Switching = FALSE;
5949     player->push_delay = 0;
5950     return MF_NO_ACTION;
5951   }
5952
5953   if (IS_MOVING(x, y) || IS_PLAYER(x, y))
5954     return MF_NO_ACTION;
5955
5956   if (IS_TUBE(Feld[jx][jy]))
5957   {
5958     int i = 0;
5959     int tube_leave_directions[][2] =
5960     {
5961       { EL_TUBE_ALL,                    MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN },
5962       { EL_TUBE_VERTICAL,                                    MV_UP | MV_DOWN },
5963       { EL_TUBE_HORIZONTAL,             MV_LEFT | MV_RIGHT                   },
5964       { EL_TUBE_VERTICAL_LEFT,          MV_LEFT |            MV_UP | MV_DOWN },
5965       { EL_TUBE_VERTICAL_RIGHT,                   MV_RIGHT | MV_UP | MV_DOWN },
5966       { EL_TUBE_HORIZONTAL_UP,          MV_LEFT | MV_RIGHT | MV_UP           },
5967       { EL_TUBE_HORIZONTAL_DOWN,        MV_LEFT | MV_RIGHT |         MV_DOWN },
5968       { EL_TUBE_LEFT_UP,                MV_LEFT |            MV_UP           },
5969       { EL_TUBE_LEFT_DOWN,              MV_LEFT |                    MV_DOWN },
5970       { EL_TUBE_RIGHT_UP,                         MV_RIGHT | MV_UP           },
5971       { EL_TUBE_RIGHT_DOWN,                       MV_RIGHT |         MV_DOWN },
5972       { -1,                             MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN }
5973     };
5974
5975     while (tube_leave_directions[i][0] != Feld[jx][jy])
5976     {
5977       i++;
5978       if (tube_leave_directions[i][0] == -1)    /* should not happen */
5979         break;
5980     }
5981
5982     if (!(tube_leave_directions[i][1] & move_direction))
5983       return MF_NO_ACTION;      /* tube has no opening in this direction */
5984   }
5985
5986   element = Feld[x][y];
5987
5988   switch (element)
5989   {
5990     case EL_EMPTY:
5991     case EL_SAND:
5992     case EL_INVISIBLE_SAND:
5993     case EL_INVISIBLE_SAND_ACTIVE:
5994     case EL_TRAP:
5995     case EL_SP_BASE:
5996     case EL_SP_BUGGY_BASE:
5997       RemoveField(x, y);
5998       PlaySoundLevelElementAction(x, y, element, SND_ACTION_DIGGING);
5999       break;
6000
6001     case EL_EMERALD:
6002     case EL_BD_DIAMOND:
6003     case EL_EMERALD_YELLOW:
6004     case EL_EMERALD_RED:
6005     case EL_EMERALD_PURPLE:
6006     case EL_DIAMOND:
6007     case EL_SP_INFOTRON:
6008     case EL_PEARL:
6009     case EL_CRYSTAL:
6010       RemoveField(x, y);
6011       local_player->gems_still_needed -= (element == EL_DIAMOND ? 3 :
6012                                           element == EL_PEARL ? 5 :
6013                                           element == EL_CRYSTAL ? 8 : 1);
6014       if (local_player->gems_still_needed < 0)
6015         local_player->gems_still_needed = 0;
6016       RaiseScoreElement(element);
6017       DrawText(DX_EMERALDS, DY_EMERALDS,
6018                int2str(local_player->gems_still_needed, 3),
6019                FS_SMALL, FC_YELLOW);
6020       PlaySoundLevelElementAction(x, y, element, SND_ACTION_COLLECTING);
6021       break;
6022
6023     case EL_SPEED_PILL:
6024       RemoveField(x, y);
6025       player->move_delay_value = MOVE_DELAY_HIGH_SPEED;
6026       PlaySoundLevel(x, y, SND_SPEED_PILL_COLLECTING);
6027       break;
6028
6029     case EL_ENVELOPE:
6030       Feld[x][y] = EL_EMPTY;
6031       PlaySoundLevel(x, y, SND_ENVELOPE_COLLECTING);
6032       break;
6033
6034     case EL_EXTRA_TIME:
6035       RemoveField(x, y);
6036       if (level.time > 0)
6037       {
6038         TimeLeft += 10;
6039         DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
6040       }
6041       PlaySoundStereo(SND_EXTRA_TIME_COLLECTING, SOUND_MAX_RIGHT);
6042       break;
6043
6044     case EL_SHIELD_NORMAL:
6045       RemoveField(x, y);
6046       player->shield_normal_time_left += 10;
6047       PlaySoundLevel(x, y, SND_SHIELD_NORMAL_COLLECTING);
6048       break;
6049
6050     case EL_SHIELD_DEADLY:
6051       RemoveField(x, y);
6052       player->shield_normal_time_left += 10;
6053       player->shield_deadly_time_left += 10;
6054       PlaySoundLevel(x, y, SND_SHIELD_DEADLY_COLLECTING);
6055       break;
6056
6057     case EL_DYNAMITE:
6058     case EL_SP_DISK_RED:
6059       RemoveField(x, y);
6060       player->dynamite++;
6061       RaiseScoreElement(EL_DYNAMITE);
6062       DrawText(DX_DYNAMITE, DY_DYNAMITE,
6063                int2str(local_player->dynamite, 3),
6064                FS_SMALL, FC_YELLOW);
6065       PlaySoundLevelElementAction(x, y, element, SND_ACTION_COLLECTING);
6066       break;
6067
6068     case EL_DYNABOMB_NR:
6069       RemoveField(x, y);
6070       player->dynabomb_count++;
6071       player->dynabombs_left++;
6072       RaiseScoreElement(EL_DYNAMITE);
6073       PlaySoundLevel(x, y, SND_DYNABOMB_NR_COLLECTING);
6074       break;
6075
6076     case EL_DYNABOMB_SZ:
6077       RemoveField(x, y);
6078       player->dynabomb_size++;
6079       RaiseScoreElement(EL_DYNAMITE);
6080       PlaySoundLevel(x, y, SND_DYNABOMB_SZ_COLLECTING);
6081       break;
6082
6083     case EL_DYNABOMB_XL:
6084       RemoveField(x, y);
6085       player->dynabomb_xl = TRUE;
6086       RaiseScoreElement(EL_DYNAMITE);
6087       PlaySoundLevel(x, y, SND_DYNABOMB_XL_COLLECTING);
6088       break;
6089
6090     case EL_KEY1:
6091     case EL_KEY2:
6092     case EL_KEY3:
6093     case EL_KEY4:
6094     {
6095       int key_nr = element - EL_KEY1;
6096
6097       RemoveField(x, y);
6098       player->key[key_nr] = TRUE;
6099       RaiseScoreElement(element);
6100       DrawMiniGraphicExt(drawto, DX_KEYS + key_nr * MINI_TILEX, DY_KEYS,
6101                          GFX_SCHLUESSEL1 + key_nr);
6102       DrawMiniGraphicExt(window, DX_KEYS + key_nr * MINI_TILEX, DY_KEYS,
6103                          GFX_SCHLUESSEL1 + key_nr);
6104       PlaySoundLevel(x, y, SND_KEY_COLLECTING);
6105       break;
6106     }
6107
6108     case EL_EM_KEY1:
6109     case EL_EM_KEY2:
6110     case EL_EM_KEY3:
6111     case EL_EM_KEY4:
6112     {
6113       int key_nr = element - EL_EM_KEY1;
6114
6115       RemoveField(x, y);
6116       player->key[key_nr] = TRUE;
6117       RaiseScoreElement(element);
6118       DrawMiniGraphicExt(drawto, DX_KEYS + key_nr * MINI_TILEX, DY_KEYS,
6119                          GFX_SCHLUESSEL1 + key_nr);
6120       DrawMiniGraphicExt(window, DX_KEYS + key_nr * MINI_TILEX, DY_KEYS,
6121                          GFX_SCHLUESSEL1 + key_nr);
6122       PlaySoundLevel(x, y, SND_KEY_COLLECTING);
6123       break;
6124     }
6125
6126     case EL_ROBOT_WHEEL:
6127       Feld[x][y] = EL_ROBOT_WHEEL_ACTIVE;
6128       ZX = x;
6129       ZY = y;
6130       DrawLevelField(x, y);
6131       PlaySoundLevel(x, y, SND_ROBOT_WHEEL_ACTIVATING);
6132       return MF_ACTION;
6133       break;
6134
6135     case EL_SP_TERMINAL:
6136       {
6137         int xx, yy;
6138
6139         PlaySoundLevel(x, y, SND_SP_TERMINAL_ACTIVATING);
6140
6141         for (yy=0; yy<lev_fieldy; yy++)
6142         {
6143           for (xx=0; xx<lev_fieldx; xx++)
6144           {
6145             if (Feld[xx][yy] == EL_SP_DISK_YELLOW)
6146               Bang(xx, yy);
6147             else if (Feld[xx][yy] == EL_SP_TERMINAL)
6148               Feld[xx][yy] = EL_SP_TERMINAL_ACTIVE;
6149           }
6150         }
6151
6152         return MF_ACTION;
6153       }
6154       break;
6155
6156     case EL_CONVEYOR_BELT1_SWITCH_LEFT:
6157     case EL_CONVEYOR_BELT1_SWITCH_MIDDLE:
6158     case EL_CONVEYOR_BELT1_SWITCH_RIGHT:
6159     case EL_CONVEYOR_BELT2_SWITCH_LEFT:
6160     case EL_CONVEYOR_BELT2_SWITCH_MIDDLE:
6161     case EL_CONVEYOR_BELT2_SWITCH_RIGHT:
6162     case EL_CONVEYOR_BELT3_SWITCH_LEFT:
6163     case EL_CONVEYOR_BELT3_SWITCH_MIDDLE:
6164     case EL_CONVEYOR_BELT3_SWITCH_RIGHT:
6165     case EL_CONVEYOR_BELT4_SWITCH_LEFT:
6166     case EL_CONVEYOR_BELT4_SWITCH_MIDDLE:
6167     case EL_CONVEYOR_BELT4_SWITCH_RIGHT:
6168       if (!player->Switching)
6169       {
6170         player->Switching = TRUE;
6171         ToggleBeltSwitch(x, y);
6172         PlaySoundLevel(x, y, SND_CONVEYOR_BELT_SWITCH_ACTIVATING);
6173       }
6174       return MF_ACTION;
6175       break;
6176
6177     case EL_SWITCHGATE_SWITCH_UP:
6178     case EL_SWITCHGATE_SWITCH_DOWN:
6179       if (!player->Switching)
6180       {
6181         player->Switching = TRUE;
6182         ToggleSwitchgateSwitch(x, y);
6183         PlaySoundLevel(x, y, SND_SWITCHGATE_SWITCH_ACTIVATING);
6184       }
6185       return MF_ACTION;
6186       break;
6187
6188     case EL_LIGHT_SWITCH:
6189     case EL_LIGHT_SWITCH_ACTIVE:
6190       if (!player->Switching)
6191       {
6192         player->Switching = TRUE;
6193         ToggleLightSwitch(x, y);
6194         PlaySoundLevel(x, y, element == EL_LIGHT_SWITCH ?
6195                        SND_LIGHT_SWITCH_ACTIVATING :
6196                        SND_LIGHT_SWITCH_DEACTIVATING);
6197       }
6198       return MF_ACTION;
6199       break;
6200
6201     case EL_TIMEGATE_SWITCH:
6202       ActivateTimegateSwitch(x, y);
6203       PlaySoundLevel(x, y, SND_TIMEGATE_SWITCH_ACTIVATING);
6204
6205       return MF_ACTION;
6206       break;
6207
6208     case EL_BALLOON_SEND_LEFT:
6209     case EL_BALLOON_SEND_RIGHT:
6210     case EL_BALLOON_SEND_UP:
6211     case EL_BALLOON_SEND_DOWN:
6212     case EL_BALLOON_SEND_ANY_DIRECTION:
6213       if (element == EL_BALLOON_SEND_ANY_DIRECTION)
6214         game.balloon_dir = move_direction;
6215       else
6216         game.balloon_dir = (element == EL_BALLOON_SEND_LEFT  ? MV_LEFT :
6217                             element == EL_BALLOON_SEND_RIGHT ? MV_RIGHT :
6218                             element == EL_BALLOON_SEND_UP    ? MV_UP :
6219                             element == EL_BALLOON_SEND_DOWN  ? MV_DOWN :
6220                             MV_NO_MOVING);
6221       PlaySoundLevel(x, y, SND_BALLOON_SWITCH_ACTIVATING);
6222
6223       return MF_ACTION;
6224       break;
6225
6226       /* the following elements cannot be pushed by "snapping" */
6227     case EL_ROCK:
6228     case EL_BOMB:
6229     case EL_DX_SUPABOMB:
6230     case EL_NUT:
6231     case EL_TIME_ORB_EMPTY:
6232     case EL_SP_ZONK:
6233     case EL_SP_DISK_ORANGE:
6234     case EL_SPRING:
6235       if (mode == DF_SNAP)
6236         return MF_NO_ACTION;
6237       /* no "break" -- fall through to next case */
6238       /* the following elements can be pushed by "snapping" */
6239     case EL_BD_ROCK:
6240       if (dy)
6241         return MF_NO_ACTION;
6242
6243       player->Pushing = TRUE;
6244
6245       if (!IN_LEV_FIELD(x+dx, y+dy) || !IS_FREE(x+dx, y+dy))
6246         return MF_NO_ACTION;
6247
6248       if (real_dy)
6249       {
6250         if (IN_LEV_FIELD(jx, jy+real_dy) && !IS_SOLID(Feld[jx][jy+real_dy]))
6251           return MF_NO_ACTION;
6252       }
6253
6254       if (player->push_delay == 0)
6255         player->push_delay = FrameCounter;
6256 #if 0
6257       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
6258           !tape.playing && element != EL_SPRING)
6259         return MF_NO_ACTION;
6260 #else
6261       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
6262           !(tape.playing && tape.file_version < FILE_VERSION_2_0) &&
6263           element != EL_SPRING)
6264         return MF_NO_ACTION;
6265 #endif
6266
6267       if (mode == DF_SNAP)
6268       {
6269         InitMovingField(x, y, move_direction);
6270         ContinueMoving(x, y);
6271       }
6272       else
6273       {
6274         RemoveField(x, y);
6275         Feld[x + dx][y + dy] = element;
6276       }
6277
6278       if (element == EL_SPRING)
6279       {
6280         Feld[x + dx][y + dy] = EL_SPRING;
6281         MovDir[x + dx][y + dy] = move_direction;
6282       }
6283
6284       player->push_delay_value = (element == EL_SPRING ? 0 : 2 + RND(8));
6285
6286       DrawLevelField(x + dx, y + dy);
6287       PlaySoundLevelElementAction(x, y, element, SND_ACTION_PUSHING);
6288       break;
6289
6290     case EL_GATE1:
6291     case EL_GATE2:
6292     case EL_GATE3:
6293     case EL_GATE4:
6294       if (!player->key[element - EL_GATE1])
6295         return MF_NO_ACTION;
6296       break;
6297
6298     case EL_GATE1_GRAY:
6299     case EL_GATE2_GRAY:
6300     case EL_GATE3_GRAY:
6301     case EL_GATE4_GRAY:
6302       if (!player->key[element - EL_GATE1_GRAY])
6303         return MF_NO_ACTION;
6304       break;
6305
6306     case EL_EM_GATE1:
6307     case EL_EM_GATE2:
6308     case EL_EM_GATE3:
6309     case EL_EM_GATE4:
6310       if (!player->key[element - EL_EM_GATE1])
6311         return MF_NO_ACTION;
6312       if (!IN_LEV_FIELD(x + dx, y + dy) || !IS_FREE(x + dx, y + dy))
6313         return MF_NO_ACTION;
6314
6315       /* automatically move to the next field with double speed */
6316       player->programmed_action = move_direction;
6317       DOUBLE_PLAYER_SPEED(player);
6318
6319       PlaySoundLevel(x, y, SND_GATE_PASSING);
6320       break;
6321
6322     case EL_EM_GATE1_GRAY:
6323     case EL_EM_GATE2_GRAY:
6324     case EL_EM_GATE3_GRAY:
6325     case EL_EM_GATE4_GRAY:
6326       if (!player->key[element - EL_EM_GATE1_GRAY])
6327         return MF_NO_ACTION;
6328       if (!IN_LEV_FIELD(x + dx, y + dy) || !IS_FREE(x + dx, y + dy))
6329         return MF_NO_ACTION;
6330
6331       /* automatically move to the next field with double speed */
6332       player->programmed_action = move_direction;
6333       DOUBLE_PLAYER_SPEED(player);
6334
6335       PlaySoundLevel(x, y, SND_GATE_PASSING);
6336       break;
6337
6338     case EL_SWITCHGATE_OPEN:
6339     case EL_TIMEGATE_OPEN:
6340       if (!IN_LEV_FIELD(x + dx, y + dy) || !IS_FREE(x + dx, y + dy))
6341         return MF_NO_ACTION;
6342
6343       /* automatically move to the next field with double speed */
6344       player->programmed_action = move_direction;
6345       DOUBLE_PLAYER_SPEED(player);
6346
6347       PlaySoundLevelElementAction(x, y, element, SND_ACTION_PASSING);
6348       break;
6349
6350     case EL_SP_PORT1_LEFT:
6351     case EL_SP_PORT2_LEFT:
6352     case EL_SP_PORT1_RIGHT:
6353     case EL_SP_PORT2_RIGHT:
6354     case EL_SP_PORT1_UP:
6355     case EL_SP_PORT2_UP:
6356     case EL_SP_PORT1_DOWN:
6357     case EL_SP_PORT2_DOWN:
6358     case EL_SP_PORT_X:
6359     case EL_SP_PORT_Y:
6360     case EL_SP_PORT_XY:
6361       if ((dx == -1 &&
6362            element != EL_SP_PORT1_LEFT &&
6363            element != EL_SP_PORT2_LEFT &&
6364            element != EL_SP_PORT_X &&
6365            element != EL_SP_PORT_XY) ||
6366           (dx == +1 &&
6367            element != EL_SP_PORT1_RIGHT &&
6368            element != EL_SP_PORT2_RIGHT &&
6369            element != EL_SP_PORT_X &&
6370            element != EL_SP_PORT_XY) ||
6371           (dy == -1 &&
6372            element != EL_SP_PORT1_UP &&
6373            element != EL_SP_PORT2_UP &&
6374            element != EL_SP_PORT_Y &&
6375            element != EL_SP_PORT_XY) ||
6376           (dy == +1 &&
6377            element != EL_SP_PORT1_DOWN &&
6378            element != EL_SP_PORT2_DOWN &&
6379            element != EL_SP_PORT_Y &&
6380            element != EL_SP_PORT_XY) ||
6381           !IN_LEV_FIELD(x + dx, y + dy) ||
6382           !IS_FREE(x + dx, y + dy))
6383         return MF_NO_ACTION;
6384
6385       /* automatically move to the next field with double speed */
6386       player->programmed_action = move_direction;
6387       DOUBLE_PLAYER_SPEED(player);
6388
6389       PlaySoundLevel(x, y, SND_SP_PORT_PASSING);
6390       break;
6391
6392     case EL_TUBE_ALL:
6393     case EL_TUBE_VERTICAL:
6394     case EL_TUBE_HORIZONTAL:
6395     case EL_TUBE_VERTICAL_LEFT:
6396     case EL_TUBE_VERTICAL_RIGHT:
6397     case EL_TUBE_HORIZONTAL_UP:
6398     case EL_TUBE_HORIZONTAL_DOWN:
6399     case EL_TUBE_LEFT_UP:
6400     case EL_TUBE_LEFT_DOWN:
6401     case EL_TUBE_RIGHT_UP:
6402     case EL_TUBE_RIGHT_DOWN:
6403       {
6404         int i = 0;
6405         int tube_enter_directions[][2] =
6406         {
6407           { EL_TUBE_ALL,                MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN },
6408           { EL_TUBE_VERTICAL,                                MV_UP | MV_DOWN },
6409           { EL_TUBE_HORIZONTAL,         MV_LEFT | MV_RIGHT                   },
6410           { EL_TUBE_VERTICAL_LEFT,                MV_RIGHT | MV_UP | MV_DOWN },
6411           { EL_TUBE_VERTICAL_RIGHT,     MV_LEFT            | MV_UP | MV_DOWN },
6412           { EL_TUBE_HORIZONTAL_UP,      MV_LEFT | MV_RIGHT |         MV_DOWN },
6413           { EL_TUBE_HORIZONTAL_DOWN,    MV_LEFT | MV_RIGHT | MV_UP           },
6414           { EL_TUBE_LEFT_UP,                      MV_RIGHT |         MV_DOWN },
6415           { EL_TUBE_LEFT_DOWN,                    MV_RIGHT | MV_UP           },
6416           { EL_TUBE_RIGHT_UP,           MV_LEFT |                    MV_DOWN },
6417           { EL_TUBE_RIGHT_DOWN,         MV_LEFT |            MV_UP           },
6418           { -1,                         MV_NO_MOVING                         }
6419         };
6420
6421         while (tube_enter_directions[i][0] != element)
6422         {
6423           i++;
6424           if (tube_enter_directions[i][0] == -1)        /* should not happen */
6425             break;
6426         }
6427
6428         if (!(tube_enter_directions[i][1] & move_direction))
6429           return MF_NO_ACTION;  /* tube has no opening in this direction */
6430
6431         PlaySoundLevel(x, y, SND_TUBE_PASSING);
6432       }
6433       break;
6434
6435     case EL_EXIT_CLOSED:
6436     case EL_SP_EXIT_CLOSED:
6437     case EL_EXIT_OPENING:
6438       return MF_NO_ACTION;
6439       break;
6440
6441     case EL_EXIT_OPEN:
6442     case EL_SP_EXIT_OPEN:
6443       if (mode == DF_SNAP)
6444         return MF_NO_ACTION;
6445
6446       if (element == EL_EXIT_OPEN)
6447         PlaySoundLevel(x, y, SND_EXIT_PASSING);
6448       else
6449         PlaySoundLevel(x, y, SND_SP_EXIT_PASSING);
6450
6451       break;
6452
6453     case EL_LAMP:
6454       Feld[x][y] = EL_LAMP_ACTIVE;
6455       local_player->lights_still_needed--;
6456       DrawLevelField(x, y);
6457       PlaySoundLevel(x, y, SND_LAMP_ACTIVATING);
6458       return MF_ACTION;
6459       break;
6460
6461     case EL_TIME_ORB_FULL:
6462       Feld[x][y] = EL_TIME_ORB_EMPTY;
6463       TimeLeft += 10;
6464       DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
6465       DrawLevelField(x, y);
6466       PlaySoundStereo(SND_TIME_ORB_FULL_COLLECTING, SOUND_MAX_RIGHT);
6467       return MF_ACTION;
6468       break;
6469
6470     case EL_SOKOBAN_FIELD_EMPTY:
6471       break;
6472
6473     case EL_SOKOBAN_OBJECT:
6474     case EL_SOKOBAN_FIELD_FULL:
6475     case EL_SATELLITE:
6476     case EL_SP_DISK_YELLOW:
6477     case EL_BALLOON:
6478       if (mode == DF_SNAP)
6479         return MF_NO_ACTION;
6480
6481       player->Pushing = TRUE;
6482
6483       if (!IN_LEV_FIELD(x+dx, y+dy)
6484           || (!IS_FREE(x+dx, y+dy)
6485               && (Feld[x+dx][y+dy] != EL_SOKOBAN_FIELD_EMPTY
6486                   || !IS_SB_ELEMENT(element))))
6487         return MF_NO_ACTION;
6488
6489       if (dx && real_dy)
6490       {
6491         if (IN_LEV_FIELD(jx, jy+real_dy) && !IS_SOLID(Feld[jx][jy+real_dy]))
6492           return MF_NO_ACTION;
6493       }
6494       else if (dy && real_dx)
6495       {
6496         if (IN_LEV_FIELD(jx+real_dx, jy) && !IS_SOLID(Feld[jx+real_dx][jy]))
6497           return MF_NO_ACTION;
6498       }
6499
6500       if (player->push_delay == 0)
6501         player->push_delay = FrameCounter;
6502 #if 0
6503       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
6504           !tape.playing && element != EL_BALLOON)
6505         return MF_NO_ACTION;
6506 #else
6507       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
6508           !(tape.playing && tape.file_version < FILE_VERSION_2_0) &&
6509           element != EL_BALLOON)
6510         return MF_NO_ACTION;
6511 #endif
6512
6513       if (IS_SB_ELEMENT(element))
6514       {
6515         if (element == EL_SOKOBAN_FIELD_FULL)
6516         {
6517           Feld[x][y] = EL_SOKOBAN_FIELD_EMPTY;
6518           local_player->sokobanfields_still_needed++;
6519         }
6520         else
6521           RemoveField(x, y);
6522
6523         if (Feld[x+dx][y+dy] == EL_SOKOBAN_FIELD_EMPTY)
6524         {
6525           Feld[x+dx][y+dy] = EL_SOKOBAN_FIELD_FULL;
6526           local_player->sokobanfields_still_needed--;
6527           if (element == EL_SOKOBAN_OBJECT)
6528             PlaySoundLevel(x, y, SND_SOKOBAN_FIELD_FILLING);
6529           else
6530             PlaySoundLevel(x, y, SND_SOKOBAN_OBJECT_PUSHING);
6531         }
6532         else
6533         {
6534           Feld[x+dx][y+dy] = EL_SOKOBAN_OBJECT;
6535           if (element == EL_SOKOBAN_FIELD_FULL)
6536             PlaySoundLevel(x, y, SND_SOKOBAN_FIELD_EMPTYING);
6537           else
6538             PlaySoundLevel(x, y, SND_SOKOBAN_OBJECT_PUSHING);
6539         }
6540       }
6541       else
6542       {
6543         RemoveField(x, y);
6544         Feld[x+dx][y+dy] = element;
6545         PlaySoundLevelElementAction(x, y, element, SND_ACTION_PUSHING);
6546       }
6547
6548       player->push_delay_value = (element == EL_BALLOON ? 0 : 2);
6549
6550       DrawLevelField(x, y);
6551       DrawLevelField(x + dx, y + dy);
6552
6553       if (IS_SB_ELEMENT(element) &&
6554           local_player->sokobanfields_still_needed == 0 &&
6555           game.emulation == EMU_SOKOBAN)
6556       {
6557         player->LevelSolved = player->GameOver = TRUE;
6558         PlaySoundLevel(x, y, SND_SOKOBAN_GAME_SOLVING);
6559       }
6560
6561       break;
6562
6563     case EL_PENGUIN:
6564     case EL_PIG:
6565     case EL_DRAGON:
6566       break;
6567
6568     default:
6569       return MF_NO_ACTION;
6570   }
6571
6572   player->push_delay = 0;
6573
6574   return MF_MOVING;
6575 }
6576
6577 boolean SnapField(struct PlayerInfo *player, int dx, int dy)
6578 {
6579   int jx = player->jx, jy = player->jy;
6580   int x = jx + dx, y = jy + dy;
6581
6582   if (!player->active || !IN_LEV_FIELD(x, y))
6583     return FALSE;
6584
6585   if (dx && dy)
6586     return FALSE;
6587
6588   if (!dx && !dy)
6589   {
6590     if (player->MovPos == 0)
6591       player->Pushing = FALSE;
6592
6593     player->snapped = FALSE;
6594     return FALSE;
6595   }
6596
6597   if (player->snapped)
6598     return FALSE;
6599
6600   player->MovDir = (dx < 0 ? MV_LEFT :
6601                     dx > 0 ? MV_RIGHT :
6602                     dy < 0 ? MV_UP :
6603                     dy > 0 ? MV_DOWN :  MV_NO_MOVING);
6604
6605   if (!DigField(player, x, y, 0, 0, DF_SNAP))
6606     return FALSE;
6607
6608   player->snapped = TRUE;
6609   DrawLevelField(x, y);
6610   BackToFront();
6611
6612   return TRUE;
6613 }
6614
6615 boolean PlaceBomb(struct PlayerInfo *player)
6616 {
6617   int jx = player->jx, jy = player->jy;
6618   int element;
6619
6620   if (!player->active || player->MovPos)
6621     return FALSE;
6622
6623   element = Feld[jx][jy];
6624
6625   if ((player->dynamite == 0 && player->dynabombs_left == 0) ||
6626       IS_ACTIVE_BOMB(element) || element == EL_EXPLOSION)
6627     return FALSE;
6628
6629   if (element != EL_EMPTY)
6630     Store[jx][jy] = element;
6631
6632   if (player->dynamite)
6633   {
6634     Feld[jx][jy] = EL_DYNAMITE_ACTIVE;
6635     MovDelay[jx][jy] = 96;
6636     player->dynamite--;
6637     DrawText(DX_DYNAMITE, DY_DYNAMITE, int2str(local_player->dynamite, 3),
6638              FS_SMALL, FC_YELLOW);
6639     if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy)))
6640     {
6641       if (game.emulation == EMU_SUPAPLEX)
6642         DrawGraphic(SCREENX(jx), SCREENY(jy), IMG_SP_DISK_RED, 0);
6643       else
6644         DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), IMG_DYNAMITE_ACTIVE, 0);
6645     }
6646
6647     PlaySoundLevel(jx, jy, SND_DYNAMITE_DROPPING);
6648   }
6649   else
6650   {
6651     Feld[jx][jy] =
6652       EL_DYNABOMB_PLAYER1_ACTIVE + (player->element_nr - EL_PLAYER1);
6653     MovDelay[jx][jy] = 96;
6654     player->dynabombs_left--;
6655     if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy)))
6656       DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), el2img(Feld[jx][jy]), 0);
6657
6658     PlaySoundLevel(jx, jy, SND_DYNABOMB_DROPPING);
6659   }
6660
6661   return TRUE;
6662 }
6663
6664 void PlaySoundLevel(int x, int y, int nr)
6665 {
6666   static int loop_sound_frame[NUM_SOUND_FILES];
6667   static int loop_sound_volume[NUM_SOUND_FILES];
6668   int sx = SCREENX(x), sy = SCREENY(y);
6669   int volume, stereo_position;
6670   int max_distance = 8;
6671   int type = (IS_LOOP_SOUND(nr) ? SND_CTRL_PLAY_LOOP : SND_CTRL_PLAY_SOUND);
6672
6673   if ((!setup.sound_simple && !IS_LOOP_SOUND(nr)) ||
6674       (!setup.sound_loops && IS_LOOP_SOUND(nr)))
6675     return;
6676
6677   if (!IN_LEV_FIELD(x, y) ||
6678       sx < -max_distance || sx >= SCR_FIELDX + max_distance ||
6679       sy < -max_distance || sy >= SCR_FIELDY + max_distance)
6680     return;
6681
6682   volume = SOUND_MAX_VOLUME;
6683
6684   if (!IN_SCR_FIELD(sx, sy))
6685   {
6686     int dx = ABS(sx - SCR_FIELDX / 2) - SCR_FIELDX / 2;
6687     int dy = ABS(sy - SCR_FIELDY / 2) - SCR_FIELDY / 2;
6688
6689     volume -= volume * (dx > dy ? dx : dy) / max_distance;
6690   }
6691
6692   stereo_position = (SOUND_MAX_LEFT +
6693                      (sx + max_distance) * SOUND_MAX_LEFT2RIGHT /
6694                      (SCR_FIELDX + 2 * max_distance));
6695
6696   if (IS_LOOP_SOUND(nr))
6697   {
6698     /* This assures that quieter loop sounds do not overwrite louder ones,
6699        while restarting sound volume comparison with each new game frame. */
6700
6701     if (loop_sound_volume[nr] > volume && loop_sound_frame[nr] == FrameCounter)
6702       return;
6703
6704     loop_sound_volume[nr] = volume;
6705     loop_sound_frame[nr] = FrameCounter;
6706   }
6707
6708   PlaySoundExt(nr, volume, stereo_position, type);
6709 }
6710
6711 void PlaySoundLevelAction(int x, int y, int sound_action)
6712 {
6713   PlaySoundLevelElementAction(x, y, Feld[x][y], sound_action);
6714 }
6715
6716 void PlaySoundLevelElementAction(int x, int y, int element, int sound_action)
6717 {
6718   int sound_effect = element_action_sound[element][sound_action];
6719
6720   if (sound_effect != -1)
6721     PlaySoundLevel(x, y, sound_effect);
6722 }
6723
6724 void RaiseScore(int value)
6725 {
6726   local_player->score += value;
6727   DrawText(DX_SCORE, DY_SCORE, int2str(local_player->score, 5),
6728            FS_SMALL, FC_YELLOW);
6729 }
6730
6731 void RaiseScoreElement(int element)
6732 {
6733   switch(element)
6734   {
6735     case EL_EMERALD:
6736     case EL_BD_DIAMOND:
6737     case EL_EMERALD_YELLOW:
6738     case EL_EMERALD_RED:
6739     case EL_EMERALD_PURPLE:
6740       RaiseScore(level.score[SC_EDELSTEIN]);
6741       break;
6742     case EL_DIAMOND:
6743       RaiseScore(level.score[SC_DIAMANT]);
6744       break;
6745     case EL_BUG:
6746     case EL_BD_BUTTERFLY:
6747       RaiseScore(level.score[SC_KAEFER]);
6748       break;
6749     case EL_SPACESHIP:
6750     case EL_BD_FIREFLY:
6751       RaiseScore(level.score[SC_FLIEGER]);
6752       break;
6753     case EL_YAMYAM:
6754     case EL_DARK_YAMYAM:
6755       RaiseScore(level.score[SC_MAMPFER]);
6756       break;
6757     case EL_ROBOT:
6758       RaiseScore(level.score[SC_ROBOT]);
6759       break;
6760     case EL_PACMAN:
6761       RaiseScore(level.score[SC_PACMAN]);
6762       break;
6763     case EL_NUT:
6764       RaiseScore(level.score[SC_KOKOSNUSS]);
6765       break;
6766     case EL_DYNAMITE:
6767       RaiseScore(level.score[SC_DYNAMIT]);
6768       break;
6769     case EL_KEY1:
6770     case EL_KEY2:
6771     case EL_KEY3:
6772     case EL_KEY4:
6773       RaiseScore(level.score[SC_SCHLUESSEL]);
6774       break;
6775     default:
6776       break;
6777   }
6778 }
6779
6780 void RequestQuitGame(boolean ask_if_really_quit)
6781 {
6782   if (AllPlayersGone ||
6783       !ask_if_really_quit ||
6784       level_editor_test_game ||
6785       Request("Do you really want to quit the game ?",
6786               REQ_ASK | REQ_STAY_CLOSED))
6787   {
6788 #if defined(PLATFORM_UNIX)
6789     if (options.network)
6790       SendToServer_StopPlaying();
6791     else
6792 #endif
6793     {
6794       game_status = MAINMENU;
6795       DrawMainMenu();
6796     }
6797   }
6798   else
6799   {
6800     OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
6801   }
6802 }
6803
6804
6805 /* ---------- new game button stuff ---------------------------------------- */
6806
6807 /* graphic position values for game buttons */
6808 #define GAME_BUTTON_XSIZE       30
6809 #define GAME_BUTTON_YSIZE       30
6810 #define GAME_BUTTON_XPOS        5
6811 #define GAME_BUTTON_YPOS        215
6812 #define SOUND_BUTTON_XPOS       5
6813 #define SOUND_BUTTON_YPOS       (GAME_BUTTON_YPOS + GAME_BUTTON_YSIZE)
6814
6815 #define GAME_BUTTON_STOP_XPOS   (GAME_BUTTON_XPOS + 0 * GAME_BUTTON_XSIZE)
6816 #define GAME_BUTTON_PAUSE_XPOS  (GAME_BUTTON_XPOS + 1 * GAME_BUTTON_XSIZE)
6817 #define GAME_BUTTON_PLAY_XPOS   (GAME_BUTTON_XPOS + 2 * GAME_BUTTON_XSIZE)
6818 #define SOUND_BUTTON_MUSIC_XPOS (SOUND_BUTTON_XPOS + 0 * GAME_BUTTON_XSIZE)
6819 #define SOUND_BUTTON_LOOPS_XPOS (SOUND_BUTTON_XPOS + 1 * GAME_BUTTON_XSIZE)
6820 #define SOUND_BUTTON_SIMPLE_XPOS (SOUND_BUTTON_XPOS + 2 * GAME_BUTTON_XSIZE)
6821
6822 static struct
6823 {
6824   int x, y;
6825   int gadget_id;
6826   char *infotext;
6827 } gamebutton_info[NUM_GAME_BUTTONS] =
6828 {
6829   {
6830     GAME_BUTTON_STOP_XPOS,      GAME_BUTTON_YPOS,
6831     GAME_CTRL_ID_STOP,
6832     "stop game"
6833   },
6834   {
6835     GAME_BUTTON_PAUSE_XPOS,     GAME_BUTTON_YPOS,
6836     GAME_CTRL_ID_PAUSE,
6837     "pause game"
6838   },
6839   {
6840     GAME_BUTTON_PLAY_XPOS,      GAME_BUTTON_YPOS,
6841     GAME_CTRL_ID_PLAY,
6842     "play game"
6843   },
6844   {
6845     SOUND_BUTTON_MUSIC_XPOS,    SOUND_BUTTON_YPOS,
6846     SOUND_CTRL_ID_MUSIC,
6847     "background music on/off"
6848   },
6849   {
6850     SOUND_BUTTON_LOOPS_XPOS,    SOUND_BUTTON_YPOS,
6851     SOUND_CTRL_ID_LOOPS,
6852     "sound loops on/off"
6853   },
6854   {
6855     SOUND_BUTTON_SIMPLE_XPOS,   SOUND_BUTTON_YPOS,
6856     SOUND_CTRL_ID_SIMPLE,
6857     "normal sounds on/off"
6858   }
6859 };
6860
6861 void CreateGameButtons()
6862 {
6863   int i;
6864
6865   for (i=0; i<NUM_GAME_BUTTONS; i++)
6866   {
6867     Bitmap *gd_bitmap = new_graphic_info[IMG_MENU_DOOR].bitmap;
6868     struct GadgetInfo *gi;
6869     int button_type;
6870     boolean checked;
6871     unsigned long event_mask;
6872     int gd_xoffset, gd_yoffset;
6873     int gd_x1, gd_x2, gd_y1, gd_y2;
6874     int id = i;
6875
6876     gd_xoffset = gamebutton_info[i].x;
6877     gd_yoffset = gamebutton_info[i].y;
6878     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
6879     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
6880
6881     if (id == GAME_CTRL_ID_STOP ||
6882         id == GAME_CTRL_ID_PAUSE ||
6883         id == GAME_CTRL_ID_PLAY)
6884     {
6885       button_type = GD_TYPE_NORMAL_BUTTON;
6886       checked = FALSE;
6887       event_mask = GD_EVENT_RELEASED;
6888       gd_y1  = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
6889       gd_y2  = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
6890     }
6891     else
6892     {
6893       button_type = GD_TYPE_CHECK_BUTTON;
6894       checked =
6895         ((id == SOUND_CTRL_ID_MUSIC && setup.sound_music) ||
6896          (id == SOUND_CTRL_ID_LOOPS && setup.sound_loops) ||
6897          (id == SOUND_CTRL_ID_SIMPLE && setup.sound_simple) ? TRUE : FALSE);
6898       event_mask = GD_EVENT_PRESSED;
6899       gd_y1  = DOOR_GFX_PAGEY1 + gd_yoffset;
6900       gd_y2  = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
6901     }
6902
6903     gi = CreateGadget(GDI_CUSTOM_ID, id,
6904                       GDI_INFO_TEXT, gamebutton_info[i].infotext,
6905                       GDI_X, DX + gd_xoffset,
6906                       GDI_Y, DY + gd_yoffset,
6907                       GDI_WIDTH, GAME_BUTTON_XSIZE,
6908                       GDI_HEIGHT, GAME_BUTTON_YSIZE,
6909                       GDI_TYPE, button_type,
6910                       GDI_STATE, GD_BUTTON_UNPRESSED,
6911                       GDI_CHECKED, checked,
6912                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
6913                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y1,
6914                       GDI_ALT_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y2,
6915                       GDI_ALT_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
6916                       GDI_EVENT_MASK, event_mask,
6917                       GDI_CALLBACK_ACTION, HandleGameButtons,
6918                       GDI_END);
6919
6920     if (gi == NULL)
6921       Error(ERR_EXIT, "cannot create gadget");
6922
6923     game_gadget[id] = gi;
6924   }
6925 }
6926
6927 static void MapGameButtons()
6928 {
6929   int i;
6930
6931   for (i=0; i<NUM_GAME_BUTTONS; i++)
6932     MapGadget(game_gadget[i]);
6933 }
6934
6935 void UnmapGameButtons()
6936 {
6937   int i;
6938
6939   for (i=0; i<NUM_GAME_BUTTONS; i++)
6940     UnmapGadget(game_gadget[i]);
6941 }
6942
6943 static void HandleGameButtons(struct GadgetInfo *gi)
6944 {
6945   int id = gi->custom_id;
6946
6947   if (game_status != PLAYING)
6948     return;
6949
6950   switch (id)
6951   {
6952     case GAME_CTRL_ID_STOP:
6953       RequestQuitGame(TRUE);
6954       break;
6955
6956     case GAME_CTRL_ID_PAUSE:
6957       if (options.network)
6958       {
6959 #if defined(PLATFORM_UNIX)
6960         if (tape.pausing)
6961           SendToServer_ContinuePlaying();
6962         else
6963           SendToServer_PausePlaying();
6964 #endif
6965       }
6966       else
6967         TapeTogglePause(TAPE_TOGGLE_MANUAL);
6968       break;
6969
6970     case GAME_CTRL_ID_PLAY:
6971       if (tape.pausing)
6972       {
6973 #if defined(PLATFORM_UNIX)
6974         if (options.network)
6975           SendToServer_ContinuePlaying();
6976         else
6977 #endif
6978         {
6979           tape.pausing = FALSE;
6980           DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0);
6981         }
6982       }
6983       break;
6984
6985     case SOUND_CTRL_ID_MUSIC:
6986       if (setup.sound_music)
6987       { 
6988         setup.sound_music = FALSE;
6989         FadeMusic();
6990       }
6991       else if (audio.music_available)
6992       { 
6993         setup.sound = setup.sound_music = TRUE;
6994         PlayMusic(level_nr);
6995       }
6996       break;
6997
6998     case SOUND_CTRL_ID_LOOPS:
6999       if (setup.sound_loops)
7000         setup.sound_loops = FALSE;
7001       else if (audio.loops_available)
7002         setup.sound = setup.sound_loops = TRUE;
7003       break;
7004
7005     case SOUND_CTRL_ID_SIMPLE:
7006       if (setup.sound_simple)
7007         setup.sound_simple = FALSE;
7008       else if (audio.sound_available)
7009         setup.sound = setup.sound_simple = TRUE;
7010       break;
7011
7012     default:
7013       break;
7014   }
7015 }