5a6a248936827043d5a28bf9ec565323df6be7dc
[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   FadeToFront();
966
967   /* after drawing the level, correct some elements */
968   if (game.timegate_time_left == 0)
969     CloseAllOpenTimegates();
970
971   if (setup.soft_scrolling)
972     BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
973
974   redraw_mask |= REDRAW_FROM_BACKBUFFER;
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);
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   int element = Feld[x][y];
2811
2812   if (Stop[x][y])
2813     return;
2814
2815   GfxAction[x][y] = GFX_ACTION_DEFAULT;
2816
2817   if (CAN_FALL(element) && y<lev_fieldy-1)
2818   {
2819     if ((x>0 && IS_PLAYER(x-1, y)) || (x<lev_fieldx-1 && IS_PLAYER(x+1, y)))
2820       if (JustBeingPushed(x, y))
2821         return;
2822
2823     if (element == EL_QUICKSAND_FULL)
2824     {
2825       if (IS_FREE(x, y+1))
2826       {
2827         InitMovingField(x, y, MV_DOWN);
2828         Feld[x][y] = EL_QUICKSAND_EMPTYING;
2829         Store[x][y] = EL_ROCK;
2830         PlaySoundLevel(x, y, SND_QUICKSAND_EMPTYING);
2831       }
2832       else if (Feld[x][y+1] == EL_QUICKSAND_EMPTY)
2833       {
2834         if (!MovDelay[x][y])
2835           MovDelay[x][y] = TILEY + 1;
2836
2837         if (MovDelay[x][y])
2838         {
2839           MovDelay[x][y]--;
2840           if (MovDelay[x][y])
2841             return;
2842         }
2843
2844         Feld[x][y] = EL_QUICKSAND_EMPTY;
2845         Feld[x][y+1] = EL_QUICKSAND_FULL;
2846         Store[x][y+1] = Store[x][y];
2847         Store[x][y] = 0;
2848         PlaySoundLevel(x, y, SND_QUICKSAND_SLIPPING);
2849       }
2850     }
2851     else if ((element == EL_ROCK || element == EL_BD_ROCK) &&
2852              Feld[x][y+1] == EL_QUICKSAND_EMPTY)
2853     {
2854       InitMovingField(x, y, MV_DOWN);
2855       Feld[x][y] = EL_QUICKSAND_FILLING;
2856       Store[x][y] = element;
2857       PlaySoundLevel(x, y, SND_QUICKSAND_FILLING);
2858     }
2859     else if (element == EL_MAGIC_WALL_FULL)
2860     {
2861       if (IS_FREE(x, y+1))
2862       {
2863         InitMovingField(x, y, MV_DOWN);
2864         Feld[x][y] = EL_MAGIC_WALL_EMPTYING;
2865         Store[x][y] = EL_CHANGED(Store[x][y]);
2866       }
2867       else if (Feld[x][y+1] == EL_MAGIC_WALL_ACTIVE)
2868       {
2869         if (!MovDelay[x][y])
2870           MovDelay[x][y] = TILEY/4 + 1;
2871
2872         if (MovDelay[x][y])
2873         {
2874           MovDelay[x][y]--;
2875           if (MovDelay[x][y])
2876             return;
2877         }
2878
2879         Feld[x][y] = EL_MAGIC_WALL_ACTIVE;
2880         Feld[x][y+1] = EL_MAGIC_WALL_FULL;
2881         Store[x][y+1] = EL_CHANGED(Store[x][y]);
2882         Store[x][y] = 0;
2883       }
2884     }
2885     else if (element == EL_BD_MAGIC_WALL_FULL)
2886     {
2887       if (IS_FREE(x, y+1))
2888       {
2889         InitMovingField(x, y, MV_DOWN);
2890         Feld[x][y] = EL_BD_MAGIC_WALL_EMPTYING;
2891         Store[x][y] = EL_CHANGED2(Store[x][y]);
2892       }
2893       else if (Feld[x][y+1] == EL_BD_MAGIC_WALL_ACTIVE)
2894       {
2895         if (!MovDelay[x][y])
2896           MovDelay[x][y] = TILEY/4 + 1;
2897
2898         if (MovDelay[x][y])
2899         {
2900           MovDelay[x][y]--;
2901           if (MovDelay[x][y])
2902             return;
2903         }
2904
2905         Feld[x][y] = EL_BD_MAGIC_WALL_ACTIVE;
2906         Feld[x][y+1] = EL_BD_MAGIC_WALL_FULL;
2907         Store[x][y+1] = EL_CHANGED2(Store[x][y]);
2908         Store[x][y] = 0;
2909       }
2910     }
2911     else if (CAN_CHANGE(element) &&
2912              (Feld[x][y+1] == EL_MAGIC_WALL_ACTIVE ||
2913               Feld[x][y+1] == EL_BD_MAGIC_WALL_ACTIVE))
2914     {
2915       InitMovingField(x, y, MV_DOWN);
2916       Feld[x][y] =
2917         (Feld[x][y+1] == EL_MAGIC_WALL_ACTIVE ? EL_MAGIC_WALL_FILLING :
2918          EL_BD_MAGIC_WALL_FILLING);
2919       Store[x][y] = element;
2920     }
2921     else if (CAN_SMASH(element) && Feld[x][y+1] == EL_ACID)
2922     {
2923       Blurb(x, y);
2924       InitMovingField(x, y, MV_DOWN);
2925       Store[x][y] = EL_ACID;
2926     }
2927     else if (CAN_SMASH(element) && Feld[x][y+1] == EL_BLOCKED &&
2928              JustStopped[x][y])
2929     {
2930       Impact(x, y);
2931     }
2932     else if (IS_FREE(x, y+1))
2933     {
2934       InitMovingField(x, y, MV_DOWN);
2935     }
2936     else if (element == EL_AMOEBA_DROP)
2937     {
2938       Feld[x][y] = EL_AMOEBA_CREATING;
2939       Store[x][y] = EL_AMOEBA_WET;
2940     }
2941     /* Store[x][y+1] must be zero, because:
2942        (EL_QUICKSAND_FULL -> EL_ROCK): Store[x][y+1] == EL_QUICKSAND_EMPTY
2943     */
2944 #if 0
2945 #if OLD_GAME_BEHAVIOUR
2946     else if (IS_SLIPPERY(Feld[x][y+1]) && !Store[x][y+1])
2947 #else
2948     else if (IS_SLIPPERY(Feld[x][y+1]) && !Store[x][y+1] &&
2949              !IS_FALLING(x, y+1) && !JustStopped[x][y+1] &&
2950              element != EL_DX_SUPABOMB)
2951 #endif
2952 #else
2953     else if ((IS_SLIPPERY(Feld[x][y+1]) ||
2954               (IS_EM_SLIPPERY_WALL(Feld[x][y+1]) && IS_GEM(element))) &&
2955              !IS_FALLING(x, y+1) && !JustStopped[x][y+1] &&
2956              element != EL_DX_SUPABOMB && element != EL_SP_DISK_ORANGE)
2957 #endif
2958     {
2959       boolean left  = (x>0 && IS_FREE(x-1, y) &&
2960                        (IS_FREE(x-1, y+1) || Feld[x-1][y+1] == EL_ACID));
2961       boolean right = (x<lev_fieldx-1 && IS_FREE(x+1, y) &&
2962                        (IS_FREE(x+1, y+1) || Feld[x+1][y+1] == EL_ACID));
2963
2964       if (left || right)
2965       {
2966         if (left && right &&
2967             (game.emulation != EMU_BOULDERDASH &&
2968              element != EL_BD_ROCK && element != EL_BD_DIAMOND))
2969           left = !(right = RND(2));
2970
2971         InitMovingField(x, y, left ? MV_LEFT : MV_RIGHT);
2972       }
2973     }
2974     else if (IS_BELT_ACTIVE(Feld[x][y+1]))
2975     {
2976       boolean left_is_free  = (x>0 && IS_FREE(x-1, y));
2977       boolean right_is_free = (x<lev_fieldx-1 && IS_FREE(x+1, y));
2978       int belt_nr = getBeltNrFromBeltActiveElement(Feld[x][y+1]);
2979       int belt_dir = game.belt_dir[belt_nr];
2980
2981       if ((belt_dir == MV_LEFT  && left_is_free) ||
2982           (belt_dir == MV_RIGHT && right_is_free))
2983       {
2984         InitMovingField(x, y, belt_dir);
2985         GfxAction[x][y] = GFX_ACTION_DEFAULT;
2986       }
2987     }
2988   }
2989
2990   if (CAN_MOVE(element))        /* not "else if" because of EL_SPRING */
2991   {
2992     int newx, newy;
2993
2994     if ((element == EL_SATELLITE ||
2995          element == EL_BALLOON ||
2996          element == EL_SPRING)
2997         && JustBeingPushed(x, y))
2998       return;
2999
3000     if (element == EL_SPRING && MovDir[x][y] == MV_DOWN)
3001       Feld[x][y + 1] = EL_EMPTY;        /* was set to EL_BLOCKED above */
3002
3003     if (!MovDelay[x][y])        /* start new movement phase */
3004     {
3005       /* all objects that can change their move direction after each step */
3006       /* (MAMPFER, MAMPFER2 and PACMAN go straight until they hit a wall  */
3007
3008       if (element != EL_YAMYAM &&
3009           element != EL_DARK_YAMYAM &&
3010           element != EL_PACMAN)
3011       {
3012 #if 0
3013   if (element == EL_SPRING)
3014     printf("1--> %d\n", MovDir[x][y]);
3015 #endif
3016         TurnRound(x, y);
3017 #if 0
3018   if (element == EL_SPRING)
3019     printf("2--> %d\n", MovDir[x][y]);
3020 #endif
3021         if (MovDelay[x][y] && (element == EL_BUG ||
3022                                element == EL_SPACESHIP ||
3023                                element == EL_SP_SNIKSNAK ||
3024                                element == EL_SP_ELECTRON ||
3025                                element == EL_MOLE))
3026           DrawLevelField(x, y);
3027       }
3028     }
3029
3030     if (MovDelay[x][y])         /* wait some time before next movement */
3031     {
3032       MovDelay[x][y]--;
3033
3034       if (element == EL_ROBOT ||
3035           element == EL_YAMYAM || element == EL_DARK_YAMYAM)
3036       {
3037         if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3038         {
3039           int graphic = el2img(element);
3040           int frame = getGraphicAnimationFrame(graphic, MovDelay[x][y] % 8);
3041
3042           DrawGraphic(SCREENX(x), SCREENY(y), graphic, frame);
3043         }
3044
3045         if (MovDelay[x][y] % 4 == 3)
3046         {
3047           if (element == EL_YAMYAM)
3048             PlaySoundLevel(x, y, SND_YAMYAM_WAITING);
3049           else if (element == EL_DARK_YAMYAM)
3050             PlaySoundLevel(x, y, SND_DARK_YAMYAM_WAITING);
3051         }
3052       }
3053       else if (element == EL_SP_ELECTRON)
3054         DrawGraphicAnimation(SCREENX(x), SCREENY(y), IMG_SP_ELECTRON);
3055       else if (element == EL_DRAGON)
3056       {
3057         int i;
3058         int dir = MovDir[x][y];
3059         int dx = (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
3060         int dy = (dir == MV_UP   ? -1 : dir == MV_DOWN  ? +1 : 0);
3061         int graphic = (dir == MV_LEFT   ? IMG_FLAMES_LEFT1 :
3062                        dir == MV_RIGHT  ? IMG_FLAMES_RIGHT1 :
3063                        dir == MV_UP     ? IMG_FLAMES_UP1 :
3064                        dir == MV_DOWN   ? IMG_FLAMES_DOWN1 : IMG_EMPTY);
3065         int frame = getGraphicAnimationFrame(graphic, -1);
3066
3067         for (i=1; i<=3; i++)
3068         {
3069           int xx = x + i*dx, yy = y + i*dy;
3070           int sx = SCREENX(xx), sy = SCREENY(yy);
3071           int flame_graphic = graphic + (i - 1);
3072
3073           if (!IN_LEV_FIELD(xx, yy) ||
3074               IS_SOLID(Feld[xx][yy]) || Feld[xx][yy] == EL_EXPLOSION)
3075             break;
3076
3077           if (MovDelay[x][y])
3078           {
3079             int flamed = MovingOrBlocked2Element(xx, yy);
3080
3081             if (IS_ENEMY(flamed) || IS_EXPLOSIVE(flamed))
3082               Bang(xx, yy);
3083             else
3084               RemoveMovingField(xx, yy);
3085
3086             Feld[xx][yy] = EL_FLAMES;
3087             if (IN_SCR_FIELD(sx, sy))
3088               DrawGraphic(sx, sy, flame_graphic, frame);
3089           }
3090           else
3091           {
3092             if (Feld[xx][yy] == EL_FLAMES)
3093               Feld[xx][yy] = EL_EMPTY;
3094             DrawLevelField(xx, yy);
3095           }
3096         }
3097       }
3098
3099       if (MovDelay[x][y])       /* element still has to wait some time */
3100       {
3101         PlaySoundLevelAction(x, y, SND_ACTION_WAITING);
3102
3103         return;
3104       }
3105     }
3106
3107     /* now make next step */
3108
3109     Moving2Blocked(x, y, &newx, &newy); /* get next screen position */
3110
3111     if (IS_ENEMY(element) && IS_PLAYER(newx, newy) &&
3112         !PLAYER_PROTECTED(newx, newy))
3113     {
3114
3115 #if 1
3116       TestIfBadThingRunsIntoHero(x, y, MovDir[x][y]);
3117       return;
3118 #else
3119       /* enemy got the player */
3120       MovDir[x][y] = 0;
3121       KillHero(PLAYERINFO(newx, newy));
3122       return;
3123 #endif
3124
3125     }
3126     else if ((element == EL_PENGUIN || element == EL_ROBOT ||
3127               element == EL_SATELLITE || element == EL_BALLOON) &&
3128              IN_LEV_FIELD(newx, newy) &&
3129              MovDir[x][y] == MV_DOWN && Feld[newx][newy] == EL_ACID)
3130     {
3131       Blurb(x, y);
3132       Store[x][y] = EL_ACID;
3133     }
3134     else if (element == EL_PENGUIN && IN_LEV_FIELD(newx, newy))
3135     {
3136       if (Feld[newx][newy] == EL_EXIT_OPEN)
3137       {
3138         Feld[x][y] = EL_EMPTY;
3139         DrawLevelField(x, y);
3140
3141         PlaySoundLevel(newx, newy, SND_PENGUIN_PASSING_EXIT);
3142         if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
3143           DrawGraphicThruMask(SCREENX(newx),SCREENY(newy), el2img(element), 0);
3144
3145         local_player->friends_still_needed--;
3146         if (!local_player->friends_still_needed &&
3147             !local_player->GameOver && AllPlayersGone)
3148           local_player->LevelSolved = local_player->GameOver = TRUE;
3149
3150         return;
3151       }
3152       else if (IS_MAMPF3(Feld[newx][newy]))
3153       {
3154         if (DigField(local_player, newx, newy, 0, 0, DF_DIG) == MF_MOVING)
3155           DrawLevelField(newx, newy);
3156         else
3157           MovDir[x][y] = MV_NO_MOVING;
3158       }
3159       else if (!IS_FREE(newx, newy))
3160       {
3161         if (IS_PLAYER(x, y))
3162           DrawPlayerField(x, y);
3163         else
3164           DrawLevelField(x, y);
3165         return;
3166       }
3167     }
3168     else if (element == EL_PIG && IN_LEV_FIELD(newx, newy))
3169     {
3170       if (IS_GEM(Feld[newx][newy]))
3171       {
3172         if (IS_MOVING(newx, newy))
3173           RemoveMovingField(newx, newy);
3174         else
3175         {
3176           Feld[newx][newy] = EL_EMPTY;
3177           DrawLevelField(newx, newy);
3178         }
3179
3180         PlaySoundLevel(x, y, SND_PIG_EATING);
3181       }
3182       else if (!IS_FREE(newx, newy))
3183       {
3184         if (IS_PLAYER(x, y))
3185           DrawPlayerField(x, y);
3186         else
3187           DrawLevelField(x, y);
3188         return;
3189       }
3190     }
3191     else if (element == EL_DRAGON && IN_LEV_FIELD(newx, newy))
3192     {
3193       if (!IS_FREE(newx, newy))
3194       {
3195         if (IS_PLAYER(x, y))
3196           DrawPlayerField(x, y);
3197         else
3198           DrawLevelField(x, y);
3199         return;
3200       }
3201       else
3202       {
3203         boolean wanna_flame = !RND(10);
3204         int dx = newx - x, dy = newy - y;
3205         int newx1 = newx+1*dx, newy1 = newy+1*dy;
3206         int newx2 = newx+2*dx, newy2 = newy+2*dy;
3207         int element1 = (IN_LEV_FIELD(newx1, newy1) ?
3208                         MovingOrBlocked2Element(newx1, newy1) : EL_STEELWALL);
3209         int element2 = (IN_LEV_FIELD(newx2, newy2) ?
3210                         MovingOrBlocked2Element(newx2, newy2) : EL_STEELWALL);
3211
3212         if ((wanna_flame || IS_ENEMY(element1) || IS_ENEMY(element2)) &&
3213             element1 != EL_DRAGON && element2 != EL_DRAGON &&
3214             element1 != EL_FLAMES && element2 != EL_FLAMES)
3215         {
3216           if (IS_PLAYER(x, y))
3217             DrawPlayerField(x, y);
3218           else
3219             DrawLevelField(x, y);
3220
3221           PlaySoundLevel(x, y, SND_DRAGON_ATTACKING);
3222
3223           MovDelay[x][y] = 50;
3224           Feld[newx][newy] = EL_FLAMES;
3225           if (IN_LEV_FIELD(newx1, newy1) && Feld[newx1][newy1] == EL_EMPTY)
3226             Feld[newx1][newy1] = EL_FLAMES;
3227           if (IN_LEV_FIELD(newx2, newy2) && Feld[newx2][newy2] == EL_EMPTY)
3228             Feld[newx2][newy2] = EL_FLAMES;
3229           return;
3230         }
3231       }
3232     }
3233     else if (element == EL_YAMYAM && IN_LEV_FIELD(newx, newy) &&
3234              Feld[newx][newy] == EL_DIAMOND)
3235     {
3236       if (IS_MOVING(newx, newy))
3237         RemoveMovingField(newx, newy);
3238       else
3239       {
3240         Feld[newx][newy] = EL_EMPTY;
3241         DrawLevelField(newx, newy);
3242       }
3243
3244       PlaySoundLevel(x, y, SND_YAMYAM_EATING);
3245     }
3246     else if (element == EL_DARK_YAMYAM && IN_LEV_FIELD(newx, newy) &&
3247              IS_MAMPF2(Feld[newx][newy]))
3248     {
3249       if (AmoebaNr[newx][newy])
3250       {
3251         AmoebaCnt2[AmoebaNr[newx][newy]]--;
3252         if (Feld[newx][newy] == EL_AMOEBA_FULL ||
3253             Feld[newx][newy] == EL_BD_AMOEBA)
3254           AmoebaCnt[AmoebaNr[newx][newy]]--;
3255       }
3256
3257       if (IS_MOVING(newx, newy))
3258         RemoveMovingField(newx, newy);
3259       else
3260       {
3261         Feld[newx][newy] = EL_EMPTY;
3262         DrawLevelField(newx, newy);
3263       }
3264
3265       PlaySoundLevel(x, y, SND_DARK_YAMYAM_EATING);
3266     }
3267     else if ((element == EL_PACMAN || element == EL_MOLE)
3268              && IN_LEV_FIELD(newx, newy) && IS_AMOEBOID(Feld[newx][newy]))
3269     {
3270       if (AmoebaNr[newx][newy])
3271       {
3272         AmoebaCnt2[AmoebaNr[newx][newy]]--;
3273         if (Feld[newx][newy] == EL_AMOEBA_FULL ||
3274             Feld[newx][newy] == EL_BD_AMOEBA)
3275           AmoebaCnt[AmoebaNr[newx][newy]]--;
3276       }
3277
3278       if (element == EL_MOLE)
3279       {
3280         Feld[newx][newy] = EL_AMOEBA_SHRINKING;
3281         PlaySoundLevel(x, y, SND_MOLE_EATING);
3282         MovDelay[newx][newy] = 0;       /* start amoeba shrinking delay */
3283         return;                         /* wait for shrinking amoeba */
3284       }
3285       else      /* element == EL_PACMAN */
3286       {
3287         Feld[newx][newy] = EL_EMPTY;
3288         DrawLevelField(newx, newy);
3289         PlaySoundLevel(x, y, SND_PACMAN_EATING);
3290       }
3291     }
3292     else if (element == EL_MOLE && IN_LEV_FIELD(newx, newy) &&
3293              (Feld[newx][newy] == EL_AMOEBA_SHRINKING ||
3294               (Feld[newx][newy] == EL_EMPTY && Stop[newx][newy])))
3295     {
3296       /* wait for shrinking amoeba to completely disappear */
3297       return;
3298     }
3299     else if (!IN_LEV_FIELD(newx, newy) || !IS_FREE(newx, newy))
3300     {
3301       /* object was running against a wall */
3302
3303       TurnRound(x, y);
3304
3305       if (element == EL_BUG || element == EL_SPACESHIP ||
3306           element == EL_SP_SNIKSNAK)
3307         DrawLevelField(x, y);
3308       else if (element == EL_BUG || element == EL_SPACESHIP ||
3309                element == EL_SP_SNIKSNAK || element == EL_MOLE)
3310         DrawLevelField(x, y);
3311       else if (element == EL_BD_BUTTERFLY || element == EL_BD_FIREFLY)
3312         DrawGraphicAnimation(SCREENX(x), SCREENY(y), el2img(element));
3313       else if (element == EL_SATELLITE)
3314         DrawGraphicAnimation(SCREENX(x), SCREENY(y), IMG_SATELLITE);
3315       else if (element == EL_SP_ELECTRON)
3316         DrawGraphicAnimation(SCREENX(x), SCREENY(y), IMG_SP_ELECTRON);
3317
3318       if (DONT_TOUCH(element))
3319         TestIfBadThingTouchesHero(x, y);
3320
3321       PlaySoundLevelAction(x, y, SND_ACTION_WAITING);
3322
3323       return;
3324     }
3325
3326     InitMovingField(x, y, MovDir[x][y]);
3327
3328     PlaySoundLevelAction(x, y, SND_ACTION_MOVING);
3329   }
3330
3331   if (MovDir[x][y])
3332     ContinueMoving(x, y);
3333 }
3334
3335 void ContinueMoving(int x, int y)
3336 {
3337   int element = Feld[x][y];
3338   int direction = MovDir[x][y];
3339   int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
3340   int dy = (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
3341   int horiz_move = (dx != 0);
3342   int newx = x + dx, newy = y + dy;
3343   int step = (horiz_move ? dx : dy) * TILEX / 8;
3344
3345   if (element == EL_AMOEBA_DROP || element == EL_AMOEBA_DRIPPING)
3346     step /= 2;
3347   else if (element == EL_QUICKSAND_FILLING ||
3348            element == EL_QUICKSAND_EMPTYING)
3349     step /= 4;
3350   else if (element == EL_MAGIC_WALL_FILLING ||
3351            element == EL_BD_MAGIC_WALL_FILLING ||
3352            element == EL_MAGIC_WALL_EMPTYING ||
3353            element == EL_BD_MAGIC_WALL_EMPTYING)
3354     step /= 2;
3355   else if (CAN_FALL(element) && horiz_move &&
3356            y < lev_fieldy-1 && IS_BELT_ACTIVE(Feld[x][y+1]))
3357     step /= 2;
3358   else if (element == EL_SPRING && horiz_move)
3359     step *= 2;
3360
3361 #if OLD_GAME_BEHAVIOUR
3362   else if (CAN_FALL(element) && horiz_move && !IS_SP_ELEMENT(element))
3363     step*=2;
3364 #endif
3365
3366   MovPos[x][y] += step;
3367
3368   if (ABS(MovPos[x][y]) >= TILEX)       /* object reached its destination */
3369   {
3370     Feld[x][y] = EL_EMPTY;
3371     Feld[newx][newy] = element;
3372
3373     if (element == EL_MOLE)
3374     {
3375       int i;
3376       static int xy[4][2] =
3377       {
3378         { 0, -1 },
3379         { -1, 0 },
3380         { +1, 0 },
3381         { 0, +1 }
3382       };
3383
3384       Feld[x][y] = EL_SAND;
3385       DrawLevelField(x, y);
3386
3387       for(i=0; i<4; i++)
3388       {
3389         int xx, yy;
3390
3391         xx = x + xy[i][0];
3392         yy = y + xy[i][1];
3393
3394         if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == EL_SAND)
3395           DrawLevelField(xx, yy);       /* for "DrawCrumbledSand()" */
3396       }
3397     }
3398
3399     if (element == EL_QUICKSAND_FILLING)
3400     {
3401       element = Feld[newx][newy] = get_next_element(element);
3402       Store[newx][newy] = Store[x][y];
3403     }
3404     else if (element == EL_QUICKSAND_EMPTYING)
3405     {
3406       Feld[x][y] = get_next_element(element);
3407       element = Feld[newx][newy] = Store[x][y];
3408     }
3409     else if (element == EL_MAGIC_WALL_FILLING)
3410     {
3411       element = Feld[newx][newy] = get_next_element(element);
3412       if (!game.magic_wall_active)
3413         element = Feld[newx][newy] = EL_MAGIC_WALL_DEAD;
3414       Store[newx][newy] = Store[x][y];
3415     }
3416     else if (element == EL_MAGIC_WALL_EMPTYING)
3417     {
3418       Feld[x][y] = get_next_element(element);
3419       if (!game.magic_wall_active)
3420         Feld[x][y] = EL_MAGIC_WALL_DEAD;
3421       element = Feld[newx][newy] = Store[x][y];
3422     }
3423     else if (element == EL_BD_MAGIC_WALL_FILLING)
3424     {
3425       element = Feld[newx][newy] = get_next_element(element);
3426       if (!game.magic_wall_active)
3427         element = Feld[newx][newy] = EL_BD_MAGIC_WALL_DEAD;
3428       Store[newx][newy] = Store[x][y];
3429     }
3430     else if (element == EL_BD_MAGIC_WALL_EMPTYING)
3431     {
3432       Feld[x][y] = get_next_element(element);
3433       if (!game.magic_wall_active)
3434         Feld[x][y] = EL_BD_MAGIC_WALL_DEAD;
3435       element = Feld[newx][newy] = Store[x][y];
3436     }
3437     else if (element == EL_AMOEBA_DRIPPING)
3438     {
3439       Feld[x][y] = get_next_element(element);
3440       element = Feld[newx][newy] = Store[x][y];
3441     }
3442     else if (Store[x][y] == EL_ACID)
3443     {
3444       element = Feld[newx][newy] = EL_ACID;
3445     }
3446
3447     Store[x][y] = 0;
3448     MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
3449     MovDelay[newx][newy] = 0;
3450
3451     GfxAction[newx][newy] = GfxAction[x][y];    /* keep action one frame */
3452     GfxAction[x][y] = GFX_ACTION_DEFAULT;
3453
3454 #if 0
3455     if (!CAN_MOVE(element))
3456       MovDir[newx][newy] = 0;
3457 #else
3458     /*
3459     if (CAN_FALL(element) && MovDir[newx][newy] == MV_DOWN)
3460       MovDir[newx][newy] = 0;
3461     */
3462
3463     if (!CAN_MOVE(element) ||
3464         (element == EL_SPRING && MovDir[newx][newy] == MV_DOWN))
3465       MovDir[newx][newy] = 0;
3466 #endif
3467
3468     DrawLevelField(x, y);
3469     DrawLevelField(newx, newy);
3470
3471     Stop[newx][newy] = TRUE;
3472     JustStopped[newx][newy] = 3;
3473
3474     if (DONT_TOUCH(element))    /* object may be nasty to player or others */
3475     {
3476       TestIfBadThingTouchesHero(newx, newy);
3477       TestIfBadThingTouchesFriend(newx, newy);
3478       TestIfBadThingTouchesOtherBadThing(newx, newy);
3479     }
3480     else if (element == EL_PENGUIN)
3481       TestIfFriendTouchesBadThing(newx, newy);
3482
3483     if (CAN_SMASH(element) && direction == MV_DOWN &&
3484         (newy == lev_fieldy-1 || !IS_FREE(x, newy+1)))
3485       Impact(x, newy);
3486   }
3487   else                          /* still moving on */
3488   {
3489 #if 0
3490     if (GfxAction[x][y] == GFX_ACTION_DEFAULT)
3491     {
3492       printf("reset GfxAction...\n");
3493
3494       GfxAction[x][y] = GFX_ACTION_MOVING;
3495     }
3496 #endif
3497
3498     DrawLevelField(x, y);
3499   }
3500 }
3501
3502 int AmoebeNachbarNr(int ax, int ay)
3503 {
3504   int i;
3505   int element = Feld[ax][ay];
3506   int group_nr = 0;
3507   static int xy[4][2] =
3508   {
3509     { 0, -1 },
3510     { -1, 0 },
3511     { +1, 0 },
3512     { 0, +1 }
3513   };
3514
3515   for (i=0; i<4; i++)
3516   {
3517     int x = ax + xy[i][0];
3518     int y = ay + xy[i][1];
3519
3520     if (!IN_LEV_FIELD(x, y))
3521       continue;
3522
3523     if (Feld[x][y] == element && AmoebaNr[x][y] > 0)
3524       group_nr = AmoebaNr[x][y];
3525   }
3526
3527   return group_nr;
3528 }
3529
3530 void AmoebenVereinigen(int ax, int ay)
3531 {
3532   int i, x, y, xx, yy;
3533   int new_group_nr = AmoebaNr[ax][ay];
3534   static int xy[4][2] =
3535   {
3536     { 0, -1 },
3537     { -1, 0 },
3538     { +1, 0 },
3539     { 0, +1 }
3540   };
3541
3542   if (new_group_nr == 0)
3543     return;
3544
3545   for (i=0; i<4; i++)
3546   {
3547     x = ax + xy[i][0];
3548     y = ay + xy[i][1];
3549
3550     if (!IN_LEV_FIELD(x, y))
3551       continue;
3552
3553     if ((Feld[x][y] == EL_AMOEBA_FULL ||
3554          Feld[x][y] == EL_BD_AMOEBA ||
3555          Feld[x][y] == EL_AMOEBA_DEAD) &&
3556         AmoebaNr[x][y] != new_group_nr)
3557     {
3558       int old_group_nr = AmoebaNr[x][y];
3559
3560       if (old_group_nr == 0)
3561         return;
3562
3563       AmoebaCnt[new_group_nr] += AmoebaCnt[old_group_nr];
3564       AmoebaCnt[old_group_nr] = 0;
3565       AmoebaCnt2[new_group_nr] += AmoebaCnt2[old_group_nr];
3566       AmoebaCnt2[old_group_nr] = 0;
3567
3568       for (yy=0; yy<lev_fieldy; yy++)
3569       {
3570         for (xx=0; xx<lev_fieldx; xx++)
3571         {
3572           if (AmoebaNr[xx][yy] == old_group_nr)
3573             AmoebaNr[xx][yy] = new_group_nr;
3574         }
3575       }
3576     }
3577   }
3578 }
3579
3580 void AmoebeUmwandeln(int ax, int ay)
3581 {
3582   int i, x, y;
3583
3584   if (Feld[ax][ay] == EL_AMOEBA_DEAD)
3585   {
3586     int group_nr = AmoebaNr[ax][ay];
3587
3588 #ifdef DEBUG
3589     if (group_nr == 0)
3590     {
3591       printf("AmoebeUmwandeln(): ax = %d, ay = %d\n", ax, ay);
3592       printf("AmoebeUmwandeln(): This should never happen!\n");
3593       return;
3594     }
3595 #endif
3596
3597     for (y=0; y<lev_fieldy; y++)
3598     {
3599       for (x=0; x<lev_fieldx; x++)
3600       {
3601         if (Feld[x][y] == EL_AMOEBA_DEAD && AmoebaNr[x][y] == group_nr)
3602         {
3603           AmoebaNr[x][y] = 0;
3604           Feld[x][y] = EL_AMOEBA_TO_DIAMOND;
3605         }
3606       }
3607     }
3608     PlaySoundLevel(ax, ay, (IS_GEM(level.amoeba_content) ?
3609                             SND_AMOEBA_TURNING_TO_GEM :
3610                             SND_AMOEBA_TURNING_TO_ROCK));
3611     Bang(ax, ay);
3612   }
3613   else
3614   {
3615     static int xy[4][2] =
3616     {
3617       { 0, -1 },
3618       { -1, 0 },
3619       { +1, 0 },
3620       { 0, +1 }
3621     };
3622
3623     for (i=0; i<4; i++)
3624     {
3625       x = ax + xy[i][0];
3626       y = ay + xy[i][1];
3627
3628       if (!IN_LEV_FIELD(x, y))
3629         continue;
3630
3631       if (Feld[x][y] == EL_AMOEBA_TO_DIAMOND)
3632       {
3633         PlaySoundLevel(x, y, (IS_GEM(level.amoeba_content) ?
3634                               SND_AMOEBA_TURNING_TO_GEM :
3635                               SND_AMOEBA_TURNING_TO_ROCK));
3636         Bang(x, y);
3637       }
3638     }
3639   }
3640 }
3641
3642 void AmoebeUmwandelnBD(int ax, int ay, int new_element)
3643 {
3644   int x, y;
3645   int group_nr = AmoebaNr[ax][ay];
3646   boolean done = FALSE;
3647
3648 #ifdef DEBUG
3649   if (group_nr == 0)
3650   {
3651     printf("AmoebeUmwandelnBD(): ax = %d, ay = %d\n", ax, ay);
3652     printf("AmoebeUmwandelnBD(): This should never happen!\n");
3653     return;
3654   }
3655 #endif
3656
3657   for (y=0; y<lev_fieldy; y++)
3658   {
3659     for (x=0; x<lev_fieldx; x++)
3660     {
3661       if (AmoebaNr[x][y] == group_nr &&
3662           (Feld[x][y] == EL_AMOEBA_DEAD ||
3663            Feld[x][y] == EL_BD_AMOEBA ||
3664            Feld[x][y] == EL_AMOEBA_CREATING))
3665       {
3666         AmoebaNr[x][y] = 0;
3667         Feld[x][y] = new_element;
3668         InitField(x, y, FALSE);
3669         DrawLevelField(x, y);
3670         done = TRUE;
3671       }
3672     }
3673   }
3674
3675   if (done)
3676     PlaySoundLevel(ax, ay, (new_element == EL_BD_ROCK ?
3677                             SND_BD_AMOEBA_TURNING_TO_ROCK :
3678                             SND_BD_AMOEBA_TURNING_TO_GEM));
3679 }
3680
3681 void AmoebeWaechst(int x, int y)
3682 {
3683   static unsigned long sound_delay = 0;
3684   static unsigned long sound_delay_value = 0;
3685
3686   if (!MovDelay[x][y])          /* start new growing cycle */
3687   {
3688     MovDelay[x][y] = 7;
3689
3690     if (DelayReached(&sound_delay, sound_delay_value))
3691     {
3692       if (Store[x][y] == EL_BD_AMOEBA)
3693         PlaySoundLevel(x, y, SND_BD_AMOEBA_CREATING);
3694       else
3695         PlaySoundLevel(x, y, SND_AMOEBA_CREATING);
3696       sound_delay_value = 30;
3697     }
3698   }
3699
3700   if (MovDelay[x][y])           /* wait some time before growing bigger */
3701   {
3702     MovDelay[x][y]--;
3703     if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3704     {
3705       int frame = getGraphicAnimationFrame(IMG_AMOEBA_CREATING,
3706                                            6 - MovDelay[x][y]);
3707
3708       DrawGraphic(SCREENX(x), SCREENY(y), IMG_AMOEBA_CREATING, frame);
3709     }
3710
3711     if (!MovDelay[x][y])
3712     {
3713       Feld[x][y] = Store[x][y];
3714       Store[x][y] = 0;
3715       DrawLevelField(x, y);
3716     }
3717   }
3718 }
3719
3720 void AmoebaDisappearing(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 shrinking cycle */
3726   {
3727     MovDelay[x][y] = 7;
3728
3729     if (DelayReached(&sound_delay, sound_delay_value))
3730       sound_delay_value = 30;
3731   }
3732
3733   if (MovDelay[x][y])           /* wait some time before shrinking */
3734   {
3735     MovDelay[x][y]--;
3736     if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3737     {
3738       int frame = getGraphicAnimationFrame(IMG_AMOEBA_SHRINKING,
3739                                            6 - MovDelay[x][y]);
3740
3741       DrawGraphic(SCREENX(x), SCREENY(y), IMG_AMOEBA_SHRINKING, frame);
3742     }
3743
3744     if (!MovDelay[x][y])
3745     {
3746       Feld[x][y] = EL_EMPTY;
3747       DrawLevelField(x, y);
3748
3749       /* don't let mole enter this field in this cycle;
3750          (give priority to objects falling to this field from above) */
3751       Stop[x][y] = TRUE;
3752     }
3753   }
3754 }
3755
3756 void AmoebeAbleger(int ax, int ay)
3757 {
3758   int i;
3759   int element = Feld[ax][ay];
3760   int newax = ax, neway = ay;
3761   static int xy[4][2] =
3762   {
3763     { 0, -1 },
3764     { -1, 0 },
3765     { +1, 0 },
3766     { 0, +1 }
3767   };
3768
3769   if (!level.amoeba_speed)
3770   {
3771     Feld[ax][ay] = EL_AMOEBA_DEAD;
3772     DrawLevelField(ax, ay);
3773     return;
3774   }
3775
3776   if (!MovDelay[ax][ay])        /* start making new amoeba field */
3777     MovDelay[ax][ay] = RND(FRAMES_PER_SECOND * 25 / (1 + level.amoeba_speed));
3778
3779   if (MovDelay[ax][ay])         /* wait some time before making new amoeba */
3780   {
3781     MovDelay[ax][ay]--;
3782     if (MovDelay[ax][ay])
3783       return;
3784   }
3785
3786   if (element == EL_AMOEBA_WET) /* object is an acid / amoeba drop */
3787   {
3788     int start = RND(4);
3789     int x = ax + xy[start][0];
3790     int y = ay + xy[start][1];
3791
3792     if (!IN_LEV_FIELD(x, y))
3793       return;
3794
3795     if (IS_FREE(x, y) ||
3796         Feld[x][y] == EL_SAND || Feld[x][y] == EL_QUICKSAND_EMPTY)
3797     {
3798       newax = x;
3799       neway = y;
3800     }
3801
3802     if (newax == ax && neway == ay)
3803       return;
3804   }
3805   else                          /* normal or "filled" (BD style) amoeba */
3806   {
3807     int start = RND(4);
3808     boolean waiting_for_player = FALSE;
3809
3810     for (i=0; i<4; i++)
3811     {
3812       int j = (start + i) % 4;
3813       int x = ax + xy[j][0];
3814       int y = ay + xy[j][1];
3815
3816       if (!IN_LEV_FIELD(x, y))
3817         continue;
3818
3819       if (IS_FREE(x, y) ||
3820           Feld[x][y] == EL_SAND || Feld[x][y] == EL_QUICKSAND_EMPTY)
3821       {
3822         newax = x;
3823         neway = y;
3824         break;
3825       }
3826       else if (IS_PLAYER(x, y))
3827         waiting_for_player = TRUE;
3828     }
3829
3830     if (newax == ax && neway == ay)             /* amoeba cannot grow */
3831     {
3832       if (i == 4 && (!waiting_for_player || game.emulation == EMU_BOULDERDASH))
3833       {
3834         Feld[ax][ay] = EL_AMOEBA_DEAD;
3835         DrawLevelField(ax, ay);
3836         AmoebaCnt[AmoebaNr[ax][ay]]--;
3837
3838         if (AmoebaCnt[AmoebaNr[ax][ay]] <= 0)   /* amoeba is completely dead */
3839         {
3840           if (element == EL_AMOEBA_FULL)
3841             AmoebeUmwandeln(ax, ay);
3842           else if (element == EL_BD_AMOEBA)
3843             AmoebeUmwandelnBD(ax, ay, level.amoeba_content);
3844         }
3845       }
3846       return;
3847     }
3848     else if (element == EL_AMOEBA_FULL || element == EL_BD_AMOEBA)
3849     {
3850       /* amoeba gets larger by growing in some direction */
3851
3852       int new_group_nr = AmoebaNr[ax][ay];
3853
3854 #ifdef DEBUG
3855   if (new_group_nr == 0)
3856   {
3857     printf("AmoebeAbleger(): newax = %d, neway = %d\n", newax, neway);
3858     printf("AmoebeAbleger(): This should never happen!\n");
3859     return;
3860   }
3861 #endif
3862
3863       AmoebaNr[newax][neway] = new_group_nr;
3864       AmoebaCnt[new_group_nr]++;
3865       AmoebaCnt2[new_group_nr]++;
3866
3867       /* if amoeba touches other amoeba(s) after growing, unify them */
3868       AmoebenVereinigen(newax, neway);
3869
3870       if (element == EL_BD_AMOEBA && AmoebaCnt2[new_group_nr] >= 200)
3871       {
3872         AmoebeUmwandelnBD(newax, neway, EL_BD_ROCK);
3873         return;
3874       }
3875     }
3876   }
3877
3878   if (element != EL_AMOEBA_WET || neway < ay || !IS_FREE(newax, neway) ||
3879       (neway == lev_fieldy - 1 && newax != ax))
3880   {
3881     Feld[newax][neway] = EL_AMOEBA_CREATING;    /* creation of new amoeba */
3882     Store[newax][neway] = element;
3883   }
3884   else if (neway == ay)
3885   {
3886     Feld[newax][neway] = EL_AMOEBA_DROP;        /* drop left/right of amoeba */
3887     PlaySoundLevel(newax, neway, SND_AMOEBA_DROP_CREATING);
3888   }
3889   else
3890   {
3891     InitMovingField(ax, ay, MV_DOWN);           /* drop dripping from amoeba */
3892     Feld[ax][ay] = EL_AMOEBA_DRIPPING;
3893     Store[ax][ay] = EL_AMOEBA_DROP;
3894     ContinueMoving(ax, ay);
3895     return;
3896   }
3897
3898   DrawLevelField(newax, neway);
3899 }
3900
3901 void Life(int ax, int ay)
3902 {
3903   int x1, y1, x2, y2;
3904   static int life[4] = { 2, 3, 3, 3 };  /* parameters for "game of life" */
3905   int life_time = 40;
3906   int element = Feld[ax][ay];
3907   boolean changed = FALSE;
3908
3909   if (Stop[ax][ay])
3910     return;
3911
3912   if (!MovDelay[ax][ay])        /* start new "game of life" cycle */
3913     MovDelay[ax][ay] = life_time;
3914
3915   if (MovDelay[ax][ay])         /* wait some time before next cycle */
3916   {
3917     MovDelay[ax][ay]--;
3918     if (MovDelay[ax][ay])
3919       return;
3920   }
3921
3922   for (y1=-1; y1<2; y1++) for(x1=-1; x1<2; x1++)
3923   {
3924     int xx = ax+x1, yy = ay+y1;
3925     int nachbarn = 0;
3926
3927     if (!IN_LEV_FIELD(xx, yy))
3928       continue;
3929
3930     for (y2=-1; y2<2; y2++) for (x2=-1; x2<2; x2++)
3931     {
3932       int x = xx+x2, y = yy+y2;
3933
3934       if (!IN_LEV_FIELD(x, y) || (x == xx && y == yy))
3935         continue;
3936
3937       if (((Feld[x][y] == element ||
3938             (element == EL_GAMEOFLIFE && IS_PLAYER(x, y))) &&
3939            !Stop[x][y]) ||
3940           (IS_FREE(x, y) && Stop[x][y]))
3941         nachbarn++;
3942     }
3943
3944     if (xx == ax && yy == ay)           /* field in the middle */
3945     {
3946       if (nachbarn < life[0] || nachbarn > life[1])
3947       {
3948         Feld[xx][yy] = EL_EMPTY;
3949         if (!Stop[xx][yy])
3950           DrawLevelField(xx, yy);
3951         Stop[xx][yy] = TRUE;
3952         changed = TRUE;
3953       }
3954     }
3955     else if (IS_FREE(xx, yy) || Feld[xx][yy] == EL_SAND)
3956     {                                   /* free border field */
3957       if (nachbarn >= life[2] && nachbarn <= life[3])
3958       {
3959         Feld[xx][yy] = element;
3960         MovDelay[xx][yy] = (element == EL_GAMEOFLIFE ? 0 : life_time-1);
3961         if (!Stop[xx][yy])
3962           DrawLevelField(xx, yy);
3963         Stop[xx][yy] = TRUE;
3964         changed = TRUE;
3965       }
3966     }
3967   }
3968
3969   if (changed)
3970     PlaySoundLevel(ax, ay, element == EL_GAMEOFLIFE ? SND_GAMEOFLIFE_CREATING :
3971                    SND_BIOMAZE_CREATING);
3972 }
3973
3974 void RobotWheel(int x, int y)
3975 {
3976   if (!MovDelay[x][y])          /* next animation frame */
3977     MovDelay[x][y] = level.time_wheel * FRAMES_PER_SECOND;
3978
3979   if (MovDelay[x][y])           /* wait some time before next frame */
3980   {
3981     MovDelay[x][y]--;
3982     if (MovDelay[x][y])
3983     {
3984       if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3985       {
3986         int frame = getGraphicAnimationFrame(IMG_ROBOT_WHEEL_ACTIVE, -1);
3987
3988         DrawGraphic(SCREENX(x), SCREENY(y), IMG_ROBOT_WHEEL_ACTIVE, frame);
3989       }
3990
3991       PlaySoundLevel(x, y, SND_ROBOT_WHEEL_ACTIVE);
3992
3993       return;
3994     }
3995   }
3996
3997   Feld[x][y] = EL_ROBOT_WHEEL;
3998   DrawLevelField(x, y);
3999
4000   if (ZX == x && ZY == y)
4001     ZX = ZY = -1;
4002 }
4003
4004 void TimegateWheel(int x, int y)
4005 {
4006   if (!MovDelay[x][y])          /* next animation frame */
4007     MovDelay[x][y] = level.time_wheel * FRAMES_PER_SECOND;
4008
4009   if (MovDelay[x][y])           /* wait some time before next frame */
4010   {
4011     MovDelay[x][y]--;
4012     if (MovDelay[x][y])
4013     {
4014       if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
4015       {
4016         int frame = getGraphicAnimationFrame(IMG_TIMEGATE_SWITCH_ACTIVE, -1);
4017
4018         DrawGraphic(SCREENX(x), SCREENY(y), IMG_TIMEGATE_SWITCH_ACTIVE, frame);
4019       }
4020
4021       PlaySoundLevel(x, y, SND_TIMEGATE_SWITCH_ACTIVE);
4022
4023       return;
4024     }
4025   }
4026
4027   Feld[x][y] = EL_TIMEGATE_SWITCH;
4028   DrawLevelField(x, y);
4029
4030   /* !!! THIS LOOKS WRONG !!! */
4031   if (ZX == x && ZY == y)
4032     ZX = ZY = -1;
4033 }
4034
4035 void NussKnacken(int x, int y)
4036 {
4037   if (!MovDelay[x][y])          /* next animation frame */
4038     MovDelay[x][y] = 7;
4039
4040   if (MovDelay[x][y])           /* wait some time before next frame */
4041   {
4042     MovDelay[x][y]--;
4043     if (MovDelay[x][y])
4044     {
4045       if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
4046       {
4047         int frame = getGraphicAnimationFrame(IMG_NUT_CRACKING,
4048                                              6 - MovDelay[x][y]);
4049
4050         DrawGraphic(SCREENX(x), SCREENY(y), IMG_NUT_CRACKING, frame);
4051       }
4052
4053       return;
4054     }
4055   }
4056
4057   Feld[x][y] = EL_EMERALD;
4058   DrawLevelField(x, y);
4059 }
4060
4061 void BreakingPearl(int x, int y)
4062 {
4063   if (!MovDelay[x][y])          /* next animation frame */
4064     MovDelay[x][y] = 9;
4065
4066   if (MovDelay[x][y])           /* wait some time before next frame */
4067   {
4068     MovDelay[x][y]--;
4069     if (MovDelay[x][y])
4070     {
4071       if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
4072       {
4073         int frame = getGraphicAnimationFrame(IMG_PEARL_BREAKING,
4074                                              8 - MovDelay[x][y]);
4075
4076         DrawGraphic(SCREENX(x), SCREENY(y), IMG_PEARL_BREAKING, frame);
4077       }
4078
4079       return;
4080     }
4081   }
4082
4083   Feld[x][y] = EL_EMPTY;
4084   DrawLevelField(x, y);
4085 }
4086
4087 void SiebAktivieren(int x, int y, int type)
4088 {
4089   int graphic = (type == 1 ? IMG_MAGIC_WALL_FULL : IMG_BD_MAGIC_WALL_FULL);
4090
4091   DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
4092 }
4093
4094 void AusgangstuerPruefen(int x, int y)
4095 {
4096   if (local_player->gems_still_needed > 0 ||
4097       local_player->sokobanfields_still_needed > 0 ||
4098       local_player->lights_still_needed > 0)
4099     return;
4100
4101   Feld[x][y] = EL_EXIT_OPENING;
4102
4103   PlaySoundLevel(x < LEVELX(BX1) ? LEVELX(BX1) :
4104                  (x > LEVELX(BX2) ? LEVELX(BX2) : x),
4105                  y < LEVELY(BY1) ? LEVELY(BY1) :
4106                  (y > LEVELY(BY2) ? LEVELY(BY2) : y),
4107                  SND_EXIT_OPENING);
4108 }
4109
4110 void AusgangstuerPruefen_SP(int x, int y)
4111 {
4112   if (local_player->gems_still_needed > 0)
4113     return;
4114
4115   Feld[x][y] = EL_SP_EXIT_OPEN;
4116
4117   PlaySoundLevel(x < LEVELX(BX1) ? LEVELX(BX1) :
4118                  (x > LEVELX(BX2) ? LEVELX(BX2) : x),
4119                  y < LEVELY(BY1) ? LEVELY(BY1) :
4120                  (y > LEVELY(BY2) ? LEVELY(BY2) : y),
4121                  SND_SP_EXIT_OPENING);
4122 }
4123
4124 void AusgangstuerOeffnen(int x, int y)
4125 {
4126   int delay = 6;
4127
4128   if (!MovDelay[x][y])          /* next animation frame */
4129     MovDelay[x][y] = 5 * delay;
4130
4131   if (MovDelay[x][y])           /* wait some time before next frame */
4132   {
4133     int tuer;
4134
4135     MovDelay[x][y]--;
4136     tuer = MovDelay[x][y] / delay;
4137
4138     if (!(MovDelay[x][y] % delay))
4139     {
4140       if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
4141       {
4142         int frame = getGraphicAnimationFrame(IMG_EXIT_OPENING,
4143                                              29 - MovDelay[x][y]);
4144
4145         DrawGraphic(SCREENX(x), SCREENY(y), IMG_EXIT_OPENING, frame);
4146       }
4147     }
4148
4149     if (MovDelay[x][y])
4150       return;
4151   }
4152
4153   Feld[x][y] = EL_EXIT_OPEN;
4154   DrawLevelField(x, y);
4155 }
4156
4157 void OpenSwitchgate(int x, int y)
4158 {
4159   int delay = 6;
4160
4161   if (!MovDelay[x][y])          /* next animation frame */
4162     MovDelay[x][y] = 5 * delay;
4163
4164   if (MovDelay[x][y])           /* wait some time before next frame */
4165   {
4166     MovDelay[x][y]--;
4167
4168     if (!(MovDelay[x][y] % delay))
4169     {
4170       if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
4171       {
4172         int frame = getGraphicAnimationFrame(IMG_SWITCHGATE_OPENING,
4173                                              29 - MovDelay[x][y]);
4174
4175         DrawGraphic(SCREENX(x), SCREENY(y), IMG_SWITCHGATE_OPENING, frame);
4176       }
4177     }
4178
4179     if (MovDelay[x][y])
4180       return;
4181   }
4182
4183   Feld[x][y] = EL_SWITCHGATE_OPEN;
4184   DrawLevelField(x, y);
4185 }
4186
4187 void CloseSwitchgate(int x, int y)
4188 {
4189   int delay = 6;
4190
4191   if (!MovDelay[x][y])          /* next animation frame */
4192     MovDelay[x][y] = 5 * delay;
4193
4194   if (MovDelay[x][y])           /* wait some time before next frame */
4195   {
4196     MovDelay[x][y]--;
4197
4198     if (!(MovDelay[x][y] % delay))
4199     {
4200       if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
4201       {
4202         int frame = getGraphicAnimationFrame(IMG_SWITCHGATE_CLOSING,
4203                                              29 - MovDelay[x][y]);
4204
4205         DrawGraphic(SCREENX(x), SCREENY(y), IMG_SWITCHGATE_CLOSING, frame);
4206       }
4207     }
4208
4209     if (MovDelay[x][y])
4210       return;
4211   }
4212
4213   Feld[x][y] = EL_SWITCHGATE_CLOSED;
4214   DrawLevelField(x, y);
4215 }
4216
4217 void OpenTimegate(int x, int y)
4218 {
4219   int delay = 6;
4220
4221   if (!MovDelay[x][y])          /* next animation frame */
4222     MovDelay[x][y] = 5 * delay;
4223
4224   if (MovDelay[x][y])           /* wait some time before next frame */
4225   {
4226     MovDelay[x][y]--;
4227
4228     if (!(MovDelay[x][y] % delay))
4229     {
4230       if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
4231       {
4232         int frame = getGraphicAnimationFrame(IMG_TIMEGATE_OPENING,
4233                                              29 - MovDelay[x][y]);
4234
4235         DrawGraphic(SCREENX(x), SCREENY(y), IMG_TIMEGATE_OPENING, frame);
4236       }
4237     }
4238
4239     if (MovDelay[x][y])
4240       return;
4241   }
4242
4243   Feld[x][y] = EL_TIMEGATE_OPEN;
4244   DrawLevelField(x, y);
4245 }
4246
4247 void CloseTimegate(int x, int y)
4248 {
4249   int delay = 6;
4250
4251   if (!MovDelay[x][y])          /* next animation frame */
4252     MovDelay[x][y] = 5 * delay;
4253
4254   if (MovDelay[x][y])           /* wait some time before next frame */
4255   {
4256     MovDelay[x][y]--;
4257
4258     if (!(MovDelay[x][y] % delay))
4259     {
4260       if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
4261       {
4262         int frame = getGraphicAnimationFrame(IMG_TIMEGATE_CLOSING,
4263                                              29 - MovDelay[x][y]);
4264
4265         DrawGraphic(SCREENX(x), SCREENY(y), IMG_TIMEGATE_CLOSING, frame);
4266       }
4267     }
4268
4269     if (MovDelay[x][y])
4270       return;
4271   }
4272
4273   Feld[x][y] = EL_TIMEGATE_CLOSED;
4274   DrawLevelField(x, y);
4275 }
4276
4277 static void CloseAllOpenTimegates()
4278 {
4279   int x, y;
4280
4281   for (y=0; y<lev_fieldy; y++)
4282   {
4283     for (x=0; x<lev_fieldx; x++)
4284     {
4285       int element = Feld[x][y];
4286
4287       if (element == EL_TIMEGATE_OPEN || element == EL_TIMEGATE_OPENING)
4288       {
4289         Feld[x][y] = EL_TIMEGATE_CLOSING;
4290         PlaySoundLevel(x, y, SND_TIMEGATE_CLOSING);
4291       }
4292     }
4293   }
4294 }
4295
4296 void EdelsteinFunkeln(int x, int y)
4297 {
4298   if (!IN_SCR_FIELD(SCREENX(x), SCREENY(y)) || IS_MOVING(x, y))
4299     return;
4300
4301   if (Feld[x][y] == EL_BD_DIAMOND)
4302     DrawGraphicAnimation(SCREENX(x), SCREENY(y), IMG_BD_DIAMOND);
4303   else
4304   {
4305     if (!MovDelay[x][y])        /* next animation frame */
4306       MovDelay[x][y] = 11 * !SimpleRND(500);
4307
4308     if (MovDelay[x][y])         /* wait some time before next frame */
4309     {
4310       MovDelay[x][y]--;
4311
4312       if (setup.direct_draw && MovDelay[x][y])
4313         SetDrawtoField(DRAW_BUFFERED);
4314
4315 #if 0
4316       DrawGraphic(SCREENX(x), SCREENY(y), el2img(Feld[x][y]), 0);
4317 #else
4318       DrawGraphicAnimation(SCREENX(x), SCREENY(y), el2img(Feld[x][y]));
4319 #endif
4320
4321       if (MovDelay[x][y])
4322       {
4323         int frame = getGraphicAnimationFrame(IMG_TWINKLE_WHITE,
4324                                              10 - MovDelay[x][y]);
4325
4326         DrawGraphicThruMask(SCREENX(x), SCREENY(y), IMG_TWINKLE_WHITE, frame);
4327
4328         if (setup.direct_draw)
4329         {
4330           int dest_x, dest_y;
4331
4332           dest_x = FX + SCREENX(x) * TILEX;
4333           dest_y = FY + SCREENY(y) * TILEY;
4334
4335           BlitBitmap(drawto_field, window,
4336                      dest_x, dest_y, TILEX, TILEY, dest_x, dest_y);
4337           SetDrawtoField(DRAW_DIRECT);
4338         }
4339       }
4340     }
4341   }
4342 }
4343
4344 void MauerWaechst(int x, int y)
4345 {
4346   int delay = 6;
4347
4348   if (!MovDelay[x][y])          /* next animation frame */
4349     MovDelay[x][y] = 3 * delay;
4350
4351   if (MovDelay[x][y])           /* wait some time before next frame */
4352   {
4353     MovDelay[x][y]--;
4354
4355     if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
4356     {
4357       int graphic = el_dir2img(Feld[x][y], MovDir[x][y]);
4358       int frame = getGraphicAnimationFrame(graphic, 17 - MovDelay[x][y]);
4359
4360       DrawGraphic(SCREENX(x), SCREENY(y), graphic, frame);
4361     }
4362
4363     if (!MovDelay[x][y])
4364     {
4365       if (MovDir[x][y] == MV_LEFT)
4366       {
4367         if (IN_LEV_FIELD(x - 1, y) && IS_MAUER(Feld[x - 1][y]))
4368           DrawLevelField(x - 1, y);
4369       }
4370       else if (MovDir[x][y] == MV_RIGHT)
4371       {
4372         if (IN_LEV_FIELD(x + 1, y) && IS_MAUER(Feld[x + 1][y]))
4373           DrawLevelField(x + 1, y);
4374       }
4375       else if (MovDir[x][y] == MV_UP)
4376       {
4377         if (IN_LEV_FIELD(x, y - 1) && IS_MAUER(Feld[x][y - 1]))
4378           DrawLevelField(x, y - 1);
4379       }
4380       else
4381       {
4382         if (IN_LEV_FIELD(x, y + 1) && IS_MAUER(Feld[x][y + 1]))
4383           DrawLevelField(x, y + 1);
4384       }
4385
4386       Feld[x][y] = Store[x][y];
4387       Store[x][y] = 0;
4388       MovDir[x][y] = MV_NO_MOVING;
4389       DrawLevelField(x, y);
4390     }
4391   }
4392 }
4393
4394 void MauerAbleger(int ax, int ay)
4395 {
4396   int element = Feld[ax][ay];
4397   boolean oben_frei = FALSE, unten_frei = FALSE;
4398   boolean links_frei = FALSE, rechts_frei = FALSE;
4399   boolean oben_massiv = FALSE, unten_massiv = FALSE;
4400   boolean links_massiv = FALSE, rechts_massiv = FALSE;
4401   boolean new_wall = FALSE;
4402
4403   if (!MovDelay[ax][ay])        /* start building new wall */
4404     MovDelay[ax][ay] = 6;
4405
4406   if (MovDelay[ax][ay])         /* wait some time before building new wall */
4407   {
4408     MovDelay[ax][ay]--;
4409     if (MovDelay[ax][ay])
4410       return;
4411   }
4412
4413   if (IN_LEV_FIELD(ax, ay-1) && IS_FREE(ax, ay-1))
4414     oben_frei = TRUE;
4415   if (IN_LEV_FIELD(ax, ay+1) && IS_FREE(ax, ay+1))
4416     unten_frei = TRUE;
4417   if (IN_LEV_FIELD(ax-1, ay) && IS_FREE(ax-1, ay))
4418     links_frei = TRUE;
4419   if (IN_LEV_FIELD(ax+1, ay) && IS_FREE(ax+1, ay))
4420     rechts_frei = TRUE;
4421
4422   if (element == EL_WALL_GROWING_Y || element == EL_WALL_GROWING_XY)
4423   {
4424     if (oben_frei)
4425     {
4426       Feld[ax][ay-1] = EL_WALL_GROWING_ACTIVE;
4427       Store[ax][ay-1] = element;
4428       MovDir[ax][ay-1] = MV_UP;
4429       if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay-1)))
4430         DrawGraphic(SCREENX(ax), SCREENY(ay - 1),
4431                     IMG_WALL_GROWING_ACTIVE_UP, 0);
4432       new_wall = TRUE;
4433     }
4434     if (unten_frei)
4435     {
4436       Feld[ax][ay+1] = EL_WALL_GROWING_ACTIVE;
4437       Store[ax][ay+1] = element;
4438       MovDir[ax][ay+1] = MV_DOWN;
4439       if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay+1)))
4440         DrawGraphic(SCREENX(ax), SCREENY(ay + 1),
4441                     IMG_WALL_GROWING_ACTIVE_DOWN, 0);
4442       new_wall = TRUE;
4443     }
4444   }
4445
4446   if (element == EL_WALL_GROWING_X || element == EL_WALL_GROWING_XY ||
4447       element == EL_WALL_GROWING)
4448   {
4449     if (links_frei)
4450     {
4451       Feld[ax-1][ay] = EL_WALL_GROWING_ACTIVE;
4452       Store[ax-1][ay] = element;
4453       MovDir[ax-1][ay] = MV_LEFT;
4454       if (IN_SCR_FIELD(SCREENX(ax-1), SCREENY(ay)))
4455         DrawGraphic(SCREENX(ax - 1), SCREENY(ay),
4456                     IMG_WALL_GROWING_ACTIVE_LEFT, 0);
4457       new_wall = TRUE;
4458     }
4459
4460     if (rechts_frei)
4461     {
4462       Feld[ax+1][ay] = EL_WALL_GROWING_ACTIVE;
4463       Store[ax+1][ay] = element;
4464       MovDir[ax+1][ay] = MV_RIGHT;
4465       if (IN_SCR_FIELD(SCREENX(ax+1), SCREENY(ay)))
4466         DrawGraphic(SCREENX(ax + 1), SCREENY(ay),
4467                     IMG_WALL_GROWING_ACTIVE_RIGHT, 0);
4468       new_wall = TRUE;
4469     }
4470   }
4471
4472   if (element == EL_WALL_GROWING && (links_frei || rechts_frei))
4473     DrawLevelField(ax, ay);
4474
4475   if (!IN_LEV_FIELD(ax, ay-1) || IS_MAUER(Feld[ax][ay-1]))
4476     oben_massiv = TRUE;
4477   if (!IN_LEV_FIELD(ax, ay+1) || IS_MAUER(Feld[ax][ay+1]))
4478     unten_massiv = TRUE;
4479   if (!IN_LEV_FIELD(ax-1, ay) || IS_MAUER(Feld[ax-1][ay]))
4480     links_massiv = TRUE;
4481   if (!IN_LEV_FIELD(ax+1, ay) || IS_MAUER(Feld[ax+1][ay]))
4482     rechts_massiv = TRUE;
4483
4484   if (((oben_massiv && unten_massiv) ||
4485        element == EL_WALL_GROWING_X || element == EL_WALL_GROWING) &&
4486       ((links_massiv && rechts_massiv) ||
4487        element == EL_WALL_GROWING_Y))
4488     Feld[ax][ay] = EL_WALL;
4489
4490   if (new_wall)
4491     PlaySoundLevel(ax, ay, SND_WALL_GROWING);
4492 }
4493
4494 void CheckForDragon(int x, int y)
4495 {
4496   int i, j;
4497   boolean dragon_found = FALSE;
4498   static int xy[4][2] =
4499   {
4500     { 0, -1 },
4501     { -1, 0 },
4502     { +1, 0 },
4503     { 0, +1 }
4504   };
4505
4506   for (i=0; i<4; i++)
4507   {
4508     for (j=0; j<4; j++)
4509     {
4510       int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
4511
4512       if (IN_LEV_FIELD(xx, yy) &&
4513           (Feld[xx][yy] == EL_FLAMES || Feld[xx][yy] == EL_DRAGON))
4514       {
4515         if (Feld[xx][yy] == EL_DRAGON)
4516           dragon_found = TRUE;
4517       }
4518       else
4519         break;
4520     }
4521   }
4522
4523   if (!dragon_found)
4524   {
4525     for (i=0; i<4; i++)
4526     {
4527       for (j=0; j<3; j++)
4528       {
4529         int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
4530   
4531         if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == EL_FLAMES)
4532         {
4533           Feld[xx][yy] = EL_EMPTY;
4534           DrawLevelField(xx, yy);
4535         }
4536         else
4537           break;
4538       }
4539     }
4540   }
4541 }
4542
4543 static void CheckBuggyBase(int x, int y)
4544 {
4545   int element = Feld[x][y];
4546
4547   if (element == EL_SP_BUGGY_BASE)
4548   {
4549     if (!MovDelay[x][y])        /* wait some time before activating base */
4550       MovDelay[x][y] = 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND);
4551
4552     if (MovDelay[x][y])
4553     {
4554       MovDelay[x][y]--;
4555       if (MovDelay[x][y] < 5 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
4556         DrawGraphic(SCREENX(x), SCREENY(y), IMG_SP_BUGGY_BASE, 0);
4557       if (MovDelay[x][y])
4558         return;
4559
4560       Feld[x][y] = EL_SP_BUGGY_BASE_ACTIVE;
4561     }
4562   }
4563   else if (element == EL_SP_BUGGY_BASE_ACTIVE)
4564   {
4565     if (!MovDelay[x][y])        /* start activating buggy base */
4566       MovDelay[x][y] = 1 * FRAMES_PER_SECOND + RND(1 * FRAMES_PER_SECOND);
4567
4568     if (MovDelay[x][y])
4569     {
4570       MovDelay[x][y]--;
4571       if (MovDelay[x][y])
4572       {
4573         int i;
4574         static int xy[4][2] =
4575         {
4576           { 0, -1 },
4577           { -1, 0 },
4578           { +1, 0 },
4579           { 0, +1 }
4580         };
4581
4582         if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
4583         {
4584           int graphic = IMG_SP_BUGGY_BASE_ACTIVE;
4585           int frame = getGraphicAnimationFrame(graphic, SimpleRND(100));
4586
4587           DrawGraphic(SCREENX(x), SCREENY(y), graphic, frame);
4588         }
4589
4590         for (i=0; i<4; i++)
4591         {
4592           int xx = x + xy[i][0], yy = y + xy[i][1];
4593
4594           if (IS_PLAYER(xx, yy))
4595           {
4596             PlaySoundLevel(x, y, SND_SP_BUGGY_BASE_ACTIVE);
4597             break;
4598           }
4599         }
4600
4601         return;
4602       }
4603
4604       Feld[x][y] = EL_SP_BUGGY_BASE;
4605       DrawLevelField(x, y);
4606     }
4607   }
4608 }
4609
4610 static void CheckTrap(int x, int y)
4611 {
4612   int element = Feld[x][y];
4613
4614   if (element == EL_TRAP)
4615   {
4616     if (!MovDelay[x][y])        /* wait some time before activating trap */
4617       MovDelay[x][y] = 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND);
4618
4619     if (MovDelay[x][y])
4620     {
4621       MovDelay[x][y]--;
4622       if (MovDelay[x][y])
4623         return;
4624
4625       Feld[x][y] = EL_TRAP_ACTIVE;
4626       PlaySoundLevel(x, y, SND_TRAP_ACTIVATING);
4627     }
4628   }
4629   else if (element == EL_TRAP_ACTIVE)
4630   {
4631     int delay = 4;
4632     int num_frames = 8;
4633
4634     if (!MovDelay[x][y])        /* start activating trap */
4635       MovDelay[x][y] = num_frames * delay;
4636
4637     if (MovDelay[x][y])
4638     {
4639       MovDelay[x][y]--;
4640
4641       if (MovDelay[x][y])
4642       {
4643         if (!(MovDelay[x][y] % delay))
4644         {
4645           if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
4646           {
4647             int graphic = IMG_TRAP_ACTIVE;
4648             int frame = getGraphicAnimationFrame(graphic, 31 - MovDelay[x][y]);
4649
4650             DrawGraphic(SCREENX(x),SCREENY(y), graphic, frame);
4651             DrawCrumbledSand(SCREENX(x), SCREENY(y));
4652           }
4653         }
4654
4655         return;
4656       }
4657
4658       Feld[x][y] = EL_TRAP;
4659       DrawLevelField(x, y);
4660     }
4661   }
4662 }
4663
4664 static void DrawBeltAnimation(int x, int y, int element)
4665 {
4666   int belt_nr = getBeltNrFromBeltActiveElement(element);
4667   int belt_dir = game.belt_dir[belt_nr];
4668
4669   if (belt_dir != MV_NO_MOVING)
4670   {
4671     int graphic = el2img(element);
4672
4673     DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
4674
4675     if (!(FrameCounter % 2))
4676       PlaySoundLevel(x, y, SND_CONVEYOR_BELT_ACTIVE);
4677   }
4678 }
4679
4680 static void PlayerActions(struct PlayerInfo *player, byte player_action)
4681 {
4682   static byte stored_player_action[MAX_PLAYERS];
4683   static int num_stored_actions = 0;
4684 #if 0
4685   static boolean save_tape_entry = FALSE;
4686 #endif
4687   boolean moved = FALSE, snapped = FALSE, bombed = FALSE;
4688   int left      = player_action & JOY_LEFT;
4689   int right     = player_action & JOY_RIGHT;
4690   int up        = player_action & JOY_UP;
4691   int down      = player_action & JOY_DOWN;
4692   int button1   = player_action & JOY_BUTTON_1;
4693   int button2   = player_action & JOY_BUTTON_2;
4694   int dx        = (left ? -1    : right ? 1     : 0);
4695   int dy        = (up   ? -1    : down  ? 1     : 0);
4696
4697   stored_player_action[player->index_nr] = 0;
4698   num_stored_actions++;
4699
4700   if (!player->active || tape.pausing)
4701     return;
4702
4703   if (player_action)
4704   {
4705 #if 0
4706     save_tape_entry = TRUE;
4707 #endif
4708     player->frame_reset_delay = 0;
4709
4710     if (button1)
4711       snapped = SnapField(player, dx, dy);
4712     else
4713     {
4714       if (button2)
4715         bombed = PlaceBomb(player);
4716       moved = MoveFigure(player, dx, dy);
4717     }
4718
4719     if (tape.single_step && tape.recording && !tape.pausing)
4720     {
4721       if (button1 || (bombed && !moved))
4722       {
4723         TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
4724         SnapField(player, 0, 0);                /* stop snapping */
4725       }
4726     }
4727
4728 #if 0
4729     if (tape.recording && (moved || snapped || bombed))
4730     {
4731       if (bombed && !moved)
4732         player_action &= JOY_BUTTON;
4733
4734       stored_player_action[player->index_nr] = player_action;
4735       save_tape_entry = TRUE;
4736     }
4737     else if (tape.playing && snapped)
4738       SnapField(player, 0, 0);                  /* stop snapping */
4739 #else
4740     stored_player_action[player->index_nr] = player_action;
4741 #endif
4742   }
4743   else
4744   {
4745     /* no actions for this player (no input at player's configured device) */
4746
4747     DigField(player, 0, 0, 0, 0, DF_NO_PUSH);
4748     SnapField(player, 0, 0);
4749     CheckGravityMovement(player);
4750
4751 #if 1
4752     if (player->MovPos == 0)    /* needed for tape.playing */
4753       player->is_moving = FALSE;
4754 #endif
4755 #if 0
4756     if (player->MovPos == 0)    /* needed for tape.playing */
4757       player->last_move_dir = MV_NO_MOVING;
4758
4759     /* !!! CHECK THIS AGAIN !!!
4760        (Seems to be needed for some EL_ROBOT stuff, but breaks
4761        tapes when walking through pipes!)
4762     */
4763
4764     /* it seems that "player->last_move_dir" is misused as some sort of
4765        "player->is_just_moving_in_this_moment", which is needed for the
4766        robot stuff (robots don't kill players when they are moving)
4767     */
4768 #endif 
4769
4770     /* if the player does not move for some time, reset animation to start */
4771     if (++player->frame_reset_delay > player->move_delay_value)
4772       player->Frame = 0;
4773   }
4774
4775 #if 0
4776   if (tape.recording && num_stored_actions >= MAX_PLAYERS && save_tape_entry)
4777   {
4778     TapeRecordAction(stored_player_action);
4779     num_stored_actions = 0;
4780     save_tape_entry = FALSE;
4781   }
4782 #else
4783   if (tape.recording && num_stored_actions >= MAX_PLAYERS)
4784   {
4785     TapeRecordAction(stored_player_action);
4786     num_stored_actions = 0;
4787   }
4788 #endif
4789
4790 #if 0
4791   if (tape.playing && !tape.pausing && !player_action &&
4792       tape.counter < tape.length)
4793   {
4794     int jx = player->jx, jy = player->jy;
4795     int next_joy =
4796       tape.pos[tape.counter].action[player->index_nr] & (JOY_LEFT|JOY_RIGHT);
4797
4798     if ((next_joy == JOY_LEFT || next_joy == JOY_RIGHT) &&
4799         (player->MovDir != JOY_UP && player->MovDir != JOY_DOWN))
4800     {
4801       int dx = (next_joy == JOY_LEFT ? -1 : +1);
4802
4803       if (IN_LEV_FIELD(jx+dx, jy) && IS_PUSHABLE(Feld[jx+dx][jy]))
4804       {
4805         int el = Feld[jx+dx][jy];
4806         int push_delay = (IS_SB_ELEMENT(el) || el == EL_SATELLITE ? 2 :
4807                           (el == EL_BALLOON || el == EL_SPRING) ? 0 : 10);
4808
4809         if (tape.delay_played + push_delay >= tape.pos[tape.counter].delay)
4810         {
4811           player->MovDir = next_joy;
4812           player->Frame = FrameCounter % 4;
4813           player->Pushing = TRUE;
4814         }
4815       }
4816     }
4817   }
4818 #endif
4819 }
4820
4821 void GameActions()
4822 {
4823   static unsigned long action_delay = 0;
4824   unsigned long action_delay_value;
4825   int sieb_x = 0, sieb_y = 0;
4826   int i, x, y, element, graphic;
4827   byte *recorded_player_action;
4828   byte summarized_player_action = 0;
4829
4830   if (game_status != PLAYING)
4831     return;
4832
4833   action_delay_value =
4834     (tape.playing && tape.fast_forward ? FfwdFrameDelay : GameFrameDelay);
4835
4836   if (tape.playing && tape.index_search && !tape.pausing)
4837     action_delay_value = 0;
4838
4839   /* ---------- main game synchronization point ---------- */
4840
4841   WaitUntilDelayReached(&action_delay, action_delay_value);
4842
4843   if (network_playing && !network_player_action_received)
4844   {
4845     /*
4846 #ifdef DEBUG
4847     printf("DEBUG: try to get network player actions in time\n");
4848 #endif
4849     */
4850
4851 #if defined(PLATFORM_UNIX)
4852     /* last chance to get network player actions without main loop delay */
4853     HandleNetworking();
4854 #endif
4855
4856     if (game_status != PLAYING)
4857       return;
4858
4859     if (!network_player_action_received)
4860     {
4861       /*
4862 #ifdef DEBUG
4863       printf("DEBUG: failed to get network player actions in time\n");
4864 #endif
4865       */
4866       return;
4867     }
4868   }
4869
4870   if (tape.pausing)
4871     return;
4872
4873   recorded_player_action = (tape.playing ? TapePlayAction() : NULL);
4874
4875   for (i=0; i<MAX_PLAYERS; i++)
4876   {
4877     summarized_player_action |= stored_player[i].action;
4878
4879     if (!network_playing)
4880       stored_player[i].effective_action = stored_player[i].action;
4881   }
4882
4883 #if defined(PLATFORM_UNIX)
4884   if (network_playing)
4885     SendToServer_MovePlayer(summarized_player_action);
4886 #endif
4887
4888   if (!options.network && !setup.team_mode)
4889     local_player->effective_action = summarized_player_action;
4890
4891   for (i=0; i<MAX_PLAYERS; i++)
4892   {
4893     int actual_player_action = stored_player[i].effective_action;
4894
4895     if (stored_player[i].programmed_action)
4896       actual_player_action = stored_player[i].programmed_action;
4897
4898     if (recorded_player_action)
4899       actual_player_action = recorded_player_action[i];
4900
4901     PlayerActions(&stored_player[i], actual_player_action);
4902     ScrollFigure(&stored_player[i], SCROLL_GO_ON);
4903   }
4904
4905   network_player_action_received = FALSE;
4906
4907   ScrollScreen(NULL, SCROLL_GO_ON);
4908
4909
4910
4911 #ifdef DEBUG
4912 #if 0
4913   if (TimeFrames == 0 && local_player->active)
4914   {
4915     extern unsigned int last_RND();
4916
4917     printf("DEBUG: %03d last RND was %d \t [state checksum is %d]\n",
4918            TimePlayed, last_RND(), getStateCheckSum(TimePlayed));
4919   }
4920 #endif
4921 #endif
4922
4923 #ifdef DEBUG
4924 #if 0
4925   if (GameFrameDelay >= 500)
4926     printf("FrameCounter == %d\n", FrameCounter);
4927 #endif
4928 #endif
4929
4930
4931
4932   FrameCounter++;
4933   TimeFrames++;
4934
4935   for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
4936   {
4937     Stop[x][y] = FALSE;
4938     if (JustStopped[x][y] > 0)
4939       JustStopped[x][y]--;
4940
4941 #if DEBUG
4942     if (IS_BLOCKED(x, y))
4943     {
4944       int oldx, oldy;
4945
4946       Blocked2Moving(x, y, &oldx, &oldy);
4947       if (!IS_MOVING(oldx, oldy))
4948       {
4949         printf("GameActions(): (BLOCKED => MOVING) context corrupted!\n");
4950         printf("GameActions(): BLOCKED: x = %d, y = %d\n", x, y);
4951         printf("GameActions(): !MOVING: oldx = %d, oldy = %d\n", oldx, oldy);
4952         printf("GameActions(): This should never happen!\n");
4953       }
4954     }
4955 #endif
4956   }
4957
4958   for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
4959   {
4960     element = Feld[x][y];
4961     graphic = el2img(element);
4962
4963     if (IS_INACTIVE(element))
4964     {
4965
4966 #if 1
4967       if (new_graphic_info[graphic].anim_frames > 1)
4968         DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
4969 #endif
4970
4971       continue;
4972     }
4973
4974     if (!IS_MOVING(x, y) && (CAN_FALL(element) || CAN_MOVE(element)))
4975     {
4976       StartMoving(x, y);
4977
4978 #if 1
4979       if (Feld[x][y] == EL_EMERALD &&
4980           new_graphic_info[graphic].anim_frames > 1 &&
4981           !IS_MOVING(x, y))
4982         DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
4983 #endif
4984
4985       if (IS_GEM(element) || element == EL_SP_INFOTRON)
4986         EdelsteinFunkeln(x, y);
4987     }
4988
4989 #if 1
4990     else if ((element == EL_ACID ||
4991               element == EL_EXIT_OPEN ||
4992               element == EL_SP_EXIT_OPEN ||
4993               element == EL_SP_TERMINAL ||
4994               element == EL_SP_TERMINAL_ACTIVE ||
4995               element == EL_EXTRA_TIME ||
4996               element == EL_SHIELD_NORMAL ||
4997               element == EL_SHIELD_DEADLY) &&
4998              new_graphic_info[graphic].anim_frames > 1)
4999       DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
5000 #endif
5001
5002     else if (IS_MOVING(x, y))
5003       ContinueMoving(x, y);
5004     else if (IS_ACTIVE_BOMB(element))
5005       CheckDynamite(x, y);
5006 #if 0
5007     else if (element == EL_EXPLOSION && !game.explosions_delayed)
5008       Explode(x, y, Frame[x][y], EX_NORMAL);
5009 #endif
5010     else if (element == EL_AMOEBA_CREATING)
5011       AmoebeWaechst(x, y);
5012     else if (element == EL_AMOEBA_SHRINKING)
5013       AmoebaDisappearing(x, y);
5014
5015 #if !USE_NEW_AMOEBA_CODE
5016     else if (IS_AMOEBALIVE(element))
5017       AmoebeAbleger(x, y);
5018 #endif
5019
5020     else if (element == EL_GAMEOFLIFE || element == EL_BIOMAZE)
5021       Life(x, y);
5022     else if (element == EL_ROBOT_WHEEL_ACTIVE)
5023       RobotWheel(x, y);
5024     else if (element == EL_TIMEGATE_SWITCH_ACTIVE)
5025       TimegateWheel(x, y);
5026     else if (element == EL_ACID_SPLASH_LEFT ||
5027              element == EL_ACID_SPLASH_RIGHT)
5028       Blurb(x, y);
5029     else if (element == EL_NUT_CRACKING)
5030       NussKnacken(x, y);
5031     else if (element == EL_PEARL_BREAKING)
5032       BreakingPearl(x, y);
5033     else if (element == EL_EXIT_CLOSED)
5034       AusgangstuerPruefen(x, y);
5035     else if (element == EL_SP_EXIT_CLOSED)
5036       AusgangstuerPruefen_SP(x, y);
5037     else if (element == EL_EXIT_OPENING)
5038       AusgangstuerOeffnen(x, y);
5039     else if (element == EL_WALL_GROWING_ACTIVE)
5040       MauerWaechst(x, y);
5041     else if (element == EL_WALL_GROWING ||
5042              element == EL_WALL_GROWING_X ||
5043              element == EL_WALL_GROWING_Y ||
5044              element == EL_WALL_GROWING_XY)
5045       MauerAbleger(x, y);
5046     else if (element == EL_FLAMES)
5047       CheckForDragon(x, y);
5048     else if (element == EL_SP_BUGGY_BASE || element == EL_SP_BUGGY_BASE_ACTIVE)
5049       CheckBuggyBase(x, y);
5050     else if (element == EL_TRAP || element == EL_TRAP_ACTIVE)
5051       CheckTrap(x, y);
5052     else if (IS_BELT_ACTIVE(element))
5053       DrawBeltAnimation(x, y, element);
5054     else if (element == EL_SWITCHGATE_OPENING)
5055       OpenSwitchgate(x, y);
5056     else if (element == EL_SWITCHGATE_CLOSING)
5057       CloseSwitchgate(x, y);
5058     else if (element == EL_TIMEGATE_OPENING)
5059       OpenTimegate(x, y);
5060     else if (element == EL_TIMEGATE_CLOSING)
5061       CloseTimegate(x, y);
5062
5063 #if 1
5064     else if (new_graphic_info[graphic].anim_frames > 1)
5065       DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
5066 #endif
5067
5068     if (game.magic_wall_active)
5069     {
5070       boolean sieb = FALSE;
5071       int jx = local_player->jx, jy = local_player->jy;
5072
5073       if (element == EL_MAGIC_WALL_FULL ||
5074           element == EL_MAGIC_WALL_ACTIVE ||
5075           element == EL_MAGIC_WALL_EMPTYING)
5076       {
5077         SiebAktivieren(x, y, 1);
5078         sieb = TRUE;
5079       }
5080       else if (element == EL_BD_MAGIC_WALL_FULL ||
5081                element == EL_BD_MAGIC_WALL_ACTIVE ||
5082                element == EL_BD_MAGIC_WALL_EMPTYING)
5083       {
5084         SiebAktivieren(x, y, 2);
5085         sieb = TRUE;
5086       }
5087
5088       /* play the element sound at the position nearest to the player */
5089       if (sieb && ABS(x-jx)+ABS(y-jy) < ABS(sieb_x-jx)+ABS(sieb_y-jy))
5090       {
5091         sieb_x = x;
5092         sieb_y = y;
5093       }
5094     }
5095   }
5096
5097 #if USE_NEW_AMOEBA_CODE
5098   /* new experimental amoeba growth stuff */
5099 #if 1
5100   if (!(FrameCounter % 8))
5101 #endif
5102   {
5103     static unsigned long random = 1684108901;
5104
5105     for (i = 0; i < level.amoeba_speed * 28 / 8; i++)
5106     {
5107 #if 0
5108       x = (random >> 10) % lev_fieldx;
5109       y = (random >> 20) % lev_fieldy;
5110 #else
5111       x = RND(lev_fieldx);
5112       y = RND(lev_fieldy);
5113 #endif
5114       element = Feld[x][y];
5115
5116       if (!IS_PLAYER(x,y) &&
5117           (element == EL_EMPTY ||
5118            element == EL_SAND ||
5119            element == EL_QUICKSAND_EMPTY ||
5120            element == EL_ACID_SPLASH_LEFT ||
5121            element == EL_ACID_SPLASH_RIGHT))
5122       {
5123         if ((IN_LEV_FIELD(x, y-1) && Feld[x][y-1] == EL_AMOEBA_WET) ||
5124             (IN_LEV_FIELD(x-1, y) && Feld[x-1][y] == EL_AMOEBA_WET) ||
5125             (IN_LEV_FIELD(x+1, y) && Feld[x+1][y] == EL_AMOEBA_WET) ||
5126             (IN_LEV_FIELD(x, y+1) && Feld[x][y+1] == EL_AMOEBA_WET))
5127           Feld[x][y] = EL_AMOEBA_DROP;
5128       }
5129
5130       random = random * 129 + 1;
5131     }
5132   }
5133 #endif
5134
5135 #if 0
5136   if (game.explosions_delayed)
5137 #endif
5138   {
5139     game.explosions_delayed = FALSE;
5140
5141     for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
5142     {
5143       element = Feld[x][y];
5144
5145       if (ExplodeField[x][y])
5146         Explode(x, y, EX_PHASE_START, ExplodeField[x][y]);
5147       else if (element == EL_EXPLOSION)
5148         Explode(x, y, Frame[x][y], EX_NORMAL);
5149
5150       ExplodeField[x][y] = EX_NO_EXPLOSION;
5151     }
5152
5153     game.explosions_delayed = TRUE;
5154   }
5155
5156   if (game.magic_wall_active)
5157   {
5158     if (!(game.magic_wall_time_left % 4))
5159     {
5160       int element = Feld[sieb_x][sieb_y];
5161
5162       if (element == EL_BD_MAGIC_WALL_FULL ||
5163           element == EL_BD_MAGIC_WALL_ACTIVE ||
5164           element == EL_BD_MAGIC_WALL_EMPTYING)
5165         PlaySoundLevel(sieb_x, sieb_y, SND_BD_MAGIC_WALL_ACTIVE);
5166       else
5167         PlaySoundLevel(sieb_x, sieb_y, SND_MAGIC_WALL_ACTIVE);
5168     }
5169
5170     if (game.magic_wall_time_left > 0)
5171     {
5172       game.magic_wall_time_left--;
5173       if (!game.magic_wall_time_left)
5174       {
5175         for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
5176         {
5177           element = Feld[x][y];
5178
5179           if (element == EL_MAGIC_WALL_ACTIVE ||
5180               element == EL_MAGIC_WALL_FULL)
5181           {
5182             Feld[x][y] = EL_MAGIC_WALL_DEAD;
5183             DrawLevelField(x, y);
5184           }
5185           else if (element == EL_BD_MAGIC_WALL_ACTIVE ||
5186                    element == EL_BD_MAGIC_WALL_FULL)
5187           {
5188             Feld[x][y] = EL_BD_MAGIC_WALL_DEAD;
5189             DrawLevelField(x, y);
5190           }
5191         }
5192
5193         game.magic_wall_active = FALSE;
5194       }
5195     }
5196   }
5197
5198   if (game.light_time_left > 0)
5199   {
5200     game.light_time_left--;
5201
5202     if (game.light_time_left == 0)
5203       RedrawAllLightSwitchesAndInvisibleElements();
5204   }
5205
5206   if (game.timegate_time_left > 0)
5207   {
5208     game.timegate_time_left--;
5209
5210     if (game.timegate_time_left == 0)
5211       CloseAllOpenTimegates();
5212   }
5213
5214   for (i=0; i<MAX_PLAYERS; i++)
5215   {
5216     struct PlayerInfo *player = &stored_player[i];
5217
5218     if (SHIELD_ON(player))
5219     {
5220       if (player->shield_deadly_time_left)
5221         PlaySoundLevel(player->jx, player->jy, SND_SHIELD_DEADLY_ACTIVE);
5222       else if (player->shield_normal_time_left)
5223         PlaySoundLevel(player->jx, player->jy, SND_SHIELD_NORMAL_ACTIVE);
5224     }
5225   }
5226
5227   if (TimeFrames >= (1000 / GameFrameDelay))
5228   {
5229     TimeFrames = 0;
5230     TimePlayed++;
5231
5232     for (i=0; i<MAX_PLAYERS; i++)
5233     {
5234       struct PlayerInfo *player = &stored_player[i];
5235
5236       if (SHIELD_ON(player))
5237       {
5238         player->shield_normal_time_left--;
5239
5240         if (player->shield_deadly_time_left > 0)
5241           player->shield_deadly_time_left--;
5242       }
5243     }
5244
5245     if (tape.recording || tape.playing)
5246       DrawVideoDisplay(VIDEO_STATE_TIME_ON, TimePlayed);
5247
5248     if (TimeLeft > 0)
5249     {
5250       TimeLeft--;
5251
5252       if (TimeLeft <= 10 && setup.time_limit)
5253         PlaySoundStereo(SND_GAME_RUNNING_OUT_OF_TIME, SOUND_MAX_RIGHT);
5254
5255       DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
5256
5257       if (!TimeLeft && setup.time_limit)
5258         for (i=0; i<MAX_PLAYERS; i++)
5259           KillHero(&stored_player[i]);
5260     }
5261     else if (level.time == 0 && !AllPlayersGone) /* level without time limit */
5262       DrawText(DX_TIME, DY_TIME, int2str(TimePlayed, 3), FS_SMALL, FC_YELLOW);
5263   }
5264
5265   DrawAllPlayers();
5266
5267   if (options.debug)                    /* calculate frames per second */
5268   {
5269     static unsigned long fps_counter = 0;
5270     static int fps_frames = 0;
5271     unsigned long fps_delay_ms = Counter() - fps_counter;
5272
5273     fps_frames++;
5274
5275     if (fps_delay_ms >= 500)    /* calculate fps every 0.5 seconds */
5276     {
5277       global.frames_per_second = 1000 * (float)fps_frames / fps_delay_ms;
5278
5279       fps_frames = 0;
5280       fps_counter = Counter();
5281     }
5282
5283     redraw_mask |= REDRAW_FPS;
5284   }
5285 }
5286
5287 static boolean AllPlayersInSight(struct PlayerInfo *player, int x, int y)
5288 {
5289   int min_x = x, min_y = y, max_x = x, max_y = y;
5290   int i;
5291
5292   for (i=0; i<MAX_PLAYERS; i++)
5293   {
5294     int jx = stored_player[i].jx, jy = stored_player[i].jy;
5295
5296     if (!stored_player[i].active || &stored_player[i] == player)
5297       continue;
5298
5299     min_x = MIN(min_x, jx);
5300     min_y = MIN(min_y, jy);
5301     max_x = MAX(max_x, jx);
5302     max_y = MAX(max_y, jy);
5303   }
5304
5305   return (max_x - min_x < SCR_FIELDX && max_y - min_y < SCR_FIELDY);
5306 }
5307
5308 static boolean AllPlayersInVisibleScreen()
5309 {
5310   int i;
5311
5312   for (i=0; i<MAX_PLAYERS; i++)
5313   {
5314     int jx = stored_player[i].jx, jy = stored_player[i].jy;
5315
5316     if (!stored_player[i].active)
5317       continue;
5318
5319     if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
5320       return FALSE;
5321   }
5322
5323   return TRUE;
5324 }
5325
5326 void ScrollLevel(int dx, int dy)
5327 {
5328   int softscroll_offset = (setup.soft_scrolling ? TILEX : 0);
5329   int x, y;
5330
5331   BlitBitmap(drawto_field, drawto_field,
5332              FX + TILEX*(dx == -1) - softscroll_offset,
5333              FY + TILEY*(dy == -1) - softscroll_offset,
5334              SXSIZE - TILEX*(dx!=0) + 2*softscroll_offset,
5335              SYSIZE - TILEY*(dy!=0) + 2*softscroll_offset,
5336              FX + TILEX*(dx == 1) - softscroll_offset,
5337              FY + TILEY*(dy == 1) - softscroll_offset);
5338
5339   if (dx)
5340   {
5341     x = (dx == 1 ? BX1 : BX2);
5342     for (y=BY1; y<=BY2; y++)
5343       DrawScreenField(x, y);
5344   }
5345
5346   if (dy)
5347   {
5348     y = (dy == 1 ? BY1 : BY2);
5349     for (x=BX1; x<=BX2; x++)
5350       DrawScreenField(x, y);
5351   }
5352
5353   redraw_mask |= REDRAW_FIELD;
5354 }
5355
5356 static void CheckGravityMovement(struct PlayerInfo *player)
5357 {
5358   if (level.gravity && !player->programmed_action)
5359   {
5360     int move_dir_vertical = player->action & (MV_UP | MV_DOWN);
5361     int move_dir_horizontal = player->action & (MV_LEFT | MV_RIGHT);
5362     int move_dir =
5363       (player->last_move_dir & (MV_LEFT | MV_RIGHT) ?
5364        (move_dir_vertical ? move_dir_vertical : move_dir_horizontal) :
5365        (move_dir_horizontal ? move_dir_horizontal : move_dir_vertical));
5366     int jx = player->jx, jy = player->jy;
5367     int dx = (move_dir & MV_LEFT ? -1 : move_dir & MV_RIGHT ? +1 : 0);
5368     int dy = (move_dir & MV_UP ? -1 : move_dir & MV_DOWN ? +1 : 0);
5369     int new_jx = jx + dx, new_jy = jy + dy;
5370     boolean field_under_player_is_free =
5371       (IN_LEV_FIELD(jx, jy + 1) && IS_FREE(jx, jy + 1));
5372     boolean player_is_moving_to_valid_field =
5373       (IN_LEV_FIELD(new_jx, new_jy) &&
5374        (Feld[new_jx][new_jy] == EL_SP_BASE ||
5375         Feld[new_jx][new_jy] == EL_SAND));
5376
5377     if (field_under_player_is_free &&
5378         !player_is_moving_to_valid_field &&
5379         !IS_TUBE(Feld[jx][jy]))
5380       player->programmed_action = MV_DOWN;
5381   }
5382 }
5383
5384 boolean MoveFigureOneStep(struct PlayerInfo *player,
5385                           int dx, int dy, int real_dx, int real_dy)
5386 {
5387   int jx = player->jx, jy = player->jy;
5388   int new_jx = jx+dx, new_jy = jy+dy;
5389   int element;
5390   int can_move;
5391
5392   if (!player->active || (!dx && !dy))
5393     return MF_NO_ACTION;
5394
5395   player->MovDir = (dx < 0 ? MV_LEFT :
5396                     dx > 0 ? MV_RIGHT :
5397                     dy < 0 ? MV_UP :
5398                     dy > 0 ? MV_DOWN :  MV_NO_MOVING);
5399
5400   if (!IN_LEV_FIELD(new_jx, new_jy))
5401     return MF_NO_ACTION;
5402
5403   if (!options.network && !AllPlayersInSight(player, new_jx, new_jy))
5404     return MF_NO_ACTION;
5405
5406 #if 0
5407   element = MovingOrBlocked2Element(new_jx, new_jy);
5408 #else
5409   element = MovingOrBlocked2ElementIfNotLeaving(new_jx, new_jy);
5410 #endif
5411
5412   if (DONT_GO_TO(element))
5413   {
5414     if (element == EL_ACID && dx == 0 && dy == 1)
5415     {
5416       Blurb(jx, jy);
5417       Feld[jx][jy] = EL_PLAYER1;
5418       InitMovingField(jx, jy, MV_DOWN);
5419       Store[jx][jy] = EL_ACID;
5420       ContinueMoving(jx, jy);
5421       BuryHero(player);
5422     }
5423     else
5424       TestIfHeroRunsIntoBadThing(jx, jy, player->MovDir);
5425
5426     return MF_MOVING;
5427   }
5428
5429   can_move = DigField(player, new_jx, new_jy, real_dx, real_dy, DF_DIG);
5430   if (can_move != MF_MOVING)
5431     return can_move;
5432
5433   StorePlayer[jx][jy] = 0;
5434   player->last_jx = jx;
5435   player->last_jy = jy;
5436   jx = player->jx = new_jx;
5437   jy = player->jy = new_jy;
5438   StorePlayer[jx][jy] = player->element_nr;
5439
5440   player->MovPos =
5441     (dx > 0 || dy > 0 ? -1 : 1) * (TILEX - TILEX / player->move_delay_value);
5442
5443   ScrollFigure(player, SCROLL_INIT);
5444
5445   return MF_MOVING;
5446 }
5447
5448 boolean MoveFigure(struct PlayerInfo *player, int dx, int dy)
5449 {
5450   int jx = player->jx, jy = player->jy;
5451   int old_jx = jx, old_jy = jy;
5452   int moved = MF_NO_ACTION;
5453
5454   if (!player->active || (!dx && !dy))
5455     return FALSE;
5456
5457 #if 0
5458   if (!FrameReached(&player->move_delay, player->move_delay_value) &&
5459       !tape.playing)
5460     return FALSE;
5461 #else
5462   if (!FrameReached(&player->move_delay, player->move_delay_value) &&
5463       !(tape.playing && tape.file_version < FILE_VERSION_2_0))
5464     return FALSE;
5465 #endif
5466
5467   /* remove the last programmed player action */
5468   player->programmed_action = 0;
5469
5470   if (player->MovPos)
5471   {
5472     /* should only happen if pre-1.2 tape recordings are played */
5473     /* this is only for backward compatibility */
5474
5475     int original_move_delay_value = player->move_delay_value;
5476
5477 #if DEBUG
5478     printf("THIS SHOULD ONLY HAPPEN WITH PRE-1.2 LEVEL TAPES.\n");
5479 #endif
5480
5481     /* scroll remaining steps with finest movement resolution */
5482     player->move_delay_value = MOVE_DELAY_NORMAL_SPEED;
5483
5484     while (player->MovPos)
5485     {
5486       ScrollFigure(player, SCROLL_GO_ON);
5487       ScrollScreen(NULL, SCROLL_GO_ON);
5488       FrameCounter++;
5489       DrawAllPlayers();
5490       BackToFront();
5491     }
5492
5493     player->move_delay_value = original_move_delay_value;
5494   }
5495
5496   if (player->last_move_dir & (MV_LEFT | MV_RIGHT))
5497   {
5498     if (!(moved |= MoveFigureOneStep(player, 0, dy, dx, dy)))
5499       moved |= MoveFigureOneStep(player, dx, 0, dx, dy);
5500   }
5501   else
5502   {
5503     if (!(moved |= MoveFigureOneStep(player, dx, 0, dx, dy)))
5504       moved |= MoveFigureOneStep(player, 0, dy, dx, dy);
5505   }
5506
5507   jx = player->jx;
5508   jy = player->jy;
5509
5510   if (moved & MF_MOVING && !ScreenMovPos &&
5511       (player == local_player || !options.network))
5512   {
5513     int old_scroll_x = scroll_x, old_scroll_y = scroll_y;
5514     int offset = (setup.scroll_delay ? 3 : 0);
5515
5516     if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
5517     {
5518       /* actual player has left the screen -- scroll in that direction */
5519       if (jx != old_jx)         /* player has moved horizontally */
5520         scroll_x += (jx - old_jx);
5521       else                      /* player has moved vertically */
5522         scroll_y += (jy - old_jy);
5523     }
5524     else
5525     {
5526       if (jx != old_jx)         /* player has moved horizontally */
5527       {
5528         if ((player->MovDir == MV_LEFT && scroll_x > jx - MIDPOSX + offset) ||
5529             (player->MovDir == MV_RIGHT && scroll_x < jx - MIDPOSX - offset))
5530           scroll_x = jx-MIDPOSX + (scroll_x < jx-MIDPOSX ? -offset : +offset);
5531
5532         /* don't scroll over playfield boundaries */
5533         if (scroll_x < SBX_Left || scroll_x > SBX_Right)
5534           scroll_x = (scroll_x < SBX_Left ? SBX_Left : SBX_Right);
5535
5536         /* don't scroll more than one field at a time */
5537         scroll_x = old_scroll_x + SIGN(scroll_x - old_scroll_x);
5538
5539         /* don't scroll against the player's moving direction */
5540         if ((player->MovDir == MV_LEFT && scroll_x > old_scroll_x) ||
5541             (player->MovDir == MV_RIGHT && scroll_x < old_scroll_x))
5542           scroll_x = old_scroll_x;
5543       }
5544       else                      /* player has moved vertically */
5545       {
5546         if ((player->MovDir == MV_UP && scroll_y > jy - MIDPOSY + offset) ||
5547             (player->MovDir == MV_DOWN && scroll_y < jy - MIDPOSY - offset))
5548           scroll_y = jy-MIDPOSY + (scroll_y < jy-MIDPOSY ? -offset : +offset);
5549
5550         /* don't scroll over playfield boundaries */
5551         if (scroll_y < SBY_Upper || scroll_y > SBY_Lower)
5552           scroll_y = (scroll_y < SBY_Upper ? SBY_Upper : SBY_Lower);
5553
5554         /* don't scroll more than one field at a time */
5555         scroll_y = old_scroll_y + SIGN(scroll_y - old_scroll_y);
5556
5557         /* don't scroll against the player's moving direction */
5558         if ((player->MovDir == MV_UP && scroll_y > old_scroll_y) ||
5559             (player->MovDir == MV_DOWN && scroll_y < old_scroll_y))
5560           scroll_y = old_scroll_y;
5561       }
5562     }
5563
5564     if (scroll_x != old_scroll_x || scroll_y != old_scroll_y)
5565     {
5566       if (!options.network && !AllPlayersInVisibleScreen())
5567       {
5568         scroll_x = old_scroll_x;
5569         scroll_y = old_scroll_y;
5570       }
5571       else
5572       {
5573         ScrollScreen(player, SCROLL_INIT);
5574         ScrollLevel(old_scroll_x - scroll_x, old_scroll_y - scroll_y);
5575       }
5576     }
5577   }
5578
5579   if (!(moved & MF_MOVING) && !player->Pushing)
5580     player->Frame = 0;
5581   else
5582 #if 0
5583     player->Frame = (player->Frame + 1) % 4;
5584 #else
5585     player->Frame += 1 * 0;
5586 #endif
5587
5588   if (moved & MF_MOVING)
5589   {
5590     if (old_jx != jx && old_jy == jy)
5591       player->MovDir = (old_jx < jx ? MV_RIGHT : MV_LEFT);
5592     else if (old_jx == jx && old_jy != jy)
5593       player->MovDir = (old_jy < jy ? MV_DOWN : MV_UP);
5594
5595     DrawLevelField(jx, jy);     /* for "DrawCrumbledSand()" */
5596
5597     player->last_move_dir = player->MovDir;
5598     player->is_moving = TRUE;
5599   }
5600   else
5601   {
5602     CheckGravityMovement(player);
5603
5604     /*
5605     player->last_move_dir = MV_NO_MOVING;
5606     */
5607     player->is_moving = FALSE;
5608   }
5609
5610   TestIfHeroTouchesBadThing(jx, jy);
5611
5612   if (!player->active)
5613     RemoveHero(player);
5614
5615   return moved;
5616 }
5617
5618 void ScrollFigure(struct PlayerInfo *player, int mode)
5619 {
5620   int jx = player->jx, jy = player->jy;
5621   int last_jx = player->last_jx, last_jy = player->last_jy;
5622   int move_stepsize = TILEX / player->move_delay_value;
5623
5624   if (!player->active || !player->MovPos)
5625     return;
5626
5627   if (mode == SCROLL_INIT)
5628   {
5629     player->actual_frame_counter = FrameCounter;
5630     player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
5631     if (player->Frame)
5632       player->Frame += 1;
5633
5634     if (Feld[last_jx][last_jy] == EL_EMPTY)
5635       Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING;
5636
5637     DrawPlayer(player);
5638     return;
5639   }
5640   else if (!FrameReached(&player->actual_frame_counter, 1))
5641     return;
5642
5643   player->MovPos += (player->MovPos > 0 ? -1 : 1) * move_stepsize;
5644   player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
5645   player->Frame += 1;
5646
5647   if (Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING)
5648     Feld[last_jx][last_jy] = EL_EMPTY;
5649
5650   /* before DrawPlayer() to draw correct player graphic for this case */
5651   if (player->MovPos == 0)
5652     CheckGravityMovement(player);
5653
5654   DrawPlayer(player);
5655
5656   if (player->MovPos == 0)
5657   {
5658     if (IS_QUICK_GATE(Feld[last_jx][last_jy]))
5659     {
5660       /* continue with normal speed after quickly moving through gate */
5661       HALVE_PLAYER_SPEED(player);
5662
5663       /* be able to make the next move without delay */
5664       player->move_delay = 0;
5665     }
5666
5667     player->last_jx = jx;
5668     player->last_jy = jy;
5669
5670     if (Feld[jx][jy] == EL_EXIT_OPEN ||
5671         Feld[jx][jy] == EL_SP_EXIT_OPEN)
5672     {
5673       RemoveHero(player);
5674
5675       if (local_player->friends_still_needed == 0 ||
5676           Feld[jx][jy] == EL_SP_EXIT_OPEN)
5677         player->LevelSolved = player->GameOver = TRUE;
5678     }
5679
5680     if (tape.single_step && tape.recording && !tape.pausing &&
5681         !player->programmed_action)
5682       TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
5683   }
5684 }
5685
5686 void ScrollScreen(struct PlayerInfo *player, int mode)
5687 {
5688   static unsigned long screen_frame_counter = 0;
5689
5690   if (mode == SCROLL_INIT)
5691   {
5692     /* set scrolling step size according to actual player's moving speed */
5693     ScrollStepSize = TILEX / player->move_delay_value;
5694
5695     screen_frame_counter = FrameCounter;
5696     ScreenMovDir = player->MovDir;
5697     ScreenMovPos = player->MovPos;
5698     ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
5699     return;
5700   }
5701   else if (!FrameReached(&screen_frame_counter, 1))
5702     return;
5703
5704   if (ScreenMovPos)
5705   {
5706     ScreenMovPos += (ScreenMovPos > 0 ? -1 : 1) * ScrollStepSize;
5707     ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
5708     redraw_mask |= REDRAW_FIELD;
5709   }
5710   else
5711     ScreenMovDir = MV_NO_MOVING;
5712 }
5713
5714 void TestIfGoodThingHitsBadThing(int good_x, int good_y, int good_move_dir)
5715 {
5716   int i, kill_x = -1, kill_y = -1;
5717   static int test_xy[4][2] =
5718   {
5719     { 0, -1 },
5720     { -1, 0 },
5721     { +1, 0 },
5722     { 0, +1 }
5723   };
5724   static int test_dir[4] =
5725   {
5726     MV_UP,
5727     MV_LEFT,
5728     MV_RIGHT,
5729     MV_DOWN
5730   };
5731
5732   for (i=0; i<4; i++)
5733   {
5734     int test_x, test_y, test_move_dir, test_element;
5735
5736     test_x = good_x + test_xy[i][0];
5737     test_y = good_y + test_xy[i][1];
5738     if (!IN_LEV_FIELD(test_x, test_y))
5739       continue;
5740
5741     test_move_dir =
5742       (IS_MOVING(test_x, test_y) ? MovDir[test_x][test_y] : MV_NO_MOVING);
5743
5744 #if 0
5745     test_element = Feld[test_x][test_y];
5746 #else
5747     test_element = MovingOrBlocked2ElementIfNotLeaving(test_x, test_y);
5748 #endif
5749
5750     /* 1st case: good thing is moving towards DONT_GO_TO style bad thing;
5751        2nd case: DONT_TOUCH style bad thing does not move away from good thing
5752     */
5753     if ((DONT_GO_TO(test_element) && good_move_dir == test_dir[i]) ||
5754         (DONT_TOUCH(test_element) && test_move_dir != test_dir[i]))
5755     {
5756       kill_x = test_x;
5757       kill_y = test_y;
5758       break;
5759     }
5760   }
5761
5762   if (kill_x != -1 || kill_y != -1)
5763   {
5764     if (IS_PLAYER(good_x, good_y))
5765     {
5766       struct PlayerInfo *player = PLAYERINFO(good_x, good_y);
5767
5768       if (player->shield_deadly_time_left > 0)
5769         Bang(kill_x, kill_y);
5770       else if (!PLAYER_PROTECTED(good_x, good_y))
5771         KillHero(player);
5772     }
5773     else
5774       Bang(good_x, good_y);
5775   }
5776 }
5777
5778 void TestIfBadThingHitsGoodThing(int bad_x, int bad_y, int bad_move_dir)
5779 {
5780   int i, kill_x = -1, kill_y = -1;
5781   int bad_element = Feld[bad_x][bad_y];
5782   static int test_xy[4][2] =
5783   {
5784     { 0, -1 },
5785     { -1, 0 },
5786     { +1, 0 },
5787     { 0, +1 }
5788   };
5789   static int test_dir[4] =
5790   {
5791     MV_UP,
5792     MV_LEFT,
5793     MV_RIGHT,
5794     MV_DOWN
5795   };
5796
5797   if (bad_element == EL_EXPLOSION)      /* skip just exploding bad things */
5798     return;
5799
5800   for (i=0; i<4; i++)
5801   {
5802     int test_x, test_y, test_move_dir, test_element;
5803
5804     test_x = bad_x + test_xy[i][0];
5805     test_y = bad_y + test_xy[i][1];
5806     if (!IN_LEV_FIELD(test_x, test_y))
5807       continue;
5808
5809     test_move_dir =
5810       (IS_MOVING(test_x, test_y) ? MovDir[test_x][test_y] : MV_NO_MOVING);
5811
5812     test_element = Feld[test_x][test_y];
5813
5814     /* 1st case: good thing is moving towards DONT_GO_TO style bad thing;
5815        2nd case: DONT_TOUCH style bad thing does not move away from good thing
5816     */
5817     if ((DONT_GO_TO(bad_element) &&  bad_move_dir == test_dir[i]) ||
5818         (DONT_TOUCH(bad_element) && test_move_dir != test_dir[i]))
5819     {
5820       /* good thing is player or penguin that does not move away */
5821       if (IS_PLAYER(test_x, test_y))
5822       {
5823         struct PlayerInfo *player = PLAYERINFO(test_x, test_y);
5824
5825         if (bad_element == EL_ROBOT && player->is_moving)
5826           continue;     /* robot does not kill player if he is moving */
5827
5828         kill_x = test_x;
5829         kill_y = test_y;
5830         break;
5831       }
5832       else if (test_element == EL_PENGUIN)
5833       {
5834         kill_x = test_x;
5835         kill_y = test_y;
5836         break;
5837       }
5838     }
5839   }
5840
5841   if (kill_x != -1 || kill_y != -1)
5842   {
5843     if (IS_PLAYER(kill_x, kill_y))
5844     {
5845       struct PlayerInfo *player = PLAYERINFO(kill_x, kill_y);
5846
5847 #if 0
5848       int dir = player->MovDir;
5849       int newx = player->jx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
5850       int newy = player->jy + (dir == MV_UP   ? -1 : dir == MV_DOWN  ? +1 : 0);
5851
5852       if (Feld[bad_x][bad_y] == EL_ROBOT && player->is_moving &&
5853           newx != bad_x && newy != bad_y)
5854         ;       /* robot does not kill player if he is moving */
5855       else
5856         printf("-> %d\n", player->MovDir);
5857
5858       if (Feld[bad_x][bad_y] == EL_ROBOT && player->is_moving &&
5859           newx != bad_x && newy != bad_y)
5860         ;       /* robot does not kill player if he is moving */
5861       else
5862         ;
5863 #endif
5864
5865       if (player->shield_deadly_time_left > 0)
5866         Bang(bad_x, bad_y);
5867       else if (!PLAYER_PROTECTED(kill_x, kill_y))
5868         KillHero(player);
5869     }
5870     else
5871       Bang(kill_x, kill_y);
5872   }
5873 }
5874
5875 void TestIfHeroTouchesBadThing(int x, int y)
5876 {
5877   TestIfGoodThingHitsBadThing(x, y, MV_NO_MOVING);
5878 }
5879
5880 void TestIfHeroRunsIntoBadThing(int x, int y, int move_dir)
5881 {
5882   TestIfGoodThingHitsBadThing(x, y, move_dir);
5883 }
5884
5885 void TestIfBadThingTouchesHero(int x, int y)
5886 {
5887   TestIfBadThingHitsGoodThing(x, y, MV_NO_MOVING);
5888 }
5889
5890 void TestIfBadThingRunsIntoHero(int x, int y, int move_dir)
5891 {
5892   TestIfBadThingHitsGoodThing(x, y, move_dir);
5893 }
5894
5895 void TestIfFriendTouchesBadThing(int x, int y)
5896 {
5897   TestIfGoodThingHitsBadThing(x, y, MV_NO_MOVING);
5898 }
5899
5900 void TestIfBadThingTouchesFriend(int x, int y)
5901 {
5902   TestIfBadThingHitsGoodThing(x, y, MV_NO_MOVING);
5903 }
5904
5905 void TestIfBadThingTouchesOtherBadThing(int bad_x, int bad_y)
5906 {
5907   int i, kill_x = bad_x, kill_y = bad_y;
5908   static int xy[4][2] =
5909   {
5910     { 0, -1 },
5911     { -1, 0 },
5912     { +1, 0 },
5913     { 0, +1 }
5914   };
5915
5916   for (i=0; i<4; i++)
5917   {
5918     int x, y, element;
5919
5920     x = bad_x + xy[i][0];
5921     y = bad_y + xy[i][1];
5922     if (!IN_LEV_FIELD(x, y))
5923       continue;
5924
5925     element = Feld[x][y];
5926     if (IS_AMOEBOID(element) || element == EL_GAMEOFLIFE ||
5927         element == EL_AMOEBA_CREATING || element == EL_AMOEBA_DROP)
5928     {
5929       kill_x = x;
5930       kill_y = y;
5931       break;
5932     }
5933   }
5934
5935   if (kill_x != bad_x || kill_y != bad_y)
5936     Bang(bad_x, bad_y);
5937 }
5938
5939 void KillHero(struct PlayerInfo *player)
5940 {
5941   int jx = player->jx, jy = player->jy;
5942
5943   if (!player->active)
5944     return;
5945
5946   if (IS_PFORTE(Feld[jx][jy]))
5947     Feld[jx][jy] = EL_EMPTY;
5948
5949   /* deactivate shield (else Bang()/Explode() would not work right) */
5950   player->shield_normal_time_left = 0;
5951   player->shield_deadly_time_left = 0;
5952
5953   Bang(jx, jy);
5954   BuryHero(player);
5955 }
5956
5957 static void KillHeroUnlessProtected(int x, int y)
5958 {
5959   if (!PLAYER_PROTECTED(x, y))
5960     KillHero(PLAYERINFO(x, y));
5961 }
5962
5963 void BuryHero(struct PlayerInfo *player)
5964 {
5965   int jx = player->jx, jy = player->jy;
5966
5967   if (!player->active)
5968     return;
5969
5970   PlaySoundLevel(jx, jy, SND_PLAYER_DYING);
5971   PlaySoundLevel(jx, jy, SND_GAME_LOSING);
5972
5973   player->GameOver = TRUE;
5974   RemoveHero(player);
5975 }
5976
5977 void RemoveHero(struct PlayerInfo *player)
5978 {
5979   int jx = player->jx, jy = player->jy;
5980   int i, found = FALSE;
5981
5982   player->present = FALSE;
5983   player->active = FALSE;
5984
5985   if (!ExplodeField[jx][jy])
5986     StorePlayer[jx][jy] = 0;
5987
5988   for (i=0; i<MAX_PLAYERS; i++)
5989     if (stored_player[i].active)
5990       found = TRUE;
5991
5992   if (!found)
5993     AllPlayersGone = TRUE;
5994
5995   ExitX = ZX = jx;
5996   ExitY = ZY = jy;
5997 }
5998
5999 int DigField(struct PlayerInfo *player,
6000              int x, int y, int real_dx, int real_dy, int mode)
6001 {
6002   int jx = player->jx, jy = player->jy;
6003   int dx = x - jx, dy = y - jy;
6004   int move_direction = (dx == -1 ? MV_LEFT :
6005                         dx == +1 ? MV_RIGHT :
6006                         dy == -1 ? MV_UP :
6007                         dy == +1 ? MV_DOWN : MV_NO_MOVING);
6008   int element;
6009
6010   if (player->MovPos == 0)
6011     player->Pushing = FALSE;
6012
6013   if (mode == DF_NO_PUSH)
6014   {
6015     player->Switching = FALSE;
6016     player->push_delay = 0;
6017     return MF_NO_ACTION;
6018   }
6019
6020   if (IS_MOVING(x, y) || IS_PLAYER(x, y))
6021     return MF_NO_ACTION;
6022
6023   if (IS_TUBE(Feld[jx][jy]))
6024   {
6025     int i = 0;
6026     int tube_leave_directions[][2] =
6027     {
6028       { EL_TUBE_ALL,                    MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN },
6029       { EL_TUBE_VERTICAL,                                    MV_UP | MV_DOWN },
6030       { EL_TUBE_HORIZONTAL,             MV_LEFT | MV_RIGHT                   },
6031       { EL_TUBE_VERTICAL_LEFT,          MV_LEFT |            MV_UP | MV_DOWN },
6032       { EL_TUBE_VERTICAL_RIGHT,                   MV_RIGHT | MV_UP | MV_DOWN },
6033       { EL_TUBE_HORIZONTAL_UP,          MV_LEFT | MV_RIGHT | MV_UP           },
6034       { EL_TUBE_HORIZONTAL_DOWN,        MV_LEFT | MV_RIGHT |         MV_DOWN },
6035       { EL_TUBE_LEFT_UP,                MV_LEFT |            MV_UP           },
6036       { EL_TUBE_LEFT_DOWN,              MV_LEFT |                    MV_DOWN },
6037       { EL_TUBE_RIGHT_UP,                         MV_RIGHT | MV_UP           },
6038       { EL_TUBE_RIGHT_DOWN,                       MV_RIGHT |         MV_DOWN },
6039       { -1,                             MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN }
6040     };
6041
6042     while (tube_leave_directions[i][0] != Feld[jx][jy])
6043     {
6044       i++;
6045       if (tube_leave_directions[i][0] == -1)    /* should not happen */
6046         break;
6047     }
6048
6049     if (!(tube_leave_directions[i][1] & move_direction))
6050       return MF_NO_ACTION;      /* tube has no opening in this direction */
6051   }
6052
6053   element = Feld[x][y];
6054
6055   switch (element)
6056   {
6057     case EL_EMPTY:
6058     case EL_SAND:
6059     case EL_INVISIBLE_SAND:
6060     case EL_INVISIBLE_SAND_ACTIVE:
6061     case EL_TRAP:
6062     case EL_SP_BASE:
6063     case EL_SP_BUGGY_BASE:
6064       RemoveField(x, y);
6065       PlaySoundLevelElementAction(x, y, element, SND_ACTION_DIGGING);
6066       break;
6067
6068     case EL_EMERALD:
6069     case EL_BD_DIAMOND:
6070     case EL_EMERALD_YELLOW:
6071     case EL_EMERALD_RED:
6072     case EL_EMERALD_PURPLE:
6073     case EL_DIAMOND:
6074     case EL_SP_INFOTRON:
6075     case EL_PEARL:
6076     case EL_CRYSTAL:
6077       RemoveField(x, y);
6078       local_player->gems_still_needed -= (element == EL_DIAMOND ? 3 :
6079                                           element == EL_PEARL ? 5 :
6080                                           element == EL_CRYSTAL ? 8 : 1);
6081       if (local_player->gems_still_needed < 0)
6082         local_player->gems_still_needed = 0;
6083       RaiseScoreElement(element);
6084       DrawText(DX_EMERALDS, DY_EMERALDS,
6085                int2str(local_player->gems_still_needed, 3),
6086                FS_SMALL, FC_YELLOW);
6087       PlaySoundLevelElementAction(x, y, element, SND_ACTION_COLLECTING);
6088       break;
6089
6090     case EL_SPEED_PILL:
6091       RemoveField(x, y);
6092       player->move_delay_value = MOVE_DELAY_HIGH_SPEED;
6093       PlaySoundLevel(x, y, SND_SPEED_PILL_COLLECTING);
6094       break;
6095
6096     case EL_ENVELOPE:
6097       Feld[x][y] = EL_EMPTY;
6098       PlaySoundLevel(x, y, SND_ENVELOPE_COLLECTING);
6099       break;
6100
6101     case EL_EXTRA_TIME:
6102       RemoveField(x, y);
6103       if (level.time > 0)
6104       {
6105         TimeLeft += 10;
6106         DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
6107       }
6108       PlaySoundStereo(SND_EXTRA_TIME_COLLECTING, SOUND_MAX_RIGHT);
6109       break;
6110
6111     case EL_SHIELD_NORMAL:
6112       RemoveField(x, y);
6113       player->shield_normal_time_left += 10;
6114       PlaySoundLevel(x, y, SND_SHIELD_NORMAL_COLLECTING);
6115       break;
6116
6117     case EL_SHIELD_DEADLY:
6118       RemoveField(x, y);
6119       player->shield_normal_time_left += 10;
6120       player->shield_deadly_time_left += 10;
6121       PlaySoundLevel(x, y, SND_SHIELD_DEADLY_COLLECTING);
6122       break;
6123
6124     case EL_DYNAMITE:
6125     case EL_SP_DISK_RED:
6126       RemoveField(x, y);
6127       player->dynamite++;
6128       RaiseScoreElement(EL_DYNAMITE);
6129       DrawText(DX_DYNAMITE, DY_DYNAMITE,
6130                int2str(local_player->dynamite, 3),
6131                FS_SMALL, FC_YELLOW);
6132       PlaySoundLevelElementAction(x, y, element, SND_ACTION_COLLECTING);
6133       break;
6134
6135     case EL_DYNABOMB_NR:
6136       RemoveField(x, y);
6137       player->dynabomb_count++;
6138       player->dynabombs_left++;
6139       RaiseScoreElement(EL_DYNAMITE);
6140       PlaySoundLevel(x, y, SND_DYNABOMB_NR_COLLECTING);
6141       break;
6142
6143     case EL_DYNABOMB_SZ:
6144       RemoveField(x, y);
6145       player->dynabomb_size++;
6146       RaiseScoreElement(EL_DYNAMITE);
6147       PlaySoundLevel(x, y, SND_DYNABOMB_SZ_COLLECTING);
6148       break;
6149
6150     case EL_DYNABOMB_XL:
6151       RemoveField(x, y);
6152       player->dynabomb_xl = TRUE;
6153       RaiseScoreElement(EL_DYNAMITE);
6154       PlaySoundLevel(x, y, SND_DYNABOMB_XL_COLLECTING);
6155       break;
6156
6157     case EL_KEY1:
6158     case EL_KEY2:
6159     case EL_KEY3:
6160     case EL_KEY4:
6161     {
6162       int key_nr = element - EL_KEY1;
6163
6164       RemoveField(x, y);
6165       player->key[key_nr] = TRUE;
6166       RaiseScoreElement(element);
6167       DrawMiniGraphicExt(drawto, DX_KEYS + key_nr * MINI_TILEX, DY_KEYS,
6168                          IMG_KEY1 + key_nr);
6169       DrawMiniGraphicExt(window, DX_KEYS + key_nr * MINI_TILEX, DY_KEYS,
6170                          IMG_KEY1 + key_nr);
6171       PlaySoundLevel(x, y, SND_KEY_COLLECTING);
6172       break;
6173     }
6174
6175     case EL_EM_KEY1:
6176     case EL_EM_KEY2:
6177     case EL_EM_KEY3:
6178     case EL_EM_KEY4:
6179     {
6180       int key_nr = element - EL_EM_KEY1;
6181
6182       RemoveField(x, y);
6183       player->key[key_nr] = TRUE;
6184       RaiseScoreElement(element);
6185       DrawMiniGraphicExt(drawto, DX_KEYS + key_nr * MINI_TILEX, DY_KEYS,
6186                          IMG_KEY1 + key_nr);
6187       DrawMiniGraphicExt(window, DX_KEYS + key_nr * MINI_TILEX, DY_KEYS,
6188                          IMG_KEY1 + key_nr);
6189       PlaySoundLevel(x, y, SND_KEY_COLLECTING);
6190       break;
6191     }
6192
6193     case EL_ROBOT_WHEEL:
6194       Feld[x][y] = EL_ROBOT_WHEEL_ACTIVE;
6195       ZX = x;
6196       ZY = y;
6197       DrawLevelField(x, y);
6198       PlaySoundLevel(x, y, SND_ROBOT_WHEEL_ACTIVATING);
6199       return MF_ACTION;
6200       break;
6201
6202     case EL_SP_TERMINAL:
6203       {
6204         int xx, yy;
6205
6206         PlaySoundLevel(x, y, SND_SP_TERMINAL_ACTIVATING);
6207
6208         for (yy=0; yy<lev_fieldy; yy++)
6209         {
6210           for (xx=0; xx<lev_fieldx; xx++)
6211           {
6212             if (Feld[xx][yy] == EL_SP_DISK_YELLOW)
6213               Bang(xx, yy);
6214             else if (Feld[xx][yy] == EL_SP_TERMINAL)
6215               Feld[xx][yy] = EL_SP_TERMINAL_ACTIVE;
6216           }
6217         }
6218
6219         return MF_ACTION;
6220       }
6221       break;
6222
6223     case EL_CONVEYOR_BELT1_SWITCH_LEFT:
6224     case EL_CONVEYOR_BELT1_SWITCH_MIDDLE:
6225     case EL_CONVEYOR_BELT1_SWITCH_RIGHT:
6226     case EL_CONVEYOR_BELT2_SWITCH_LEFT:
6227     case EL_CONVEYOR_BELT2_SWITCH_MIDDLE:
6228     case EL_CONVEYOR_BELT2_SWITCH_RIGHT:
6229     case EL_CONVEYOR_BELT3_SWITCH_LEFT:
6230     case EL_CONVEYOR_BELT3_SWITCH_MIDDLE:
6231     case EL_CONVEYOR_BELT3_SWITCH_RIGHT:
6232     case EL_CONVEYOR_BELT4_SWITCH_LEFT:
6233     case EL_CONVEYOR_BELT4_SWITCH_MIDDLE:
6234     case EL_CONVEYOR_BELT4_SWITCH_RIGHT:
6235       if (!player->Switching)
6236       {
6237         player->Switching = TRUE;
6238         ToggleBeltSwitch(x, y);
6239         PlaySoundLevel(x, y, SND_CONVEYOR_BELT_SWITCH_ACTIVATING);
6240       }
6241       return MF_ACTION;
6242       break;
6243
6244     case EL_SWITCHGATE_SWITCH_UP:
6245     case EL_SWITCHGATE_SWITCH_DOWN:
6246       if (!player->Switching)
6247       {
6248         player->Switching = TRUE;
6249         ToggleSwitchgateSwitch(x, y);
6250         PlaySoundLevel(x, y, SND_SWITCHGATE_SWITCH_ACTIVATING);
6251       }
6252       return MF_ACTION;
6253       break;
6254
6255     case EL_LIGHT_SWITCH:
6256     case EL_LIGHT_SWITCH_ACTIVE:
6257       if (!player->Switching)
6258       {
6259         player->Switching = TRUE;
6260         ToggleLightSwitch(x, y);
6261         PlaySoundLevel(x, y, element == EL_LIGHT_SWITCH ?
6262                        SND_LIGHT_SWITCH_ACTIVATING :
6263                        SND_LIGHT_SWITCH_DEACTIVATING);
6264       }
6265       return MF_ACTION;
6266       break;
6267
6268     case EL_TIMEGATE_SWITCH:
6269       ActivateTimegateSwitch(x, y);
6270       PlaySoundLevel(x, y, SND_TIMEGATE_SWITCH_ACTIVATING);
6271
6272       return MF_ACTION;
6273       break;
6274
6275     case EL_BALLOON_SEND_LEFT:
6276     case EL_BALLOON_SEND_RIGHT:
6277     case EL_BALLOON_SEND_UP:
6278     case EL_BALLOON_SEND_DOWN:
6279     case EL_BALLOON_SEND_ANY_DIRECTION:
6280       if (element == EL_BALLOON_SEND_ANY_DIRECTION)
6281         game.balloon_dir = move_direction;
6282       else
6283         game.balloon_dir = (element == EL_BALLOON_SEND_LEFT  ? MV_LEFT :
6284                             element == EL_BALLOON_SEND_RIGHT ? MV_RIGHT :
6285                             element == EL_BALLOON_SEND_UP    ? MV_UP :
6286                             element == EL_BALLOON_SEND_DOWN  ? MV_DOWN :
6287                             MV_NO_MOVING);
6288       PlaySoundLevel(x, y, SND_BALLOON_SWITCH_ACTIVATING);
6289
6290       return MF_ACTION;
6291       break;
6292
6293       /* the following elements cannot be pushed by "snapping" */
6294     case EL_ROCK:
6295     case EL_BOMB:
6296     case EL_DX_SUPABOMB:
6297     case EL_NUT:
6298     case EL_TIME_ORB_EMPTY:
6299     case EL_SP_ZONK:
6300     case EL_SP_DISK_ORANGE:
6301     case EL_SPRING:
6302       if (mode == DF_SNAP)
6303         return MF_NO_ACTION;
6304       /* no "break" -- fall through to next case */
6305       /* the following elements can be pushed by "snapping" */
6306     case EL_BD_ROCK:
6307       if (dy)
6308         return MF_NO_ACTION;
6309
6310       player->Pushing = TRUE;
6311
6312       if (!IN_LEV_FIELD(x+dx, y+dy) || !IS_FREE(x+dx, y+dy))
6313         return MF_NO_ACTION;
6314
6315       if (real_dy)
6316       {
6317         if (IN_LEV_FIELD(jx, jy+real_dy) && !IS_SOLID(Feld[jx][jy+real_dy]))
6318           return MF_NO_ACTION;
6319       }
6320
6321       if (player->push_delay == 0)
6322         player->push_delay = FrameCounter;
6323 #if 0
6324       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
6325           !tape.playing && element != EL_SPRING)
6326         return MF_NO_ACTION;
6327 #else
6328       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
6329           !(tape.playing && tape.file_version < FILE_VERSION_2_0) &&
6330           element != EL_SPRING)
6331         return MF_NO_ACTION;
6332 #endif
6333
6334       if (mode == DF_SNAP)
6335       {
6336         InitMovingField(x, y, move_direction);
6337         ContinueMoving(x, y);
6338       }
6339       else
6340       {
6341         RemoveField(x, y);
6342         Feld[x + dx][y + dy] = element;
6343       }
6344
6345       if (element == EL_SPRING)
6346       {
6347         Feld[x + dx][y + dy] = EL_SPRING;
6348         MovDir[x + dx][y + dy] = move_direction;
6349       }
6350
6351       player->push_delay_value = (element == EL_SPRING ? 0 : 2 + RND(8));
6352
6353       DrawLevelField(x + dx, y + dy);
6354       PlaySoundLevelElementAction(x, y, element, SND_ACTION_PUSHING);
6355       break;
6356
6357     case EL_GATE1:
6358     case EL_GATE2:
6359     case EL_GATE3:
6360     case EL_GATE4:
6361       if (!player->key[element - EL_GATE1])
6362         return MF_NO_ACTION;
6363       break;
6364
6365     case EL_GATE1_GRAY:
6366     case EL_GATE2_GRAY:
6367     case EL_GATE3_GRAY:
6368     case EL_GATE4_GRAY:
6369       if (!player->key[element - EL_GATE1_GRAY])
6370         return MF_NO_ACTION;
6371       break;
6372
6373     case EL_EM_GATE1:
6374     case EL_EM_GATE2:
6375     case EL_EM_GATE3:
6376     case EL_EM_GATE4:
6377       if (!player->key[element - EL_EM_GATE1])
6378         return MF_NO_ACTION;
6379       if (!IN_LEV_FIELD(x + dx, y + dy) || !IS_FREE(x + dx, y + dy))
6380         return MF_NO_ACTION;
6381
6382       /* automatically move to the next field with double speed */
6383       player->programmed_action = move_direction;
6384       DOUBLE_PLAYER_SPEED(player);
6385
6386       PlaySoundLevel(x, y, SND_GATE_PASSING);
6387       break;
6388
6389     case EL_EM_GATE1_GRAY:
6390     case EL_EM_GATE2_GRAY:
6391     case EL_EM_GATE3_GRAY:
6392     case EL_EM_GATE4_GRAY:
6393       if (!player->key[element - EL_EM_GATE1_GRAY])
6394         return MF_NO_ACTION;
6395       if (!IN_LEV_FIELD(x + dx, y + dy) || !IS_FREE(x + dx, y + dy))
6396         return MF_NO_ACTION;
6397
6398       /* automatically move to the next field with double speed */
6399       player->programmed_action = move_direction;
6400       DOUBLE_PLAYER_SPEED(player);
6401
6402       PlaySoundLevel(x, y, SND_GATE_PASSING);
6403       break;
6404
6405     case EL_SWITCHGATE_OPEN:
6406     case EL_TIMEGATE_OPEN:
6407       if (!IN_LEV_FIELD(x + dx, y + dy) || !IS_FREE(x + dx, y + dy))
6408         return MF_NO_ACTION;
6409
6410       /* automatically move to the next field with double speed */
6411       player->programmed_action = move_direction;
6412       DOUBLE_PLAYER_SPEED(player);
6413
6414       PlaySoundLevelElementAction(x, y, element, SND_ACTION_PASSING);
6415       break;
6416
6417     case EL_SP_PORT1_LEFT:
6418     case EL_SP_PORT2_LEFT:
6419     case EL_SP_PORT1_RIGHT:
6420     case EL_SP_PORT2_RIGHT:
6421     case EL_SP_PORT1_UP:
6422     case EL_SP_PORT2_UP:
6423     case EL_SP_PORT1_DOWN:
6424     case EL_SP_PORT2_DOWN:
6425     case EL_SP_PORT_X:
6426     case EL_SP_PORT_Y:
6427     case EL_SP_PORT_XY:
6428       if ((dx == -1 &&
6429            element != EL_SP_PORT1_LEFT &&
6430            element != EL_SP_PORT2_LEFT &&
6431            element != EL_SP_PORT_X &&
6432            element != EL_SP_PORT_XY) ||
6433           (dx == +1 &&
6434            element != EL_SP_PORT1_RIGHT &&
6435            element != EL_SP_PORT2_RIGHT &&
6436            element != EL_SP_PORT_X &&
6437            element != EL_SP_PORT_XY) ||
6438           (dy == -1 &&
6439            element != EL_SP_PORT1_UP &&
6440            element != EL_SP_PORT2_UP &&
6441            element != EL_SP_PORT_Y &&
6442            element != EL_SP_PORT_XY) ||
6443           (dy == +1 &&
6444            element != EL_SP_PORT1_DOWN &&
6445            element != EL_SP_PORT2_DOWN &&
6446            element != EL_SP_PORT_Y &&
6447            element != EL_SP_PORT_XY) ||
6448           !IN_LEV_FIELD(x + dx, y + dy) ||
6449           !IS_FREE(x + dx, y + dy))
6450         return MF_NO_ACTION;
6451
6452       /* automatically move to the next field with double speed */
6453       player->programmed_action = move_direction;
6454       DOUBLE_PLAYER_SPEED(player);
6455
6456       PlaySoundLevel(x, y, SND_SP_PORT_PASSING);
6457       break;
6458
6459     case EL_TUBE_ALL:
6460     case EL_TUBE_VERTICAL:
6461     case EL_TUBE_HORIZONTAL:
6462     case EL_TUBE_VERTICAL_LEFT:
6463     case EL_TUBE_VERTICAL_RIGHT:
6464     case EL_TUBE_HORIZONTAL_UP:
6465     case EL_TUBE_HORIZONTAL_DOWN:
6466     case EL_TUBE_LEFT_UP:
6467     case EL_TUBE_LEFT_DOWN:
6468     case EL_TUBE_RIGHT_UP:
6469     case EL_TUBE_RIGHT_DOWN:
6470       {
6471         int i = 0;
6472         int tube_enter_directions[][2] =
6473         {
6474           { EL_TUBE_ALL,                MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN },
6475           { EL_TUBE_VERTICAL,                                MV_UP | MV_DOWN },
6476           { EL_TUBE_HORIZONTAL,         MV_LEFT | MV_RIGHT                   },
6477           { EL_TUBE_VERTICAL_LEFT,                MV_RIGHT | MV_UP | MV_DOWN },
6478           { EL_TUBE_VERTICAL_RIGHT,     MV_LEFT            | MV_UP | MV_DOWN },
6479           { EL_TUBE_HORIZONTAL_UP,      MV_LEFT | MV_RIGHT |         MV_DOWN },
6480           { EL_TUBE_HORIZONTAL_DOWN,    MV_LEFT | MV_RIGHT | MV_UP           },
6481           { EL_TUBE_LEFT_UP,                      MV_RIGHT |         MV_DOWN },
6482           { EL_TUBE_LEFT_DOWN,                    MV_RIGHT | MV_UP           },
6483           { EL_TUBE_RIGHT_UP,           MV_LEFT |                    MV_DOWN },
6484           { EL_TUBE_RIGHT_DOWN,         MV_LEFT |            MV_UP           },
6485           { -1,                         MV_NO_MOVING                         }
6486         };
6487
6488         while (tube_enter_directions[i][0] != element)
6489         {
6490           i++;
6491           if (tube_enter_directions[i][0] == -1)        /* should not happen */
6492             break;
6493         }
6494
6495         if (!(tube_enter_directions[i][1] & move_direction))
6496           return MF_NO_ACTION;  /* tube has no opening in this direction */
6497
6498         PlaySoundLevel(x, y, SND_TUBE_PASSING);
6499       }
6500       break;
6501
6502     case EL_EXIT_CLOSED:
6503     case EL_SP_EXIT_CLOSED:
6504     case EL_EXIT_OPENING:
6505       return MF_NO_ACTION;
6506       break;
6507
6508     case EL_EXIT_OPEN:
6509     case EL_SP_EXIT_OPEN:
6510       if (mode == DF_SNAP)
6511         return MF_NO_ACTION;
6512
6513       if (element == EL_EXIT_OPEN)
6514         PlaySoundLevel(x, y, SND_EXIT_PASSING);
6515       else
6516         PlaySoundLevel(x, y, SND_SP_EXIT_PASSING);
6517
6518       break;
6519
6520     case EL_LAMP:
6521       Feld[x][y] = EL_LAMP_ACTIVE;
6522       local_player->lights_still_needed--;
6523       DrawLevelField(x, y);
6524       PlaySoundLevel(x, y, SND_LAMP_ACTIVATING);
6525       return MF_ACTION;
6526       break;
6527
6528     case EL_TIME_ORB_FULL:
6529       Feld[x][y] = EL_TIME_ORB_EMPTY;
6530       TimeLeft += 10;
6531       DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
6532       DrawLevelField(x, y);
6533       PlaySoundStereo(SND_TIME_ORB_FULL_COLLECTING, SOUND_MAX_RIGHT);
6534       return MF_ACTION;
6535       break;
6536
6537     case EL_SOKOBAN_FIELD_EMPTY:
6538       break;
6539
6540     case EL_SOKOBAN_OBJECT:
6541     case EL_SOKOBAN_FIELD_FULL:
6542     case EL_SATELLITE:
6543     case EL_SP_DISK_YELLOW:
6544     case EL_BALLOON:
6545       if (mode == DF_SNAP)
6546         return MF_NO_ACTION;
6547
6548       player->Pushing = TRUE;
6549
6550       if (!IN_LEV_FIELD(x+dx, y+dy)
6551           || (!IS_FREE(x+dx, y+dy)
6552               && (Feld[x+dx][y+dy] != EL_SOKOBAN_FIELD_EMPTY
6553                   || !IS_SB_ELEMENT(element))))
6554         return MF_NO_ACTION;
6555
6556       if (dx && real_dy)
6557       {
6558         if (IN_LEV_FIELD(jx, jy+real_dy) && !IS_SOLID(Feld[jx][jy+real_dy]))
6559           return MF_NO_ACTION;
6560       }
6561       else if (dy && real_dx)
6562       {
6563         if (IN_LEV_FIELD(jx+real_dx, jy) && !IS_SOLID(Feld[jx+real_dx][jy]))
6564           return MF_NO_ACTION;
6565       }
6566
6567       if (player->push_delay == 0)
6568         player->push_delay = FrameCounter;
6569 #if 0
6570       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
6571           !tape.playing && element != EL_BALLOON)
6572         return MF_NO_ACTION;
6573 #else
6574       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
6575           !(tape.playing && tape.file_version < FILE_VERSION_2_0) &&
6576           element != EL_BALLOON)
6577         return MF_NO_ACTION;
6578 #endif
6579
6580       if (IS_SB_ELEMENT(element))
6581       {
6582         if (element == EL_SOKOBAN_FIELD_FULL)
6583         {
6584           Feld[x][y] = EL_SOKOBAN_FIELD_EMPTY;
6585           local_player->sokobanfields_still_needed++;
6586         }
6587         else
6588           RemoveField(x, y);
6589
6590         if (Feld[x+dx][y+dy] == EL_SOKOBAN_FIELD_EMPTY)
6591         {
6592           Feld[x+dx][y+dy] = EL_SOKOBAN_FIELD_FULL;
6593           local_player->sokobanfields_still_needed--;
6594           if (element == EL_SOKOBAN_OBJECT)
6595             PlaySoundLevel(x, y, SND_SOKOBAN_FIELD_FILLING);
6596           else
6597             PlaySoundLevel(x, y, SND_SOKOBAN_OBJECT_PUSHING);
6598         }
6599         else
6600         {
6601           Feld[x+dx][y+dy] = EL_SOKOBAN_OBJECT;
6602           if (element == EL_SOKOBAN_FIELD_FULL)
6603             PlaySoundLevel(x, y, SND_SOKOBAN_FIELD_EMPTYING);
6604           else
6605             PlaySoundLevel(x, y, SND_SOKOBAN_OBJECT_PUSHING);
6606         }
6607       }
6608       else
6609       {
6610         RemoveField(x, y);
6611         Feld[x+dx][y+dy] = element;
6612         PlaySoundLevelElementAction(x, y, element, SND_ACTION_PUSHING);
6613       }
6614
6615       player->push_delay_value = (element == EL_BALLOON ? 0 : 2);
6616
6617       DrawLevelField(x, y);
6618       DrawLevelField(x + dx, y + dy);
6619
6620       if (IS_SB_ELEMENT(element) &&
6621           local_player->sokobanfields_still_needed == 0 &&
6622           game.emulation == EMU_SOKOBAN)
6623       {
6624         player->LevelSolved = player->GameOver = TRUE;
6625         PlaySoundLevel(x, y, SND_SOKOBAN_GAME_SOLVING);
6626       }
6627
6628       break;
6629
6630     case EL_PENGUIN:
6631     case EL_PIG:
6632     case EL_DRAGON:
6633       break;
6634
6635     default:
6636       return MF_NO_ACTION;
6637   }
6638
6639   player->push_delay = 0;
6640
6641   return MF_MOVING;
6642 }
6643
6644 boolean SnapField(struct PlayerInfo *player, int dx, int dy)
6645 {
6646   int jx = player->jx, jy = player->jy;
6647   int x = jx + dx, y = jy + dy;
6648
6649   if (!player->active || !IN_LEV_FIELD(x, y))
6650     return FALSE;
6651
6652   if (dx && dy)
6653     return FALSE;
6654
6655   if (!dx && !dy)
6656   {
6657     if (player->MovPos == 0)
6658       player->Pushing = FALSE;
6659
6660     player->snapped = FALSE;
6661     return FALSE;
6662   }
6663
6664   if (player->snapped)
6665     return FALSE;
6666
6667   player->MovDir = (dx < 0 ? MV_LEFT :
6668                     dx > 0 ? MV_RIGHT :
6669                     dy < 0 ? MV_UP :
6670                     dy > 0 ? MV_DOWN :  MV_NO_MOVING);
6671
6672   if (!DigField(player, x, y, 0, 0, DF_SNAP))
6673     return FALSE;
6674
6675   player->snapped = TRUE;
6676   DrawLevelField(x, y);
6677   BackToFront();
6678
6679   return TRUE;
6680 }
6681
6682 boolean PlaceBomb(struct PlayerInfo *player)
6683 {
6684   int jx = player->jx, jy = player->jy;
6685   int element;
6686
6687   if (!player->active || player->MovPos)
6688     return FALSE;
6689
6690   element = Feld[jx][jy];
6691
6692   if ((player->dynamite == 0 && player->dynabombs_left == 0) ||
6693       IS_ACTIVE_BOMB(element) || element == EL_EXPLOSION)
6694     return FALSE;
6695
6696   if (element != EL_EMPTY)
6697     Store[jx][jy] = element;
6698
6699   if (player->dynamite)
6700   {
6701     Feld[jx][jy] = EL_DYNAMITE_ACTIVE;
6702     MovDelay[jx][jy] = 96;
6703     player->dynamite--;
6704     DrawText(DX_DYNAMITE, DY_DYNAMITE, int2str(local_player->dynamite, 3),
6705              FS_SMALL, FC_YELLOW);
6706     if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy)))
6707     {
6708       if (game.emulation == EMU_SUPAPLEX)
6709         DrawGraphic(SCREENX(jx), SCREENY(jy), IMG_SP_DISK_RED, 0);
6710       else
6711         DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), IMG_DYNAMITE_ACTIVE, 0);
6712     }
6713
6714     PlaySoundLevel(jx, jy, SND_DYNAMITE_DROPPING);
6715   }
6716   else
6717   {
6718     Feld[jx][jy] =
6719       EL_DYNABOMB_PLAYER1_ACTIVE + (player->element_nr - EL_PLAYER1);
6720     MovDelay[jx][jy] = 96;
6721     player->dynabombs_left--;
6722     if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy)))
6723       DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), el2img(Feld[jx][jy]), 0);
6724
6725     PlaySoundLevel(jx, jy, SND_DYNABOMB_DROPPING);
6726   }
6727
6728   return TRUE;
6729 }
6730
6731 void PlaySoundLevel(int x, int y, int nr)
6732 {
6733   static int loop_sound_frame[NUM_SOUND_FILES];
6734   static int loop_sound_volume[NUM_SOUND_FILES];
6735   int sx = SCREENX(x), sy = SCREENY(y);
6736   int volume, stereo_position;
6737   int max_distance = 8;
6738   int type = (IS_LOOP_SOUND(nr) ? SND_CTRL_PLAY_LOOP : SND_CTRL_PLAY_SOUND);
6739
6740   if ((!setup.sound_simple && !IS_LOOP_SOUND(nr)) ||
6741       (!setup.sound_loops && IS_LOOP_SOUND(nr)))
6742     return;
6743
6744   if (!IN_LEV_FIELD(x, y) ||
6745       sx < -max_distance || sx >= SCR_FIELDX + max_distance ||
6746       sy < -max_distance || sy >= SCR_FIELDY + max_distance)
6747     return;
6748
6749   volume = SOUND_MAX_VOLUME;
6750
6751   if (!IN_SCR_FIELD(sx, sy))
6752   {
6753     int dx = ABS(sx - SCR_FIELDX / 2) - SCR_FIELDX / 2;
6754     int dy = ABS(sy - SCR_FIELDY / 2) - SCR_FIELDY / 2;
6755
6756     volume -= volume * (dx > dy ? dx : dy) / max_distance;
6757   }
6758
6759   stereo_position = (SOUND_MAX_LEFT +
6760                      (sx + max_distance) * SOUND_MAX_LEFT2RIGHT /
6761                      (SCR_FIELDX + 2 * max_distance));
6762
6763   if (IS_LOOP_SOUND(nr))
6764   {
6765     /* This assures that quieter loop sounds do not overwrite louder ones,
6766        while restarting sound volume comparison with each new game frame. */
6767
6768     if (loop_sound_volume[nr] > volume && loop_sound_frame[nr] == FrameCounter)
6769       return;
6770
6771     loop_sound_volume[nr] = volume;
6772     loop_sound_frame[nr] = FrameCounter;
6773   }
6774
6775   PlaySoundExt(nr, volume, stereo_position, type);
6776 }
6777
6778 void PlaySoundLevelAction(int x, int y, int sound_action)
6779 {
6780   PlaySoundLevelElementAction(x, y, Feld[x][y], sound_action);
6781 }
6782
6783 void PlaySoundLevelElementAction(int x, int y, int element, int sound_action)
6784 {
6785   int sound_effect = element_action_sound[element][sound_action];
6786
6787   if (sound_effect != -1)
6788     PlaySoundLevel(x, y, sound_effect);
6789 }
6790
6791 void RaiseScore(int value)
6792 {
6793   local_player->score += value;
6794   DrawText(DX_SCORE, DY_SCORE, int2str(local_player->score, 5),
6795            FS_SMALL, FC_YELLOW);
6796 }
6797
6798 void RaiseScoreElement(int element)
6799 {
6800   switch(element)
6801   {
6802     case EL_EMERALD:
6803     case EL_BD_DIAMOND:
6804     case EL_EMERALD_YELLOW:
6805     case EL_EMERALD_RED:
6806     case EL_EMERALD_PURPLE:
6807       RaiseScore(level.score[SC_EDELSTEIN]);
6808       break;
6809     case EL_DIAMOND:
6810       RaiseScore(level.score[SC_DIAMANT]);
6811       break;
6812     case EL_BUG:
6813     case EL_BD_BUTTERFLY:
6814       RaiseScore(level.score[SC_KAEFER]);
6815       break;
6816     case EL_SPACESHIP:
6817     case EL_BD_FIREFLY:
6818       RaiseScore(level.score[SC_FLIEGER]);
6819       break;
6820     case EL_YAMYAM:
6821     case EL_DARK_YAMYAM:
6822       RaiseScore(level.score[SC_MAMPFER]);
6823       break;
6824     case EL_ROBOT:
6825       RaiseScore(level.score[SC_ROBOT]);
6826       break;
6827     case EL_PACMAN:
6828       RaiseScore(level.score[SC_PACMAN]);
6829       break;
6830     case EL_NUT:
6831       RaiseScore(level.score[SC_KOKOSNUSS]);
6832       break;
6833     case EL_DYNAMITE:
6834       RaiseScore(level.score[SC_DYNAMIT]);
6835       break;
6836     case EL_KEY1:
6837     case EL_KEY2:
6838     case EL_KEY3:
6839     case EL_KEY4:
6840       RaiseScore(level.score[SC_SCHLUESSEL]);
6841       break;
6842     default:
6843       break;
6844   }
6845 }
6846
6847 void RequestQuitGame(boolean ask_if_really_quit)
6848 {
6849   if (AllPlayersGone ||
6850       !ask_if_really_quit ||
6851       level_editor_test_game ||
6852       Request("Do you really want to quit the game ?",
6853               REQ_ASK | REQ_STAY_CLOSED))
6854   {
6855 #if defined(PLATFORM_UNIX)
6856     if (options.network)
6857       SendToServer_StopPlaying();
6858     else
6859 #endif
6860     {
6861       game_status = MAINMENU;
6862       DrawMainMenu();
6863     }
6864   }
6865   else
6866   {
6867     OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
6868   }
6869 }
6870
6871
6872 /* ---------- new game button stuff ---------------------------------------- */
6873
6874 /* graphic position values for game buttons */
6875 #define GAME_BUTTON_XSIZE       30
6876 #define GAME_BUTTON_YSIZE       30
6877 #define GAME_BUTTON_XPOS        5
6878 #define GAME_BUTTON_YPOS        215
6879 #define SOUND_BUTTON_XPOS       5
6880 #define SOUND_BUTTON_YPOS       (GAME_BUTTON_YPOS + GAME_BUTTON_YSIZE)
6881
6882 #define GAME_BUTTON_STOP_XPOS   (GAME_BUTTON_XPOS + 0 * GAME_BUTTON_XSIZE)
6883 #define GAME_BUTTON_PAUSE_XPOS  (GAME_BUTTON_XPOS + 1 * GAME_BUTTON_XSIZE)
6884 #define GAME_BUTTON_PLAY_XPOS   (GAME_BUTTON_XPOS + 2 * GAME_BUTTON_XSIZE)
6885 #define SOUND_BUTTON_MUSIC_XPOS (SOUND_BUTTON_XPOS + 0 * GAME_BUTTON_XSIZE)
6886 #define SOUND_BUTTON_LOOPS_XPOS (SOUND_BUTTON_XPOS + 1 * GAME_BUTTON_XSIZE)
6887 #define SOUND_BUTTON_SIMPLE_XPOS (SOUND_BUTTON_XPOS + 2 * GAME_BUTTON_XSIZE)
6888
6889 static struct
6890 {
6891   int x, y;
6892   int gadget_id;
6893   char *infotext;
6894 } gamebutton_info[NUM_GAME_BUTTONS] =
6895 {
6896   {
6897     GAME_BUTTON_STOP_XPOS,      GAME_BUTTON_YPOS,
6898     GAME_CTRL_ID_STOP,
6899     "stop game"
6900   },
6901   {
6902     GAME_BUTTON_PAUSE_XPOS,     GAME_BUTTON_YPOS,
6903     GAME_CTRL_ID_PAUSE,
6904     "pause game"
6905   },
6906   {
6907     GAME_BUTTON_PLAY_XPOS,      GAME_BUTTON_YPOS,
6908     GAME_CTRL_ID_PLAY,
6909     "play game"
6910   },
6911   {
6912     SOUND_BUTTON_MUSIC_XPOS,    SOUND_BUTTON_YPOS,
6913     SOUND_CTRL_ID_MUSIC,
6914     "background music on/off"
6915   },
6916   {
6917     SOUND_BUTTON_LOOPS_XPOS,    SOUND_BUTTON_YPOS,
6918     SOUND_CTRL_ID_LOOPS,
6919     "sound loops on/off"
6920   },
6921   {
6922     SOUND_BUTTON_SIMPLE_XPOS,   SOUND_BUTTON_YPOS,
6923     SOUND_CTRL_ID_SIMPLE,
6924     "normal sounds on/off"
6925   }
6926 };
6927
6928 void CreateGameButtons()
6929 {
6930   int i;
6931
6932   for (i=0; i<NUM_GAME_BUTTONS; i++)
6933   {
6934     Bitmap *gd_bitmap = new_graphic_info[IMG_MENU_DOOR].bitmap;
6935     struct GadgetInfo *gi;
6936     int button_type;
6937     boolean checked;
6938     unsigned long event_mask;
6939     int gd_xoffset, gd_yoffset;
6940     int gd_x1, gd_x2, gd_y1, gd_y2;
6941     int id = i;
6942
6943     gd_xoffset = gamebutton_info[i].x;
6944     gd_yoffset = gamebutton_info[i].y;
6945     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
6946     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
6947
6948     if (id == GAME_CTRL_ID_STOP ||
6949         id == GAME_CTRL_ID_PAUSE ||
6950         id == GAME_CTRL_ID_PLAY)
6951     {
6952       button_type = GD_TYPE_NORMAL_BUTTON;
6953       checked = FALSE;
6954       event_mask = GD_EVENT_RELEASED;
6955       gd_y1  = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
6956       gd_y2  = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
6957     }
6958     else
6959     {
6960       button_type = GD_TYPE_CHECK_BUTTON;
6961       checked =
6962         ((id == SOUND_CTRL_ID_MUSIC && setup.sound_music) ||
6963          (id == SOUND_CTRL_ID_LOOPS && setup.sound_loops) ||
6964          (id == SOUND_CTRL_ID_SIMPLE && setup.sound_simple) ? TRUE : FALSE);
6965       event_mask = GD_EVENT_PRESSED;
6966       gd_y1  = DOOR_GFX_PAGEY1 + gd_yoffset;
6967       gd_y2  = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
6968     }
6969
6970     gi = CreateGadget(GDI_CUSTOM_ID, id,
6971                       GDI_INFO_TEXT, gamebutton_info[i].infotext,
6972                       GDI_X, DX + gd_xoffset,
6973                       GDI_Y, DY + gd_yoffset,
6974                       GDI_WIDTH, GAME_BUTTON_XSIZE,
6975                       GDI_HEIGHT, GAME_BUTTON_YSIZE,
6976                       GDI_TYPE, button_type,
6977                       GDI_STATE, GD_BUTTON_UNPRESSED,
6978                       GDI_CHECKED, checked,
6979                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
6980                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y1,
6981                       GDI_ALT_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y2,
6982                       GDI_ALT_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
6983                       GDI_EVENT_MASK, event_mask,
6984                       GDI_CALLBACK_ACTION, HandleGameButtons,
6985                       GDI_END);
6986
6987     if (gi == NULL)
6988       Error(ERR_EXIT, "cannot create gadget");
6989
6990     game_gadget[id] = gi;
6991   }
6992 }
6993
6994 static void MapGameButtons()
6995 {
6996   int i;
6997
6998   for (i=0; i<NUM_GAME_BUTTONS; i++)
6999     MapGadget(game_gadget[i]);
7000 }
7001
7002 void UnmapGameButtons()
7003 {
7004   int i;
7005
7006   for (i=0; i<NUM_GAME_BUTTONS; i++)
7007     UnmapGadget(game_gadget[i]);
7008 }
7009
7010 static void HandleGameButtons(struct GadgetInfo *gi)
7011 {
7012   int id = gi->custom_id;
7013
7014   if (game_status != PLAYING)
7015     return;
7016
7017   switch (id)
7018   {
7019     case GAME_CTRL_ID_STOP:
7020       RequestQuitGame(TRUE);
7021       break;
7022
7023     case GAME_CTRL_ID_PAUSE:
7024       if (options.network)
7025       {
7026 #if defined(PLATFORM_UNIX)
7027         if (tape.pausing)
7028           SendToServer_ContinuePlaying();
7029         else
7030           SendToServer_PausePlaying();
7031 #endif
7032       }
7033       else
7034         TapeTogglePause(TAPE_TOGGLE_MANUAL);
7035       break;
7036
7037     case GAME_CTRL_ID_PLAY:
7038       if (tape.pausing)
7039       {
7040 #if defined(PLATFORM_UNIX)
7041         if (options.network)
7042           SendToServer_ContinuePlaying();
7043         else
7044 #endif
7045         {
7046           tape.pausing = FALSE;
7047           DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0);
7048         }
7049       }
7050       break;
7051
7052     case SOUND_CTRL_ID_MUSIC:
7053       if (setup.sound_music)
7054       { 
7055         setup.sound_music = FALSE;
7056         FadeMusic();
7057       }
7058       else if (audio.music_available)
7059       { 
7060         setup.sound = setup.sound_music = TRUE;
7061         PlayMusic(level_nr);
7062       }
7063       break;
7064
7065     case SOUND_CTRL_ID_LOOPS:
7066       if (setup.sound_loops)
7067         setup.sound_loops = FALSE;
7068       else if (audio.loops_available)
7069         setup.sound = setup.sound_loops = TRUE;
7070       break;
7071
7072     case SOUND_CTRL_ID_SIMPLE:
7073       if (setup.sound_simple)
7074         setup.sound_simple = FALSE;
7075       else if (audio.sound_available)
7076         setup.sound = setup.sound_simple = TRUE;
7077       break;
7078
7079     default:
7080       break;
7081   }
7082 }