rnd-19991010-2-src
[rocksndiamonds.git] / src / game.c
1 /***********************************************************
2 *  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
3 *----------------------------------------------------------*
4 *  (c) 1995-98 Artsoft Entertainment                       *
5 *              Holger Schemel                              *
6 *              Oststrasse 11a                              *
7 *              33604 Bielefeld                             *
8 *              phone: ++49 +521 290471                     *
9 *              email: aeglos@valinor.owl.de                *
10 *----------------------------------------------------------*
11 *  game.c                                                  *
12 ***********************************************************/
13
14 #include "game.h"
15 #include "misc.h"
16 #include "tools.h"
17 #include "screens.h"
18 #include "sound.h"
19 #include "init.h"
20 #include "buttons.h"
21 #include "files.h"
22 #include "tape.h"
23 #include "joystick.h"
24 #include "network.h"
25
26 /* this switch controls how rocks move horizontally */
27 #define OLD_GAME_BEHAVIOUR      FALSE
28
29 /* for DigField() */
30 #define DF_NO_PUSH              0
31 #define DF_DIG                  1
32 #define DF_SNAP                 2
33
34 /* for MoveFigure() */
35 #define MF_NO_ACTION            0
36 #define MF_MOVING               1
37 #define MF_ACTION               2
38
39 /* for ScrollFigure() */
40 #define SCROLL_INIT             0
41 #define SCROLL_GO_ON            1
42
43 /* for Explode() */
44 #define EX_PHASE_START          0
45 #define EX_NORMAL               0
46 #define EX_CENTER               1
47 #define EX_BORDER               2
48
49 /* special positions in the game control window (relative to control window) */
50 #define XX_LEVEL                37
51 #define YY_LEVEL                20
52 #define XX_EMERALDS             29
53 #define YY_EMERALDS             54
54 #define XX_DYNAMITE             29
55 #define YY_DYNAMITE             89
56 #define XX_KEYS                 18
57 #define YY_KEYS                 123
58 #define XX_SCORE                15
59 #define YY_SCORE                159
60 #define XX_TIME                 29
61 #define YY_TIME                 194
62
63 /* special positions in the game control window (relative to main window) */
64 #define DX_LEVEL                (DX + XX_LEVEL)
65 #define DY_LEVEL                (DY + YY_LEVEL)
66 #define DX_EMERALDS             (DX + XX_EMERALDS)
67 #define DY_EMERALDS             (DY + YY_EMERALDS)
68 #define DX_DYNAMITE             (DX + XX_DYNAMITE)
69 #define DY_DYNAMITE             (DY + YY_DYNAMITE)
70 #define DX_KEYS                 (DX + XX_KEYS)
71 #define DY_KEYS                 (DY + YY_KEYS)
72 #define DX_SCORE                (DX + XX_SCORE)
73 #define DY_SCORE                (DY + YY_SCORE)
74 #define DX_TIME                 (DX + XX_TIME)
75 #define DY_TIME                 (DY + YY_TIME)
76
77 #define IS_LOOP_SOUND(s)        ((s)==SND_KLAPPER || (s)==SND_ROEHR ||  \
78                                  (s)==SND_NJAM || (s)==SND_MIEP)
79 #define IS_MUSIC_SOUND(s)       ((s)==SND_ALCHEMY || (s)==SND_CHASE || \
80                                  (s)==SND_NETWORK || (s)==SND_CZARDASZ || \
81                                  (s)==SND_TYGER || (s)==SND_VOYAGER || \
82                                  (s)==SND_TWILIGHT)
83
84 /* values for player movement speed (which is in fact a delay value) */
85 #define MOVE_DELAY_NORMAL_SPEED 8
86 #define MOVE_DELAY_HIGH_SPEED   4
87
88 #define DOUBLE_MOVE_DELAY(x)    (x = (x <= MOVE_DELAY_HIGH_SPEED ? x * 2 : x))
89 #define HALVE_MOVE_DELAY(x)     (x = (x >= MOVE_DELAY_HIGH_SPEED ? x / 2 : x))
90 #define DOUBLE_PLAYER_SPEED(p)  (HALVE_MOVE_DELAY((p)->move_delay_value))
91 #define HALVE_PLAYER_SPEED(p)   (DOUBLE_MOVE_DELAY((p)->move_delay_value))
92
93 /* game button identifiers */
94 #define GAME_CTRL_ID_STOP               0
95 #define GAME_CTRL_ID_PAUSE              1
96 #define GAME_CTRL_ID_PLAY               2
97 #define SOUND_CTRL_ID_MUSIC             3
98 #define SOUND_CTRL_ID_LOOPS             4
99 #define SOUND_CTRL_ID_SIMPLE            5
100
101 #define NUM_GAME_BUTTONS                6
102
103 /* forward declaration for internal use */
104 static void CloseAllOpenTimegates(void);
105 static void CheckGravityMovement(struct PlayerInfo *);
106 static void KillHeroUnlessProtected(int, int);
107
108 static void MapGameButtons();
109 static void HandleGameButtons(struct GadgetInfo *);
110
111 static struct GadgetInfo *game_gadget[NUM_GAME_BUTTONS];
112
113
114
115 #ifdef DEBUG
116 #if 0
117 static unsigned int getStateCheckSum(int counter)
118 {
119   int x, y;
120   unsigned int mult = 1;
121   unsigned int checksum = 0;
122   /*
123   static short lastFeld[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
124   */
125   static boolean first_game = TRUE;
126
127   for (y=0; y<lev_fieldy; y++) for(x=0; x<lev_fieldx; x++)
128   {
129     /*
130     if (counter == 3)
131     {
132       if (first_game)
133         lastFeld[x][y] = Feld[x][y];
134       else if (lastFeld[x][y] != Feld[x][y])
135         printf("DIFF: [%d][%d]: lastFeld == %d != %d == Feld\n",
136                x, y, lastFeld[x][y], Feld[x][y]);
137     }
138     */
139
140     checksum += mult++ * Ur[x][y];
141     checksum += mult++ * Feld[x][y];
142
143     /*
144     checksum += mult++ * MovPos[x][y];
145     checksum += mult++ * MovDir[x][y];
146     checksum += mult++ * MovDelay[x][y];
147     checksum += mult++ * Store[x][y];
148     checksum += mult++ * Store2[x][y];
149     checksum += mult++ * StorePlayer[x][y];
150     checksum += mult++ * Frame[x][y];
151     checksum += mult++ * AmoebaNr[x][y];
152     checksum += mult++ * JustStopped[x][y];
153     checksum += mult++ * Stop[x][y];
154     */
155   }
156
157   if (counter == 3 && first_game)
158     first_game = FALSE;
159
160   return checksum;
161 }
162 #endif
163 #endif
164
165
166
167
168 void GetPlayerConfig()
169 {
170   if (sound_status == SOUND_OFF)
171     setup.sound = FALSE;
172
173   if (!sound_loops_allowed)
174   {
175     setup.sound_loops = FALSE;
176     setup.sound_music = FALSE;
177   }
178
179   setup.sound_simple = setup.sound;
180
181   InitJoysticks();
182 }
183
184 static int getBeltNrFromElement(int element)
185 {
186   return (element < EL_BELT2_LEFT ? 0 :
187           element < EL_BELT3_LEFT ? 1 :
188           element < EL_BELT4_LEFT ? 2 : 3);
189 }
190
191 static int getBeltNrFromSwitchElement(int element)
192 {
193   return (element < EL_BELT2_SWITCH_LEFT ? 0 :
194           element < EL_BELT3_SWITCH_LEFT ? 1 :
195           element < EL_BELT4_SWITCH_LEFT ? 2 : 3);
196 }
197
198 static int getBeltDirNrFromSwitchElement(int element)
199 {
200   static int belt_base_element[4] =
201   {
202     EL_BELT1_SWITCH_LEFT,
203     EL_BELT2_SWITCH_LEFT,
204     EL_BELT3_SWITCH_LEFT,
205     EL_BELT4_SWITCH_LEFT
206   };
207
208   int belt_nr = getBeltNrFromSwitchElement(element);
209   int belt_dir_nr = element - belt_base_element[belt_nr];
210
211   return (belt_dir_nr % 3);
212 }
213
214 static int getBeltDirFromSwitchElement(int element)
215 {
216   static int belt_move_dir[3] =
217   {
218     MV_LEFT,
219     MV_NO_MOVING,
220     MV_RIGHT
221   };
222
223   int belt_dir_nr = getBeltDirNrFromSwitchElement(element);
224
225   return belt_move_dir[belt_dir_nr];
226 }
227
228 static void InitField(int x, int y, boolean init_game)
229 {
230   switch (Feld[x][y])
231   {
232     case EL_SPIELFIGUR:
233     case EL_SP_MURPHY:
234       if (init_game)
235         Feld[x][y] = EL_SPIELER1;
236       /* no break! */
237     case EL_SPIELER1:
238     case EL_SPIELER2:
239     case EL_SPIELER3:
240     case EL_SPIELER4:
241       if (init_game)
242       {
243         struct PlayerInfo *player = &stored_player[Feld[x][y] - EL_SPIELER1];
244         int jx = player->jx, jy = player->jy;
245
246         player->present = TRUE;
247
248         if (!options.network || player->connected)
249         {
250           player->active = TRUE;
251
252           /* remove potentially duplicate players */
253           if (StorePlayer[jx][jy] == Feld[x][y])
254             StorePlayer[jx][jy] = 0;
255
256           StorePlayer[x][y] = Feld[x][y];
257
258           if (options.verbose)
259           {
260             printf("Player %d activated.\n", player->element_nr);
261             printf("[Local player is %d and currently %s.]\n",
262                    local_player->element_nr,
263                    local_player->active ? "active" : "not active");
264           }
265         }
266
267         Feld[x][y] = EL_LEERRAUM;
268         player->jx = player->last_jx = x;
269         player->jy = player->last_jy = y;
270       }
271       break;
272
273     case EL_BADEWANNE:
274       if (x < lev_fieldx-1 && Feld[x+1][y] == EL_SALZSAEURE)
275         Feld[x][y] = EL_BADEWANNE1;
276       else if (x > 0 && Feld[x-1][y] == EL_SALZSAEURE)
277         Feld[x][y] = EL_BADEWANNE2;
278       else if (y > 0 && Feld[x][y-1] == EL_BADEWANNE1)
279         Feld[x][y] = EL_BADEWANNE3;
280       else if (y > 0 && Feld[x][y-1] == EL_SALZSAEURE)
281         Feld[x][y] = EL_BADEWANNE4;
282       else if (y > 0 && Feld[x][y-1] == EL_BADEWANNE2)
283         Feld[x][y] = EL_BADEWANNE5;
284       break;
285
286     case EL_KAEFER_RIGHT:
287     case EL_KAEFER_UP:
288     case EL_KAEFER_LEFT:
289     case EL_KAEFER_DOWN:
290     case EL_KAEFER:
291     case EL_FLIEGER_RIGHT:
292     case EL_FLIEGER_UP:
293     case EL_FLIEGER_LEFT:
294     case EL_FLIEGER_DOWN:
295     case EL_FLIEGER:
296     case EL_BUTTERFLY_RIGHT:
297     case EL_BUTTERFLY_UP:
298     case EL_BUTTERFLY_LEFT:
299     case EL_BUTTERFLY_DOWN:
300     case EL_BUTTERFLY:
301     case EL_FIREFLY_RIGHT:
302     case EL_FIREFLY_UP:
303     case EL_FIREFLY_LEFT:
304     case EL_FIREFLY_DOWN:
305     case EL_FIREFLY:
306     case EL_PACMAN_RIGHT:
307     case EL_PACMAN_UP:
308     case EL_PACMAN_LEFT:
309     case EL_PACMAN_DOWN:
310     case EL_MAMPFER:
311     case EL_MAMPFER2:
312     case EL_ROBOT:
313     case EL_PACMAN:
314     case EL_SP_SNIKSNAK:
315     case EL_SP_ELECTRON:
316     case EL_MOLE_LEFT:
317     case EL_MOLE_RIGHT:
318     case EL_MOLE_UP:
319     case EL_MOLE_DOWN:
320     case EL_MOLE:
321       InitMovDir(x, y);
322       break;
323
324     case EL_AMOEBE_VOLL:
325     case EL_AMOEBE_BD:
326       InitAmoebaNr(x, y);
327       break;
328
329     case EL_TROPFEN:
330       if (y == lev_fieldy - 1)
331       {
332         Feld[x][y] = EL_AMOEBING;
333         Store[x][y] = EL_AMOEBE_NASS;
334       }
335       break;
336
337     case EL_DYNAMITE_ACTIVE:
338       MovDelay[x][y] = 96;
339       break;
340
341     case EL_BIRNE_AUS:
342       local_player->lights_still_needed++;
343       break;
344
345     case EL_SOKOBAN_FELD_LEER:
346       local_player->sokobanfields_still_needed++;
347       break;
348
349     case EL_PINGUIN:
350       local_player->friends_still_needed++;
351       break;
352
353     case EL_SCHWEIN:
354     case EL_DRACHE:
355       MovDir[x][y] = 1 << RND(4);
356       break;
357
358     case EL_SP_EMPTY:
359       Feld[x][y] = EL_LEERRAUM;
360       break;
361
362     case EL_EM_KEY_1_FILE:
363       Feld[x][y] = EL_EM_KEY_1;
364       break;
365     case EL_EM_KEY_2_FILE:
366       Feld[x][y] = EL_EM_KEY_2;
367       break;
368     case EL_EM_KEY_3_FILE:
369       Feld[x][y] = EL_EM_KEY_3;
370       break;
371     case EL_EM_KEY_4_FILE:
372       Feld[x][y] = EL_EM_KEY_4;
373       break;
374
375     case EL_BELT1_SWITCH_LEFT:
376     case EL_BELT1_SWITCH_MIDDLE:
377     case EL_BELT1_SWITCH_RIGHT:
378     case EL_BELT2_SWITCH_LEFT:
379     case EL_BELT2_SWITCH_MIDDLE:
380     case EL_BELT2_SWITCH_RIGHT:
381     case EL_BELT3_SWITCH_LEFT:
382     case EL_BELT3_SWITCH_MIDDLE:
383     case EL_BELT3_SWITCH_RIGHT:
384     case EL_BELT4_SWITCH_LEFT:
385     case EL_BELT4_SWITCH_MIDDLE:
386     case EL_BELT4_SWITCH_RIGHT:
387       if (init_game)
388       {
389         int belt_nr = getBeltNrFromSwitchElement(Feld[x][y]);
390         int belt_dir = getBeltDirFromSwitchElement(Feld[x][y]);
391         int belt_dir_nr = getBeltDirNrFromSwitchElement(Feld[x][y]);
392
393         if (game.belt_dir_nr[belt_nr] == 3)     /* initial value */
394         {
395           game.belt_dir[belt_nr] = belt_dir;
396           game.belt_dir_nr[belt_nr] = belt_dir_nr;
397         }
398         else    /* more than one switch -- set it like the first switch */
399         {
400           Feld[x][y] = Feld[x][y] - belt_dir_nr + game.belt_dir_nr[belt_nr];
401         }
402       }
403       break;
404
405     case EL_SWITCHGATE_SWITCH_2:        /* always start with same switch pos */
406       if (init_game)
407         Feld[x][y] = EL_SWITCHGATE_SWITCH_1;
408       break;
409
410     case EL_LIGHT_SWITCH_ON:
411       if (init_game)
412         game.light_time_left = level.time_light * FRAMES_PER_SECOND;
413       break;
414
415     default:
416       break;
417   }
418 }
419
420 void InitGame()
421 {
422   int i, j, x, y;
423   boolean emulate_bd = TRUE;    /* unless non-BOULDERDASH elements found */
424   boolean emulate_sb = TRUE;    /* unless non-SOKOBAN     elements found */
425   boolean emulate_sp = TRUE;    /* unless non-SUPAPLEX    elements found */
426
427   /* don't play tapes over network */
428   network_playing = (options.network && !tape.playing);
429
430   for (i=0; i<MAX_PLAYERS; i++)
431   {
432     struct PlayerInfo *player = &stored_player[i];
433
434     player->index_nr = i;
435     player->element_nr = EL_SPIELER1 + i;
436
437     player->present = FALSE;
438     player->active = FALSE;
439
440     player->action = 0;
441     player->effective_action = 0;
442     player->programmed_action = 0;
443
444     player->score = 0;
445     player->gems_still_needed = level.gems_needed;
446     player->sokobanfields_still_needed = 0;
447     player->lights_still_needed = 0;
448     player->friends_still_needed = 0;
449
450     for (j=0; j<4; j++)
451       player->key[j] = FALSE;
452
453     player->dynamite = 0;
454     player->dynabomb_count = 0;
455     player->dynabomb_size = 1;
456     player->dynabombs_left = 0;
457     player->dynabomb_xl = FALSE;
458
459     player->MovDir = MV_NO_MOVING;
460     player->MovPos = 0;
461     player->Pushing = FALSE;
462     player->Switching = FALSE;
463     player->GfxPos = 0;
464     player->Frame = 0;
465
466     player->actual_frame_counter = 0;
467
468     player->frame_reset_delay = 0;
469
470     player->push_delay = 0;
471     player->push_delay_value = 5;
472
473     player->move_delay = 0;
474     player->last_move_dir = MV_NO_MOVING;
475
476     player->move_delay_value =
477       (level.double_speed ? MOVE_DELAY_HIGH_SPEED : MOVE_DELAY_NORMAL_SPEED);
478
479     player->snapped = FALSE;
480
481     player->last_jx = player->last_jy = 0;
482     player->jx = player->jy = 0;
483
484     player->shield_passive_time_left = 0;
485     player->shield_active_time_left = 0;
486
487     DigField(player, 0, 0, 0, 0, DF_NO_PUSH);
488     SnapField(player, 0, 0);
489
490     player->LevelSolved = FALSE;
491     player->GameOver = FALSE;
492   }
493
494   network_player_action_received = FALSE;
495
496 #ifndef MSDOS
497   /* initial null action */
498   if (network_playing)
499     SendToServer_MovePlayer(MV_NO_MOVING);
500 #endif
501
502   ZX = ZY = -1;
503
504   game.yam_content_nr = 0;
505   FrameCounter = 0;
506   TimeFrames = 0;
507   TimePlayed = 0;
508   TimeLeft = level.time;
509
510   ScreenMovDir = MV_NO_MOVING;
511   ScreenMovPos = 0;
512   ScreenGfxPos = 0;
513
514   ScrollStepSize = 0;   /* will be correctly initialized by ScrollScreen() */
515
516   AllPlayersGone = FALSE;
517   game.magic_wall_active = FALSE;
518   game.magic_wall_time_left = 0;
519   game.light_time_left = 0;
520   game.timegate_time_left = 0;
521   game.switchgate_pos = 0;
522   game.balloon_dir = MV_NO_MOVING;
523
524   for (i=0; i<4; i++)
525   {
526     game.belt_dir[i] = MV_NO_MOVING;
527     game.belt_dir_nr[i] = 3;            /* not moving, next moving left */
528   }
529
530   for (i=0; i<MAX_NUM_AMOEBA; i++)
531     AmoebaCnt[i] = AmoebaCnt2[i] = 0;
532
533   for (x=0; x<lev_fieldx; x++)
534   {
535     for (y=0; y<lev_fieldy; y++)
536     {
537       Feld[x][y] = Ur[x][y];
538       MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
539       Store[x][y] = Store2[x][y] = StorePlayer[x][y] = 0;
540       Frame[x][y] = 0;
541       AmoebaNr[x][y] = 0;
542       JustStopped[x][y] = 0;
543       Stop[x][y] = FALSE;
544     }
545   }
546
547   for(y=0; y<lev_fieldy; y++)
548   {
549     for(x=0; x<lev_fieldx; x++)
550     {
551       if (emulate_bd && !IS_BD_ELEMENT(Feld[x][y]))
552         emulate_bd = FALSE;
553       if (emulate_sb && !IS_SB_ELEMENT(Feld[x][y]))
554         emulate_sb = FALSE;
555       if (emulate_sp && !IS_SP_ELEMENT(Feld[x][y]))
556         emulate_sp = FALSE;
557
558       InitField(x, y, TRUE);
559     }
560   }
561
562   /* correct non-moving belts to start moving left */
563   for (i=0; i<4; i++)
564     if (game.belt_dir[i] == MV_NO_MOVING)
565       game.belt_dir_nr[i] = 3;          /* not moving, next moving left */
566
567   /* check if any connected player was not found in playfield */
568   for (i=0; i<MAX_PLAYERS; i++)
569   {
570     struct PlayerInfo *player = &stored_player[i];
571
572     if (player->connected && !player->present)
573     {
574       for (j=0; j<MAX_PLAYERS; j++)
575       {
576         struct PlayerInfo *some_player = &stored_player[j];
577         int jx = some_player->jx, jy = some_player->jy;
578
579         /* assign first free player found that is present in the playfield */
580         if (some_player->present && !some_player->connected)
581         {
582           player->present = TRUE;
583           player->active = TRUE;
584           some_player->present = FALSE;
585
586           StorePlayer[jx][jy] = player->element_nr;
587           player->jx = player->last_jx = jx;
588           player->jy = player->last_jy = jy;
589
590           break;
591         }
592       }
593     }
594   }
595
596   if (tape.playing)
597   {
598     /* when playing a tape, eliminate all players who do not participate */
599
600     for (i=0; i<MAX_PLAYERS; i++)
601     {
602       if (stored_player[i].active && !tape.player_participates[i])
603       {
604         struct PlayerInfo *player = &stored_player[i];
605         int jx = player->jx, jy = player->jy;
606
607         player->active = FALSE;
608         StorePlayer[jx][jy] = 0;
609         Feld[jx][jy] = EL_LEERRAUM;
610       }
611     }
612   }
613   else if (!options.network && !setup.team_mode)        /* && !tape.playing */
614   {
615     /* when in single player mode, eliminate all but the first active player */
616
617     for (i=0; i<MAX_PLAYERS; i++)
618     {
619       if (stored_player[i].active)
620       {
621         for (j=i+1; j<MAX_PLAYERS; j++)
622         {
623           if (stored_player[j].active)
624           {
625             struct PlayerInfo *player = &stored_player[j];
626             int jx = player->jx, jy = player->jy;
627
628             player->active = FALSE;
629             StorePlayer[jx][jy] = 0;
630             Feld[jx][jy] = EL_LEERRAUM;
631           }
632         }
633       }
634     }
635   }
636
637   /* when recording the game, store which players take part in the game */
638   if (tape.recording)
639   {
640     for (i=0; i<MAX_PLAYERS; i++)
641       if (stored_player[i].active)
642         tape.player_participates[i] = TRUE;
643   }
644
645   if (options.verbose)
646   {
647     for (i=0; i<MAX_PLAYERS; i++)
648     {
649       struct PlayerInfo *player = &stored_player[i];
650
651       printf("Player %d: present == %d, connected == %d, active == %d.\n",
652              i+1,
653              player->present,
654              player->connected,
655              player->active);
656       if (local_player == player)
657         printf("Player  %d is local player.\n", i+1);
658     }
659   }
660
661   game.emulation = (emulate_bd ? EMU_BOULDERDASH :
662                     emulate_sb ? EMU_SOKOBAN :
663                     emulate_sp ? EMU_SUPAPLEX : EMU_NONE);
664
665   if (BorderElement == EL_LEERRAUM)
666   {
667     SBX_Left = 0;
668     SBX_Right = lev_fieldx - SCR_FIELDX;
669     SBY_Upper = 0;
670     SBY_Lower = lev_fieldy - SCR_FIELDY;
671   }
672   else
673   {
674     SBX_Left = -1;
675     SBX_Right = lev_fieldx - SCR_FIELDX + 1;
676     SBY_Upper = -1;
677     SBY_Lower = lev_fieldy - SCR_FIELDY + 1;
678   }
679
680   if (lev_fieldx + (SBX_Left == -1 ? 2 : 0) <= SCR_FIELDX)
681     SBX_Left = SBX_Right = -1 * (SCR_FIELDX - lev_fieldx) / 2;
682
683   if (lev_fieldy + (SBY_Upper == -1 ? 2 : 0) <= SCR_FIELDY)
684     SBY_Upper = SBY_Lower = -1 * (SCR_FIELDY - lev_fieldy) / 2;
685
686   scroll_x = SBX_Left;
687   scroll_y = SBY_Upper;
688   if (local_player->jx >= SBX_Left + MIDPOSX)
689     scroll_x = (local_player->jx <= SBX_Right + MIDPOSX ?
690                 local_player->jx - MIDPOSX :
691                 SBX_Right);
692   if (local_player->jy >= SBY_Upper + MIDPOSY)
693     scroll_y = (local_player->jy <= SBY_Lower + MIDPOSY ?
694                 local_player->jy - MIDPOSY :
695                 SBY_Lower);
696
697   CloseDoor(DOOR_CLOSE_1);
698
699   DrawLevel();
700   DrawAllPlayers();
701   FadeToFront();
702
703   /* after drawing the level, corect some elements */
704
705   if (game.timegate_time_left == 0)
706     CloseAllOpenTimegates();
707
708   if (setup.soft_scrolling)
709     XCopyArea(display, fieldbuffer, backbuffer, gc,
710               FX, FY, SXSIZE, SYSIZE, SX, SY);
711
712   redraw_mask |= REDRAW_FROM_BACKBUFFER;
713
714   /* copy default game door content to main double buffer */
715   XCopyArea(display, pix[PIX_DOOR], drawto, gc,
716             DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY);
717
718   if (level_nr < 100)
719     DrawText(DX + XX_LEVEL, DY + YY_LEVEL,
720              int2str(level_nr, 2), FS_SMALL, FC_YELLOW);
721   else
722   {
723     DrawTextExt(drawto, gc, DX + XX_EMERALDS, DY + YY_EMERALDS,
724                 int2str(level_nr, 3), FS_SMALL, FC_SPECIAL3);
725     XCopyArea(display, drawto, drawto, gc,
726               DX + XX_EMERALDS, DY + YY_EMERALDS + 1,
727               FONT5_XSIZE * 3, FONT5_YSIZE - 1,
728               DX + XX_LEVEL - 1, DY + YY_LEVEL + 1);
729   }
730
731   DrawText(DX + XX_EMERALDS, DY + YY_EMERALDS,
732            int2str(local_player->gems_still_needed, 3), FS_SMALL, FC_YELLOW);
733   DrawText(DX + XX_DYNAMITE, DY + YY_DYNAMITE,
734            int2str(local_player->dynamite, 3), FS_SMALL, FC_YELLOW);
735   DrawText(DX + XX_SCORE, DY + YY_SCORE,
736            int2str(local_player->score, 5), FS_SMALL, FC_YELLOW);
737   DrawText(DX + XX_TIME, DY + YY_TIME,
738            int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
739
740   UnmapGameButtons();
741   game_gadget[SOUND_CTRL_ID_MUSIC]->checked = setup.sound_music;
742   game_gadget[SOUND_CTRL_ID_LOOPS]->checked = setup.sound_loops;
743   game_gadget[SOUND_CTRL_ID_SIMPLE]->checked = setup.sound_simple;
744   MapGameButtons();
745   MapTapeButtons();
746
747   /* copy actual game door content to door double buffer for OpenDoor() */
748   XCopyArea(display, drawto, pix[PIX_DB_DOOR], gc,
749             DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
750
751   OpenDoor(DOOR_OPEN_ALL);
752
753   if (setup.sound_music)
754     PlaySoundLoop(background_loop[level_nr % num_bg_loops]);
755
756   XAutoRepeatOff(display);
757
758   if (options.verbose)
759   {
760     for (i=0; i<4; i++)
761       printf("Player %d %sactive.\n",
762              i + 1, (stored_player[i].active ? "" : "not "));
763   }
764 }
765
766 void InitMovDir(int x, int y)
767 {
768   int i, element = Feld[x][y];
769   static int xy[4][2] =
770   {
771     {  0, +1 },
772     { +1,  0 },
773     {  0, -1 },
774     { -1,  0 }
775   };
776   static int direction[3][4] =
777   {
778     { MV_RIGHT, MV_UP,   MV_LEFT,  MV_DOWN },
779     { MV_LEFT,  MV_DOWN, MV_RIGHT, MV_UP },
780     { MV_LEFT,  MV_RIGHT, MV_UP, MV_DOWN }
781   };
782
783   switch(element)
784   {
785     case EL_KAEFER_RIGHT:
786     case EL_KAEFER_UP:
787     case EL_KAEFER_LEFT:
788     case EL_KAEFER_DOWN:
789       Feld[x][y] = EL_KAEFER;
790       MovDir[x][y] = direction[0][element - EL_KAEFER_RIGHT];
791       break;
792
793     case EL_FLIEGER_RIGHT:
794     case EL_FLIEGER_UP:
795     case EL_FLIEGER_LEFT:
796     case EL_FLIEGER_DOWN:
797       Feld[x][y] = EL_FLIEGER;
798       MovDir[x][y] = direction[0][element - EL_FLIEGER_RIGHT];
799       break;
800
801     case EL_BUTTERFLY_RIGHT:
802     case EL_BUTTERFLY_UP:
803     case EL_BUTTERFLY_LEFT:
804     case EL_BUTTERFLY_DOWN:
805       Feld[x][y] = EL_BUTTERFLY;
806       MovDir[x][y] = direction[0][element - EL_BUTTERFLY_RIGHT];
807       break;
808
809     case EL_FIREFLY_RIGHT:
810     case EL_FIREFLY_UP:
811     case EL_FIREFLY_LEFT:
812     case EL_FIREFLY_DOWN:
813       Feld[x][y] = EL_FIREFLY;
814       MovDir[x][y] = direction[0][element - EL_FIREFLY_RIGHT];
815       break;
816
817     case EL_PACMAN_RIGHT:
818     case EL_PACMAN_UP:
819     case EL_PACMAN_LEFT:
820     case EL_PACMAN_DOWN:
821       Feld[x][y] = EL_PACMAN;
822       MovDir[x][y] = direction[0][element - EL_PACMAN_RIGHT];
823       break;
824
825     case EL_SP_SNIKSNAK:
826       MovDir[x][y] = MV_UP;
827       break;
828
829     case EL_SP_ELECTRON:
830       MovDir[x][y] = MV_LEFT;
831       break;
832
833     case EL_MOLE_LEFT:
834     case EL_MOLE_RIGHT:
835     case EL_MOLE_UP:
836     case EL_MOLE_DOWN:
837       Feld[x][y] = EL_MOLE;
838       MovDir[x][y] = direction[2][element - EL_MOLE_LEFT];
839       break;
840
841     default:
842       MovDir[x][y] = 1 << RND(4);
843       if (element != EL_KAEFER &&
844           element != EL_FLIEGER &&
845           element != EL_BUTTERFLY &&
846           element != EL_FIREFLY)
847         break;
848
849       for (i=0; i<4; i++)
850       {
851         int x1 = x + xy[i][0];
852         int y1 = y + xy[i][1];
853
854         if (!IN_LEV_FIELD(x1, y1) || !IS_FREE(x1, y1))
855         {
856           if (element == EL_KAEFER || element == EL_BUTTERFLY)
857           {
858             MovDir[x][y] = direction[0][i];
859             break;
860           }
861           else if (element == EL_FLIEGER || element == EL_FIREFLY ||
862                    element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
863           {
864             MovDir[x][y] = direction[1][i];
865             break;
866           }
867         }
868       }
869       break;
870   }
871 }
872
873 void InitAmoebaNr(int x, int y)
874 {
875   int i;
876   int group_nr = AmoebeNachbarNr(x, y);
877
878   if (group_nr == 0)
879   {
880     for (i=1; i<MAX_NUM_AMOEBA; i++)
881     {
882       if (AmoebaCnt[i] == 0)
883       {
884         group_nr = i;
885         break;
886       }
887     }
888   }
889
890   AmoebaNr[x][y] = group_nr;
891   AmoebaCnt[group_nr]++;
892   AmoebaCnt2[group_nr]++;
893 }
894
895 void GameWon()
896 {
897   int hi_pos;
898   boolean raise_level = FALSE;
899
900   if (local_player->MovPos)
901     return;
902
903   local_player->LevelSolved = FALSE;
904
905   if (TimeLeft)
906   {
907     if (setup.sound_loops)
908       PlaySoundExt(SND_SIRR, PSND_MAX_VOLUME, PSND_MAX_RIGHT, PSND_LOOP);
909
910     while(TimeLeft > 0)
911     {
912       if (!setup.sound_loops)
913         PlaySoundStereo(SND_SIRR, PSND_MAX_RIGHT);
914       if (TimeLeft > 0 && !(TimeLeft % 10))
915         RaiseScore(level.score[SC_ZEITBONUS]);
916       if (TimeLeft > 100 && !(TimeLeft % 10))
917         TimeLeft -= 10;
918       else
919         TimeLeft--;
920       DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
921       BackToFront();
922       Delay(10);
923     }
924
925     if (setup.sound_loops)
926       StopSound(SND_SIRR);
927   }
928   else if (level.time == 0)             /* level without time limit */
929   {
930     if (setup.sound_loops)
931       PlaySoundExt(SND_SIRR, PSND_MAX_VOLUME, PSND_MAX_RIGHT, PSND_LOOP);
932
933     while(TimePlayed < 999)
934     {
935       if (!setup.sound_loops)
936         PlaySoundStereo(SND_SIRR, PSND_MAX_RIGHT);
937       if (TimePlayed < 999 && !(TimePlayed % 10))
938         RaiseScore(level.score[SC_ZEITBONUS]);
939       if (TimePlayed < 900 && !(TimePlayed % 10))
940         TimePlayed += 10;
941       else
942         TimePlayed++;
943       DrawText(DX_TIME, DY_TIME, int2str(TimePlayed, 3), FS_SMALL, FC_YELLOW);
944       BackToFront();
945       Delay(10);
946     }
947
948     if (setup.sound_loops)
949       StopSound(SND_SIRR);
950   }
951
952   FadeSounds();
953
954   /* Hero disappears */
955   DrawLevelField(ExitX, ExitY);
956   BackToFront();
957
958   if (tape.playing)
959     return;
960
961   CloseDoor(DOOR_CLOSE_1);
962
963   if (tape.recording)
964   {
965     TapeStop();
966     SaveTape(tape.level_nr);            /* Ask to save tape */
967   }
968
969   if (level_nr == leveldir_current->handicap_level)
970   {
971     leveldir_current->handicap_level++;
972     SaveLevelSetup_SeriesInfo();
973
974     if (level_nr < leveldir_current->last_level)
975       raise_level = TRUE;
976   }
977
978   if ((hi_pos = NewHiScore()) >= 0) 
979   {
980     game_status = HALLOFFAME;
981     DrawHallOfFame(hi_pos);
982     if (raise_level)
983       level_nr++;
984   }
985   else
986   {
987     game_status = MAINMENU;
988     if (raise_level)
989       level_nr++;
990     DrawMainMenu();
991   }
992
993   BackToFront();
994 }
995
996 int NewHiScore()
997 {
998   int k, l;
999   int position = -1;
1000
1001   LoadScore(level_nr);
1002
1003   if (strcmp(setup.player_name, EMPTY_PLAYER_NAME) == 0 ||
1004       local_player->score < highscore[MAX_SCORE_ENTRIES - 1].Score) 
1005     return -1;
1006
1007   for (k=0; k<MAX_SCORE_ENTRIES; k++) 
1008   {
1009     if (local_player->score > highscore[k].Score)
1010     {
1011       /* player has made it to the hall of fame */
1012
1013       if (k < MAX_SCORE_ENTRIES - 1)
1014       {
1015         int m = MAX_SCORE_ENTRIES - 1;
1016
1017 #ifdef ONE_PER_NAME
1018         for (l=k; l<MAX_SCORE_ENTRIES; l++)
1019           if (!strcmp(setup.player_name, highscore[l].Name))
1020             m = l;
1021         if (m == k)     /* player's new highscore overwrites his old one */
1022           goto put_into_list;
1023 #endif
1024
1025         for (l=m; l>k; l--)
1026         {
1027           strcpy(highscore[l].Name, highscore[l - 1].Name);
1028           highscore[l].Score = highscore[l - 1].Score;
1029         }
1030       }
1031
1032 #ifdef ONE_PER_NAME
1033       put_into_list:
1034 #endif
1035       strncpy(highscore[k].Name, setup.player_name, MAX_PLAYER_NAME_LEN);
1036       highscore[k].Name[MAX_PLAYER_NAME_LEN] = '\0';
1037       highscore[k].Score = local_player->score; 
1038       position = k;
1039       break;
1040     }
1041
1042 #ifdef ONE_PER_NAME
1043     else if (!strncmp(setup.player_name, highscore[k].Name,
1044                       MAX_PLAYER_NAME_LEN))
1045       break;    /* player already there with a higher score */
1046 #endif
1047
1048   }
1049
1050   if (position >= 0) 
1051     SaveScore(level_nr);
1052
1053   return position;
1054 }
1055
1056 void InitMovingField(int x, int y, int direction)
1057 {
1058   int newx = x + (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
1059   int newy = y + (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
1060
1061   MovDir[x][y] = direction;
1062   MovDir[newx][newy] = direction;
1063   if (Feld[newx][newy] == EL_LEERRAUM)
1064     Feld[newx][newy] = EL_BLOCKED;
1065 }
1066
1067 void Moving2Blocked(int x, int y, int *goes_to_x, int *goes_to_y)
1068 {
1069   int direction = MovDir[x][y];
1070   int newx = x + (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
1071   int newy = y + (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
1072
1073   *goes_to_x = newx;
1074   *goes_to_y = newy;
1075 }
1076
1077 void Blocked2Moving(int x, int y, int *comes_from_x, int *comes_from_y)
1078 {
1079   int oldx = x, oldy = y;
1080   int direction = MovDir[x][y];
1081
1082   if (direction == MV_LEFT)
1083     oldx++;
1084   else if (direction == MV_RIGHT)
1085     oldx--;
1086   else if (direction == MV_UP)
1087     oldy++;
1088   else if (direction == MV_DOWN)
1089     oldy--;
1090
1091   *comes_from_x = oldx;
1092   *comes_from_y = oldy;
1093 }
1094
1095 int MovingOrBlocked2Element(int x, int y)
1096 {
1097   int element = Feld[x][y];
1098
1099   if (element == EL_BLOCKED)
1100   {
1101     int oldx, oldy;
1102
1103     Blocked2Moving(x, y, &oldx, &oldy);
1104     return Feld[oldx][oldy];
1105   }
1106   else
1107     return element;
1108 }
1109
1110 static int MovingOrBlocked2ElementIfNotLeaving(int x, int y)
1111 {
1112   /* like MovingOrBlocked2Element(), but if element is moving
1113      and (x,y) is the field the moving element is just leaving,
1114      return EL_BLOCKED instead of the element value */
1115   int element = Feld[x][y];
1116
1117   if (IS_MOVING(x, y))
1118   {
1119     if (element == EL_BLOCKED)
1120     {
1121       int oldx, oldy;
1122
1123       Blocked2Moving(x, y, &oldx, &oldy);
1124       return Feld[oldx][oldy];
1125     }
1126     else
1127       return EL_BLOCKED;
1128   }
1129   else
1130     return element;
1131 }
1132
1133 static void RemoveField(int x, int y)
1134 {
1135   Feld[x][y] = EL_LEERRAUM;
1136   MovPos[x][y] = 0;
1137   MovDir[x][y] = 0;
1138   MovDelay[x][y] = 0;
1139 }
1140
1141 void RemoveMovingField(int x, int y)
1142 {
1143   int oldx = x, oldy = y, newx = x, newy = y;
1144
1145   if (Feld[x][y] != EL_BLOCKED && !IS_MOVING(x, y))
1146     return;
1147
1148   if (IS_MOVING(x, y))
1149   {
1150     Moving2Blocked(x, y, &newx, &newy);
1151     if (Feld[newx][newy] != EL_BLOCKED)
1152       return;
1153   }
1154   else if (Feld[x][y] == EL_BLOCKED)
1155   {
1156     Blocked2Moving(x, y, &oldx, &oldy);
1157     if (!IS_MOVING(oldx, oldy))
1158       return;
1159   }
1160
1161   if (Feld[x][y] == EL_BLOCKED &&
1162       (Store[oldx][oldy] == EL_MORAST_LEER ||
1163        Store[oldx][oldy] == EL_SIEB_LEER ||
1164        Store[oldx][oldy] == EL_SIEB2_LEER ||
1165        Store[oldx][oldy] == EL_AMOEBE_NASS))
1166   {
1167     Feld[oldx][oldy] = Store[oldx][oldy];
1168     Store[oldx][oldy] = Store2[oldx][oldy] = 0;
1169   }
1170   else
1171     Feld[oldx][oldy] = EL_LEERRAUM;
1172
1173   Feld[newx][newy] = EL_LEERRAUM;
1174   MovPos[oldx][oldy] = MovDir[oldx][oldy] = MovDelay[oldx][oldy] = 0;
1175   MovPos[newx][newy] = MovDir[newx][newy] = MovDelay[newx][newy] = 0;
1176
1177   DrawLevelField(oldx, oldy);
1178   DrawLevelField(newx, newy);
1179 }
1180
1181 void DrawDynamite(int x, int y)
1182 {
1183   int sx = SCREENX(x), sy = SCREENY(y);
1184   int graphic = el2gfx(Feld[x][y]);
1185   int phase;
1186
1187   if (!IN_SCR_FIELD(sx, sy) || IS_PLAYER(x, y))
1188     return;
1189
1190   if (Store[x][y])
1191     DrawGraphic(sx, sy, el2gfx(Store[x][y]));
1192
1193   if (Feld[x][y] == EL_DYNAMITE_ACTIVE)
1194   {
1195     if ((phase = (96 - MovDelay[x][y]) / 12) > 6)
1196       phase = 6;
1197   }
1198   else
1199   {
1200     if ((phase = ((96 - MovDelay[x][y]) / 6) % 8) > 3)
1201       phase = 7 - phase;
1202   }
1203
1204   if (game.emulation == EMU_SUPAPLEX)
1205     DrawGraphic(sx, sy, GFX_SP_DISK_RED);
1206   else if (Store[x][y])
1207     DrawGraphicThruMask(sx, sy, graphic + phase);
1208   else
1209     DrawGraphic(sx, sy, graphic + phase);
1210 }
1211
1212 void CheckDynamite(int x, int y)
1213 {
1214   if (MovDelay[x][y])           /* dynamite is still waiting to explode */
1215   {
1216     MovDelay[x][y]--;
1217     if (MovDelay[x][y])
1218     {
1219       if (!(MovDelay[x][y] % 12))
1220         PlaySoundLevel(x, y, SND_ZISCH);
1221
1222       if (IS_ACTIVE_BOMB(Feld[x][y]))
1223       {
1224         int delay = (Feld[x][y] == EL_DYNAMITE_ACTIVE ? 12 : 6);
1225
1226         if (!(MovDelay[x][y] % delay))
1227           DrawDynamite(x, y);
1228       }
1229
1230       return;
1231     }
1232   }
1233
1234   StopSound(SND_ZISCH);
1235   Bang(x, y);
1236 }
1237
1238 void Explode(int ex, int ey, int phase, int mode)
1239 {
1240   int x, y;
1241   int num_phase = 9, delay = 2;
1242   int last_phase = num_phase * delay;
1243   int half_phase = (num_phase / 2) * delay;
1244   int first_phase_after_start = EX_PHASE_START + 1;
1245
1246   if (phase == EX_PHASE_START)          /* initialize 'Store[][]' field */
1247   {
1248     int center_element = Feld[ex][ey];
1249
1250     if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey))
1251     {
1252       /* put moving element to center field (and let it explode there) */
1253       center_element = MovingOrBlocked2Element(ex, ey);
1254       RemoveMovingField(ex, ey);
1255       Feld[ex][ey] = center_element;
1256     }
1257
1258     for (y=ey-1; y<=ey+1; y++) for(x=ex-1; x<=ex+1; x++)
1259     {
1260       int element;
1261
1262       if (!IN_LEV_FIELD(x, y) ||
1263           ((mode != EX_NORMAL || center_element == EL_AMOEBA2DIAM) &&
1264            (x != ex || y != ey)))
1265         continue;
1266
1267       element = Feld[x][y];
1268
1269       if (IS_MOVING(x, y) || IS_BLOCKED(x, y))
1270       {
1271         element = MovingOrBlocked2Element(x, y);
1272         RemoveMovingField(x, y);
1273       }
1274
1275       if (IS_MASSIVE(element) || element == EL_BURNING)
1276         continue;
1277
1278       if (IS_PLAYER(x, y) && SHIELD_ON(PLAYERINFO(x, y)))
1279       {
1280         if (IS_ACTIVE_BOMB(element))
1281         {
1282           /* re-activate things under the bomb like gate or penguin */
1283           Feld[x][y] = (Store[x][y] ? Store[x][y] : EL_LEERRAUM);
1284           Store[x][y] = 0;
1285         }
1286
1287         continue;
1288       }
1289
1290       if (element == EL_EXPLODING)
1291         element = Store2[x][y];
1292
1293       if (IS_PLAYER(ex, ey) && !PLAYER_PROTECTED(ex, ey))
1294       {
1295         switch(StorePlayer[ex][ey])
1296         {
1297           case EL_SPIELER2:
1298             Store[x][y] = EL_EDELSTEIN_ROT;
1299             break;
1300           case EL_SPIELER3:
1301             Store[x][y] = EL_EDELSTEIN;
1302             break;
1303           case EL_SPIELER4:
1304             Store[x][y] = EL_EDELSTEIN_LILA;
1305             break;
1306           case EL_SPIELER1:
1307           default:
1308             Store[x][y] = EL_EDELSTEIN_GELB;
1309             break;
1310         }
1311
1312         if (game.emulation == EMU_SUPAPLEX)
1313           Store[x][y] = EL_LEERRAUM;
1314       }
1315       else if (center_element == EL_MOLE)
1316         Store[x][y] = EL_EDELSTEIN_ROT;
1317       else if (center_element == EL_PINGUIN)
1318         Store[x][y] = EL_EDELSTEIN_LILA;
1319       else if (center_element == EL_KAEFER)
1320         Store[x][y] = ((x == ex && y == ey) ? EL_DIAMANT : EL_EDELSTEIN);
1321       else if (center_element == EL_BUTTERFLY)
1322         Store[x][y] = EL_EDELSTEIN_BD;
1323       else if (center_element == EL_SP_ELECTRON)
1324         Store[x][y] = EL_SP_INFOTRON;
1325       else if (center_element == EL_MAMPFER)
1326         Store[x][y] = level.yam_content[game.yam_content_nr][x-ex+1][y-ey+1];
1327       else if (center_element == EL_AMOEBA2DIAM)
1328         Store[x][y] = level.amoeba_content;
1329       else if (element == EL_ERZ_EDEL)
1330         Store[x][y] = EL_EDELSTEIN;
1331       else if (element == EL_ERZ_DIAM)
1332         Store[x][y] = EL_DIAMANT;
1333       else if (element == EL_ERZ_EDEL_BD)
1334         Store[x][y] = EL_EDELSTEIN_BD;
1335       else if (element == EL_ERZ_EDEL_GELB)
1336         Store[x][y] = EL_EDELSTEIN_GELB;
1337       else if (element == EL_ERZ_EDEL_ROT)
1338         Store[x][y] = EL_EDELSTEIN_ROT;
1339       else if (element == EL_ERZ_EDEL_LILA)
1340         Store[x][y] = EL_EDELSTEIN_LILA;
1341       else if (element == EL_WALL_PEARL)
1342         Store[x][y] = EL_PEARL;
1343       else if (element == EL_WALL_CRYSTAL)
1344         Store[x][y] = EL_CRYSTAL;
1345       else if (!IS_PFORTE(Store[x][y]))
1346         Store[x][y] = EL_LEERRAUM;
1347
1348       if (x != ex || y != ey ||
1349           center_element == EL_AMOEBA2DIAM || mode == EX_BORDER)
1350         Store2[x][y] = element;
1351
1352       if (AmoebaNr[x][y] &&
1353           (element == EL_AMOEBE_VOLL ||
1354            element == EL_AMOEBE_BD ||
1355            element == EL_AMOEBING))
1356       {
1357         AmoebaCnt[AmoebaNr[x][y]]--;
1358         AmoebaCnt2[AmoebaNr[x][y]]--;
1359       }
1360
1361       Feld[x][y] = EL_EXPLODING;
1362       MovDir[x][y] = MovPos[x][y] = 0;
1363       AmoebaNr[x][y] = 0;
1364       Frame[x][y] = 1;
1365       Stop[x][y] = TRUE;
1366     }
1367
1368     if (center_element == EL_MAMPFER)
1369       game.yam_content_nr = (game.yam_content_nr + 1) % level.num_yam_contents;
1370
1371     return;
1372   }
1373
1374   if (Stop[ex][ey])
1375     return;
1376
1377   x = ex;
1378   y = ey;
1379
1380   Frame[x][y] = (phase < last_phase ? phase + 1 : 0);
1381
1382   if (phase == first_phase_after_start)
1383   {
1384     int element = Store2[x][y];
1385
1386     if (element == EL_BLACK_ORB)
1387     {
1388       Feld[x][y] = Store2[x][y];
1389       Store2[x][y] = 0;
1390       Bang(x, y);
1391     }
1392   }
1393   else if (phase == half_phase)
1394   {
1395     int element = Store2[x][y];
1396
1397     if (IS_PLAYER(x, y))
1398       KillHeroUnlessProtected(x, y);
1399     else if (IS_EXPLOSIVE(element))
1400     {
1401       Feld[x][y] = Store2[x][y];
1402       Store2[x][y] = 0;
1403       Bang(x, y);
1404     }
1405     else if (element == EL_AMOEBA2DIAM)
1406       AmoebeUmwandeln(x, y);
1407   }
1408
1409   if (phase == last_phase)
1410   {
1411     int element;
1412
1413     element = Feld[x][y] = Store[x][y];
1414     Store[x][y] = Store2[x][y] = 0;
1415     MovDir[x][y] = MovPos[x][y] = MovDelay[x][y] = 0;
1416     InitField(x, y, FALSE);
1417     if (CAN_MOVE(element) || COULD_MOVE(element))
1418       InitMovDir(x, y);
1419     DrawLevelField(x, y);
1420   }
1421   else if (!(phase % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1422   {
1423     int graphic = GFX_EXPLOSION;
1424
1425     if (game.emulation == EMU_SUPAPLEX)
1426       graphic = (Store[x][y] == EL_SP_INFOTRON ?
1427                  GFX_SP_EXPLODE_INFOTRON :
1428                  GFX_SP_EXPLODE_EMPTY);
1429
1430     if (phase == delay)
1431       ErdreichAnbroeckeln(SCREENX(x), SCREENY(y));
1432
1433     DrawGraphic(SCREENX(x), SCREENY(y), graphic + (phase / delay - 1));
1434   }
1435 }
1436
1437 void DynaExplode(int ex, int ey)
1438 {
1439   int i, j;
1440   int dynabomb_size = 1;
1441   boolean dynabomb_xl = FALSE;
1442   struct PlayerInfo *player;
1443   static int xy[4][2] =
1444   {
1445     { 0, -1 },
1446     { -1, 0 },
1447     { +1, 0 },
1448     { 0, +1 }
1449   };
1450
1451   if (IS_ACTIVE_BOMB(Feld[ex][ey]))
1452   {
1453     player = &stored_player[Feld[ex][ey] - EL_DYNABOMB_ACTIVE_1];
1454     dynabomb_size = player->dynabomb_size;
1455     dynabomb_xl = player->dynabomb_xl;
1456     player->dynabombs_left++;
1457   }
1458
1459   Explode(ex, ey, EX_PHASE_START, EX_CENTER);
1460
1461   for (i=0; i<4; i++)
1462   {
1463     for (j=1; j<=dynabomb_size; j++)
1464     {
1465       int x = ex + j * xy[i % 4][0];
1466       int y = ey + j * xy[i % 4][1];
1467       int element;
1468
1469       if (!IN_LEV_FIELD(x, y) || IS_MASSIVE(Feld[x][y]))
1470         break;
1471
1472       element = Feld[x][y];
1473
1474       /* do not restart explosions of fields with active bombs */
1475       if (element == EL_EXPLODING && IS_ACTIVE_BOMB(Store2[x][y]))
1476         continue;
1477
1478       Explode(x, y, EX_PHASE_START, EX_BORDER);
1479
1480       if (element != EL_LEERRAUM &&
1481           element != EL_ERDREICH &&
1482           element != EL_EXPLODING &&
1483           !dynabomb_xl)
1484         break;
1485     }
1486   }
1487 }
1488
1489 void Bang(int x, int y)
1490 {
1491   int element = Feld[x][y];
1492
1493   if (game.emulation == EMU_SUPAPLEX)
1494     PlaySoundLevel(x, y, SND_SP_BOOOM);
1495   else
1496     PlaySoundLevel(x, y, SND_ROAAAR);
1497
1498 #if 0
1499   if (IS_PLAYER(x, y))  /* remove objects that might cause smaller explosion */
1500     element = EL_LEERRAUM;
1501 #endif
1502
1503   switch(element)
1504   {
1505     case EL_KAEFER:
1506     case EL_FLIEGER:
1507     case EL_BUTTERFLY:
1508     case EL_FIREFLY:
1509     case EL_MAMPFER:
1510     case EL_MAMPFER2:
1511     case EL_ROBOT:
1512     case EL_PACMAN:
1513     case EL_MOLE:
1514       RaiseScoreElement(element);
1515       Explode(x, y, EX_PHASE_START, EX_NORMAL);
1516       break;
1517     case EL_DYNABOMB_ACTIVE_1:
1518     case EL_DYNABOMB_ACTIVE_2:
1519     case EL_DYNABOMB_ACTIVE_3:
1520     case EL_DYNABOMB_ACTIVE_4:
1521     case EL_DYNABOMB_NR:
1522     case EL_DYNABOMB_SZ:
1523     case EL_DYNABOMB_XL:
1524       DynaExplode(x, y);
1525       break;
1526     case EL_PINGUIN:
1527     case EL_BIRNE_AUS:
1528     case EL_BIRNE_EIN:
1529       if (IS_PLAYER(x, y))
1530         Explode(x, y, EX_PHASE_START, EX_NORMAL);
1531       else
1532         Explode(x, y, EX_PHASE_START, EX_CENTER);
1533       break;
1534     default:
1535       Explode(x, y, EX_PHASE_START, EX_NORMAL);
1536       break;
1537   }
1538 }
1539
1540 void Blurb(int x, int y)
1541 {
1542   int element = Feld[x][y];
1543
1544   if (element != EL_BLURB_LEFT && element != EL_BLURB_RIGHT)    /* start */
1545   {
1546     PlaySoundLevel(x, y, SND_BLURB);
1547     if (IN_LEV_FIELD(x-1, y) && IS_FREE(x-1, y) &&
1548         (!IN_LEV_FIELD(x-1, y-1) ||
1549          !CAN_FALL(MovingOrBlocked2Element(x-1, y-1))))
1550     {
1551       Feld[x-1][y] = EL_BLURB_LEFT;
1552     }
1553     if (IN_LEV_FIELD(x+1, y) && IS_FREE(x+1, y) &&
1554         (!IN_LEV_FIELD(x+1, y-1) ||
1555          !CAN_FALL(MovingOrBlocked2Element(x+1, y-1))))
1556     {
1557       Feld[x+1][y] = EL_BLURB_RIGHT;
1558     }
1559   }
1560   else                                                          /* go on */
1561   {
1562     int graphic = (element==EL_BLURB_LEFT ? GFX_BLURB_LEFT : GFX_BLURB_RIGHT);
1563
1564     if (!MovDelay[x][y])        /* initialize animation counter */
1565       MovDelay[x][y] = 9;
1566
1567     if (MovDelay[x][y])         /* continue animation */
1568     {
1569       MovDelay[x][y]--;
1570       if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1571         DrawGraphic(SCREENX(x), SCREENY(y), graphic+4-MovDelay[x][y]/2);
1572
1573       if (!MovDelay[x][y])
1574       {
1575         Feld[x][y] = EL_LEERRAUM;
1576         DrawLevelField(x, y);
1577       }
1578     }
1579   }
1580 }
1581
1582 static void ToggleBeltSwitch(int x, int y)
1583 {
1584   static int belt_base_element[4] =
1585   {
1586     EL_BELT1_SWITCH_LEFT,
1587     EL_BELT2_SWITCH_LEFT,
1588     EL_BELT3_SWITCH_LEFT,
1589     EL_BELT4_SWITCH_LEFT
1590   };
1591   static int belt_move_dir[4] =
1592   {
1593     MV_LEFT,
1594     MV_NO_MOVING,
1595     MV_RIGHT,
1596     MV_NO_MOVING,
1597   };
1598
1599   int element = Feld[x][y];
1600   int belt_nr = getBeltNrFromSwitchElement(element);
1601   int belt_dir_nr = (game.belt_dir_nr[belt_nr] + 1) % 4;
1602   int belt_dir = belt_move_dir[belt_dir_nr];
1603   int xx, yy;
1604
1605   if (!IS_BELT_SWITCH(element))
1606     return;
1607
1608   game.belt_dir_nr[belt_nr] = belt_dir_nr;
1609   game.belt_dir[belt_nr] = belt_dir;
1610
1611   if (belt_dir_nr == 3)
1612     belt_dir_nr = 1;
1613
1614   for (yy=0; yy<lev_fieldy; yy++)
1615   {
1616     for (xx=0; xx<lev_fieldx; xx++)
1617     {
1618       int element = Feld[xx][yy];
1619
1620       if (IS_BELT_SWITCH(element))
1621       {
1622         int e_belt_nr = getBeltNrFromSwitchElement(element);
1623
1624         if (e_belt_nr == belt_nr)
1625         {
1626           Feld[xx][yy] = belt_base_element[belt_nr] + belt_dir_nr;
1627           DrawLevelField(xx, yy);
1628         }
1629       }
1630       else if (belt_dir == MV_NO_MOVING && IS_BELT(element))
1631       {
1632         int e_belt_nr = getBeltNrFromElement(element);
1633
1634         if (e_belt_nr == belt_nr)
1635           DrawLevelField(xx, yy);    /* set belt to parking position */
1636       }
1637     }
1638   }
1639 }
1640
1641 static void ToggleSwitchgateSwitch(int x, int y)
1642 {
1643   int xx, yy;
1644
1645   game.switchgate_pos = !game.switchgate_pos;
1646
1647   for (yy=0; yy<lev_fieldy; yy++)
1648   {
1649     for (xx=0; xx<lev_fieldx; xx++)
1650     {
1651       int element = Feld[xx][yy];
1652
1653       if (element == EL_SWITCHGATE_SWITCH_1 ||
1654           element == EL_SWITCHGATE_SWITCH_2)
1655       {
1656         Feld[xx][yy] = EL_SWITCHGATE_SWITCH_1 + game.switchgate_pos;
1657         DrawLevelField(xx, yy);
1658       }
1659       else if (element == EL_SWITCHGATE_OPEN ||
1660                element == EL_SWITCHGATE_OPENING)
1661       {
1662         Feld[xx][yy] = EL_SWITCHGATE_CLOSING;
1663         PlaySoundLevel(xx, yy, SND_OEFFNEN);
1664       }
1665       else if (element == EL_SWITCHGATE_CLOSED ||
1666                element == EL_SWITCHGATE_CLOSING)
1667       {
1668         Feld[xx][yy] = EL_SWITCHGATE_OPENING;
1669         PlaySoundLevel(xx, yy, SND_OEFFNEN);
1670       }
1671     }
1672   }
1673 }
1674
1675 static void RedrawAllLightSwitchesAndInvisibleElements()
1676 {
1677   int x, y;
1678
1679   for (y=0; y<lev_fieldy; y++)
1680   {
1681     for (x=0; x<lev_fieldx; x++)
1682     {
1683       int element = Feld[x][y];
1684
1685       if (element == EL_LIGHT_SWITCH_OFF &&
1686           game.light_time_left > 0)
1687       {
1688         Feld[x][y] = EL_LIGHT_SWITCH_ON;
1689         DrawLevelField(x, y);
1690       }
1691       else if (element == EL_LIGHT_SWITCH_ON &&
1692                game.light_time_left == 0)
1693       {
1694         Feld[x][y] = EL_LIGHT_SWITCH_OFF;
1695         DrawLevelField(x, y);
1696       }
1697
1698       if (element == EL_INVISIBLE_STEEL ||
1699           element == EL_UNSICHTBAR ||
1700           element == EL_SAND_INVISIBLE)
1701         DrawLevelField(x, y);
1702     }
1703   }
1704 }
1705
1706 static void ToggleLightSwitch(int x, int y)
1707 {
1708   int element = Feld[x][y];
1709
1710   game.light_time_left =
1711     (element == EL_LIGHT_SWITCH_OFF ?
1712      level.time_light * FRAMES_PER_SECOND : 0);
1713
1714   RedrawAllLightSwitchesAndInvisibleElements();
1715 }
1716
1717 static void ActivateTimegateSwitch(int x, int y)
1718 {
1719   int xx, yy;
1720
1721   game.timegate_time_left = level.time_timegate * FRAMES_PER_SECOND;
1722
1723   for (yy=0; yy<lev_fieldy; yy++)
1724   {
1725     for (xx=0; xx<lev_fieldx; xx++)
1726     {
1727       int element = Feld[xx][yy];
1728
1729       if (element == EL_TIMEGATE_CLOSED ||
1730           element == EL_TIMEGATE_CLOSING)
1731       {
1732         Feld[xx][yy] = EL_TIMEGATE_OPENING;
1733         PlaySoundLevel(xx, yy, SND_OEFFNEN);
1734       }
1735
1736       /*
1737       else if (element == EL_TIMEGATE_SWITCH_ON)
1738       {
1739         Feld[xx][yy] = EL_TIMEGATE_SWITCH_OFF;
1740         DrawLevelField(xx, yy);
1741       }
1742       */
1743
1744     }
1745   }
1746
1747   Feld[x][y] = EL_TIMEGATE_SWITCH_ON;
1748 }
1749
1750 void Impact(int x, int y)
1751 {
1752   boolean lastline = (y == lev_fieldy-1);
1753   boolean object_hit = FALSE;
1754   int element = Feld[x][y];
1755   int smashed = 0;
1756
1757   if (!lastline)        /* check if element below was hit */
1758   {
1759     if (Feld[x][y+1] == EL_PLAYER_IS_LEAVING)
1760       return;
1761
1762     object_hit = (!IS_FREE(x, y+1) && (!IS_MOVING(x, y+1) ||
1763                                       MovDir[x][y+1]!=MV_DOWN ||
1764                                       MovPos[x][y+1]<=TILEY/2));
1765     if (object_hit)
1766       smashed = MovingOrBlocked2Element(x, y+1);
1767   }
1768
1769   if (!lastline && smashed == EL_SALZSAEURE)    /* element falls into acid */
1770   {
1771     Blurb(x, y);
1772     return;
1773   }
1774
1775   if ((element == EL_BOMBE ||
1776        element == EL_SP_DISK_ORANGE ||
1777        element == EL_DX_SUPABOMB) &&
1778       (lastline || object_hit)) /* element is bomb */
1779   {
1780     Bang(x, y);
1781     return;
1782   }
1783   else if (element == EL_PEARL)
1784   {
1785     Feld[x][y] = EL_PEARL_BREAKING;
1786     PlaySoundLevel(x, y, SND_KNACK);
1787     return;
1788   }
1789
1790   if (element == EL_TROPFEN && (lastline || object_hit))        /* acid drop */
1791   {
1792     if (object_hit && IS_PLAYER(x, y+1))
1793       KillHeroUnlessProtected(x, y+1);
1794     else if (object_hit && smashed == EL_PINGUIN)
1795       Bang(x, y+1);
1796     else
1797     {
1798       Feld[x][y] = EL_AMOEBING;
1799       Store[x][y] = EL_AMOEBE_NASS;
1800     }
1801     return;
1802   }
1803
1804   if (!lastline && object_hit)          /* check which object was hit */
1805   {
1806     if (CAN_CHANGE(element) && 
1807         (smashed == EL_SIEB_INAKTIV || smashed == EL_SIEB2_INAKTIV))
1808     {
1809       int x, y;
1810       int activated_magic_wall =
1811         (smashed == EL_SIEB_INAKTIV ? EL_SIEB_LEER : EL_SIEB2_LEER);
1812
1813       /* activate magic wall / mill */
1814
1815       for (y=0; y<lev_fieldy; y++)
1816         for (x=0; x<lev_fieldx; x++)
1817           if (Feld[x][y] == smashed)
1818             Feld[x][y] = activated_magic_wall;
1819
1820       game.magic_wall_time_left = level.time_magic_wall * FRAMES_PER_SECOND;
1821       game.magic_wall_active = TRUE;
1822     }
1823
1824     if (IS_PLAYER(x, y+1))
1825     {
1826       KillHeroUnlessProtected(x, y+1);
1827       return;
1828     }
1829     else if (smashed == EL_PINGUIN)
1830     {
1831       Bang(x, y+1);
1832       return;
1833     }
1834     else if (element == EL_EDELSTEIN_BD)
1835     {
1836       if (IS_ENEMY(smashed) && IS_BD_ELEMENT(smashed))
1837       {
1838         Bang(x, y+1);
1839         return;
1840       }
1841     }
1842     else if (element == EL_FELSBROCKEN ||
1843              element == EL_SP_ZONK ||
1844              element == EL_BD_ROCK)
1845     {
1846       if (IS_ENEMY(smashed) ||
1847           smashed == EL_BOMBE || smashed == EL_SP_DISK_ORANGE ||
1848           smashed == EL_DX_SUPABOMB ||
1849           smashed == EL_SONDE || smashed == EL_SCHWEIN ||
1850           smashed == EL_DRACHE || smashed == EL_MOLE)
1851       {
1852         Bang(x, y+1);
1853         return;
1854       }
1855       else if (!IS_MOVING(x, y+1))
1856       {
1857         if (smashed == EL_BIRNE_AUS || smashed == EL_BIRNE_EIN)
1858         {
1859           Bang(x, y+1);
1860           return;
1861         }
1862         else if (smashed == EL_KOKOSNUSS)
1863         {
1864           Feld[x][y+1] = EL_CRACKINGNUT;
1865           PlaySoundLevel(x, y, SND_KNACK);
1866           RaiseScoreElement(EL_KOKOSNUSS);
1867           return;
1868         }
1869         else if (smashed == EL_PEARL)
1870         {
1871           Feld[x][y+1] = EL_PEARL_BREAKING;
1872           PlaySoundLevel(x, y, SND_KNACK);
1873           return;
1874         }
1875         else if (smashed == EL_DIAMANT)
1876         {
1877           Feld[x][y+1] = EL_LEERRAUM;
1878           PlaySoundLevel(x, y, SND_QUIRK);
1879           return;
1880         }
1881         else if (IS_BELT_SWITCH(smashed))
1882         {
1883           ToggleBeltSwitch(x, y+1);
1884         }
1885         else if (smashed == EL_SWITCHGATE_SWITCH_1 ||
1886                  smashed == EL_SWITCHGATE_SWITCH_2)
1887         {
1888           ToggleSwitchgateSwitch(x, y+1);
1889         }
1890         else if (smashed == EL_LIGHT_SWITCH_OFF ||
1891                  smashed == EL_LIGHT_SWITCH_ON)
1892         {
1893           ToggleLightSwitch(x, y+1);
1894         }
1895       }
1896     }
1897   }
1898
1899   /* play sound of magic wall / mill */
1900   if (!lastline &&
1901       (Feld[x][y+1] == EL_SIEB_LEER || Feld[x][y+1] == EL_SIEB2_LEER))
1902   {
1903     PlaySoundLevel(x, y, SND_QUIRK);
1904     return;
1905   }
1906
1907   /* play sound of object that hits the ground */
1908   if (lastline || object_hit)
1909   {
1910     int sound;
1911
1912     switch(element)
1913     {
1914       case EL_EDELSTEIN:
1915       case EL_EDELSTEIN_BD:
1916       case EL_EDELSTEIN_GELB:
1917       case EL_EDELSTEIN_ROT:
1918       case EL_EDELSTEIN_LILA:
1919       case EL_DIAMANT:
1920       case EL_SP_INFOTRON:
1921         sound = SND_PLING;
1922         break;
1923       case EL_KOKOSNUSS:
1924         sound = SND_KLUMPF;
1925         break;
1926       case EL_FELSBROCKEN:
1927       case EL_BD_ROCK:
1928         sound = SND_KLOPF;
1929         break;
1930       case EL_SP_ZONK:
1931         sound = SND_SP_ZONKDOWN;
1932         break;
1933       case EL_SCHLUESSEL:
1934       case EL_SCHLUESSEL1:
1935       case EL_SCHLUESSEL2:
1936       case EL_SCHLUESSEL3:
1937       case EL_SCHLUESSEL4:
1938       case EL_EM_KEY_1:
1939       case EL_EM_KEY_2:
1940       case EL_EM_KEY_3:
1941       case EL_EM_KEY_4:
1942         sound = SND_KINK;
1943         break;
1944       case EL_ZEIT_VOLL:
1945       case EL_ZEIT_LEER:
1946         sound = SND_DENG;
1947         break;
1948       default:
1949         sound = -1;
1950         break;
1951     }
1952
1953     if (sound >= 0)
1954       PlaySoundLevel(x, y, sound);
1955   }
1956 }
1957
1958 void TurnRound(int x, int y)
1959 {
1960   static struct
1961   {
1962     int x, y;
1963   } move_xy[] =
1964   {
1965     { 0, 0 },
1966     {-1, 0 },
1967     {+1, 0 },
1968     { 0, 0 },
1969     { 0, -1 },
1970     { 0, 0 }, { 0, 0 }, { 0, 0 },
1971     { 0, +1 }
1972   };
1973   static struct
1974   {
1975     int left, right, back;
1976   } turn[] =
1977   {
1978     { 0,        0,              0 },
1979     { MV_DOWN,  MV_UP,          MV_RIGHT },
1980     { MV_UP,    MV_DOWN,        MV_LEFT },
1981     { 0,        0,              0 },
1982     { MV_LEFT,  MV_RIGHT,       MV_DOWN },
1983     { 0,0,0 },  { 0,0,0 },      { 0,0,0 },
1984     { MV_RIGHT, MV_LEFT,        MV_UP }
1985   };
1986
1987   int element = Feld[x][y];
1988   int old_move_dir = MovDir[x][y];
1989   int left_dir = turn[old_move_dir].left;
1990   int right_dir = turn[old_move_dir].right;
1991   int back_dir = turn[old_move_dir].back;
1992
1993   int left_dx = move_xy[left_dir].x, left_dy = move_xy[left_dir].y;
1994   int right_dx = move_xy[right_dir].x, right_dy = move_xy[right_dir].y;
1995   int move_dx = move_xy[old_move_dir].x, move_dy = move_xy[old_move_dir].y;
1996   int back_dx = move_xy[back_dir].x, back_dy = move_xy[back_dir].y;
1997
1998   int left_x = x+left_dx, left_y = y+left_dy;
1999   int right_x = x+right_dx, right_y = y+right_dy;
2000   int move_x = x+move_dx, move_y = y+move_dy;
2001
2002   if (element == EL_KAEFER || element == EL_BUTTERFLY)
2003   {
2004     TestIfBadThingHitsOtherBadThing(x, y);
2005
2006     if (IN_LEV_FIELD(right_x, right_y) &&
2007         IS_FREE(right_x, right_y))
2008       MovDir[x][y] = right_dir;
2009     else if (!IN_LEV_FIELD(move_x, move_y) ||
2010              !IS_FREE(move_x, move_y))
2011       MovDir[x][y] = left_dir;
2012
2013     if (element == EL_KAEFER && MovDir[x][y] != old_move_dir)
2014       MovDelay[x][y] = 9;
2015     else if (element == EL_BUTTERFLY)   /* && MovDir[x][y] == left_dir) */
2016       MovDelay[x][y] = 1;
2017   }
2018   else if (element == EL_FLIEGER || element == EL_FIREFLY ||
2019            element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
2020   {
2021     TestIfBadThingHitsOtherBadThing(x, y);
2022
2023     if (IN_LEV_FIELD(left_x, left_y) &&
2024         IS_FREE(left_x, left_y))
2025       MovDir[x][y] = left_dir;
2026     else if (!IN_LEV_FIELD(move_x, move_y) ||
2027              !IS_FREE(move_x, move_y))
2028       MovDir[x][y] = right_dir;
2029
2030     if ((element == EL_FLIEGER ||
2031          element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
2032         && MovDir[x][y] != old_move_dir)
2033       MovDelay[x][y] = 9;
2034     else if (element == EL_FIREFLY)     /* && MovDir[x][y] == right_dir) */
2035       MovDelay[x][y] = 1;
2036   }
2037   else if (element == EL_MAMPFER)
2038   {
2039     boolean can_turn_left = FALSE, can_turn_right = FALSE;
2040
2041     if (IN_LEV_FIELD(left_x, left_y) &&
2042         (IS_FREE_OR_PLAYER(left_x, left_y) ||
2043          Feld[left_x][left_y] == EL_DIAMANT))
2044       can_turn_left = TRUE;
2045     if (IN_LEV_FIELD(right_x, right_y) &&
2046         (IS_FREE_OR_PLAYER(right_x, right_y) ||
2047          Feld[right_x][right_y] == EL_DIAMANT))
2048       can_turn_right = TRUE;
2049
2050     if (can_turn_left && can_turn_right)
2051       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
2052     else if (can_turn_left)
2053       MovDir[x][y] = (RND(2) ? left_dir : back_dir);
2054     else if (can_turn_right)
2055       MovDir[x][y] = (RND(2) ? right_dir : back_dir);
2056     else
2057       MovDir[x][y] = back_dir;
2058
2059     MovDelay[x][y] = 16+16*RND(3);
2060   }
2061   else if (element == EL_MAMPFER2)
2062   {
2063     boolean can_turn_left = FALSE, can_turn_right = FALSE;
2064
2065     if (IN_LEV_FIELD(left_x, left_y) &&
2066         (IS_FREE_OR_PLAYER(left_x, left_y) ||
2067          IS_MAMPF2(Feld[left_x][left_y])))
2068       can_turn_left = TRUE;
2069     if (IN_LEV_FIELD(right_x, right_y) &&
2070         (IS_FREE_OR_PLAYER(right_x, right_y) ||
2071          IS_MAMPF2(Feld[right_x][right_y])))
2072       can_turn_right = TRUE;
2073
2074     if (can_turn_left && can_turn_right)
2075       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
2076     else if (can_turn_left)
2077       MovDir[x][y] = (RND(2) ? left_dir : back_dir);
2078     else if (can_turn_right)
2079       MovDir[x][y] = (RND(2) ? right_dir : back_dir);
2080     else
2081       MovDir[x][y] = back_dir;
2082
2083     MovDelay[x][y] = 16+16*RND(3);
2084   }
2085   else if (element == EL_PACMAN)
2086   {
2087     boolean can_turn_left = FALSE, can_turn_right = FALSE;
2088
2089     if (IN_LEV_FIELD(left_x, left_y) &&
2090         (IS_FREE_OR_PLAYER(left_x, left_y) ||
2091          IS_AMOEBOID(Feld[left_x][left_y])))
2092       can_turn_left = TRUE;
2093     if (IN_LEV_FIELD(right_x, right_y) &&
2094         (IS_FREE_OR_PLAYER(right_x, right_y) ||
2095          IS_AMOEBOID(Feld[right_x][right_y])))
2096       can_turn_right = TRUE;
2097
2098     if (can_turn_left && can_turn_right)
2099       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
2100     else if (can_turn_left)
2101       MovDir[x][y] = (RND(2) ? left_dir : back_dir);
2102     else if (can_turn_right)
2103       MovDir[x][y] = (RND(2) ? right_dir : back_dir);
2104     else
2105       MovDir[x][y] = back_dir;
2106
2107     MovDelay[x][y] = 6+RND(40);
2108   }
2109   else if (element == EL_SCHWEIN)
2110   {
2111     boolean can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE;
2112     boolean should_turn_left = FALSE, should_turn_right = FALSE;
2113     boolean should_move_on = FALSE;
2114     int rnd_value = 24;
2115     int rnd = RND(rnd_value);
2116
2117     if (IN_LEV_FIELD(left_x, left_y) &&
2118         (IS_FREE(left_x, left_y) || IS_GEM(Feld[left_x][left_y])))
2119       can_turn_left = TRUE;
2120     if (IN_LEV_FIELD(right_x, right_y) &&
2121         (IS_FREE(right_x, right_y) || IS_GEM(Feld[right_x][right_y])))
2122       can_turn_right = TRUE;
2123     if (IN_LEV_FIELD(move_x, move_y) &&
2124         (IS_FREE(move_x, move_y) || IS_GEM(Feld[move_x][move_y])))
2125       can_move_on = TRUE;
2126
2127     if (can_turn_left &&
2128         (!can_move_on ||
2129          (IN_LEV_FIELD(x+back_dx+left_dx, y+back_dy+left_dy) &&
2130           !IS_FREE(x+back_dx+left_dx, y+back_dy+left_dy))))
2131       should_turn_left = TRUE;
2132     if (can_turn_right &&
2133         (!can_move_on ||
2134          (IN_LEV_FIELD(x+back_dx+right_dx, y+back_dy+right_dy) &&
2135           !IS_FREE(x+back_dx+right_dx, y+back_dy+right_dy))))
2136       should_turn_right = TRUE;
2137     if (can_move_on &&
2138         (!can_turn_left || !can_turn_right ||
2139          (IN_LEV_FIELD(x+move_dx+left_dx, y+move_dy+left_dy) &&
2140           !IS_FREE(x+move_dx+left_dx, y+move_dy+left_dy)) ||
2141          (IN_LEV_FIELD(x+move_dx+right_dx, y+move_dy+right_dy) &&
2142           !IS_FREE(x+move_dx+right_dx, y+move_dy+right_dy))))
2143       should_move_on = TRUE;
2144
2145     if (should_turn_left || should_turn_right || should_move_on)
2146     {
2147       if (should_turn_left && should_turn_right && should_move_on)
2148         MovDir[x][y] = (rnd < rnd_value/3 ? left_dir :
2149                         rnd < 2*rnd_value/3 ? right_dir :
2150                         old_move_dir);
2151       else if (should_turn_left && should_turn_right)
2152         MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
2153       else if (should_turn_left && should_move_on)
2154         MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : old_move_dir);
2155       else if (should_turn_right && should_move_on)
2156         MovDir[x][y] = (rnd < rnd_value/2 ? right_dir : old_move_dir);
2157       else if (should_turn_left)
2158         MovDir[x][y] = left_dir;
2159       else if (should_turn_right)
2160         MovDir[x][y] = right_dir;
2161       else if (should_move_on)
2162         MovDir[x][y] = old_move_dir;
2163     }
2164     else if (can_move_on && rnd > rnd_value/8)
2165       MovDir[x][y] = old_move_dir;
2166     else if (can_turn_left && can_turn_right)
2167       MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
2168     else if (can_turn_left && rnd > rnd_value/8)
2169       MovDir[x][y] = left_dir;
2170     else if (can_turn_right && rnd > rnd_value/8)
2171       MovDir[x][y] = right_dir;
2172     else
2173       MovDir[x][y] = back_dir;
2174
2175     if (!IS_FREE(x+move_xy[MovDir[x][y]].x, y+move_xy[MovDir[x][y]].y) &&
2176         !IS_GEM(Feld[x+move_xy[MovDir[x][y]].x][y+move_xy[MovDir[x][y]].y]))
2177       MovDir[x][y] = old_move_dir;
2178
2179     MovDelay[x][y] = 0;
2180   }
2181   else if (element == EL_DRACHE)
2182   {
2183     boolean can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE;
2184     int rnd_value = 24;
2185     int rnd = RND(rnd_value);
2186
2187     if (IN_LEV_FIELD(left_x, left_y) && IS_FREE(left_x, left_y))
2188       can_turn_left = TRUE;
2189     if (IN_LEV_FIELD(right_x, right_y) && IS_FREE(right_x, right_y))
2190       can_turn_right = TRUE;
2191     if (IN_LEV_FIELD(move_x, move_y) && IS_FREE(move_x, move_y))
2192       can_move_on = TRUE;
2193
2194     if (can_move_on && rnd > rnd_value/8)
2195       MovDir[x][y] = old_move_dir;
2196     else if (can_turn_left && can_turn_right)
2197       MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
2198     else if (can_turn_left && rnd > rnd_value/8)
2199       MovDir[x][y] = left_dir;
2200     else if (can_turn_right && rnd > rnd_value/8)
2201       MovDir[x][y] = right_dir;
2202     else
2203       MovDir[x][y] = back_dir;
2204
2205     if (!IS_FREE(x+move_xy[MovDir[x][y]].x, y+move_xy[MovDir[x][y]].y))
2206       MovDir[x][y] = old_move_dir;
2207
2208     MovDelay[x][y] = 0;
2209   }
2210   else if (element == EL_MOLE)
2211   {
2212     boolean can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE;
2213
2214     if (IN_LEV_FIELD(move_x, move_y) &&
2215         (IS_FREE(move_x, move_y) || IS_AMOEBOID(Feld[move_x][move_y]) ||
2216          Feld[move_x][move_y] == EL_DEAMOEBING))
2217       can_move_on = TRUE;
2218
2219     if (!can_move_on)
2220     {
2221       if (IN_LEV_FIELD(left_x, left_y) &&
2222           (IS_FREE(left_x, left_y) || IS_AMOEBOID(Feld[left_x][left_y])))
2223         can_turn_left = TRUE;
2224       if (IN_LEV_FIELD(right_x, right_y) &&
2225           (IS_FREE(right_x, right_y) || IS_AMOEBOID(Feld[right_x][right_y])))
2226         can_turn_right = TRUE;
2227
2228       if (can_turn_left && can_turn_right)
2229         MovDir[x][y] = (RND(2) ? left_dir : right_dir);
2230       else if (can_turn_left)
2231         MovDir[x][y] = left_dir;
2232       else
2233         MovDir[x][y] = right_dir;
2234     }
2235
2236     if (MovDir[x][y] != old_move_dir)
2237       MovDelay[x][y] = 9;
2238   }
2239   else if (element == EL_BALLOON)
2240   {
2241     MovDir[x][y] = game.balloon_dir;
2242     MovDelay[x][y] = 0;
2243   }
2244   else if (element == EL_SPRING_MOVING)
2245   {
2246     if (!IN_LEV_FIELD(move_x, move_y) || !IS_FREE(move_x, move_y) ||
2247         (IN_LEV_FIELD(x, y+1) && IS_FREE(x, y+1)))
2248     {
2249       Feld[x][y] = EL_SPRING;
2250       MovDir[x][y] = MV_NO_MOVING;
2251     }
2252     MovDelay[x][y] = 0;
2253   }
2254   else if (element == EL_ROBOT || element == EL_SONDE || element == EL_PINGUIN)
2255   {
2256     int attr_x = -1, attr_y = -1;
2257
2258     if (AllPlayersGone)
2259     {
2260       attr_x = ExitX;
2261       attr_y = ExitY;
2262     }
2263     else
2264     {
2265       int i;
2266
2267       for (i=0; i<MAX_PLAYERS; i++)
2268       {
2269         struct PlayerInfo *player = &stored_player[i];
2270         int jx = player->jx, jy = player->jy;
2271
2272         if (!player->active)
2273           continue;
2274
2275         if (attr_x == -1 || ABS(jx-x)+ABS(jy-y) < ABS(attr_x-x)+ABS(attr_y-y))
2276         {
2277           attr_x = jx;
2278           attr_y = jy;
2279         }
2280       }
2281     }
2282
2283     if (element == EL_ROBOT && ZX>=0 && ZY>=0)
2284     {
2285       attr_x = ZX;
2286       attr_y = ZY;
2287     }
2288
2289     if (element == EL_PINGUIN)
2290     {
2291       int i;
2292       static int xy[4][2] =
2293       {
2294         { 0, -1 },
2295         { -1, 0 },
2296         { +1, 0 },
2297         { 0, +1 }
2298       };
2299
2300       for (i=0; i<4; i++)
2301       {
2302         int ex = x + xy[i%4][0];
2303         int ey = y + xy[i%4][1];
2304
2305         if (IN_LEV_FIELD(ex, ey) && Feld[ex][ey] == EL_AUSGANG_AUF)
2306         {
2307           attr_x = ex;
2308           attr_y = ey;
2309           break;
2310         }
2311       }
2312     }
2313
2314     MovDir[x][y] = MV_NO_MOVING;
2315     if (attr_x<x)
2316       MovDir[x][y] |= (AllPlayersGone ? MV_RIGHT : MV_LEFT);
2317     else if (attr_x>x)
2318       MovDir[x][y] |= (AllPlayersGone ? MV_LEFT : MV_RIGHT);
2319     if (attr_y<y)
2320       MovDir[x][y] |= (AllPlayersGone ? MV_DOWN : MV_UP);
2321     else if (attr_y>y)
2322       MovDir[x][y] |= (AllPlayersGone ? MV_UP : MV_DOWN);
2323
2324     if (element == EL_ROBOT)
2325     {
2326       int newx, newy;
2327
2328       if ((MovDir[x][y]&(MV_LEFT|MV_RIGHT)) && (MovDir[x][y]&(MV_UP|MV_DOWN)))
2329         MovDir[x][y] &= (RND(2) ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
2330       Moving2Blocked(x, y, &newx, &newy);
2331
2332       if (IN_LEV_FIELD(newx, newy) && IS_FREE_OR_PLAYER(newx, newy))
2333         MovDelay[x][y] = 8+8*!RND(3);
2334       else
2335         MovDelay[x][y] = 16;
2336     }
2337     else
2338     {
2339       int newx, newy;
2340
2341       MovDelay[x][y] = 1;
2342
2343       if ((MovDir[x][y]&(MV_LEFT|MV_RIGHT)) && (MovDir[x][y]&(MV_UP|MV_DOWN)))
2344       {
2345         boolean first_horiz = RND(2);
2346         int new_move_dir = MovDir[x][y];
2347
2348         MovDir[x][y] =
2349           new_move_dir & (first_horiz ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
2350         Moving2Blocked(x, y, &newx, &newy);
2351
2352         if (IN_LEV_FIELD(newx, newy) &&
2353             (IS_FREE(newx, newy) ||
2354              Feld[newx][newy] == EL_SALZSAEURE ||
2355              (element == EL_PINGUIN &&
2356               (Feld[newx][newy] == EL_AUSGANG_AUF ||
2357                IS_MAMPF3(Feld[newx][newy])))))
2358           return;
2359
2360         MovDir[x][y] =
2361           new_move_dir & (!first_horiz ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
2362         Moving2Blocked(x, y, &newx, &newy);
2363
2364         if (IN_LEV_FIELD(newx, newy) &&
2365             (IS_FREE(newx, newy) ||
2366              Feld[newx][newy] == EL_SALZSAEURE ||
2367              (element == EL_PINGUIN &&
2368               (Feld[newx][newy] == EL_AUSGANG_AUF ||
2369                IS_MAMPF3(Feld[newx][newy])))))
2370           return;
2371
2372         MovDir[x][y] = old_move_dir;
2373         return;
2374       }
2375     }
2376   }
2377 }
2378
2379 static boolean JustBeingPushed(int x, int y)
2380 {
2381   int i;
2382
2383   for (i=0; i<MAX_PLAYERS; i++)
2384   {
2385     struct PlayerInfo *player = &stored_player[i];
2386
2387     if (player->active && player->Pushing && player->MovPos)
2388     {
2389       int next_jx = player->jx + (player->jx - player->last_jx);
2390       int next_jy = player->jy + (player->jy - player->last_jy);
2391
2392       if (x == next_jx && y == next_jy)
2393         return TRUE;
2394     }
2395   }
2396
2397   return FALSE;
2398 }
2399
2400 void StartMoving(int x, int y)
2401 {
2402   int element = Feld[x][y];
2403
2404   if (Stop[x][y])
2405     return;
2406
2407   if (CAN_FALL(element) && y<lev_fieldy-1)
2408   {
2409     if ((x>0 && IS_PLAYER(x-1, y)) || (x<lev_fieldx-1 && IS_PLAYER(x+1, y)))
2410       if (JustBeingPushed(x, y))
2411         return;
2412
2413     if (element == EL_MORAST_VOLL)
2414     {
2415       if (IS_FREE(x, y+1))
2416       {
2417         InitMovingField(x, y, MV_DOWN);
2418         Feld[x][y] = EL_FELSBROCKEN;
2419         Store[x][y] = EL_MORAST_LEER;
2420       }
2421       else if (Feld[x][y+1] == EL_MORAST_LEER)
2422       {
2423         if (!MovDelay[x][y])
2424           MovDelay[x][y] = TILEY + 1;
2425
2426         if (MovDelay[x][y])
2427         {
2428           MovDelay[x][y]--;
2429           if (MovDelay[x][y])
2430             return;
2431         }
2432
2433         Feld[x][y] = EL_MORAST_LEER;
2434         Feld[x][y+1] = EL_MORAST_VOLL;
2435       }
2436     }
2437     else if ((element == EL_FELSBROCKEN || element == EL_BD_ROCK) &&
2438              Feld[x][y+1] == EL_MORAST_LEER)
2439     {
2440       InitMovingField(x, y, MV_DOWN);
2441       Store[x][y] = EL_MORAST_VOLL;
2442     }
2443     else if (element == EL_SIEB_VOLL)
2444     {
2445       if (IS_FREE(x, y+1))
2446       {
2447         InitMovingField(x, y, MV_DOWN);
2448         Feld[x][y] = EL_CHANGED(Store2[x][y]);
2449         Store[x][y] = EL_SIEB_LEER;
2450       }
2451       else if (Feld[x][y+1] == EL_SIEB_LEER)
2452       {
2453         if (!MovDelay[x][y])
2454           MovDelay[x][y] = TILEY/4 + 1;
2455
2456         if (MovDelay[x][y])
2457         {
2458           MovDelay[x][y]--;
2459           if (MovDelay[x][y])
2460             return;
2461         }
2462
2463         Feld[x][y] = EL_SIEB_LEER;
2464         Feld[x][y+1] = EL_SIEB_VOLL;
2465         Store2[x][y+1] = EL_CHANGED(Store2[x][y]);
2466         Store2[x][y] = 0;
2467       }
2468     }
2469     else if (element == EL_SIEB2_VOLL)
2470     {
2471       if (IS_FREE(x, y+1))
2472       {
2473         InitMovingField(x, y, MV_DOWN);
2474         Feld[x][y] = EL_CHANGED2(Store2[x][y]);
2475         Store[x][y] = EL_SIEB2_LEER;
2476       }
2477       else if (Feld[x][y+1] == EL_SIEB2_LEER)
2478       {
2479         if (!MovDelay[x][y])
2480           MovDelay[x][y] = TILEY/4 + 1;
2481
2482         if (MovDelay[x][y])
2483         {
2484           MovDelay[x][y]--;
2485           if (MovDelay[x][y])
2486             return;
2487         }
2488
2489         Feld[x][y] = EL_SIEB2_LEER;
2490         Feld[x][y+1] = EL_SIEB2_VOLL;
2491         Store2[x][y+1] = EL_CHANGED2(Store2[x][y]);
2492         Store2[x][y] = 0;
2493       }
2494     }
2495     else if (CAN_CHANGE(element) &&
2496              (Feld[x][y+1] == EL_SIEB_LEER || Feld[x][y+1] == EL_SIEB2_LEER))
2497     {
2498       InitMovingField(x, y, MV_DOWN);
2499       Store[x][y] =
2500         (Feld[x][y+1] == EL_SIEB_LEER ? EL_SIEB_VOLL : EL_SIEB2_VOLL);
2501       Store2[x][y+1] = element;
2502     }
2503     else if (CAN_SMASH(element) && Feld[x][y+1] == EL_SALZSAEURE)
2504     {
2505       Blurb(x, y);
2506       InitMovingField(x, y, MV_DOWN);
2507       Store[x][y] = EL_SALZSAEURE;
2508     }
2509     else if (CAN_SMASH(element) && Feld[x][y+1] == EL_BLOCKED &&
2510              JustStopped[x][y])
2511     {
2512       Impact(x, y);
2513     }
2514     else if (IS_FREE(x, y+1))
2515     {
2516       InitMovingField(x, y, MV_DOWN);
2517     }
2518     else if (element == EL_TROPFEN)
2519     {
2520       Feld[x][y] = EL_AMOEBING;
2521       Store[x][y] = EL_AMOEBE_NASS;
2522     }
2523 #if OLD_GAME_BEHAVIOUR
2524     else if (IS_SLIPPERY(Feld[x][y+1]) && !Store[x][y+1])
2525 #else
2526     else if (IS_SLIPPERY(Feld[x][y+1]) && !Store[x][y+1] &&
2527              !IS_FALLING(x, y+1) && !JustStopped[x][y+1] &&
2528              element != EL_DX_SUPABOMB)
2529 #endif
2530     {
2531       boolean left  = (x>0 && IS_FREE(x-1, y) &&
2532                        (IS_FREE(x-1, y+1) || Feld[x-1][y+1] == EL_SALZSAEURE));
2533       boolean right = (x<lev_fieldx-1 && IS_FREE(x+1, y) &&
2534                        (IS_FREE(x+1, y+1) || Feld[x+1][y+1] == EL_SALZSAEURE));
2535
2536       if (left || right)
2537       {
2538         if (left && right &&
2539             (game.emulation != EMU_BOULDERDASH &&
2540              element != EL_BD_ROCK && element != EL_EDELSTEIN_BD))
2541           left = !(right = RND(2));
2542
2543         InitMovingField(x, y, left ? MV_LEFT : MV_RIGHT);
2544       }
2545     }
2546     else if (IS_BELT(Feld[x][y+1]))
2547     {
2548       boolean left_is_free  = (x>0 && IS_FREE(x-1, y));
2549       boolean right_is_free = (x<lev_fieldx-1 && IS_FREE(x+1, y));
2550       int belt_nr = getBeltNrFromElement(Feld[x][y+1]);
2551       int belt_dir = game.belt_dir[belt_nr];
2552
2553       if ((belt_dir == MV_LEFT  && left_is_free) ||
2554           (belt_dir == MV_RIGHT && right_is_free))
2555         InitMovingField(x, y, belt_dir);
2556     }
2557   }
2558   else if (CAN_MOVE(element))
2559   {
2560     int newx, newy;
2561
2562     if ((element == EL_SONDE || element == EL_BALLOON ||
2563          element == EL_SPRING_MOVING)
2564         && JustBeingPushed(x, y))
2565       return;
2566
2567     if (!MovDelay[x][y])        /* start new movement phase */
2568     {
2569       /* all objects that can change their move direction after each step */
2570       /* (MAMPFER, MAMPFER2 and PACMAN go straight until they hit a wall  */
2571
2572       if (element!=EL_MAMPFER && element!=EL_MAMPFER2 && element!=EL_PACMAN)
2573       {
2574         TurnRound(x, y);
2575         if (MovDelay[x][y] && (element == EL_KAEFER ||
2576                                element == EL_FLIEGER ||
2577                                element == EL_SP_SNIKSNAK ||
2578                                element == EL_SP_ELECTRON ||
2579                                element == EL_MOLE))
2580           DrawLevelField(x, y);
2581       }
2582     }
2583
2584     if (MovDelay[x][y])         /* wait some time before next movement */
2585     {
2586       MovDelay[x][y]--;
2587
2588       if (element == EL_ROBOT ||
2589           element == EL_MAMPFER || element == EL_MAMPFER2)
2590       {
2591         int phase = MovDelay[x][y] % 8;
2592
2593         if (phase>3)
2594           phase = 7-phase;
2595
2596         if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2597           DrawGraphic(SCREENX(x), SCREENY(y), el2gfx(element)+phase);
2598
2599         if ((element == EL_MAMPFER || element == EL_MAMPFER2)
2600             && MovDelay[x][y]%4 == 3)
2601           PlaySoundLevel(x, y, SND_NJAM);
2602       }
2603       else if (element == EL_SP_ELECTRON)
2604         DrawGraphicAnimation(x, y, GFX2_SP_ELECTRON, 8, 2, ANIM_NORMAL);
2605       else if (element == EL_DRACHE)
2606       {
2607         int i;
2608         int dir = MovDir[x][y];
2609         int dx = (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2610         int dy = (dir == MV_UP   ? -1 : dir == MV_DOWN  ? +1 : 0);
2611         int graphic = (dir == MV_LEFT   ? GFX_FLAMMEN_LEFT :
2612                        dir == MV_RIGHT  ? GFX_FLAMMEN_RIGHT :
2613                        dir == MV_UP     ? GFX_FLAMMEN_UP :
2614                        dir == MV_DOWN   ? GFX_FLAMMEN_DOWN : GFX_LEERRAUM);
2615         int phase = FrameCounter % 2;
2616
2617         for (i=1; i<=3; i++)
2618         {
2619           int xx = x + i*dx, yy = y + i*dy;
2620           int sx = SCREENX(xx), sy = SCREENY(yy);
2621
2622           if (!IN_LEV_FIELD(xx, yy) ||
2623               IS_SOLID(Feld[xx][yy]) || Feld[xx][yy] == EL_EXPLODING)
2624             break;
2625
2626           if (MovDelay[x][y])
2627           {
2628             int flamed = MovingOrBlocked2Element(xx, yy);
2629
2630             if (IS_ENEMY(flamed) || IS_EXPLOSIVE(flamed))
2631               Bang(xx, yy);
2632             else
2633               RemoveMovingField(xx, yy);
2634
2635             Feld[xx][yy] = EL_BURNING;
2636             if (IN_SCR_FIELD(sx, sy))
2637               DrawGraphic(sx, sy, graphic + phase*3 + i-1);
2638           }
2639           else
2640           {
2641             if (Feld[xx][yy] == EL_BURNING)
2642               Feld[xx][yy] = EL_LEERRAUM;
2643             DrawLevelField(xx, yy);
2644           }
2645         }
2646       }
2647
2648       if (MovDelay[x][y])
2649         return;
2650     }
2651
2652     if (element == EL_KAEFER || element == EL_BUTTERFLY)
2653     {
2654       PlaySoundLevel(x, y, SND_KLAPPER);
2655     }
2656     else if (element == EL_FLIEGER || element == EL_FIREFLY)
2657     {
2658       PlaySoundLevel(x, y, SND_ROEHR);
2659     }
2660
2661     /* now make next step */
2662
2663     Moving2Blocked(x, y, &newx, &newy); /* get next screen position */
2664
2665     if (IS_ENEMY(element) && IS_PLAYER(newx, newy) &&
2666         !PLAYER_PROTECTED(newx, newy))
2667     {
2668
2669 #if 1
2670       TestIfBadThingHitsHero(x, y);
2671       return;
2672 #else
2673       /* enemy got the player */
2674       MovDir[x][y] = 0;
2675       KillHero(PLAYERINFO(newx, newy));
2676       return;
2677 #endif
2678
2679     }
2680     else if ((element == EL_PINGUIN || element == EL_ROBOT ||
2681               element == EL_SONDE || element == EL_BALLOON) &&
2682              IN_LEV_FIELD(newx, newy) &&
2683              MovDir[x][y] == MV_DOWN && Feld[newx][newy] == EL_SALZSAEURE)
2684     {
2685       Blurb(x, y);
2686       Store[x][y] = EL_SALZSAEURE;
2687     }
2688     else if (element == EL_PINGUIN && IN_LEV_FIELD(newx, newy))
2689     {
2690       if (Feld[newx][newy] == EL_AUSGANG_AUF)
2691       {
2692         Feld[x][y] = EL_LEERRAUM;
2693         DrawLevelField(x, y);
2694
2695         PlaySoundLevel(newx, newy, SND_BUING);
2696         if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2697           DrawGraphicThruMask(SCREENX(newx), SCREENY(newy), el2gfx(element));
2698
2699         local_player->friends_still_needed--;
2700         if (!local_player->friends_still_needed &&
2701             !local_player->GameOver && AllPlayersGone)
2702           local_player->LevelSolved = local_player->GameOver = TRUE;
2703
2704         return;
2705       }
2706       else if (IS_MAMPF3(Feld[newx][newy]))
2707       {
2708         if (DigField(local_player, newx, newy, 0, 0, DF_DIG) == MF_MOVING)
2709           DrawLevelField(newx, newy);
2710         else
2711           MovDir[x][y] = MV_NO_MOVING;
2712       }
2713       else if (!IS_FREE(newx, newy))
2714       {
2715         if (IS_PLAYER(x, y))
2716           DrawPlayerField(x, y);
2717         else
2718           DrawLevelField(x, y);
2719         return;
2720       }
2721     }
2722     else if (element == EL_SCHWEIN && IN_LEV_FIELD(newx, newy))
2723     {
2724       if (IS_GEM(Feld[newx][newy]))
2725       {
2726         if (IS_MOVING(newx, newy))
2727           RemoveMovingField(newx, newy);
2728         else
2729         {
2730           Feld[newx][newy] = EL_LEERRAUM;
2731           DrawLevelField(newx, newy);
2732         }
2733       }
2734       else if (!IS_FREE(newx, newy))
2735       {
2736         if (IS_PLAYER(x, y))
2737           DrawPlayerField(x, y);
2738         else
2739           DrawLevelField(x, y);
2740         return;
2741       }
2742     }
2743     else if (element == EL_DRACHE && IN_LEV_FIELD(newx, newy))
2744     {
2745       if (!IS_FREE(newx, newy))
2746       {
2747         if (IS_PLAYER(x, y))
2748           DrawPlayerField(x, y);
2749         else
2750           DrawLevelField(x, y);
2751         return;
2752       }
2753       else
2754       {
2755         boolean wanna_flame = !RND(10);
2756         int dx = newx - x, dy = newy - y;
2757         int newx1 = newx+1*dx, newy1 = newy+1*dy;
2758         int newx2 = newx+2*dx, newy2 = newy+2*dy;
2759         int element1 = (IN_LEV_FIELD(newx1, newy1) ?
2760                         MovingOrBlocked2Element(newx1, newy1) : EL_BETON);
2761         int element2 = (IN_LEV_FIELD(newx2, newy2) ?
2762                         MovingOrBlocked2Element(newx2, newy2) : EL_BETON);
2763
2764         if ((wanna_flame || IS_ENEMY(element1) || IS_ENEMY(element2)) &&
2765             element1 != EL_DRACHE && element2 != EL_DRACHE &&
2766             element1 != EL_BURNING && element2 != EL_BURNING)
2767         {
2768           if (IS_PLAYER(x, y))
2769             DrawPlayerField(x, y);
2770           else
2771             DrawLevelField(x, y);
2772
2773           MovDelay[x][y] = 50;
2774           Feld[newx][newy] = EL_BURNING;
2775           if (IN_LEV_FIELD(newx1, newy1) && Feld[newx1][newy1] == EL_LEERRAUM)
2776             Feld[newx1][newy1] = EL_BURNING;
2777           if (IN_LEV_FIELD(newx2, newy2) && Feld[newx2][newy2] == EL_LEERRAUM)
2778             Feld[newx2][newy2] = EL_BURNING;
2779           return;
2780         }
2781       }
2782     }
2783     else if (element == EL_MAMPFER && IN_LEV_FIELD(newx, newy) &&
2784              Feld[newx][newy] == EL_DIAMANT)
2785     {
2786       if (IS_MOVING(newx, newy))
2787         RemoveMovingField(newx, newy);
2788       else
2789       {
2790         Feld[newx][newy] = EL_LEERRAUM;
2791         DrawLevelField(newx, newy);
2792       }
2793     }
2794     else if (element == EL_MAMPFER2 && IN_LEV_FIELD(newx, newy) &&
2795              IS_MAMPF2(Feld[newx][newy]))
2796     {
2797       if (AmoebaNr[newx][newy])
2798       {
2799         AmoebaCnt2[AmoebaNr[newx][newy]]--;
2800         if (Feld[newx][newy] == EL_AMOEBE_VOLL ||
2801             Feld[newx][newy] == EL_AMOEBE_BD)
2802           AmoebaCnt[AmoebaNr[newx][newy]]--;
2803       }
2804
2805       if (IS_MOVING(newx, newy))
2806         RemoveMovingField(newx, newy);
2807       else
2808       {
2809         Feld[newx][newy] = EL_LEERRAUM;
2810         DrawLevelField(newx, newy);
2811       }
2812     }
2813     else if ((element == EL_PACMAN || element == EL_MOLE)
2814              && IN_LEV_FIELD(newx, newy) && IS_AMOEBOID(Feld[newx][newy]))
2815     {
2816       if (AmoebaNr[newx][newy])
2817       {
2818         AmoebaCnt2[AmoebaNr[newx][newy]]--;
2819         if (Feld[newx][newy] == EL_AMOEBE_VOLL ||
2820             Feld[newx][newy] == EL_AMOEBE_BD)
2821           AmoebaCnt[AmoebaNr[newx][newy]]--;
2822       }
2823
2824       if (element == EL_MOLE)
2825       {
2826         Feld[newx][newy] = EL_DEAMOEBING;
2827         MovDelay[newx][newy] = 0;       /* start amoeba shrinking delay */
2828         return;                         /* wait for shrinking amoeba */
2829       }
2830       else      /* element == EL_PACMAN */
2831       {
2832         Feld[newx][newy] = EL_LEERRAUM;
2833         DrawLevelField(newx, newy);
2834       }
2835     }
2836     else if (element == EL_MOLE && IN_LEV_FIELD(newx, newy) &&
2837              (Feld[newx][newy] == EL_DEAMOEBING ||
2838               (Feld[newx][newy] == EL_LEERRAUM && Stop[newx][newy])))
2839     {
2840       /* wait for shrinking amoeba to completely disappear */
2841       return;
2842     }
2843     else if (!IN_LEV_FIELD(newx, newy) || !IS_FREE(newx, newy))
2844     {
2845       /* object was running against a wall */
2846
2847       TurnRound(x, y);
2848
2849       if (element == EL_KAEFER || element == EL_FLIEGER ||
2850           element == EL_SP_SNIKSNAK || element == EL_MOLE)
2851         DrawLevelField(x, y);
2852       else if (element == EL_BUTTERFLY || element == EL_FIREFLY)
2853         DrawGraphicAnimation(x, y, el2gfx(element), 2, 4, ANIM_NORMAL);
2854       else if (element == EL_SONDE)
2855         DrawGraphicAnimation(x, y, GFX_SONDE_START, 8, 2, ANIM_NORMAL);
2856       else if (element == EL_SP_ELECTRON)
2857         DrawGraphicAnimation(x, y, GFX2_SP_ELECTRON, 8, 2, ANIM_NORMAL);
2858
2859       if (DONT_TOUCH(element))
2860         TestIfBadThingHitsHero(x, y);
2861
2862       return;
2863     }
2864
2865     if (element == EL_ROBOT && IN_SCR_FIELD(x, y))
2866       PlaySoundLevel(x, y, SND_SCHLURF);
2867
2868     InitMovingField(x, y, MovDir[x][y]);
2869   }
2870
2871   if (MovDir[x][y])
2872     ContinueMoving(x, y);
2873 }
2874
2875 void ContinueMoving(int x, int y)
2876 {
2877   int element = Feld[x][y];
2878   int direction = MovDir[x][y];
2879   int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
2880   int dy = (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
2881   int horiz_move = (dx!=0);
2882   int newx = x + dx, newy = y + dy;
2883   int step = (horiz_move ? dx : dy) * TILEX / 8;
2884
2885   if (element == EL_TROPFEN)
2886     step /= 2;
2887   else if (Store[x][y] == EL_MORAST_VOLL || Store[x][y] == EL_MORAST_LEER)
2888     step /= 4;
2889   else if (CAN_FALL(element) && horiz_move &&
2890            y < lev_fieldy-1 && IS_BELT(Feld[x][y+1]))
2891     step /= 2;
2892   else if (element == EL_SPRING_MOVING)
2893     step*=2;
2894
2895 #if OLD_GAME_BEHAVIOUR
2896   else if (CAN_FALL(element) && horiz_move && !IS_SP_ELEMENT(element))
2897     step*=2;
2898 #endif
2899
2900   MovPos[x][y] += step;
2901
2902   if (ABS(MovPos[x][y])>=TILEX)         /* object reached its destination */
2903   {
2904     Feld[x][y] = EL_LEERRAUM;
2905     Feld[newx][newy] = element;
2906
2907     if (element == EL_MOLE)
2908     {
2909       int i;
2910       static int xy[4][2] =
2911       {
2912         { 0, -1 },
2913         { -1, 0 },
2914         { +1, 0 },
2915         { 0, +1 }
2916       };
2917
2918       Feld[x][y] = EL_ERDREICH;
2919       DrawLevelField(x, y);
2920
2921       for(i=0; i<4; i++)
2922       {
2923         int xx, yy;
2924
2925         xx = x + xy[i][0];
2926         yy = y + xy[i][1];
2927
2928         if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == EL_ERDREICH)
2929           DrawLevelField(xx, yy);       /* for "ErdreichAnbroeckeln()" */
2930       }
2931     }
2932
2933     if (Store[x][y] == EL_MORAST_VOLL)
2934     {
2935       Store[x][y] = 0;
2936       Feld[newx][newy] = EL_MORAST_VOLL;
2937       element = EL_MORAST_VOLL;
2938     }
2939     else if (Store[x][y] == EL_MORAST_LEER)
2940     {
2941       Store[x][y] = 0;
2942       Feld[x][y] = EL_MORAST_LEER;
2943     }
2944     else if (Store[x][y] == EL_SIEB_VOLL)
2945     {
2946       Store[x][y] = 0;
2947       element = Feld[newx][newy] =
2948         (game.magic_wall_active ? EL_SIEB_VOLL : EL_SIEB_TOT);
2949     }
2950     else if (Store[x][y] == EL_SIEB_LEER)
2951     {
2952       Store[x][y] = Store2[x][y] = 0;
2953       Feld[x][y] = (game.magic_wall_active ? EL_SIEB_LEER : EL_SIEB_TOT);
2954     }
2955     else if (Store[x][y] == EL_SIEB2_VOLL)
2956     {
2957       Store[x][y] = 0;
2958       element = Feld[newx][newy] =
2959         (game.magic_wall_active ? EL_SIEB2_VOLL : EL_SIEB2_TOT);
2960     }
2961     else if (Store[x][y] == EL_SIEB2_LEER)
2962     {
2963       Store[x][y] = Store2[x][y] = 0;
2964       Feld[x][y] = (game.magic_wall_active ? EL_SIEB2_LEER : EL_SIEB2_TOT);
2965     }
2966     else if (Store[x][y] == EL_SALZSAEURE)
2967     {
2968       Store[x][y] = 0;
2969       Feld[newx][newy] = EL_SALZSAEURE;
2970       element = EL_SALZSAEURE;
2971     }
2972     else if (Store[x][y] == EL_AMOEBE_NASS)
2973     {
2974       Store[x][y] = 0;
2975       Feld[x][y] = EL_AMOEBE_NASS;
2976     }
2977
2978     MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
2979     MovDelay[newx][newy] = 0;
2980
2981     if (!CAN_MOVE(element))
2982       MovDir[newx][newy] = 0;
2983
2984     DrawLevelField(x, y);
2985     DrawLevelField(newx, newy);
2986
2987     Stop[newx][newy] = TRUE;
2988     JustStopped[newx][newy] = 3;
2989
2990     if (DONT_TOUCH(element))    /* object may be nasty to player or others */
2991     {
2992       TestIfBadThingHitsHero(newx, newy);
2993       TestIfBadThingHitsFriend(newx, newy);
2994       TestIfBadThingHitsOtherBadThing(newx, newy);
2995     }
2996     else if (element == EL_PINGUIN)
2997       TestIfFriendHitsBadThing(newx, newy);
2998
2999     if (CAN_SMASH(element) && direction == MV_DOWN &&
3000         (newy == lev_fieldy-1 || !IS_FREE(x, newy+1)))
3001       Impact(x, newy);
3002   }
3003   else                          /* still moving on */
3004     DrawLevelField(x, y);
3005 }
3006
3007 int AmoebeNachbarNr(int ax, int ay)
3008 {
3009   int i;
3010   int element = Feld[ax][ay];
3011   int group_nr = 0;
3012   static int xy[4][2] =
3013   {
3014     { 0, -1 },
3015     { -1, 0 },
3016     { +1, 0 },
3017     { 0, +1 }
3018   };
3019
3020   for (i=0; i<4; i++)
3021   {
3022     int x = ax + xy[i][0];
3023     int y = ay + xy[i][1];
3024
3025     if (!IN_LEV_FIELD(x, y))
3026       continue;
3027
3028     if (Feld[x][y] == element && AmoebaNr[x][y] > 0)
3029       group_nr = AmoebaNr[x][y];
3030   }
3031
3032   return group_nr;
3033 }
3034
3035 void AmoebenVereinigen(int ax, int ay)
3036 {
3037   int i, x, y, xx, yy;
3038   int new_group_nr = AmoebaNr[ax][ay];
3039   static int xy[4][2] =
3040   {
3041     { 0, -1 },
3042     { -1, 0 },
3043     { +1, 0 },
3044     { 0, +1 }
3045   };
3046
3047   if (new_group_nr == 0)
3048     return;
3049
3050   for (i=0; i<4; i++)
3051   {
3052     x = ax + xy[i][0];
3053     y = ay + xy[i][1];
3054
3055     if (!IN_LEV_FIELD(x, y))
3056       continue;
3057
3058     if ((Feld[x][y] == EL_AMOEBE_VOLL ||
3059          Feld[x][y] == EL_AMOEBE_BD ||
3060          Feld[x][y] == EL_AMOEBE_TOT) &&
3061         AmoebaNr[x][y] != new_group_nr)
3062     {
3063       int old_group_nr = AmoebaNr[x][y];
3064
3065       if (old_group_nr == 0)
3066         return;
3067
3068       AmoebaCnt[new_group_nr] += AmoebaCnt[old_group_nr];
3069       AmoebaCnt[old_group_nr] = 0;
3070       AmoebaCnt2[new_group_nr] += AmoebaCnt2[old_group_nr];
3071       AmoebaCnt2[old_group_nr] = 0;
3072
3073       for (yy=0; yy<lev_fieldy; yy++)
3074       {
3075         for (xx=0; xx<lev_fieldx; xx++)
3076         {
3077           if (AmoebaNr[xx][yy] == old_group_nr)
3078             AmoebaNr[xx][yy] = new_group_nr;
3079         }
3080       }
3081     }
3082   }
3083 }
3084
3085 void AmoebeUmwandeln(int ax, int ay)
3086 {
3087   int i, x, y;
3088
3089   if (Feld[ax][ay] == EL_AMOEBE_TOT)
3090   {
3091     int group_nr = AmoebaNr[ax][ay];
3092
3093 #ifdef DEBUG
3094     if (group_nr == 0)
3095     {
3096       printf("AmoebeUmwandeln(): ax = %d, ay = %d\n", ax, ay);
3097       printf("AmoebeUmwandeln(): This should never happen!\n");
3098       return;
3099     }
3100 #endif
3101
3102     for (y=0; y<lev_fieldy; y++)
3103     {
3104       for (x=0; x<lev_fieldx; x++)
3105       {
3106         if (Feld[x][y] == EL_AMOEBE_TOT && AmoebaNr[x][y] == group_nr)
3107         {
3108           AmoebaNr[x][y] = 0;
3109           Feld[x][y] = EL_AMOEBA2DIAM;
3110         }
3111       }
3112     }
3113     Bang(ax, ay);
3114   }
3115   else
3116   {
3117     static int xy[4][2] =
3118     {
3119       { 0, -1 },
3120       { -1, 0 },
3121       { +1, 0 },
3122       { 0, +1 }
3123     };
3124
3125     for (i=0; i<4; i++)
3126     {
3127       x = ax + xy[i][0];
3128       y = ay + xy[i][1];
3129
3130       if (!IN_LEV_FIELD(x, y))
3131         continue;
3132
3133       if (Feld[x][y] == EL_AMOEBA2DIAM)
3134         Bang(x, y);
3135     }
3136   }
3137 }
3138
3139 void AmoebeUmwandelnBD(int ax, int ay, int new_element)
3140 {
3141   int x, y;
3142   int group_nr = AmoebaNr[ax][ay];
3143   boolean done = FALSE;
3144
3145 #ifdef DEBUG
3146   if (group_nr == 0)
3147   {
3148     printf("AmoebeUmwandelnBD(): ax = %d, ay = %d\n", ax, ay);
3149     printf("AmoebeUmwandelnBD(): This should never happen!\n");
3150     return;
3151   }
3152 #endif
3153
3154   for (y=0; y<lev_fieldy; y++)
3155   {
3156     for (x=0; x<lev_fieldx; x++)
3157     {
3158       if (AmoebaNr[x][y] == group_nr &&
3159           (Feld[x][y] == EL_AMOEBE_TOT ||
3160            Feld[x][y] == EL_AMOEBE_BD ||
3161            Feld[x][y] == EL_AMOEBING))
3162       {
3163         AmoebaNr[x][y] = 0;
3164         Feld[x][y] = new_element;
3165         InitField(x, y, FALSE);
3166         DrawLevelField(x, y);
3167         done = TRUE;
3168       }
3169     }
3170   }
3171
3172   if (done)
3173     PlaySoundLevel(ax, ay,
3174                    (new_element == EL_BD_ROCK ? SND_KLOPF : SND_PLING));
3175 }
3176
3177 void AmoebeWaechst(int x, int y)
3178 {
3179   static unsigned long sound_delay = 0;
3180   static unsigned long sound_delay_value = 0;
3181
3182   if (!MovDelay[x][y])          /* start new growing cycle */
3183   {
3184     MovDelay[x][y] = 7;
3185
3186     if (DelayReached(&sound_delay, sound_delay_value))
3187     {
3188       PlaySoundLevel(x, y, SND_AMOEBE);
3189       sound_delay_value = 30;
3190     }
3191   }
3192
3193   if (MovDelay[x][y])           /* wait some time before growing bigger */
3194   {
3195     MovDelay[x][y]--;
3196     if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3197       DrawGraphic(SCREENX(x), SCREENY(y), GFX_AMOEBING + 3 - MovDelay[x][y]/2);
3198
3199     if (!MovDelay[x][y])
3200     {
3201       Feld[x][y] = Store[x][y];
3202       Store[x][y] = 0;
3203       DrawLevelField(x, y);
3204     }
3205   }
3206 }
3207
3208 void AmoebeSchrumpft(int x, int y)
3209 {
3210   static unsigned long sound_delay = 0;
3211   static unsigned long sound_delay_value = 0;
3212
3213   if (!MovDelay[x][y])          /* start new shrinking cycle */
3214   {
3215     MovDelay[x][y] = 7;
3216
3217     if (DelayReached(&sound_delay, sound_delay_value))
3218     {
3219       PlaySoundLevel(x, y, SND_BLURB);
3220       sound_delay_value = 30;
3221     }
3222   }
3223
3224   if (MovDelay[x][y])           /* wait some time before shrinking */
3225   {
3226     MovDelay[x][y]--;
3227     if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3228       DrawGraphic(SCREENX(x), SCREENY(y), GFX_AMOEBING + MovDelay[x][y]/2);
3229
3230     if (!MovDelay[x][y])
3231     {
3232       Feld[x][y] = EL_LEERRAUM;
3233       DrawLevelField(x, y);
3234
3235       /* don't let mole enter this field in this cycle;
3236          (give priority to objects falling to this field from above) */
3237       Stop[x][y] = TRUE;
3238     }
3239   }
3240 }
3241
3242 void AmoebeAbleger(int ax, int ay)
3243 {
3244   int i;
3245   int element = Feld[ax][ay];
3246   int newax = ax, neway = ay;
3247   static int xy[4][2] =
3248   {
3249     { 0, -1 },
3250     { -1, 0 },
3251     { +1, 0 },
3252     { 0, +1 }
3253   };
3254
3255   if (!level.amoeba_speed)
3256   {
3257     Feld[ax][ay] = EL_AMOEBE_TOT;
3258     DrawLevelField(ax, ay);
3259     return;
3260   }
3261
3262   if (!MovDelay[ax][ay])        /* start making new amoeba field */
3263     MovDelay[ax][ay] = RND(FRAMES_PER_SECOND * 25 / (1 + level.amoeba_speed));
3264
3265   if (MovDelay[ax][ay])         /* wait some time before making new amoeba */
3266   {
3267     MovDelay[ax][ay]--;
3268     if (MovDelay[ax][ay])
3269       return;
3270   }
3271
3272   if (element == EL_AMOEBE_NASS)        /* object is an acid / amoeba drop */
3273   {
3274     int start = RND(4);
3275     int x = ax + xy[start][0];
3276     int y = ay + xy[start][1];
3277
3278     if (!IN_LEV_FIELD(x, y))
3279       return;
3280
3281     if (IS_FREE(x, y) ||
3282         Feld[x][y] == EL_ERDREICH || Feld[x][y] == EL_MORAST_LEER)
3283     {
3284       newax = x;
3285       neway = y;
3286     }
3287
3288     if (newax == ax && neway == ay)
3289       return;
3290   }
3291   else                          /* normal or "filled" (BD style) amoeba */
3292   {
3293     int start = RND(4);
3294     boolean waiting_for_player = FALSE;
3295
3296     for (i=0; i<4; i++)
3297     {
3298       int j = (start + i) % 4;
3299       int x = ax + xy[j][0];
3300       int y = ay + xy[j][1];
3301
3302       if (!IN_LEV_FIELD(x, y))
3303         continue;
3304
3305       if (IS_FREE(x, y) ||
3306           Feld[x][y] == EL_ERDREICH || Feld[x][y] == EL_MORAST_LEER)
3307       {
3308         newax = x;
3309         neway = y;
3310         break;
3311       }
3312       else if (IS_PLAYER(x, y))
3313         waiting_for_player = TRUE;
3314     }
3315
3316     if (newax == ax && neway == ay)             /* amoeba cannot grow */
3317     {
3318       if (i == 4 && (!waiting_for_player || game.emulation == EMU_BOULDERDASH))
3319       {
3320         Feld[ax][ay] = EL_AMOEBE_TOT;
3321         DrawLevelField(ax, ay);
3322         AmoebaCnt[AmoebaNr[ax][ay]]--;
3323
3324         if (AmoebaCnt[AmoebaNr[ax][ay]] <= 0)   /* amoeba is completely dead */
3325         {
3326           if (element == EL_AMOEBE_VOLL)
3327             AmoebeUmwandeln(ax, ay);
3328           else if (element == EL_AMOEBE_BD)
3329             AmoebeUmwandelnBD(ax, ay, level.amoeba_content);
3330         }
3331       }
3332       return;
3333     }
3334     else if (element == EL_AMOEBE_VOLL || element == EL_AMOEBE_BD)
3335     {
3336       /* amoeba gets larger by growing in some direction */
3337
3338       int new_group_nr = AmoebaNr[ax][ay];
3339
3340 #ifdef DEBUG
3341   if (new_group_nr == 0)
3342   {
3343     printf("AmoebeAbleger(): newax = %d, neway = %d\n", newax, neway);
3344     printf("AmoebeAbleger(): This should never happen!\n");
3345     return;
3346   }
3347 #endif
3348
3349       AmoebaNr[newax][neway] = new_group_nr;
3350       AmoebaCnt[new_group_nr]++;
3351       AmoebaCnt2[new_group_nr]++;
3352
3353       /* if amoeba touches other amoeba(s) after growing, unify them */
3354       AmoebenVereinigen(newax, neway);
3355
3356       if (element == EL_AMOEBE_BD && AmoebaCnt2[new_group_nr] >= 200)
3357       {
3358         AmoebeUmwandelnBD(newax, neway, EL_BD_ROCK);
3359         return;
3360       }
3361     }
3362   }
3363
3364   if (element != EL_AMOEBE_NASS || neway < ay || !IS_FREE(newax, neway) ||
3365       (neway == lev_fieldy - 1 && newax != ax))
3366   {
3367     Feld[newax][neway] = EL_AMOEBING;
3368     Store[newax][neway] = element;
3369   }
3370   else if (neway == ay)
3371     Feld[newax][neway] = EL_TROPFEN;
3372   else
3373   {
3374     InitMovingField(ax, ay, MV_DOWN);
3375     Feld[ax][ay] = EL_TROPFEN;
3376     Store[ax][ay] = EL_AMOEBE_NASS;
3377     ContinueMoving(ax, ay);
3378     return;
3379   }
3380
3381   DrawLevelField(newax, neway);
3382 }
3383
3384 void Life(int ax, int ay)
3385 {
3386   int x1, y1, x2, y2;
3387   static int life[4] = { 2, 3, 3, 3 };  /* parameters for "game of life" */
3388   int life_time = 40;
3389   int element = Feld[ax][ay];
3390
3391   if (Stop[ax][ay])
3392     return;
3393
3394   if (!MovDelay[ax][ay])        /* start new "game of life" cycle */
3395     MovDelay[ax][ay] = life_time;
3396
3397   if (MovDelay[ax][ay])         /* wait some time before next cycle */
3398   {
3399     MovDelay[ax][ay]--;
3400     if (MovDelay[ax][ay])
3401       return;
3402   }
3403
3404   for (y1=-1; y1<2; y1++) for(x1=-1; x1<2; x1++)
3405   {
3406     int xx = ax+x1, yy = ay+y1;
3407     int nachbarn = 0;
3408
3409     if (!IN_LEV_FIELD(xx, yy))
3410       continue;
3411
3412     for (y2=-1; y2<2; y2++) for (x2=-1; x2<2; x2++)
3413     {
3414       int x = xx+x2, y = yy+y2;
3415
3416       if (!IN_LEV_FIELD(x, y) || (x == xx && y == yy))
3417         continue;
3418
3419       if (((Feld[x][y] == element ||
3420             (element == EL_LIFE && IS_PLAYER(x, y))) &&
3421            !Stop[x][y]) ||
3422           (IS_FREE(x, y) && Stop[x][y]))
3423         nachbarn++;
3424     }
3425
3426     if (xx == ax && yy == ay)           /* field in the middle */
3427     {
3428       if (nachbarn<life[0] || nachbarn>life[1])
3429       {
3430         Feld[xx][yy] = EL_LEERRAUM;
3431         if (!Stop[xx][yy])
3432           DrawLevelField(xx, yy);
3433         Stop[xx][yy] = TRUE;
3434       }
3435     }
3436     else if (IS_FREE(xx, yy) || Feld[xx][yy] == EL_ERDREICH)
3437     {                                   /* free border field */
3438       if (nachbarn>=life[2] && nachbarn<=life[3])
3439       {
3440         Feld[xx][yy] = element;
3441         MovDelay[xx][yy] = (element == EL_LIFE ? 0 : life_time-1);
3442         if (!Stop[xx][yy])
3443           DrawLevelField(xx, yy);
3444         Stop[xx][yy] = TRUE;
3445       }
3446     }
3447   }
3448 }
3449
3450 void Ablenk(int x, int y)
3451 {
3452   if (!MovDelay[x][y])          /* next animation frame */
3453     MovDelay[x][y] = level.time_wheel * FRAMES_PER_SECOND;
3454
3455   if (MovDelay[x][y])           /* wait some time before next frame */
3456   {
3457     MovDelay[x][y]--;
3458     if (MovDelay[x][y])
3459     {
3460       if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3461         DrawGraphic(SCREENX(x), SCREENY(y), GFX_ABLENK+MovDelay[x][y]%4);
3462       if (!(MovDelay[x][y]%4))
3463         PlaySoundLevel(x, y, SND_MIEP);
3464       return;
3465     }
3466   }
3467
3468   Feld[x][y] = EL_ABLENK_AUS;
3469   DrawLevelField(x, y);
3470   if (ZX == x && ZY == y)
3471     ZX = ZY = -1;
3472 }
3473
3474 void TimegateWheel(int x, int y)
3475 {
3476   if (!MovDelay[x][y])          /* next animation frame */
3477     MovDelay[x][y] = level.time_wheel * FRAMES_PER_SECOND;
3478
3479   if (MovDelay[x][y])           /* wait some time before next frame */
3480   {
3481     MovDelay[x][y]--;
3482     if (MovDelay[x][y])
3483     {
3484       if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3485         DrawGraphic(SCREENX(x), SCREENY(y),
3486                     GFX_TIMEGATE_SWITCH + MovDelay[x][y]%4);
3487       if (!(MovDelay[x][y]%4))
3488         PlaySoundLevel(x, y, SND_MIEP);
3489       return;
3490     }
3491   }
3492
3493   Feld[x][y] = EL_TIMEGATE_SWITCH_OFF;
3494   DrawLevelField(x, y);
3495   if (ZX == x && ZY == y)
3496     ZX = ZY = -1;
3497 }
3498
3499 void Birne(int x, int y)
3500 {
3501   if (!MovDelay[x][y])          /* next animation frame */
3502     MovDelay[x][y] = 800;
3503
3504   if (MovDelay[x][y])           /* wait some time before next frame */
3505   {
3506     MovDelay[x][y]--;
3507     if (MovDelay[x][y])
3508     {
3509       if (!(MovDelay[x][y]%5))
3510       {
3511         if (!(MovDelay[x][y]%10))
3512           Feld[x][y]=EL_ABLENK_EIN;
3513         else
3514           Feld[x][y]=EL_ABLENK_AUS;
3515         DrawLevelField(x, y);
3516         Feld[x][y]=EL_ABLENK_EIN;
3517       }
3518       return;
3519     }
3520   }
3521
3522   Feld[x][y]=EL_ABLENK_AUS;
3523   DrawLevelField(x, y);
3524   if (ZX == x && ZY == y)
3525     ZX=ZY=-1;
3526 }
3527
3528 void Blubber(int x, int y)
3529 {
3530   if (y > 0 && IS_MOVING(x, y-1) && MovDir[x][y-1] == MV_DOWN)
3531     DrawLevelField(x, y-1);
3532   else
3533     DrawGraphicAnimation(x, y, GFX_GEBLUBBER, 4, 10, ANIM_NORMAL);
3534 }
3535
3536 void NussKnacken(int x, int y)
3537 {
3538   if (!MovDelay[x][y])          /* next animation frame */
3539     MovDelay[x][y] = 7;
3540
3541   if (MovDelay[x][y])           /* wait some time before next frame */
3542   {
3543     MovDelay[x][y]--;
3544     if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3545       DrawGraphic(SCREENX(x), SCREENY(y),
3546                   GFX_CRACKINGNUT + 3 - MovDelay[x][y]/2);
3547
3548     if (!MovDelay[x][y])
3549     {
3550       Feld[x][y] = EL_EDELSTEIN;
3551       DrawLevelField(x, y);
3552     }
3553   }
3554 }
3555
3556 void BreakingPearl(int x, int y)
3557 {
3558   if (!MovDelay[x][y])          /* next animation frame */
3559     MovDelay[x][y] = 9;
3560
3561   if (MovDelay[x][y])           /* wait some time before next frame */
3562   {
3563     MovDelay[x][y]--;
3564     if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3565       DrawGraphic(SCREENX(x), SCREENY(y),
3566                   GFX_PEARL_BREAKING + 4 - MovDelay[x][y]/2);
3567
3568     if (!MovDelay[x][y])
3569     {
3570       Feld[x][y] = EL_LEERRAUM;
3571       DrawLevelField(x, y);
3572     }
3573   }
3574 }
3575
3576 void SiebAktivieren(int x, int y, int typ)
3577 {
3578   int graphic = (typ == 1 ? GFX_SIEB_VOLL : GFX_SIEB2_VOLL) + 3;
3579
3580   DrawGraphicAnimation(x, y, graphic, 4, 4, ANIM_REVERSE);
3581 }
3582
3583 void AusgangstuerPruefen(int x, int y)
3584 {
3585   if (!local_player->gems_still_needed &&
3586       !local_player->sokobanfields_still_needed &&
3587       !local_player->lights_still_needed)
3588   {
3589     Feld[x][y] = EL_AUSGANG_ACT;
3590
3591     PlaySoundLevel(x < LEVELX(BX1) ? LEVELX(BX1) :
3592                    (x > LEVELX(BX2) ? LEVELX(BX2) : x),
3593                    y < LEVELY(BY1) ? LEVELY(BY1) :
3594                    (y > LEVELY(BY2) ? LEVELY(BY2) : y),
3595                    SND_OEFFNEN);
3596   }
3597 }
3598
3599 void AusgangstuerOeffnen(int x, int y)
3600 {
3601   int delay = 6;
3602
3603   if (!MovDelay[x][y])          /* next animation frame */
3604     MovDelay[x][y] = 5*delay;
3605
3606   if (MovDelay[x][y])           /* wait some time before next frame */
3607   {
3608     int tuer;
3609
3610     MovDelay[x][y]--;
3611     tuer = MovDelay[x][y]/delay;
3612     if (!(MovDelay[x][y]%delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3613       DrawGraphic(SCREENX(x), SCREENY(y), GFX_AUSGANG_AUF-tuer);
3614
3615     if (!MovDelay[x][y])
3616     {
3617       Feld[x][y] = EL_AUSGANG_AUF;
3618       DrawLevelField(x, y);
3619     }
3620   }
3621 }
3622
3623 void AusgangstuerBlinken(int x, int y)
3624 {
3625   DrawGraphicAnimation(x, y, GFX_AUSGANG_AUF, 4, 4, ANIM_OSCILLATE);
3626 }
3627
3628 void OpenSwitchgate(int x, int y)
3629 {
3630   int delay = 6;
3631
3632   if (!MovDelay[x][y])          /* next animation frame */
3633     MovDelay[x][y] = 5 * delay;
3634
3635   if (MovDelay[x][y])           /* wait some time before next frame */
3636   {
3637     int phase;
3638
3639     MovDelay[x][y]--;
3640     phase = MovDelay[x][y] / delay;
3641     if (!(MovDelay[x][y] % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3642       DrawGraphic(SCREENX(x), SCREENY(y), GFX_SWITCHGATE_OPEN - phase);
3643
3644     if (!MovDelay[x][y])
3645     {
3646       Feld[x][y] = EL_SWITCHGATE_OPEN;
3647       DrawLevelField(x, y);
3648     }
3649   }
3650 }
3651
3652 void CloseSwitchgate(int x, int y)
3653 {
3654   int delay = 6;
3655
3656   if (!MovDelay[x][y])          /* next animation frame */
3657     MovDelay[x][y] = 5 * delay;
3658
3659   if (MovDelay[x][y])           /* wait some time before next frame */
3660   {
3661     int phase;
3662
3663     MovDelay[x][y]--;
3664     phase = MovDelay[x][y] / delay;
3665     if (!(MovDelay[x][y] % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3666       DrawGraphic(SCREENX(x), SCREENY(y), GFX_SWITCHGATE_CLOSED + phase);
3667
3668     if (!MovDelay[x][y])
3669     {
3670       Feld[x][y] = EL_SWITCHGATE_CLOSED;
3671       DrawLevelField(x, y);
3672     }
3673   }
3674 }
3675
3676 void OpenTimegate(int x, int y)
3677 {
3678   int delay = 6;
3679
3680   if (!MovDelay[x][y])          /* next animation frame */
3681     MovDelay[x][y] = 5 * delay;
3682
3683   if (MovDelay[x][y])           /* wait some time before next frame */
3684   {
3685     int phase;
3686
3687     MovDelay[x][y]--;
3688     phase = MovDelay[x][y] / delay;
3689     if (!(MovDelay[x][y] % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3690       DrawGraphic(SCREENX(x), SCREENY(y), GFX_TIMEGATE_OPEN - phase);
3691
3692     if (!MovDelay[x][y])
3693     {
3694       Feld[x][y] = EL_TIMEGATE_OPEN;
3695       DrawLevelField(x, y);
3696     }
3697   }
3698 }
3699
3700 void CloseTimegate(int x, int y)
3701 {
3702   int delay = 6;
3703
3704   if (!MovDelay[x][y])          /* next animation frame */
3705     MovDelay[x][y] = 5 * delay;
3706
3707   if (MovDelay[x][y])           /* wait some time before next frame */
3708   {
3709     int phase;
3710
3711     MovDelay[x][y]--;
3712     phase = MovDelay[x][y] / delay;
3713     if (!(MovDelay[x][y] % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3714       DrawGraphic(SCREENX(x), SCREENY(y), GFX_TIMEGATE_CLOSED + phase);
3715
3716     if (!MovDelay[x][y])
3717     {
3718       Feld[x][y] = EL_TIMEGATE_CLOSED;
3719       DrawLevelField(x, y);
3720     }
3721   }
3722 }
3723
3724 static void CloseAllOpenTimegates()
3725 {
3726   int x, y;
3727
3728   for (y=0; y<lev_fieldy; y++)
3729   {
3730     for (x=0; x<lev_fieldx; x++)
3731     {
3732       int element = Feld[x][y];
3733
3734       if (element == EL_TIMEGATE_OPEN || element == EL_TIMEGATE_OPENING)
3735       {
3736         Feld[x][y] = EL_TIMEGATE_CLOSING;
3737         PlaySoundLevel(x, y, SND_OEFFNEN);
3738       }
3739     }
3740   }
3741 }
3742
3743 void EdelsteinFunkeln(int x, int y)
3744 {
3745   if (!IN_SCR_FIELD(SCREENX(x), SCREENY(y)) || IS_MOVING(x, y))
3746     return;
3747
3748   if (Feld[x][y] == EL_EDELSTEIN_BD)
3749     DrawGraphicAnimation(x, y, GFX_EDELSTEIN_BD, 4, 4, ANIM_REVERSE);
3750   else
3751   {
3752     if (!MovDelay[x][y])        /* next animation frame */
3753       MovDelay[x][y] = 11 * !SimpleRND(500);
3754
3755     if (MovDelay[x][y])         /* wait some time before next frame */
3756     {
3757       MovDelay[x][y]--;
3758
3759       if (setup.direct_draw && MovDelay[x][y])
3760         SetDrawtoField(DRAW_BUFFERED);
3761
3762       DrawGraphic(SCREENX(x), SCREENY(y), el2gfx(Feld[x][y]));
3763
3764       if (MovDelay[x][y])
3765       {
3766         int phase = (MovDelay[x][y]-1)/2;
3767
3768         if (phase > 2)
3769           phase = 4-phase;
3770
3771         DrawGraphicThruMask(SCREENX(x), SCREENY(y), GFX_FUNKELN_WEISS + phase);
3772
3773         if (setup.direct_draw)
3774         {
3775           int dest_x, dest_y;
3776
3777           dest_x = FX + SCREENX(x)*TILEX;
3778           dest_y = FY + SCREENY(y)*TILEY;
3779
3780           XCopyArea(display, drawto_field, window, gc,
3781                     dest_x, dest_y, TILEX, TILEY, dest_x, dest_y);
3782           SetDrawtoField(DRAW_DIRECT);
3783         }
3784       }
3785     }
3786   }
3787 }
3788
3789 void MauerWaechst(int x, int y)
3790 {
3791   int delay = 6;
3792
3793   if (!MovDelay[x][y])          /* next animation frame */
3794     MovDelay[x][y] = 3*delay;
3795
3796   if (MovDelay[x][y])           /* wait some time before next frame */
3797   {
3798     int phase;
3799
3800     MovDelay[x][y]--;
3801     phase = 2-MovDelay[x][y]/delay;
3802     if (!(MovDelay[x][y]%delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3803       DrawGraphic(SCREENX(x), SCREENY(y),
3804                   (MovDir[x][y] == MV_LEFT  ? GFX_MAUER_LEFT  :
3805                    MovDir[x][y] == MV_RIGHT ? GFX_MAUER_RIGHT :
3806                    MovDir[x][y] == MV_UP    ? GFX_MAUER_UP    :
3807                                               GFX_MAUER_DOWN  ) + phase);
3808
3809     if (!MovDelay[x][y])
3810     {
3811       if (MovDir[x][y] == MV_LEFT)
3812       {
3813         if (IN_LEV_FIELD(x-1, y) && IS_MAUER(Feld[x-1][y]))
3814           DrawLevelField(x-1, y);
3815       }
3816       else if (MovDir[x][y] == MV_RIGHT)
3817       {
3818         if (IN_LEV_FIELD(x+1, y) && IS_MAUER(Feld[x+1][y]))
3819           DrawLevelField(x+1, y);
3820       }
3821       else if (MovDir[x][y] == MV_UP)
3822       {
3823         if (IN_LEV_FIELD(x, y-1) && IS_MAUER(Feld[x][y-1]))
3824           DrawLevelField(x, y-1);
3825       }
3826       else
3827       {
3828         if (IN_LEV_FIELD(x, y+1) && IS_MAUER(Feld[x][y+1]))
3829           DrawLevelField(x, y+1);
3830       }
3831
3832       Feld[x][y] = Store[x][y];
3833       Store[x][y] = 0;
3834       MovDir[x][y] = MV_NO_MOVING;
3835       DrawLevelField(x, y);
3836     }
3837   }
3838 }
3839
3840 void MauerAbleger(int ax, int ay)
3841 {
3842   int element = Feld[ax][ay];
3843   boolean oben_frei = FALSE, unten_frei = FALSE;
3844   boolean links_frei = FALSE, rechts_frei = FALSE;
3845   boolean oben_massiv = FALSE, unten_massiv = FALSE;
3846   boolean links_massiv = FALSE, rechts_massiv = FALSE;
3847
3848   if (!MovDelay[ax][ay])        /* start building new wall */
3849     MovDelay[ax][ay] = 6;
3850
3851   if (MovDelay[ax][ay])         /* wait some time before building new wall */
3852   {
3853     MovDelay[ax][ay]--;
3854     if (MovDelay[ax][ay])
3855       return;
3856   }
3857
3858   if (IN_LEV_FIELD(ax, ay-1) && IS_FREE(ax, ay-1))
3859     oben_frei = TRUE;
3860   if (IN_LEV_FIELD(ax, ay+1) && IS_FREE(ax, ay+1))
3861     unten_frei = TRUE;
3862   if (IN_LEV_FIELD(ax-1, ay) && IS_FREE(ax-1, ay))
3863     links_frei = TRUE;
3864   if (IN_LEV_FIELD(ax+1, ay) && IS_FREE(ax+1, ay))
3865     rechts_frei = TRUE;
3866
3867   if (element == EL_MAUER_Y || element == EL_MAUER_XY)
3868   {
3869     if (oben_frei)
3870     {
3871       Feld[ax][ay-1] = EL_MAUERND;
3872       Store[ax][ay-1] = element;
3873       MovDir[ax][ay-1] = MV_UP;
3874       if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay-1)))
3875         DrawGraphic(SCREENX(ax), SCREENY(ay-1), GFX_MAUER_UP);
3876     }
3877     if (unten_frei)
3878     {
3879       Feld[ax][ay+1] = EL_MAUERND;
3880       Store[ax][ay+1] = element;
3881       MovDir[ax][ay+1] = MV_DOWN;
3882       if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay+1)))
3883         DrawGraphic(SCREENX(ax), SCREENY(ay+1), GFX_MAUER_DOWN);
3884     }
3885   }
3886
3887   if (element == EL_MAUER_X || element == EL_MAUER_XY ||
3888       element == EL_MAUER_LEBT)
3889   {
3890     if (links_frei)
3891     {
3892       Feld[ax-1][ay] = EL_MAUERND;
3893       Store[ax-1][ay] = element;
3894       MovDir[ax-1][ay] = MV_LEFT;
3895       if (IN_SCR_FIELD(SCREENX(ax-1), SCREENY(ay)))
3896         DrawGraphic(SCREENX(ax-1), SCREENY(ay), GFX_MAUER_LEFT);
3897     }
3898     if (rechts_frei)
3899     {
3900       Feld[ax+1][ay] = EL_MAUERND;
3901       Store[ax+1][ay] = element;
3902       MovDir[ax+1][ay] = MV_RIGHT;
3903       if (IN_SCR_FIELD(SCREENX(ax+1), SCREENY(ay)))
3904         DrawGraphic(SCREENX(ax+1), SCREENY(ay), GFX_MAUER_RIGHT);
3905     }
3906   }
3907
3908   if (element == EL_MAUER_LEBT && (links_frei || rechts_frei))
3909     DrawLevelField(ax, ay);
3910
3911   if (!IN_LEV_FIELD(ax, ay-1) || IS_MAUER(Feld[ax][ay-1]))
3912     oben_massiv = TRUE;
3913   if (!IN_LEV_FIELD(ax, ay+1) || IS_MAUER(Feld[ax][ay+1]))
3914     unten_massiv = TRUE;
3915   if (!IN_LEV_FIELD(ax-1, ay) || IS_MAUER(Feld[ax-1][ay]))
3916     links_massiv = TRUE;
3917   if (!IN_LEV_FIELD(ax+1, ay) || IS_MAUER(Feld[ax+1][ay]))
3918     rechts_massiv = TRUE;
3919
3920   if (((oben_massiv && unten_massiv) ||
3921        element == EL_MAUER_X || element == EL_MAUER_LEBT) &&
3922       ((links_massiv && rechts_massiv) ||
3923        element == EL_MAUER_Y))
3924     Feld[ax][ay] = EL_MAUERWERK;
3925 }
3926
3927 void CheckForDragon(int x, int y)
3928 {
3929   int i, j;
3930   boolean dragon_found = FALSE;
3931   static int xy[4][2] =
3932   {
3933     { 0, -1 },
3934     { -1, 0 },
3935     { +1, 0 },
3936     { 0, +1 }
3937   };
3938
3939   for (i=0; i<4; i++)
3940   {
3941     for (j=0; j<4; j++)
3942     {
3943       int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
3944
3945       if (IN_LEV_FIELD(xx, yy) &&
3946           (Feld[xx][yy] == EL_BURNING || Feld[xx][yy] == EL_DRACHE))
3947       {
3948         if (Feld[xx][yy] == EL_DRACHE)
3949           dragon_found = TRUE;
3950       }
3951       else
3952         break;
3953     }
3954   }
3955
3956   if (!dragon_found)
3957   {
3958     for (i=0; i<4; i++)
3959     {
3960       for (j=0; j<3; j++)
3961       {
3962         int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
3963   
3964         if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == EL_BURNING)
3965         {
3966           Feld[xx][yy] = EL_LEERRAUM;
3967           DrawLevelField(xx, yy);
3968         }
3969         else
3970           break;
3971       }
3972     }
3973   }
3974 }
3975
3976 static void CheckBuggyBase(int x, int y)
3977 {
3978   int element = Feld[x][y];
3979
3980   if (element == EL_SP_BUG)
3981   {
3982     if (!MovDelay[x][y])        /* wait some time before activating base */
3983       MovDelay[x][y] = 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND);
3984
3985     if (MovDelay[x][y])
3986     {
3987       MovDelay[x][y]--;
3988       if (MovDelay[x][y] < 5 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3989         DrawGraphic(SCREENX(x), SCREENY(y), GFX_SP_BUG_WARNING);
3990       if (MovDelay[x][y])
3991         return;
3992
3993       Feld[x][y] = EL_SP_BUG_ACTIVE;
3994     }
3995   }
3996   else if (element == EL_SP_BUG_ACTIVE)
3997   {
3998     if (!MovDelay[x][y])        /* start activating buggy base */
3999       MovDelay[x][y] = 1 * FRAMES_PER_SECOND + RND(1 * FRAMES_PER_SECOND);
4000
4001     if (MovDelay[x][y])
4002     {
4003       MovDelay[x][y]--;
4004       if (MovDelay[x][y])
4005       {
4006         int i;
4007         static int xy[4][2] =
4008         {
4009           { 0, -1 },
4010           { -1, 0 },
4011           { +1, 0 },
4012           { 0, +1 }
4013         };
4014
4015         if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
4016           DrawGraphic(SCREENX(x),SCREENY(y), GFX_SP_BUG_ACTIVE + SimpleRND(4));
4017
4018         for (i=0; i<4; i++)
4019         {
4020           int xx = x + xy[i][0], yy = y + xy[i][1];
4021
4022           if (IS_PLAYER(xx, yy))
4023           {
4024             PlaySoundLevel(x, y, SND_SP_BUG);
4025             break;
4026           }
4027         }
4028
4029         return;
4030       }
4031
4032       Feld[x][y] = EL_SP_BUG;
4033       DrawLevelField(x, y);
4034     }
4035   }
4036 }
4037
4038 static void CheckTrap(int x, int y)
4039 {
4040   int element = Feld[x][y];
4041
4042   if (element == EL_TRAP_INACTIVE)
4043   {
4044     if (!MovDelay[x][y])        /* wait some time before activating trap */
4045       MovDelay[x][y] = 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND);
4046
4047     if (MovDelay[x][y])
4048     {
4049       MovDelay[x][y]--;
4050       if (MovDelay[x][y])
4051         return;
4052
4053       Feld[x][y] = EL_TRAP_ACTIVE;
4054     }
4055   }
4056   else if (element == EL_TRAP_ACTIVE)
4057   {
4058     int delay = 4;
4059     int num_frames = 8;
4060
4061     if (!MovDelay[x][y])        /* start activating trap */
4062       MovDelay[x][y] = num_frames * delay;
4063
4064     if (MovDelay[x][y])
4065     {
4066       MovDelay[x][y]--;
4067
4068       if (MovDelay[x][y])
4069       {
4070         if (!(MovDelay[x][y] % delay))
4071         {
4072           int phase = MovDelay[x][y]/delay;
4073
4074           if (phase >= num_frames/2)
4075             phase = num_frames - phase;
4076
4077           if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
4078           {
4079             DrawGraphic(SCREENX(x),SCREENY(y), GFX_TRAP_INACTIVE + phase - 1);
4080             ErdreichAnbroeckeln(SCREENX(x), SCREENY(y));
4081           }
4082         }
4083
4084         return;
4085       }
4086
4087       Feld[x][y] = EL_TRAP_INACTIVE;
4088       DrawLevelField(x, y);
4089     }
4090   }
4091 }
4092
4093 static void DrawBeltAnimation(int x, int y, int element)
4094 {
4095   int belt_nr = getBeltNrFromElement(element);
4096   int belt_dir = game.belt_dir[belt_nr];
4097
4098   if (belt_dir != MV_NO_MOVING)
4099   {
4100     int delay = 2;
4101     int mode = (belt_dir == MV_LEFT ? ANIM_NORMAL : ANIM_REVERSE);
4102     int graphic = el2gfx(element) + (belt_dir == MV_LEFT ? 0 : 7);
4103
4104     DrawGraphicAnimation(x, y, graphic, 8, delay, mode);
4105   }
4106 }
4107
4108 static void PlayerActions(struct PlayerInfo *player, byte player_action)
4109 {
4110   static byte stored_player_action[MAX_PLAYERS];
4111   static int num_stored_actions = 0;
4112   static boolean save_tape_entry = FALSE;
4113   boolean moved = FALSE, snapped = FALSE, bombed = FALSE;
4114   int jx = player->jx, jy = player->jy;
4115   int left      = player_action & JOY_LEFT;
4116   int right     = player_action & JOY_RIGHT;
4117   int up        = player_action & JOY_UP;
4118   int down      = player_action & JOY_DOWN;
4119   int button1   = player_action & JOY_BUTTON_1;
4120   int button2   = player_action & JOY_BUTTON_2;
4121   int dx        = (left ? -1    : right ? 1     : 0);
4122   int dy        = (up   ? -1    : down  ? 1     : 0);
4123
4124   stored_player_action[player->index_nr] = 0;
4125   num_stored_actions++;
4126
4127   if (!player->active || tape.pausing)
4128     return;
4129
4130   if (player_action)
4131   {
4132     save_tape_entry = TRUE;
4133     player->frame_reset_delay = 0;
4134
4135     if (button1)
4136       snapped = SnapField(player, dx, dy);
4137     else
4138     {
4139       if (button2)
4140         bombed = PlaceBomb(player);
4141       moved = MoveFigure(player, dx, dy);
4142     }
4143
4144     if (tape.recording && (moved || snapped || bombed))
4145     {
4146       if (bombed && !moved)
4147         player_action &= JOY_BUTTON;
4148
4149       stored_player_action[player->index_nr] = player_action;
4150     }
4151     else if (tape.playing && snapped)
4152       SnapField(player, 0, 0);                  /* stop snapping */
4153   }
4154   else
4155   {
4156     /* no actions for this player (no input at player's configured device) */
4157
4158     DigField(player, 0, 0, 0, 0, DF_NO_PUSH);
4159     SnapField(player, 0, 0);
4160     CheckGravityMovement(player);
4161
4162     if (++player->frame_reset_delay > player->move_delay_value)
4163       player->Frame = 0;
4164   }
4165
4166   if (tape.recording && num_stored_actions >= MAX_PLAYERS && save_tape_entry)
4167   {
4168     TapeRecordAction(stored_player_action);
4169     num_stored_actions = 0;
4170     save_tape_entry = FALSE;
4171   }
4172
4173   if (tape.playing && !tape.pausing && !player_action &&
4174       tape.counter < tape.length)
4175   {
4176     int next_joy =
4177       tape.pos[tape.counter].action[player->index_nr] & (JOY_LEFT|JOY_RIGHT);
4178
4179     if ((next_joy == JOY_LEFT || next_joy == JOY_RIGHT) &&
4180         (player->MovDir != JOY_UP && player->MovDir != JOY_DOWN))
4181     {
4182       int dx = (next_joy == JOY_LEFT ? -1 : +1);
4183
4184       if (IN_LEV_FIELD(jx+dx, jy) && IS_PUSHABLE(Feld[jx+dx][jy]))
4185       {
4186         int el = Feld[jx+dx][jy];
4187         int push_delay = (IS_SB_ELEMENT(el) || el == EL_SONDE ? 2 :
4188                           (el == EL_BALLOON || el == EL_SPRING) ? 0 : 10);
4189
4190         if (tape.delay_played + push_delay >= tape.pos[tape.counter].delay)
4191         {
4192           player->MovDir = next_joy;
4193           player->Frame = FrameCounter % 4;
4194           player->Pushing = TRUE;
4195         }
4196       }
4197     }
4198   }
4199 }
4200
4201 void GameActions()
4202 {
4203   static unsigned long action_delay = 0;
4204   unsigned long action_delay_value;
4205   int sieb_x = 0, sieb_y = 0;
4206   int i, x, y, element;
4207   byte *recorded_player_action;
4208   byte summarized_player_action = 0;
4209
4210   if (game_status != PLAYING)
4211     return;
4212
4213   action_delay_value =
4214     (tape.playing && tape.fast_forward ? FfwdFrameDelay : GameFrameDelay);
4215
4216   /* ---------- main game synchronization point ---------- */
4217
4218   WaitUntilDelayReached(&action_delay, action_delay_value);
4219
4220   if (network_playing && !network_player_action_received)
4221   {
4222     /*
4223 #ifdef DEBUG
4224     printf("DEBUG: try to get network player actions in time\n");
4225 #endif
4226     */
4227
4228 #ifndef MSDOS
4229     /* last chance to get network player actions without main loop delay */
4230     HandleNetworking();
4231 #endif
4232
4233     if (game_status != PLAYING)
4234       return;
4235
4236     if (!network_player_action_received)
4237     {
4238       /*
4239 #ifdef DEBUG
4240       printf("DEBUG: failed to get network player actions in time\n");
4241 #endif
4242       */
4243       return;
4244     }
4245   }
4246
4247   if (tape.pausing)
4248     return;
4249
4250   if (tape.playing)
4251     TapePlayDelay();
4252   else if (tape.recording)
4253     TapeRecordDelay();
4254
4255   recorded_player_action = (tape.playing ? TapePlayAction() : NULL);
4256
4257   for (i=0; i<MAX_PLAYERS; i++)
4258   {
4259     summarized_player_action |= stored_player[i].action;
4260
4261     if (!network_playing)
4262       stored_player[i].effective_action = stored_player[i].action;
4263   }
4264
4265 #ifndef MSDOS
4266   if (network_playing)
4267     SendToServer_MovePlayer(summarized_player_action);
4268 #endif
4269
4270   if (!options.network && !setup.team_mode)
4271     local_player->effective_action = summarized_player_action;
4272
4273   for (i=0; i<MAX_PLAYERS; i++)
4274   {
4275     int actual_player_action = stored_player[i].effective_action;
4276
4277     if (stored_player[i].programmed_action)
4278       actual_player_action = stored_player[i].programmed_action;
4279
4280     if (recorded_player_action)
4281       actual_player_action = recorded_player_action[i];
4282
4283     PlayerActions(&stored_player[i], actual_player_action);
4284     ScrollFigure(&stored_player[i], SCROLL_GO_ON);
4285   }
4286
4287   network_player_action_received = FALSE;
4288
4289   ScrollScreen(NULL, SCROLL_GO_ON);
4290
4291
4292
4293 #ifdef DEBUG
4294 #if 0
4295   if (TimeFrames == 0 && local_player->active)
4296   {
4297     extern unsigned int last_RND();
4298
4299     printf("DEBUG: %03d last RND was %d \t [state checksum is %d]\n",
4300            TimePlayed, last_RND(), getStateCheckSum(TimePlayed));
4301   }
4302 #endif
4303 #endif
4304
4305 #ifdef DEBUG
4306 #if 0
4307   if (GameFrameDelay >= 500)
4308     printf("FrameCounter == %d\n", FrameCounter);
4309 #endif
4310 #endif
4311
4312
4313
4314   FrameCounter++;
4315   TimeFrames++;
4316
4317   for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
4318   {
4319     Stop[x][y] = FALSE;
4320     if (JustStopped[x][y] > 0)
4321       JustStopped[x][y]--;
4322
4323 #if DEBUG
4324     if (IS_BLOCKED(x, y))
4325     {
4326       int oldx, oldy;
4327
4328       Blocked2Moving(x, y, &oldx, &oldy);
4329       if (!IS_MOVING(oldx, oldy))
4330       {
4331         printf("GameActions(): (BLOCKED => MOVING) context corrupted!\n");
4332         printf("GameActions(): BLOCKED: x = %d, y = %d\n", x, y);
4333         printf("GameActions(): !MOVING: oldx = %d, oldy = %d\n", oldx, oldy);
4334         printf("GameActions(): This should never happen!\n");
4335       }
4336     }
4337 #endif
4338   }
4339
4340   for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
4341   {
4342     element = Feld[x][y];
4343
4344     if (IS_INACTIVE(element))
4345       continue;
4346
4347     if (!IS_MOVING(x, y) && (CAN_FALL(element) || CAN_MOVE(element)))
4348     {
4349       StartMoving(x, y);
4350
4351       if (IS_GEM(element))
4352         EdelsteinFunkeln(x, y);
4353     }
4354     else if (IS_MOVING(x, y))
4355       ContinueMoving(x, y);
4356     else if (IS_ACTIVE_BOMB(element))
4357       CheckDynamite(x, y);
4358     else if (element == EL_EXPLODING)
4359       Explode(x, y, Frame[x][y], EX_NORMAL);
4360     else if (element == EL_AMOEBING)
4361       AmoebeWaechst(x, y);
4362     else if (element == EL_DEAMOEBING)
4363       AmoebeSchrumpft(x, y);
4364     else if (IS_AMOEBALIVE(element))
4365       AmoebeAbleger(x, y);
4366     else if (element == EL_LIFE || element == EL_LIFE_ASYNC)
4367       Life(x, y);
4368     else if (element == EL_ABLENK_EIN)
4369       Ablenk(x, y);
4370     else if (element == EL_TIMEGATE_SWITCH_ON)
4371       TimegateWheel(x, y);
4372     else if (element == EL_SALZSAEURE)
4373       Blubber(x, y);
4374     else if (element == EL_BLURB_LEFT || element == EL_BLURB_RIGHT)
4375       Blurb(x, y);
4376     else if (element == EL_CRACKINGNUT)
4377       NussKnacken(x, y);
4378     else if (element == EL_PEARL_BREAKING)
4379       BreakingPearl(x, y);
4380     else if (element == EL_AUSGANG_ZU)
4381       AusgangstuerPruefen(x, y);
4382     else if (element == EL_AUSGANG_ACT)
4383       AusgangstuerOeffnen(x, y);
4384     else if (element == EL_AUSGANG_AUF)
4385       AusgangstuerBlinken(x, y);
4386     else if (element == EL_MAUERND)
4387       MauerWaechst(x, y);
4388     else if (element == EL_MAUER_LEBT ||
4389              element == EL_MAUER_X ||
4390              element == EL_MAUER_Y ||
4391              element == EL_MAUER_XY)
4392       MauerAbleger(x, y);
4393     else if (element == EL_BURNING)
4394       CheckForDragon(x, y);
4395     else if (element == EL_SP_BUG || element == EL_SP_BUG_ACTIVE)
4396       CheckBuggyBase(x, y);
4397     else if (element == EL_TRAP_INACTIVE || element == EL_TRAP_ACTIVE)
4398       CheckTrap(x, y);
4399     else if (element == EL_SP_TERMINAL)
4400       DrawGraphicAnimation(x, y, GFX2_SP_TERMINAL, 7, 12, ANIM_NORMAL);
4401     else if (element == EL_SP_TERMINAL_ACTIVE)
4402       DrawGraphicAnimation(x, y, GFX2_SP_TERMINAL_ACTIVE, 7, 4, ANIM_NORMAL);
4403     else if (IS_BELT(element))
4404       DrawBeltAnimation(x, y, element);
4405     else if (element == EL_SWITCHGATE_OPENING)
4406       OpenSwitchgate(x, y);
4407     else if (element == EL_SWITCHGATE_CLOSING)
4408       CloseSwitchgate(x, y);
4409     else if (element == EL_TIMEGATE_OPENING)
4410       OpenTimegate(x, y);
4411     else if (element == EL_TIMEGATE_CLOSING)
4412       CloseTimegate(x, y);
4413     else if (element == EL_EXTRA_TIME)
4414       DrawGraphicAnimation(x, y, GFX_EXTRA_TIME, 6, 4, ANIM_NORMAL);
4415     else if (element == EL_SHIELD_PASSIVE)
4416       DrawGraphicAnimation(x, y, GFX_SHIELD_PASSIVE, 6, 4, ANIM_NORMAL);
4417     else if (element == EL_SHIELD_ACTIVE)
4418       DrawGraphicAnimation(x, y, GFX_SHIELD_ACTIVE, 6, 4, ANIM_NORMAL);
4419
4420     if (game.magic_wall_active)
4421     {
4422       boolean sieb = FALSE;
4423       int jx = local_player->jx, jy = local_player->jy;
4424
4425       if (element == EL_SIEB_LEER || element == EL_SIEB_VOLL ||
4426           Store[x][y] == EL_SIEB_LEER)
4427       {
4428         SiebAktivieren(x, y, 1);
4429         sieb = TRUE;
4430       }
4431       else if (element == EL_SIEB2_LEER || element == EL_SIEB2_VOLL ||
4432                Store[x][y] == EL_SIEB2_LEER)
4433       {
4434         SiebAktivieren(x, y, 2);
4435         sieb = TRUE;
4436       }
4437
4438       /* play the element sound at the position nearest to the player */
4439       if (sieb && ABS(x-jx)+ABS(y-jy) < ABS(sieb_x-jx)+ABS(sieb_y-jy))
4440       {
4441         sieb_x = x;
4442         sieb_y = y;
4443       }
4444     }
4445   }
4446
4447   if (game.magic_wall_active)
4448   {
4449     if (!(game.magic_wall_time_left % 4))
4450       PlaySoundLevel(sieb_x, sieb_y, SND_MIEP);
4451
4452     if (game.magic_wall_time_left > 0)
4453     {
4454       game.magic_wall_time_left--;
4455       if (!game.magic_wall_time_left)
4456       {
4457         for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
4458         {
4459           element = Feld[x][y];
4460
4461           if (element == EL_SIEB_LEER || element == EL_SIEB_VOLL)
4462           {
4463             Feld[x][y] = EL_SIEB_TOT;
4464             DrawLevelField(x, y);
4465           }
4466           else if (element == EL_SIEB2_LEER || element == EL_SIEB2_VOLL)
4467           {
4468             Feld[x][y] = EL_SIEB2_TOT;
4469             DrawLevelField(x, y);
4470           }
4471         }
4472
4473         game.magic_wall_active = FALSE;
4474       }
4475     }
4476   }
4477
4478   if (game.light_time_left > 0)
4479   {
4480     game.light_time_left--;
4481
4482     if (game.light_time_left == 0)
4483     {
4484       for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
4485       {
4486         element = Feld[x][y];
4487
4488         if (element == EL_LIGHT_SWITCH_ON)
4489         {
4490           Feld[x][y] = EL_LIGHT_SWITCH_OFF;
4491           DrawLevelField(x, y);
4492         }
4493         else if (element == EL_INVISIBLE_STEEL ||
4494                  element == EL_UNSICHTBAR ||
4495                  element == EL_SAND_INVISIBLE)
4496           DrawLevelField(x, y);
4497       }
4498     }
4499   }
4500
4501   if (game.timegate_time_left > 0)
4502   {
4503     game.timegate_time_left--;
4504
4505     if (game.timegate_time_left == 0)
4506       CloseAllOpenTimegates();
4507   }
4508
4509   if (TimeFrames >= (1000 / GameFrameDelay))
4510   {
4511     TimeFrames = 0;
4512     TimePlayed++;
4513
4514     for (i=0; i<MAX_PLAYERS; i++)
4515     {
4516       if (SHIELD_ON(&stored_player[i]))
4517       {
4518         stored_player[i].shield_passive_time_left--;
4519
4520         if (stored_player[i].shield_active_time_left > 0)
4521           stored_player[i].shield_active_time_left--;
4522       }
4523     }
4524
4525     if (tape.recording || tape.playing)
4526       DrawVideoDisplay(VIDEO_STATE_TIME_ON, TimePlayed);
4527
4528     if (TimeLeft > 0)
4529     {
4530       TimeLeft--;
4531
4532       if (TimeLeft <= 10 && setup.time_limit)
4533         PlaySoundStereo(SND_GONG, PSND_MAX_RIGHT);
4534
4535       DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
4536
4537       if (!TimeLeft && setup.time_limit)
4538         for (i=0; i<MAX_PLAYERS; i++)
4539           KillHero(&stored_player[i]);
4540     }
4541     else if (level.time == 0)           /* level without time limit */
4542       DrawText(DX_TIME, DY_TIME, int2str(TimePlayed, 3), FS_SMALL, FC_YELLOW);
4543   }
4544
4545   DrawAllPlayers();
4546 }
4547
4548 static boolean AllPlayersInSight(struct PlayerInfo *player, int x, int y)
4549 {
4550   int min_x = x, min_y = y, max_x = x, max_y = y;
4551   int i;
4552
4553   for (i=0; i<MAX_PLAYERS; i++)
4554   {
4555     int jx = stored_player[i].jx, jy = stored_player[i].jy;
4556
4557     if (!stored_player[i].active || &stored_player[i] == player)
4558       continue;
4559
4560     min_x = MIN(min_x, jx);
4561     min_y = MIN(min_y, jy);
4562     max_x = MAX(max_x, jx);
4563     max_y = MAX(max_y, jy);
4564   }
4565
4566   return (max_x - min_x < SCR_FIELDX && max_y - min_y < SCR_FIELDY);
4567 }
4568
4569 static boolean AllPlayersInVisibleScreen()
4570 {
4571   int i;
4572
4573   for (i=0; i<MAX_PLAYERS; i++)
4574   {
4575     int jx = stored_player[i].jx, jy = stored_player[i].jy;
4576
4577     if (!stored_player[i].active)
4578       continue;
4579
4580     if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
4581       return FALSE;
4582   }
4583
4584   return TRUE;
4585 }
4586
4587 void ScrollLevel(int dx, int dy)
4588 {
4589   int softscroll_offset = (setup.soft_scrolling ? TILEX : 0);
4590   int x, y;
4591
4592   XCopyArea(display, drawto_field, drawto_field, gc,
4593             FX + TILEX*(dx == -1) - softscroll_offset,
4594             FY + TILEY*(dy == -1) - softscroll_offset,
4595             SXSIZE - TILEX*(dx!=0) + 2*softscroll_offset,
4596             SYSIZE - TILEY*(dy!=0) + 2*softscroll_offset,
4597             FX + TILEX*(dx == 1) - softscroll_offset,
4598             FY + TILEY*(dy == 1) - softscroll_offset);
4599
4600   if (dx)
4601   {
4602     x = (dx == 1 ? BX1 : BX2);
4603     for (y=BY1; y<=BY2; y++)
4604       DrawScreenField(x, y);
4605   }
4606   if (dy)
4607   {
4608     y = (dy == 1 ? BY1 : BY2);
4609     for (x=BX1; x<=BX2; x++)
4610       DrawScreenField(x, y);
4611   }
4612
4613   redraw_mask |= REDRAW_FIELD;
4614 }
4615
4616 static void CheckGravityMovement(struct PlayerInfo *player)
4617 {
4618   if (level.gravity && !player->programmed_action)
4619   {
4620     int move_dir_vertical = player->action & (MV_UP | MV_DOWN);
4621     int move_dir_horizontal = player->action & (MV_LEFT | MV_RIGHT);
4622     int move_dir =
4623       (player->last_move_dir & (MV_LEFT | MV_RIGHT) ?
4624        (move_dir_vertical ? move_dir_vertical : move_dir_horizontal) :
4625        (move_dir_horizontal ? move_dir_horizontal : move_dir_vertical));
4626     int jx = player->jx, jy = player->jy;
4627     int dx = (move_dir & MV_LEFT ? -1 : move_dir & MV_RIGHT ? +1 : 0);
4628     int dy = (move_dir & MV_UP ? -1 : move_dir & MV_DOWN ? +1 : 0);
4629     int new_jx = jx + dx, new_jy = jy + dy;
4630     boolean field_under_player_is_free =
4631       (IN_LEV_FIELD(jx, jy + 1) && IS_FREE(jx, jy + 1));
4632     boolean player_is_moving_to_valid_field =
4633       (IN_LEV_FIELD(new_jx, new_jy) &&
4634        (Feld[new_jx][new_jy] == EL_SP_BASE ||
4635         Feld[new_jx][new_jy] == EL_ERDREICH));
4636
4637     if (field_under_player_is_free && !player_is_moving_to_valid_field)
4638       player->programmed_action = MV_DOWN;
4639   }
4640 }
4641
4642 boolean MoveFigureOneStep(struct PlayerInfo *player,
4643                           int dx, int dy, int real_dx, int real_dy)
4644 {
4645   int jx = player->jx, jy = player->jy;
4646   int new_jx = jx+dx, new_jy = jy+dy;
4647   int element;
4648   int can_move;
4649
4650   if (!player->active || (!dx && !dy))
4651     return MF_NO_ACTION;
4652
4653   player->MovDir = (dx < 0 ? MV_LEFT :
4654                     dx > 0 ? MV_RIGHT :
4655                     dy < 0 ? MV_UP :
4656                     dy > 0 ? MV_DOWN :  MV_NO_MOVING);
4657
4658   if (!IN_LEV_FIELD(new_jx, new_jy))
4659     return MF_NO_ACTION;
4660
4661   if (!options.network && !AllPlayersInSight(player, new_jx, new_jy))
4662     return MF_NO_ACTION;
4663
4664 #if 0
4665   element = MovingOrBlocked2Element(new_jx, new_jy);
4666 #else
4667   element = MovingOrBlocked2ElementIfNotLeaving(new_jx, new_jy);
4668 #endif
4669
4670   if (DONT_GO_TO(element))
4671   {
4672     if (element == EL_SALZSAEURE && dx == 0 && dy == 1)
4673     {
4674       Blurb(jx, jy);
4675       Feld[jx][jy] = EL_SPIELFIGUR;
4676       InitMovingField(jx, jy, MV_DOWN);
4677       Store[jx][jy] = EL_SALZSAEURE;
4678       ContinueMoving(jx, jy);
4679       BuryHero(player);
4680     }
4681     else
4682       TestIfBadThingHitsHero(new_jx, new_jy);
4683
4684     return MF_MOVING;
4685   }
4686
4687   can_move = DigField(player, new_jx, new_jy, real_dx, real_dy, DF_DIG);
4688   if (can_move != MF_MOVING)
4689     return can_move;
4690
4691   StorePlayer[jx][jy] = 0;
4692   player->last_jx = jx;
4693   player->last_jy = jy;
4694   jx = player->jx = new_jx;
4695   jy = player->jy = new_jy;
4696   StorePlayer[jx][jy] = player->element_nr;
4697
4698   player->MovPos =
4699     (dx > 0 || dy > 0 ? -1 : 1) * (TILEX - TILEX / player->move_delay_value);
4700
4701   ScrollFigure(player, SCROLL_INIT);
4702
4703   return MF_MOVING;
4704 }
4705
4706 boolean MoveFigure(struct PlayerInfo *player, int dx, int dy)
4707 {
4708   int jx = player->jx, jy = player->jy;
4709   int old_jx = jx, old_jy = jy;
4710   int moved = MF_NO_ACTION;
4711
4712   if (!player->active || (!dx && !dy))
4713     return FALSE;
4714
4715   if (!FrameReached(&player->move_delay, player->move_delay_value) &&
4716       !tape.playing)
4717     return FALSE;
4718
4719   /* remove the last programmed player action */
4720   player->programmed_action = 0;
4721
4722   if (player->MovPos)
4723   {
4724     /* should only happen if pre-1.2 tape recordings are played */
4725     /* this is only for backward compatibility */
4726
4727     int original_move_delay_value = player->move_delay_value;
4728
4729 #if DEBUG
4730     printf("THIS SHOULD ONLY HAPPEN WITH PRE-1.2 LEVEL TAPES.\n");
4731 #endif
4732
4733     /* scroll remaining steps with finest movement resolution */
4734     player->move_delay_value = MOVE_DELAY_NORMAL_SPEED;
4735
4736     while (player->MovPos)
4737     {
4738       ScrollFigure(player, SCROLL_GO_ON);
4739       ScrollScreen(NULL, SCROLL_GO_ON);
4740       FrameCounter++;
4741       DrawAllPlayers();
4742       BackToFront();
4743     }
4744
4745     player->move_delay_value = original_move_delay_value;
4746   }
4747
4748   if (player->last_move_dir & (MV_LEFT | MV_RIGHT))
4749   {
4750     if (!(moved |= MoveFigureOneStep(player, 0, dy, dx, dy)))
4751       moved |= MoveFigureOneStep(player, dx, 0, dx, dy);
4752   }
4753   else
4754   {
4755     if (!(moved |= MoveFigureOneStep(player, dx, 0, dx, dy)))
4756       moved |= MoveFigureOneStep(player, 0, dy, dx, dy);
4757   }
4758
4759   jx = player->jx;
4760   jy = player->jy;
4761
4762   if (moved & MF_MOVING && !ScreenMovPos &&
4763       (player == local_player || !options.network))
4764   {
4765     int old_scroll_x = scroll_x, old_scroll_y = scroll_y;
4766     int offset = (setup.scroll_delay ? 3 : 0);
4767
4768     if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
4769     {
4770       /* actual player has left the screen -- scroll in that direction */
4771       if (jx != old_jx)         /* player has moved horizontally */
4772         scroll_x += (jx - old_jx);
4773       else                      /* player has moved vertically */
4774         scroll_y += (jy - old_jy);
4775     }
4776     else
4777     {
4778       if (jx != old_jx)         /* player has moved horizontally */
4779       {
4780         if ((player->MovDir == MV_LEFT && scroll_x > jx - MIDPOSX + offset) ||
4781             (player->MovDir == MV_RIGHT && scroll_x < jx - MIDPOSX - offset))
4782           scroll_x = jx-MIDPOSX + (scroll_x < jx-MIDPOSX ? -offset : +offset);
4783
4784         /* don't scroll over playfield boundaries */
4785         if (scroll_x < SBX_Left || scroll_x > SBX_Right)
4786           scroll_x = (scroll_x < SBX_Left ? SBX_Left : SBX_Right);
4787
4788         /* don't scroll more than one field at a time */
4789         scroll_x = old_scroll_x + SIGN(scroll_x - old_scroll_x);
4790
4791         /* don't scroll against the player's moving direction */
4792         if ((player->MovDir == MV_LEFT && scroll_x > old_scroll_x) ||
4793             (player->MovDir == MV_RIGHT && scroll_x < old_scroll_x))
4794           scroll_x = old_scroll_x;
4795       }
4796       else                      /* player has moved vertically */
4797       {
4798         if ((player->MovDir == MV_UP && scroll_y > jy - MIDPOSY + offset) ||
4799             (player->MovDir == MV_DOWN && scroll_y < jy - MIDPOSY - offset))
4800           scroll_y = jy-MIDPOSY + (scroll_y < jy-MIDPOSY ? -offset : +offset);
4801
4802         /* don't scroll over playfield boundaries */
4803         if (scroll_y < SBY_Upper || scroll_y > SBY_Lower)
4804           scroll_y = (scroll_y < SBY_Upper ? SBY_Upper : SBY_Lower);
4805
4806         /* don't scroll more than one field at a time */
4807         scroll_y = old_scroll_y + SIGN(scroll_y - old_scroll_y);
4808
4809         /* don't scroll against the player's moving direction */
4810         if ((player->MovDir == MV_UP && scroll_y > old_scroll_y) ||
4811             (player->MovDir == MV_DOWN && scroll_y < old_scroll_y))
4812           scroll_y = old_scroll_y;
4813       }
4814     }
4815
4816     if (scroll_x != old_scroll_x || scroll_y != old_scroll_y)
4817     {
4818       if (!options.network && !AllPlayersInVisibleScreen())
4819       {
4820         scroll_x = old_scroll_x;
4821         scroll_y = old_scroll_y;
4822       }
4823       else
4824       {
4825         ScrollScreen(player, SCROLL_INIT);
4826         ScrollLevel(old_scroll_x - scroll_x, old_scroll_y - scroll_y);
4827       }
4828     }
4829   }
4830
4831   if (!(moved & MF_MOVING) && !player->Pushing)
4832     player->Frame = 0;
4833   else
4834     player->Frame = (player->Frame + 1) % 4;
4835
4836   if (moved & MF_MOVING)
4837   {
4838     if (old_jx != jx && old_jy == jy)
4839       player->MovDir = (old_jx < jx ? MV_RIGHT : MV_LEFT);
4840     else if (old_jx == jx && old_jy != jy)
4841       player->MovDir = (old_jy < jy ? MV_DOWN : MV_UP);
4842
4843     DrawLevelField(jx, jy);     /* for "ErdreichAnbroeckeln()" */
4844
4845     player->last_move_dir = player->MovDir;
4846   }
4847   else
4848   {
4849     CheckGravityMovement(player);
4850
4851     player->last_move_dir = MV_NO_MOVING;
4852   }
4853
4854   TestIfHeroHitsBadThing(jx, jy);
4855
4856   if (!player->active)
4857     RemoveHero(player);
4858
4859   return moved;
4860 }
4861
4862 void ScrollFigure(struct PlayerInfo *player, int mode)
4863 {
4864   int jx = player->jx, jy = player->jy;
4865   int last_jx = player->last_jx, last_jy = player->last_jy;
4866   int move_stepsize = TILEX / player->move_delay_value;
4867
4868   if (!player->active || !player->MovPos)
4869     return;
4870
4871   if (mode == SCROLL_INIT)
4872   {
4873     player->actual_frame_counter = FrameCounter;
4874     player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
4875
4876     if (Feld[last_jx][last_jy] == EL_LEERRAUM)
4877       Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING;
4878
4879     DrawPlayer(player);
4880     return;
4881   }
4882   else if (!FrameReached(&player->actual_frame_counter, 1))
4883     return;
4884
4885   player->MovPos += (player->MovPos > 0 ? -1 : 1) * move_stepsize;
4886   player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
4887
4888   if (Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING)
4889     Feld[last_jx][last_jy] = EL_LEERRAUM;
4890
4891   /* before DrawPlayer() to draw correct player graphic for this case */
4892   if (player->MovPos == 0)
4893     CheckGravityMovement(player);
4894
4895   DrawPlayer(player);
4896
4897   if (player->MovPos == 0)
4898   {
4899     if (IS_QUICK_GATE(Feld[last_jx][last_jy]))
4900     {
4901       /* continue with normal speed after quickly moving through gate */
4902       HALVE_PLAYER_SPEED(player);
4903
4904       /* be able to make the next move without delay */
4905       player->move_delay = 0;
4906     }
4907
4908     player->last_jx = jx;
4909     player->last_jy = jy;
4910
4911     if (Feld[jx][jy] == EL_AUSGANG_AUF)
4912     {
4913       RemoveHero(player);
4914
4915       if (!local_player->friends_still_needed)
4916         player->LevelSolved = player->GameOver = TRUE;
4917     }
4918   }
4919 }
4920
4921 void ScrollScreen(struct PlayerInfo *player, int mode)
4922 {
4923   static unsigned long screen_frame_counter = 0;
4924
4925   if (mode == SCROLL_INIT)
4926   {
4927     /* set scrolling step size according to actual player's moving speed */
4928     ScrollStepSize = TILEX / player->move_delay_value;
4929
4930     screen_frame_counter = FrameCounter;
4931     ScreenMovDir = player->MovDir;
4932     ScreenMovPos = player->MovPos;
4933     ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
4934     return;
4935   }
4936   else if (!FrameReached(&screen_frame_counter, 1))
4937     return;
4938
4939   if (ScreenMovPos)
4940   {
4941     ScreenMovPos += (ScreenMovPos > 0 ? -1 : 1) * ScrollStepSize;
4942     ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
4943     redraw_mask |= REDRAW_FIELD;
4944   }
4945   else
4946     ScreenMovDir = MV_NO_MOVING;
4947 }
4948
4949 void TestIfGoodThingHitsBadThing(int goodx, int goody)
4950 {
4951   int i, killx = goodx, killy = goody;
4952   static int xy[4][2] =
4953   {
4954     { 0, -1 },
4955     { -1, 0 },
4956     { +1, 0 },
4957     { 0, +1 }
4958   };
4959   static int harmless[4] =
4960   {
4961     MV_UP,
4962     MV_LEFT,
4963     MV_RIGHT,
4964     MV_DOWN
4965   };
4966
4967   for (i=0; i<4; i++)
4968   {
4969     int x, y, element;
4970
4971     x = goodx + xy[i][0];
4972     y = goody + xy[i][1];
4973     if (!IN_LEV_FIELD(x, y))
4974       continue;
4975
4976 #if 0
4977     element = Feld[x][y];
4978 #else
4979     element = MovingOrBlocked2ElementIfNotLeaving(x, y);
4980 #endif
4981
4982     if (DONT_TOUCH(element))
4983     {
4984       if (MovDir[x][y] == harmless[i])
4985         continue;
4986
4987       killx = x;
4988       killy = y;
4989       break;
4990     }
4991   }
4992
4993   if (killx != goodx || killy != goody)
4994   {
4995     if (IS_PLAYER(goodx, goody))
4996     {
4997       struct PlayerInfo *player = PLAYERINFO(goodx, goody);
4998
4999       if (player->shield_active_time_left > 0)
5000         Bang(killx, killy);
5001       else if (!PLAYER_PROTECTED(goodx, goody))
5002         KillHero(player);
5003     }
5004     else
5005       Bang(goodx, goody);
5006   }
5007 }
5008
5009 void TestIfBadThingHitsGoodThing(int badx, int bady)
5010 {
5011   int i, killx = badx, killy = bady;
5012   static int xy[4][2] =
5013   {
5014     { 0, -1 },
5015     { -1, 0 },
5016     { +1, 0 },
5017     { 0, +1 }
5018   };
5019   static int harmless[4] =
5020   {
5021     MV_UP,
5022     MV_LEFT,
5023     MV_RIGHT,
5024     MV_DOWN
5025   };
5026
5027   if (Feld[badx][bady] == EL_EXPLODING) /* skip just exploding bad things */
5028     return;
5029
5030   for (i=0; i<4; i++)
5031   {
5032     int x, y, element;
5033
5034     x = badx + xy[i][0];
5035     y = bady + xy[i][1];
5036     if (!IN_LEV_FIELD(x, y))
5037       continue;
5038
5039     element = Feld[x][y];
5040
5041     if (IS_PLAYER(x, y))
5042     {
5043       killx = x;
5044       killy = y;
5045       break;
5046     }
5047     else if (element == EL_PINGUIN)
5048     {
5049       if (MovDir[x][y] == harmless[i] && IS_MOVING(x, y))
5050         continue;
5051
5052       killx = x;
5053       killy = y;
5054       break;
5055     }
5056   }
5057
5058   if (killx != badx || killy != bady)
5059   {
5060     if (IS_PLAYER(killx, killy))
5061     {
5062       struct PlayerInfo *player = PLAYERINFO(killx, killy);
5063
5064       if (player->shield_active_time_left > 0)
5065         Bang(badx, bady);
5066       else if (!PLAYER_PROTECTED(killx, killy))
5067         KillHero(player);
5068     }
5069     else
5070       Bang(killx, killy);
5071   }
5072 }
5073
5074 void TestIfHeroHitsBadThing(int x, int y)
5075 {
5076   TestIfGoodThingHitsBadThing(x, y);
5077 }
5078
5079 void TestIfBadThingHitsHero(int x, int y)
5080 {
5081   TestIfBadThingHitsGoodThing(x, y);
5082 }
5083
5084 void TestIfFriendHitsBadThing(int x, int y)
5085 {
5086   TestIfGoodThingHitsBadThing(x, y);
5087 }
5088
5089 void TestIfBadThingHitsFriend(int x, int y)
5090 {
5091   TestIfBadThingHitsGoodThing(x, y);
5092 }
5093
5094 void TestIfBadThingHitsOtherBadThing(int badx, int bady)
5095 {
5096   int i, killx = badx, killy = bady;
5097   static int xy[4][2] =
5098   {
5099     { 0, -1 },
5100     { -1, 0 },
5101     { +1, 0 },
5102     { 0, +1 }
5103   };
5104
5105   for (i=0; i<4; i++)
5106   {
5107     int x, y, element;
5108
5109     x=badx + xy[i][0];
5110     y=bady + xy[i][1];
5111     if (!IN_LEV_FIELD(x, y))
5112       continue;
5113
5114     element = Feld[x][y];
5115     if (IS_AMOEBOID(element) || element == EL_LIFE ||
5116         element == EL_AMOEBING || element == EL_TROPFEN)
5117     {
5118       killx = x;
5119       killy = y;
5120       break;
5121     }
5122   }
5123
5124   if (killx != badx || killy != bady)
5125     Bang(badx, bady);
5126 }
5127
5128 void KillHero(struct PlayerInfo *player)
5129 {
5130   int jx = player->jx, jy = player->jy;
5131
5132   if (!player->active)
5133     return;
5134
5135   if (IS_PFORTE(Feld[jx][jy]))
5136     Feld[jx][jy] = EL_LEERRAUM;
5137
5138   /* deactivate shield (else Bang()/Explode() would not work right) */
5139   player->shield_passive_time_left = 0;
5140   player->shield_active_time_left = 0;
5141
5142   Bang(jx, jy);
5143   BuryHero(player);
5144 }
5145
5146 static void KillHeroUnlessProtected(int x, int y)
5147 {
5148   if (!PLAYER_PROTECTED(x, y))
5149     KillHero(PLAYERINFO(x, y));
5150 }
5151
5152 void BuryHero(struct PlayerInfo *player)
5153 {
5154   int jx = player->jx, jy = player->jy;
5155
5156   if (!player->active)
5157     return;
5158
5159   PlaySoundLevel(jx, jy, SND_AUTSCH);
5160   PlaySoundLevel(jx, jy, SND_LACHEN);
5161
5162   player->GameOver = TRUE;
5163   RemoveHero(player);
5164 }
5165
5166 void RemoveHero(struct PlayerInfo *player)
5167 {
5168   int jx = player->jx, jy = player->jy;
5169   int i, found = FALSE;
5170
5171   player->present = FALSE;
5172   player->active = FALSE;
5173
5174   StorePlayer[jx][jy] = 0;
5175
5176   for (i=0; i<MAX_PLAYERS; i++)
5177     if (stored_player[i].active)
5178       found = TRUE;
5179
5180   if (!found)
5181     AllPlayersGone = TRUE;
5182
5183   ExitX = ZX = jx;
5184   ExitY = ZY = jy;
5185 }
5186
5187 int DigField(struct PlayerInfo *player,
5188              int x, int y, int real_dx, int real_dy, int mode)
5189 {
5190   int jx = player->jx, jy = player->jy;
5191   int dx = x - jx, dy = y - jy;
5192   int move_direction = (dx == -1 ? MV_LEFT :
5193                         dx == +1 ? MV_RIGHT :
5194                         dy == -1 ? MV_UP :
5195                         dy == +1 ? MV_DOWN : MV_NO_MOVING);
5196   int element;
5197
5198   if (!player->MovPos)
5199     player->Pushing = FALSE;
5200
5201   if (mode == DF_NO_PUSH)
5202   {
5203     player->Switching = FALSE;
5204     player->push_delay = 0;
5205     return MF_NO_ACTION;
5206   }
5207
5208   if (IS_MOVING(x, y) || IS_PLAYER(x, y))
5209     return MF_NO_ACTION;
5210
5211   if (IS_TUBE(Feld[jx][jy]))
5212   {
5213     int i = 0;
5214     int tube_leave_directions[][2] =
5215     {
5216       { EL_TUBE_CROSS,          MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN },
5217       { EL_TUBE_VERTICAL,                            MV_UP | MV_DOWN },
5218       { EL_TUBE_HORIZONTAL,     MV_LEFT | MV_RIGHT                   },
5219       { EL_TUBE_VERT_LEFT,      MV_LEFT |            MV_UP | MV_DOWN },
5220       { EL_TUBE_VERT_RIGHT,               MV_RIGHT | MV_UP | MV_DOWN },
5221       { EL_TUBE_HORIZ_UP,       MV_LEFT | MV_RIGHT | MV_UP           },
5222       { EL_TUBE_HORIZ_DOWN,     MV_LEFT | MV_RIGHT |         MV_DOWN },
5223       { EL_TUBE_LEFT_UP,        MV_LEFT |            MV_UP           },
5224       { EL_TUBE_LEFT_DOWN,      MV_LEFT |                    MV_DOWN },
5225       { EL_TUBE_RIGHT_UP,                 MV_RIGHT | MV_UP           },
5226       { EL_TUBE_RIGHT_DOWN,               MV_RIGHT |         MV_DOWN },
5227       { -1,                     MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN }
5228     };
5229
5230     while (tube_leave_directions[i][0] != Feld[jx][jy])
5231     {
5232       i++;
5233       if (tube_leave_directions[i][0] == -1)    /* should not happen */
5234         break;
5235     }
5236
5237     if (!(tube_leave_directions[i][1] & move_direction))
5238       return MF_NO_ACTION;      /* tube has no opening in this direction */
5239   }
5240
5241   element = Feld[x][y];
5242
5243   switch (element)
5244   {
5245     case EL_LEERRAUM:
5246       PlaySoundLevel(x, y, SND_EMPTY);
5247       break;
5248
5249     case EL_ERDREICH:
5250     case EL_SAND_INVISIBLE:
5251     case EL_TRAP_INACTIVE:
5252       Feld[x][y] = EL_LEERRAUM;
5253       PlaySoundLevel(x, y, SND_SCHLURF);
5254       break;
5255
5256     case EL_SP_BASE:
5257     case EL_SP_BUG:
5258       Feld[x][y] = EL_LEERRAUM;
5259       PlaySoundLevel(x, y, SND_SP_BASE);
5260       break;
5261
5262     case EL_EDELSTEIN:
5263     case EL_EDELSTEIN_BD:
5264     case EL_EDELSTEIN_GELB:
5265     case EL_EDELSTEIN_ROT:
5266     case EL_EDELSTEIN_LILA:
5267     case EL_DIAMANT:
5268     case EL_SP_INFOTRON:
5269     case EL_PEARL:
5270     case EL_CRYSTAL:
5271       RemoveField(x, y);
5272       local_player->gems_still_needed -= (element == EL_DIAMANT ? 3 :
5273                                           element == EL_PEARL ? 5 :
5274                                           element == EL_CRYSTAL ? 8 : 1);
5275       if (local_player->gems_still_needed < 0)
5276         local_player->gems_still_needed = 0;
5277       RaiseScoreElement(element);
5278       DrawText(DX_EMERALDS, DY_EMERALDS,
5279                int2str(local_player->gems_still_needed, 3),
5280                FS_SMALL, FC_YELLOW);
5281       if (element == EL_SP_INFOTRON)
5282         PlaySoundLevel(x, y, SND_SP_INFOTRON);
5283       else
5284         PlaySoundLevel(x, y, SND_PONG);
5285       break;
5286
5287     case EL_SPEED_PILL:
5288       RemoveField(x, y);
5289       player->move_delay_value = MOVE_DELAY_HIGH_SPEED;
5290       PlaySoundLevel(x, y, SND_PONG);
5291       break;
5292
5293     case EL_ENVELOPE:
5294       Feld[x][y] = EL_LEERRAUM;
5295       PlaySoundLevel(x, y, SND_PONG);
5296       break;
5297
5298     case EL_EXTRA_TIME:
5299       RemoveField(x, y);
5300       if (level.time > 0)
5301       {
5302         TimeLeft += 10;
5303         DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
5304       }
5305       PlaySoundStereo(SND_GONG, PSND_MAX_RIGHT);
5306       break;
5307
5308     case EL_SHIELD_PASSIVE:
5309       RemoveField(x, y);
5310       player->shield_passive_time_left += 10;
5311       PlaySoundLevel(x, y, SND_PONG);
5312       break;
5313
5314     case EL_SHIELD_ACTIVE:
5315       RemoveField(x, y);
5316       player->shield_passive_time_left += 10;
5317       player->shield_active_time_left += 10;
5318       PlaySoundLevel(x, y, SND_PONG);
5319       break;
5320
5321     case EL_DYNAMITE_INACTIVE:
5322     case EL_SP_DISK_RED:
5323       RemoveField(x, y);
5324       player->dynamite++;
5325       RaiseScoreElement(EL_DYNAMITE_INACTIVE);
5326       DrawText(DX_DYNAMITE, DY_DYNAMITE,
5327                int2str(local_player->dynamite, 3),
5328                FS_SMALL, FC_YELLOW);
5329       if (element == EL_SP_DISK_RED)
5330         PlaySoundLevel(x, y, SND_SP_INFOTRON);
5331       else
5332         PlaySoundLevel(x, y, SND_PONG);
5333       break;
5334
5335     case EL_DYNABOMB_NR:
5336       RemoveField(x, y);
5337       player->dynabomb_count++;
5338       player->dynabombs_left++;
5339       RaiseScoreElement(EL_DYNAMITE_INACTIVE);
5340       PlaySoundLevel(x, y, SND_PONG);
5341       break;
5342
5343     case EL_DYNABOMB_SZ:
5344       RemoveField(x, y);
5345       player->dynabomb_size++;
5346       RaiseScoreElement(EL_DYNAMITE_INACTIVE);
5347       PlaySoundLevel(x, y, SND_PONG);
5348       break;
5349
5350     case EL_DYNABOMB_XL:
5351       RemoveField(x, y);
5352       player->dynabomb_xl = TRUE;
5353       RaiseScoreElement(EL_DYNAMITE_INACTIVE);
5354       PlaySoundLevel(x, y, SND_PONG);
5355       break;
5356
5357     case EL_SCHLUESSEL1:
5358     case EL_SCHLUESSEL2:
5359     case EL_SCHLUESSEL3:
5360     case EL_SCHLUESSEL4:
5361     {
5362       int key_nr = element - EL_SCHLUESSEL1;
5363
5364       RemoveField(x, y);
5365       player->key[key_nr] = TRUE;
5366       RaiseScoreElement(EL_SCHLUESSEL);
5367       DrawMiniGraphicExt(drawto, gc,
5368                          DX_KEYS+key_nr*MINI_TILEX, DY_KEYS,
5369                          GFX_SCHLUESSEL1+key_nr);
5370       DrawMiniGraphicExt(window, gc,
5371                          DX_KEYS+key_nr*MINI_TILEX, DY_KEYS,
5372                          GFX_SCHLUESSEL1+key_nr);
5373       PlaySoundLevel(x, y, SND_PONG);
5374       break;
5375     }
5376
5377     case EL_EM_KEY_1:
5378     case EL_EM_KEY_2:
5379     case EL_EM_KEY_3:
5380     case EL_EM_KEY_4:
5381     {
5382       int key_nr = element - EL_EM_KEY_1;
5383
5384       RemoveField(x, y);
5385       player->key[key_nr] = TRUE;
5386       RaiseScoreElement(EL_SCHLUESSEL);
5387       DrawMiniGraphicExt(drawto, gc,
5388                          DX_KEYS+key_nr*MINI_TILEX, DY_KEYS,
5389                          GFX_SCHLUESSEL1+key_nr);
5390       DrawMiniGraphicExt(window, gc,
5391                          DX_KEYS+key_nr*MINI_TILEX, DY_KEYS,
5392                          GFX_SCHLUESSEL1+key_nr);
5393       PlaySoundLevel(x, y, SND_PONG);
5394       break;
5395     }
5396
5397     case EL_ABLENK_AUS:
5398       Feld[x][y] = EL_ABLENK_EIN;
5399       ZX = x;
5400       ZY = y;
5401       DrawLevelField(x, y);
5402       return MF_ACTION;
5403       break;
5404
5405     case EL_SP_TERMINAL:
5406       {
5407         int xx, yy;
5408
5409         for (yy=0; yy<lev_fieldy; yy++)
5410         {
5411           for (xx=0; xx<lev_fieldx; xx++)
5412           {
5413             if (Feld[xx][yy] == EL_SP_DISK_YELLOW)
5414               Bang(xx, yy);
5415             else if (Feld[xx][yy] == EL_SP_TERMINAL)
5416               Feld[xx][yy] = EL_SP_TERMINAL_ACTIVE;
5417           }
5418         }
5419
5420         return MF_ACTION;
5421       }
5422       break;
5423
5424     case EL_BELT1_SWITCH_LEFT:
5425     case EL_BELT1_SWITCH_MIDDLE:
5426     case EL_BELT1_SWITCH_RIGHT:
5427     case EL_BELT2_SWITCH_LEFT:
5428     case EL_BELT2_SWITCH_MIDDLE:
5429     case EL_BELT2_SWITCH_RIGHT:
5430     case EL_BELT3_SWITCH_LEFT:
5431     case EL_BELT3_SWITCH_MIDDLE:
5432     case EL_BELT3_SWITCH_RIGHT:
5433     case EL_BELT4_SWITCH_LEFT:
5434     case EL_BELT4_SWITCH_MIDDLE:
5435     case EL_BELT4_SWITCH_RIGHT:
5436       if (!player->Switching)
5437       {
5438         player->Switching = TRUE;
5439         ToggleBeltSwitch(x, y);
5440       }
5441       return MF_ACTION;
5442       break;
5443
5444     case EL_SWITCHGATE_SWITCH_1:
5445     case EL_SWITCHGATE_SWITCH_2:
5446       if (!player->Switching)
5447       {
5448         player->Switching = TRUE;
5449         ToggleSwitchgateSwitch(x, y);
5450       }
5451       return MF_ACTION;
5452       break;
5453
5454     case EL_LIGHT_SWITCH_OFF:
5455     case EL_LIGHT_SWITCH_ON:
5456       if (!player->Switching)
5457       {
5458         player->Switching = TRUE;
5459         ToggleLightSwitch(x, y);
5460       }
5461       return MF_ACTION;
5462       break;
5463
5464     case EL_TIMEGATE_SWITCH_OFF:
5465       ActivateTimegateSwitch(x, y);
5466
5467       return MF_ACTION;
5468       break;
5469
5470     case EL_BALLOON_SEND_LEFT:
5471     case EL_BALLOON_SEND_RIGHT:
5472     case EL_BALLOON_SEND_UP:
5473     case EL_BALLOON_SEND_DOWN:
5474     case EL_BALLOON_SEND_ANY:
5475       if (element == EL_BALLOON_SEND_ANY)
5476         game.balloon_dir = move_direction;
5477       else
5478         game.balloon_dir = (element == EL_BALLOON_SEND_LEFT  ? MV_LEFT :
5479                             element == EL_BALLOON_SEND_RIGHT ? MV_RIGHT :
5480                             element == EL_BALLOON_SEND_UP    ? MV_UP :
5481                             element == EL_BALLOON_SEND_DOWN  ? MV_DOWN :
5482                             MV_NO_MOVING);
5483
5484       return MF_ACTION;
5485       break;
5486
5487     case EL_SP_EXIT:
5488       if (local_player->gems_still_needed > 0)
5489         return MF_NO_ACTION;
5490
5491       player->LevelSolved = player->GameOver = TRUE;
5492       PlaySoundStereo(SND_SP_EXIT, PSND_MAX_RIGHT);
5493       break;
5494
5495     case EL_FELSBROCKEN:
5496     case EL_BD_ROCK:
5497     case EL_BOMBE:
5498     case EL_DX_SUPABOMB:
5499     case EL_KOKOSNUSS:
5500     case EL_ZEIT_LEER:
5501     case EL_SP_ZONK:
5502     case EL_SP_DISK_ORANGE:
5503     case EL_SPRING:
5504       if (dy || mode == DF_SNAP)
5505         return MF_NO_ACTION;
5506
5507       player->Pushing = TRUE;
5508
5509       if (!IN_LEV_FIELD(x+dx, y+dy) || !IS_FREE(x+dx, y+dy))
5510         return MF_NO_ACTION;
5511
5512       if (real_dy)
5513       {
5514         if (IN_LEV_FIELD(jx, jy+real_dy) && !IS_SOLID(Feld[jx][jy+real_dy]))
5515           return MF_NO_ACTION;
5516       }
5517
5518       if (player->push_delay == 0)
5519         player->push_delay = FrameCounter;
5520       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
5521           !tape.playing && element != EL_SPRING)
5522         return MF_NO_ACTION;
5523
5524       RemoveField(x, y);
5525       Feld[x+dx][y+dy] = element;
5526
5527       if (element == EL_SPRING)
5528       {
5529         Feld[x+dx][y+dy] = EL_SPRING_MOVING;
5530         MovDir[x+dx][y+dy] = move_direction;
5531       }
5532
5533       player->push_delay_value = (element == EL_SPRING ? 0 : 2 + RND(8));
5534
5535       DrawLevelField(x+dx, y+dy);
5536       if (element == EL_FELSBROCKEN || element == EL_BD_ROCK)
5537         PlaySoundLevel(x+dx, y+dy, SND_PUSCH);
5538       else if (element == EL_KOKOSNUSS)
5539         PlaySoundLevel(x+dx, y+dy, SND_KNURK);
5540       else if (IS_SP_ELEMENT(element))
5541         PlaySoundLevel(x+dx, y+dy, SND_SP_ZONKPUSH);
5542       else
5543         PlaySoundLevel(x+dx, y+dy, SND_PUSCH);  /* better than "SND_KLOPF" */
5544       break;
5545
5546     case EL_PFORTE1:
5547     case EL_PFORTE2:
5548     case EL_PFORTE3:
5549     case EL_PFORTE4:
5550       if (!player->key[element - EL_PFORTE1])
5551         return MF_NO_ACTION;
5552       break;
5553
5554     case EL_PFORTE1X:
5555     case EL_PFORTE2X:
5556     case EL_PFORTE3X:
5557     case EL_PFORTE4X:
5558       if (!player->key[element - EL_PFORTE1X])
5559         return MF_NO_ACTION;
5560       break;
5561
5562     case EL_EM_GATE_1:
5563     case EL_EM_GATE_2:
5564     case EL_EM_GATE_3:
5565     case EL_EM_GATE_4:
5566       if (!player->key[element - EL_EM_GATE_1])
5567         return MF_NO_ACTION;
5568       if (!IN_LEV_FIELD(x + dx, y + dy) || !IS_FREE(x + dx, y + dy))
5569         return MF_NO_ACTION;
5570
5571       /* automatically move to the next field with double speed */
5572       player->programmed_action = move_direction;
5573       DOUBLE_PLAYER_SPEED(player);
5574
5575       PlaySoundLevel(x, y, SND_GATE);
5576
5577       break;
5578
5579     case EL_EM_GATE_1X:
5580     case EL_EM_GATE_2X:
5581     case EL_EM_GATE_3X:
5582     case EL_EM_GATE_4X:
5583       if (!player->key[element - EL_EM_GATE_1X])
5584         return MF_NO_ACTION;
5585       if (!IN_LEV_FIELD(x + dx, y + dy) || !IS_FREE(x + dx, y + dy))
5586         return MF_NO_ACTION;
5587
5588       /* automatically move to the next field with double speed */
5589       player->programmed_action = move_direction;
5590       DOUBLE_PLAYER_SPEED(player);
5591
5592       PlaySoundLevel(x, y, SND_GATE);
5593
5594       break;
5595
5596     case EL_SWITCHGATE_OPEN:
5597     case EL_TIMEGATE_OPEN:
5598       if (!IN_LEV_FIELD(x + dx, y + dy) || !IS_FREE(x + dx, y + dy))
5599         return MF_NO_ACTION;
5600
5601       /* automatically move to the next field with double speed */
5602       player->programmed_action = move_direction;
5603       DOUBLE_PLAYER_SPEED(player);
5604
5605       PlaySoundLevel(x, y, SND_GATE);
5606
5607       break;
5608
5609     case EL_SP_PORT1_LEFT:
5610     case EL_SP_PORT2_LEFT:
5611     case EL_SP_PORT1_RIGHT:
5612     case EL_SP_PORT2_RIGHT:
5613     case EL_SP_PORT1_UP:
5614     case EL_SP_PORT2_UP:
5615     case EL_SP_PORT1_DOWN:
5616     case EL_SP_PORT2_DOWN:
5617     case EL_SP_PORT_X:
5618     case EL_SP_PORT_Y:
5619     case EL_SP_PORT_XY:
5620       if ((dx == -1 &&
5621            element != EL_SP_PORT1_LEFT &&
5622            element != EL_SP_PORT2_LEFT &&
5623            element != EL_SP_PORT_X &&
5624            element != EL_SP_PORT_XY) ||
5625           (dx == +1 &&
5626            element != EL_SP_PORT1_RIGHT &&
5627            element != EL_SP_PORT2_RIGHT &&
5628            element != EL_SP_PORT_X &&
5629            element != EL_SP_PORT_XY) ||
5630           (dy == -1 &&
5631            element != EL_SP_PORT1_UP &&
5632            element != EL_SP_PORT2_UP &&
5633            element != EL_SP_PORT_Y &&
5634            element != EL_SP_PORT_XY) ||
5635           (dy == +1 &&
5636            element != EL_SP_PORT1_DOWN &&
5637            element != EL_SP_PORT2_DOWN &&
5638            element != EL_SP_PORT_Y &&
5639            element != EL_SP_PORT_XY) ||
5640           !IN_LEV_FIELD(x + dx, y + dy) ||
5641           !IS_FREE(x + dx, y + dy))
5642         return MF_NO_ACTION;
5643
5644       /* automatically move to the next field with double speed */
5645       player->programmed_action = move_direction;
5646       DOUBLE_PLAYER_SPEED(player);
5647
5648       PlaySoundLevel(x, y, SND_GATE);
5649       break;
5650
5651     case EL_TUBE_CROSS:
5652     case EL_TUBE_VERTICAL:
5653     case EL_TUBE_HORIZONTAL:
5654     case EL_TUBE_VERT_LEFT:
5655     case EL_TUBE_VERT_RIGHT:
5656     case EL_TUBE_HORIZ_UP:
5657     case EL_TUBE_HORIZ_DOWN:
5658     case EL_TUBE_LEFT_UP:
5659     case EL_TUBE_LEFT_DOWN:
5660     case EL_TUBE_RIGHT_UP:
5661     case EL_TUBE_RIGHT_DOWN:
5662       {
5663         int i = 0;
5664         int tube_enter_directions[][2] =
5665         {
5666           { EL_TUBE_CROSS,      MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN },
5667           { EL_TUBE_VERTICAL,                        MV_UP | MV_DOWN },
5668           { EL_TUBE_HORIZONTAL, MV_LEFT | MV_RIGHT                   },
5669           { EL_TUBE_VERT_LEFT,            MV_RIGHT | MV_UP | MV_DOWN },
5670           { EL_TUBE_VERT_RIGHT, MV_LEFT            | MV_UP | MV_DOWN },
5671           { EL_TUBE_HORIZ_UP,   MV_LEFT | MV_RIGHT |         MV_DOWN },
5672           { EL_TUBE_HORIZ_DOWN, MV_LEFT | MV_RIGHT | MV_UP           },
5673           { EL_TUBE_LEFT_UP,              MV_RIGHT |         MV_DOWN },
5674           { EL_TUBE_LEFT_DOWN,            MV_RIGHT | MV_UP           },
5675           { EL_TUBE_RIGHT_UP,   MV_LEFT |                    MV_DOWN },
5676           { EL_TUBE_RIGHT_DOWN, MV_LEFT |            MV_UP           },
5677           { -1,                 MV_NO_MOVING                         }
5678         };
5679
5680         while (tube_enter_directions[i][0] != element)
5681         {
5682           i++;
5683           if (tube_enter_directions[i][0] == -1)        /* should not happen */
5684             break;
5685         }
5686
5687         if (!(tube_enter_directions[i][1] & move_direction))
5688           return MF_NO_ACTION;  /* tube has no opening in this direction */
5689       }
5690       break;
5691
5692     case EL_AUSGANG_ZU:
5693     case EL_AUSGANG_ACT:
5694       /* door is not (yet) open */
5695       return MF_NO_ACTION;
5696       break;
5697
5698     case EL_AUSGANG_AUF:
5699       if (mode == DF_SNAP)
5700         return MF_NO_ACTION;
5701
5702       PlaySoundLevel(x, y, SND_BUING);
5703
5704       break;
5705
5706     case EL_BIRNE_AUS:
5707       Feld[x][y] = EL_BIRNE_EIN;
5708       local_player->lights_still_needed--;
5709       DrawLevelField(x, y);
5710       PlaySoundLevel(x, y, SND_DENG);
5711       return MF_ACTION;
5712       break;
5713
5714     case EL_ZEIT_VOLL:
5715       Feld[x][y] = EL_ZEIT_LEER;
5716       TimeLeft += 10;
5717       DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
5718       DrawLevelField(x, y);
5719       PlaySoundStereo(SND_GONG, PSND_MAX_RIGHT);
5720       return MF_ACTION;
5721       break;
5722
5723     case EL_SOKOBAN_FELD_LEER:
5724       break;
5725
5726     case EL_SOKOBAN_FELD_VOLL:
5727     case EL_SOKOBAN_OBJEKT:
5728     case EL_SONDE:
5729     case EL_SP_DISK_YELLOW:
5730     case EL_BALLOON:
5731       if (mode == DF_SNAP)
5732         return MF_NO_ACTION;
5733
5734       player->Pushing = TRUE;
5735
5736       if (!IN_LEV_FIELD(x+dx, y+dy)
5737           || (!IS_FREE(x+dx, y+dy)
5738               && (Feld[x+dx][y+dy] != EL_SOKOBAN_FELD_LEER
5739                   || !IS_SB_ELEMENT(element))))
5740         return MF_NO_ACTION;
5741
5742       if (dx && real_dy)
5743       {
5744         if (IN_LEV_FIELD(jx, jy+real_dy) && !IS_SOLID(Feld[jx][jy+real_dy]))
5745           return MF_NO_ACTION;
5746       }
5747       else if (dy && real_dx)
5748       {
5749         if (IN_LEV_FIELD(jx+real_dx, jy) && !IS_SOLID(Feld[jx+real_dx][jy]))
5750           return MF_NO_ACTION;
5751       }
5752
5753       if (player->push_delay == 0)
5754         player->push_delay = FrameCounter;
5755       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
5756           !tape.playing && element != EL_BALLOON)
5757         return MF_NO_ACTION;
5758
5759       if (IS_SB_ELEMENT(element))
5760       {
5761         if (element == EL_SOKOBAN_FELD_VOLL)
5762         {
5763           Feld[x][y] = EL_SOKOBAN_FELD_LEER;
5764           local_player->sokobanfields_still_needed++;
5765         }
5766         else
5767           RemoveField(x, y);
5768
5769         if (Feld[x+dx][y+dy] == EL_SOKOBAN_FELD_LEER)
5770         {
5771           Feld[x+dx][y+dy] = EL_SOKOBAN_FELD_VOLL;
5772           local_player->sokobanfields_still_needed--;
5773           if (element == EL_SOKOBAN_OBJEKT)
5774             PlaySoundLevel(x, y, SND_DENG);
5775         }
5776         else
5777           Feld[x+dx][y+dy] = EL_SOKOBAN_OBJEKT;
5778       }
5779       else
5780       {
5781         RemoveField(x, y);
5782         Feld[x+dx][y+dy] = element;
5783       }
5784
5785       player->push_delay_value = (element == EL_BALLOON ? 0 : 2);
5786
5787       DrawLevelField(x, y);
5788       DrawLevelField(x+dx, y+dy);
5789       if (element == EL_BALLOON)
5790         PlaySoundLevel(x+dx, y+dy, SND_SCHLURF);
5791       else
5792         PlaySoundLevel(x+dx, y+dy, SND_PUSCH);
5793
5794       if (IS_SB_ELEMENT(element) &&
5795           local_player->sokobanfields_still_needed == 0 &&
5796           game.emulation == EMU_SOKOBAN)
5797       {
5798         player->LevelSolved = player->GameOver = TRUE;
5799         PlaySoundLevel(x, y, SND_BUING);
5800       }
5801
5802       break;
5803
5804     case EL_PINGUIN:
5805     case EL_SCHWEIN:
5806     case EL_DRACHE:
5807       break;
5808
5809     default:
5810       return MF_NO_ACTION;
5811   }
5812
5813   player->push_delay = 0;
5814
5815   return MF_MOVING;
5816 }
5817
5818 boolean SnapField(struct PlayerInfo *player, int dx, int dy)
5819 {
5820   int jx = player->jx, jy = player->jy;
5821   int x = jx + dx, y = jy + dy;
5822
5823   if (!player->active || !IN_LEV_FIELD(x, y))
5824     return FALSE;
5825
5826   if (dx && dy)
5827     return FALSE;
5828
5829   if (!dx && !dy)
5830   {
5831     player->snapped = FALSE;
5832     return FALSE;
5833   }
5834
5835   if (player->snapped)
5836     return FALSE;
5837
5838   player->MovDir = (dx < 0 ? MV_LEFT :
5839                     dx > 0 ? MV_RIGHT :
5840                     dy < 0 ? MV_UP :
5841                     dy > 0 ? MV_DOWN :  MV_NO_MOVING);
5842
5843   if (!DigField(player, x, y, 0, 0, DF_SNAP))
5844     return FALSE;
5845
5846   player->snapped = TRUE;
5847   DrawLevelField(x, y);
5848   BackToFront();
5849
5850   return TRUE;
5851 }
5852
5853 boolean PlaceBomb(struct PlayerInfo *player)
5854 {
5855   int jx = player->jx, jy = player->jy;
5856   int element;
5857
5858   if (!player->active || player->MovPos)
5859     return FALSE;
5860
5861   element = Feld[jx][jy];
5862
5863   if ((player->dynamite == 0 && player->dynabombs_left == 0) ||
5864       IS_ACTIVE_BOMB(element) || element == EL_EXPLODING)
5865     return FALSE;
5866
5867   if (element != EL_LEERRAUM)
5868     Store[jx][jy] = element;
5869
5870   if (player->dynamite)
5871   {
5872     Feld[jx][jy] = EL_DYNAMITE_ACTIVE;
5873     MovDelay[jx][jy] = 96;
5874     player->dynamite--;
5875     DrawText(DX_DYNAMITE, DY_DYNAMITE, int2str(local_player->dynamite, 3),
5876              FS_SMALL, FC_YELLOW);
5877     if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy)))
5878     {
5879       if (game.emulation == EMU_SUPAPLEX)
5880         DrawGraphic(SCREENX(jx), SCREENY(jy), GFX_SP_DISK_RED);
5881       else
5882         DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), GFX_DYNAMIT);
5883     }
5884   }
5885   else
5886   {
5887     Feld[jx][jy] = EL_DYNABOMB_ACTIVE_1 + (player->element_nr - EL_SPIELER1);
5888     MovDelay[jx][jy] = 96;
5889     player->dynabombs_left--;
5890     if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy)))
5891       DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), GFX_DYNABOMB);
5892   }
5893
5894   return TRUE;
5895 }
5896
5897 void PlaySoundLevel(int x, int y, int sound_nr)
5898 {
5899   int sx = SCREENX(x), sy = SCREENY(y);
5900   int volume, stereo;
5901   int silence_distance = 8;
5902
5903   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound_nr)) ||
5904       (!setup.sound_loops && IS_LOOP_SOUND(sound_nr)))
5905     return;
5906
5907   if (!IN_LEV_FIELD(x, y) ||
5908       sx < -silence_distance || sx >= SCR_FIELDX+silence_distance ||
5909       sy < -silence_distance || sy >= SCR_FIELDY+silence_distance)
5910     return;
5911
5912   volume = PSND_MAX_VOLUME;
5913
5914 #ifndef MSDOS
5915   stereo = (sx - SCR_FIELDX/2) * 12;
5916 #else
5917   stereo = PSND_MIDDLE + (2 * sx - (SCR_FIELDX - 1)) * 5;
5918   if (stereo > PSND_MAX_RIGHT)
5919     stereo = PSND_MAX_RIGHT;
5920   if (stereo < PSND_MAX_LEFT)
5921     stereo = PSND_MAX_LEFT;
5922 #endif
5923
5924   if (!IN_SCR_FIELD(sx, sy))
5925   {
5926     int dx = ABS(sx - SCR_FIELDX/2) - SCR_FIELDX/2;
5927     int dy = ABS(sy - SCR_FIELDY/2) - SCR_FIELDY/2;
5928
5929     volume -= volume * (dx > dy ? dx : dy) / silence_distance;
5930   }
5931
5932   PlaySoundExt(sound_nr, volume, stereo, PSND_NO_LOOP);
5933 }
5934
5935 void RaiseScore(int value)
5936 {
5937   local_player->score += value;
5938   DrawText(DX_SCORE, DY_SCORE, int2str(local_player->score, 5),
5939            FS_SMALL, FC_YELLOW);
5940 }
5941
5942 void RaiseScoreElement(int element)
5943 {
5944   switch(element)
5945   {
5946     case EL_EDELSTEIN:
5947     case EL_EDELSTEIN_BD:
5948     case EL_EDELSTEIN_GELB:
5949     case EL_EDELSTEIN_ROT:
5950     case EL_EDELSTEIN_LILA:
5951       RaiseScore(level.score[SC_EDELSTEIN]);
5952       break;
5953     case EL_DIAMANT:
5954       RaiseScore(level.score[SC_DIAMANT]);
5955       break;
5956     case EL_KAEFER:
5957     case EL_BUTTERFLY:
5958       RaiseScore(level.score[SC_KAEFER]);
5959       break;
5960     case EL_FLIEGER:
5961     case EL_FIREFLY:
5962       RaiseScore(level.score[SC_FLIEGER]);
5963       break;
5964     case EL_MAMPFER:
5965     case EL_MAMPFER2:
5966       RaiseScore(level.score[SC_MAMPFER]);
5967       break;
5968     case EL_ROBOT:
5969       RaiseScore(level.score[SC_ROBOT]);
5970       break;
5971     case EL_PACMAN:
5972       RaiseScore(level.score[SC_PACMAN]);
5973       break;
5974     case EL_KOKOSNUSS:
5975       RaiseScore(level.score[SC_KOKOSNUSS]);
5976       break;
5977     case EL_DYNAMITE_INACTIVE:
5978       RaiseScore(level.score[SC_DYNAMIT]);
5979       break;
5980     case EL_SCHLUESSEL:
5981       RaiseScore(level.score[SC_SCHLUESSEL]);
5982       break;
5983     default:
5984       break;
5985   }
5986 }
5987
5988 /* ---------- new game button stuff ---------------------------------------- */
5989
5990 /* graphic position values for game buttons */
5991 #define GAME_BUTTON_XSIZE       30
5992 #define GAME_BUTTON_YSIZE       30
5993 #define GAME_BUTTON_XPOS        5
5994 #define GAME_BUTTON_YPOS        215
5995 #define SOUND_BUTTON_XPOS       5
5996 #define SOUND_BUTTON_YPOS       (GAME_BUTTON_YPOS + GAME_BUTTON_YSIZE)
5997
5998 #define GAME_BUTTON_STOP_XPOS   (GAME_BUTTON_XPOS + 0 * GAME_BUTTON_XSIZE)
5999 #define GAME_BUTTON_PAUSE_XPOS  (GAME_BUTTON_XPOS + 1 * GAME_BUTTON_XSIZE)
6000 #define GAME_BUTTON_PLAY_XPOS   (GAME_BUTTON_XPOS + 2 * GAME_BUTTON_XSIZE)
6001 #define SOUND_BUTTON_MUSIC_XPOS (SOUND_BUTTON_XPOS + 0 * GAME_BUTTON_XSIZE)
6002 #define SOUND_BUTTON_LOOPS_XPOS (SOUND_BUTTON_XPOS + 1 * GAME_BUTTON_XSIZE)
6003 #define SOUND_BUTTON_SIMPLE_XPOS (SOUND_BUTTON_XPOS + 2 * GAME_BUTTON_XSIZE)
6004
6005 static struct
6006 {
6007   int x, y;
6008   int gadget_id;
6009   char *infotext;
6010 } gamebutton_info[NUM_GAME_BUTTONS] =
6011 {
6012   {
6013     GAME_BUTTON_STOP_XPOS,      GAME_BUTTON_YPOS,
6014     GAME_CTRL_ID_STOP,
6015     "stop game"
6016   },
6017   {
6018     GAME_BUTTON_PAUSE_XPOS,     GAME_BUTTON_YPOS,
6019     GAME_CTRL_ID_PAUSE,
6020     "pause game"
6021   },
6022   {
6023     GAME_BUTTON_PLAY_XPOS,      GAME_BUTTON_YPOS,
6024     GAME_CTRL_ID_PLAY,
6025     "play game"
6026   },
6027   {
6028     SOUND_BUTTON_MUSIC_XPOS,    SOUND_BUTTON_YPOS,
6029     SOUND_CTRL_ID_MUSIC,
6030     "background music on/off"
6031   },
6032   {
6033     SOUND_BUTTON_LOOPS_XPOS,    SOUND_BUTTON_YPOS,
6034     SOUND_CTRL_ID_LOOPS,
6035     "sound loops on/off"
6036   },
6037   {
6038     SOUND_BUTTON_SIMPLE_XPOS,   SOUND_BUTTON_YPOS,
6039     SOUND_CTRL_ID_SIMPLE,
6040     "normal sounds on/off"
6041   }
6042 };
6043
6044 void CreateGameButtons()
6045 {
6046   int i;
6047
6048   for (i=0; i<NUM_GAME_BUTTONS; i++)
6049   {
6050     Pixmap gd_pixmap = pix[PIX_DOOR];
6051     struct GadgetInfo *gi;
6052     int button_type;
6053     boolean checked;
6054     unsigned long event_mask;
6055     int gd_xoffset, gd_yoffset;
6056     int gd_x1, gd_x2, gd_y1, gd_y2;
6057     int id = i;
6058
6059     gd_xoffset = gamebutton_info[i].x;
6060     gd_yoffset = gamebutton_info[i].y;
6061     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
6062     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
6063
6064     if (id == GAME_CTRL_ID_STOP ||
6065         id == GAME_CTRL_ID_PAUSE ||
6066         id == GAME_CTRL_ID_PLAY)
6067     {
6068       button_type = GD_TYPE_NORMAL_BUTTON;
6069       checked = FALSE;
6070       event_mask = GD_EVENT_RELEASED;
6071       gd_y1  = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
6072       gd_y2  = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
6073     }
6074     else
6075     {
6076       button_type = GD_TYPE_CHECK_BUTTON;
6077       checked =
6078         ((id == SOUND_CTRL_ID_MUSIC && setup.sound_music) ||
6079          (id == SOUND_CTRL_ID_LOOPS && setup.sound_loops) ||
6080          (id == SOUND_CTRL_ID_SIMPLE && setup.sound_simple) ? TRUE : FALSE);
6081       event_mask = GD_EVENT_PRESSED;
6082       gd_y1  = DOOR_GFX_PAGEY1 + gd_yoffset;
6083       gd_y2  = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
6084     }
6085
6086     gi = CreateGadget(GDI_CUSTOM_ID, id,
6087                       GDI_INFO_TEXT, gamebutton_info[i].infotext,
6088                       GDI_X, DX + gd_xoffset,
6089                       GDI_Y, DY + gd_yoffset,
6090                       GDI_WIDTH, GAME_BUTTON_XSIZE,
6091                       GDI_HEIGHT, GAME_BUTTON_YSIZE,
6092                       GDI_TYPE, button_type,
6093                       GDI_STATE, GD_BUTTON_UNPRESSED,
6094                       GDI_CHECKED, checked,
6095                       GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y1,
6096                       GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y1,
6097                       GDI_ALT_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y2,
6098                       GDI_ALT_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y2,
6099                       GDI_EVENT_MASK, event_mask,
6100                       GDI_CALLBACK_ACTION, HandleGameButtons,
6101                       GDI_END);
6102
6103     if (gi == NULL)
6104       Error(ERR_EXIT, "cannot create gadget");
6105
6106     game_gadget[id] = gi;
6107   }
6108 }
6109
6110 static void MapGameButtons()
6111 {
6112   int i;
6113
6114   for (i=0; i<NUM_GAME_BUTTONS; i++)
6115     MapGadget(game_gadget[i]);
6116 }
6117
6118 void UnmapGameButtons()
6119 {
6120   int i;
6121
6122   for (i=0; i<NUM_GAME_BUTTONS; i++)
6123     UnmapGadget(game_gadget[i]);
6124 }
6125
6126 static void HandleGameButtons(struct GadgetInfo *gi)
6127 {
6128   int id = gi->custom_id;
6129
6130   if (game_status != PLAYING)
6131     return;
6132
6133   switch (id)
6134   {
6135     case GAME_CTRL_ID_STOP:
6136       if (AllPlayersGone)
6137       {
6138         CloseDoor(DOOR_CLOSE_1);
6139         game_status = MAINMENU;
6140         DrawMainMenu();
6141         break;
6142       }
6143
6144       if (level_editor_test_game ||
6145           Request("Do you really want to quit the game ?",
6146                   REQ_ASK | REQ_STAY_CLOSED))
6147       { 
6148 #ifndef MSDOS
6149         if (options.network)
6150           SendToServer_StopPlaying();
6151         else
6152 #endif
6153         {
6154           game_status = MAINMENU;
6155           DrawMainMenu();
6156         }
6157       }
6158       else
6159         OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
6160       break;
6161
6162     case GAME_CTRL_ID_PAUSE:
6163       if (options.network)
6164       {
6165 #ifndef MSDOS
6166         if (tape.pausing)
6167           SendToServer_ContinuePlaying();
6168         else
6169           SendToServer_PausePlaying();
6170 #endif
6171       }
6172       else
6173         TapeTogglePause();
6174       break;
6175
6176     case GAME_CTRL_ID_PLAY:
6177       if (tape.pausing)
6178       {
6179 #ifndef MSDOS
6180         if (options.network)
6181           SendToServer_ContinuePlaying();
6182         else
6183 #endif
6184         {
6185           tape.pausing = FALSE;
6186           DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0);
6187         }
6188       }
6189       break;
6190
6191     case SOUND_CTRL_ID_MUSIC:
6192       if (setup.sound_music)
6193       { 
6194         setup.sound_music = FALSE;
6195         FadeSound(background_loop[level_nr % num_bg_loops]);
6196       }
6197       else if (sound_loops_allowed)
6198       { 
6199         setup.sound = setup.sound_music = TRUE;
6200         PlaySoundLoop(background_loop[level_nr % num_bg_loops]);
6201       }
6202       break;
6203
6204     case SOUND_CTRL_ID_LOOPS:
6205       if (setup.sound_loops)
6206         setup.sound_loops = FALSE;
6207       else if (sound_loops_allowed)
6208         setup.sound = setup.sound_loops = TRUE;
6209       break;
6210
6211     case SOUND_CTRL_ID_SIMPLE:
6212       if (setup.sound_simple)
6213         setup.sound_simple = FALSE;
6214       else if (sound_status==SOUND_AVAILABLE)
6215         setup.sound = setup.sound_simple = TRUE;
6216       break;
6217
6218     default:
6219       break;
6220   }
6221 }