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