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