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