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