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