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