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