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