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