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