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