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