rnd-19991010-1-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 || element == EL_SP_DISK_ORANGE) &&
1776       (lastline || object_hit)) /* element is bomb */
1777   {
1778     Bang(x, y);
1779     return;
1780   }
1781   else if (element == EL_PEARL)
1782   {
1783     Feld[x][y] = EL_PEARL_BREAKING;
1784     PlaySoundLevel(x, y, SND_KNACK);
1785     return;
1786   }
1787
1788   if (element == EL_TROPFEN && (lastline || object_hit))        /* acid drop */
1789   {
1790     if (object_hit && IS_PLAYER(x, y+1))
1791       KillHeroUnlessProtected(x, y+1);
1792     else if (object_hit && smashed == EL_PINGUIN)
1793       Bang(x, y+1);
1794     else
1795     {
1796       Feld[x][y] = EL_AMOEBING;
1797       Store[x][y] = EL_AMOEBE_NASS;
1798     }
1799     return;
1800   }
1801
1802   if (!lastline && object_hit)          /* check which object was hit */
1803   {
1804     if (CAN_CHANGE(element) && 
1805         (smashed == EL_SIEB_INAKTIV || smashed == EL_SIEB2_INAKTIV))
1806     {
1807       int x, y;
1808       int activated_magic_wall =
1809         (smashed == EL_SIEB_INAKTIV ? EL_SIEB_LEER : EL_SIEB2_LEER);
1810
1811       /* activate magic wall / mill */
1812
1813       for (y=0; y<lev_fieldy; y++)
1814         for (x=0; x<lev_fieldx; x++)
1815           if (Feld[x][y] == smashed)
1816             Feld[x][y] = activated_magic_wall;
1817
1818       game.magic_wall_time_left = level.time_magic_wall * FRAMES_PER_SECOND;
1819       game.magic_wall_active = TRUE;
1820     }
1821
1822     if (IS_PLAYER(x, y+1))
1823     {
1824       KillHeroUnlessProtected(x, y+1);
1825       return;
1826     }
1827     else if (smashed == EL_PINGUIN)
1828     {
1829       Bang(x, y+1);
1830       return;
1831     }
1832     else if (element == EL_EDELSTEIN_BD)
1833     {
1834       if (IS_ENEMY(smashed) && IS_BD_ELEMENT(smashed))
1835       {
1836         Bang(x, y+1);
1837         return;
1838       }
1839     }
1840     else if (element == EL_FELSBROCKEN || element == EL_SP_ZONK)
1841     {
1842       if (IS_ENEMY(smashed) ||
1843           smashed == EL_BOMBE || smashed == EL_SP_DISK_ORANGE ||
1844           smashed == EL_SONDE || smashed == EL_SCHWEIN ||
1845           smashed == EL_DRACHE || smashed == EL_MOLE)
1846       {
1847         Bang(x, y+1);
1848         return;
1849       }
1850       else if (!IS_MOVING(x, y+1))
1851       {
1852         if (smashed == EL_BIRNE_AUS || smashed == EL_BIRNE_EIN)
1853         {
1854           Bang(x, y+1);
1855           return;
1856         }
1857         else if (smashed == EL_KOKOSNUSS)
1858         {
1859           Feld[x][y+1] = EL_CRACKINGNUT;
1860           PlaySoundLevel(x, y, SND_KNACK);
1861           RaiseScoreElement(EL_KOKOSNUSS);
1862           return;
1863         }
1864         else if (smashed == EL_PEARL)
1865         {
1866           Feld[x][y+1] = EL_PEARL_BREAKING;
1867           PlaySoundLevel(x, y, SND_KNACK);
1868           return;
1869         }
1870         else if (smashed == EL_DIAMANT)
1871         {
1872           Feld[x][y+1] = EL_LEERRAUM;
1873           PlaySoundLevel(x, y, SND_QUIRK);
1874           return;
1875         }
1876         else if (IS_BELT_SWITCH(smashed))
1877         {
1878           ToggleBeltSwitch(x, y+1);
1879         }
1880         else if (smashed == EL_SWITCHGATE_SWITCH_1 ||
1881                  smashed == EL_SWITCHGATE_SWITCH_2)
1882         {
1883           ToggleSwitchgateSwitch(x, y+1);
1884         }
1885         else if (smashed == EL_LIGHT_SWITCH_OFF ||
1886                  smashed == EL_LIGHT_SWITCH_ON)
1887         {
1888           ToggleLightSwitch(x, y+1);
1889         }
1890       }
1891     }
1892   }
1893
1894   /* play sound of magic wall / mill */
1895   if (!lastline &&
1896       (Feld[x][y+1] == EL_SIEB_LEER || Feld[x][y+1] == EL_SIEB2_LEER))
1897   {
1898     PlaySoundLevel(x, y, SND_QUIRK);
1899     return;
1900   }
1901
1902   /* play sound of object that hits the ground */
1903   if (lastline || object_hit)
1904   {
1905     int sound;
1906
1907     switch(element)
1908     {
1909       case EL_EDELSTEIN:
1910       case EL_EDELSTEIN_BD:
1911       case EL_EDELSTEIN_GELB:
1912       case EL_EDELSTEIN_ROT:
1913       case EL_EDELSTEIN_LILA:
1914       case EL_DIAMANT:
1915       case EL_SP_INFOTRON:
1916         sound = SND_PLING;
1917         break;
1918       case EL_KOKOSNUSS:
1919         sound = SND_KLUMPF;
1920         break;
1921       case EL_FELSBROCKEN:
1922         sound = SND_KLOPF;
1923         break;
1924       case EL_SP_ZONK:
1925         sound = SND_SP_ZONKDOWN;
1926         break;
1927       case EL_SCHLUESSEL:
1928       case EL_SCHLUESSEL1:
1929       case EL_SCHLUESSEL2:
1930       case EL_SCHLUESSEL3:
1931       case EL_SCHLUESSEL4:
1932       case EL_EM_KEY_1:
1933       case EL_EM_KEY_2:
1934       case EL_EM_KEY_3:
1935       case EL_EM_KEY_4:
1936         sound = SND_KINK;
1937         break;
1938       case EL_ZEIT_VOLL:
1939       case EL_ZEIT_LEER:
1940         sound = SND_DENG;
1941         break;
1942       default:
1943         sound = -1;
1944         break;
1945     }
1946
1947     if (sound >= 0)
1948       PlaySoundLevel(x, y, sound);
1949   }
1950 }
1951
1952 void TurnRound(int x, int y)
1953 {
1954   static struct
1955   {
1956     int x, y;
1957   } move_xy[] =
1958   {
1959     { 0, 0 },
1960     {-1, 0 },
1961     {+1, 0 },
1962     { 0, 0 },
1963     { 0, -1 },
1964     { 0, 0 }, { 0, 0 }, { 0, 0 },
1965     { 0, +1 }
1966   };
1967   static struct
1968   {
1969     int left, right, back;
1970   } turn[] =
1971   {
1972     { 0,        0,              0 },
1973     { MV_DOWN,  MV_UP,          MV_RIGHT },
1974     { MV_UP,    MV_DOWN,        MV_LEFT },
1975     { 0,        0,              0 },
1976     { MV_LEFT,  MV_RIGHT,       MV_DOWN },
1977     { 0,0,0 },  { 0,0,0 },      { 0,0,0 },
1978     { MV_RIGHT, MV_LEFT,        MV_UP }
1979   };
1980
1981   int element = Feld[x][y];
1982   int old_move_dir = MovDir[x][y];
1983   int left_dir = turn[old_move_dir].left;
1984   int right_dir = turn[old_move_dir].right;
1985   int back_dir = turn[old_move_dir].back;
1986
1987   int left_dx = move_xy[left_dir].x, left_dy = move_xy[left_dir].y;
1988   int right_dx = move_xy[right_dir].x, right_dy = move_xy[right_dir].y;
1989   int move_dx = move_xy[old_move_dir].x, move_dy = move_xy[old_move_dir].y;
1990   int back_dx = move_xy[back_dir].x, back_dy = move_xy[back_dir].y;
1991
1992   int left_x = x+left_dx, left_y = y+left_dy;
1993   int right_x = x+right_dx, right_y = y+right_dy;
1994   int move_x = x+move_dx, move_y = y+move_dy;
1995
1996   if (element == EL_KAEFER || element == EL_BUTTERFLY)
1997   {
1998     TestIfBadThingHitsOtherBadThing(x, y);
1999
2000     if (IN_LEV_FIELD(right_x, right_y) &&
2001         IS_FREE(right_x, right_y))
2002       MovDir[x][y] = right_dir;
2003     else if (!IN_LEV_FIELD(move_x, move_y) ||
2004              !IS_FREE(move_x, move_y))
2005       MovDir[x][y] = left_dir;
2006
2007     if (element == EL_KAEFER && MovDir[x][y] != old_move_dir)
2008       MovDelay[x][y] = 9;
2009     else if (element == EL_BUTTERFLY)   /* && MovDir[x][y] == left_dir) */
2010       MovDelay[x][y] = 1;
2011   }
2012   else if (element == EL_FLIEGER || element == EL_FIREFLY ||
2013            element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
2014   {
2015     TestIfBadThingHitsOtherBadThing(x, y);
2016
2017     if (IN_LEV_FIELD(left_x, left_y) &&
2018         IS_FREE(left_x, left_y))
2019       MovDir[x][y] = left_dir;
2020     else if (!IN_LEV_FIELD(move_x, move_y) ||
2021              !IS_FREE(move_x, move_y))
2022       MovDir[x][y] = right_dir;
2023
2024     if ((element == EL_FLIEGER ||
2025          element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
2026         && MovDir[x][y] != old_move_dir)
2027       MovDelay[x][y] = 9;
2028     else if (element == EL_FIREFLY)     /* && MovDir[x][y] == right_dir) */
2029       MovDelay[x][y] = 1;
2030   }
2031   else if (element == EL_MAMPFER)
2032   {
2033     boolean can_turn_left = FALSE, can_turn_right = FALSE;
2034
2035     if (IN_LEV_FIELD(left_x, left_y) &&
2036         (IS_FREE_OR_PLAYER(left_x, left_y) ||
2037          Feld[left_x][left_y] == EL_DIAMANT))
2038       can_turn_left = TRUE;
2039     if (IN_LEV_FIELD(right_x, right_y) &&
2040         (IS_FREE_OR_PLAYER(right_x, right_y) ||
2041          Feld[right_x][right_y] == EL_DIAMANT))
2042       can_turn_right = TRUE;
2043
2044     if (can_turn_left && can_turn_right)
2045       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
2046     else if (can_turn_left)
2047       MovDir[x][y] = (RND(2) ? left_dir : back_dir);
2048     else if (can_turn_right)
2049       MovDir[x][y] = (RND(2) ? right_dir : back_dir);
2050     else
2051       MovDir[x][y] = back_dir;
2052
2053     MovDelay[x][y] = 16+16*RND(3);
2054   }
2055   else if (element == EL_MAMPFER2)
2056   {
2057     boolean can_turn_left = FALSE, can_turn_right = FALSE;
2058
2059     if (IN_LEV_FIELD(left_x, left_y) &&
2060         (IS_FREE_OR_PLAYER(left_x, left_y) ||
2061          IS_MAMPF2(Feld[left_x][left_y])))
2062       can_turn_left = TRUE;
2063     if (IN_LEV_FIELD(right_x, right_y) &&
2064         (IS_FREE_OR_PLAYER(right_x, right_y) ||
2065          IS_MAMPF2(Feld[right_x][right_y])))
2066       can_turn_right = TRUE;
2067
2068     if (can_turn_left && can_turn_right)
2069       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
2070     else if (can_turn_left)
2071       MovDir[x][y] = (RND(2) ? left_dir : back_dir);
2072     else if (can_turn_right)
2073       MovDir[x][y] = (RND(2) ? right_dir : back_dir);
2074     else
2075       MovDir[x][y] = back_dir;
2076
2077     MovDelay[x][y] = 16+16*RND(3);
2078   }
2079   else if (element == EL_PACMAN)
2080   {
2081     boolean can_turn_left = FALSE, can_turn_right = FALSE;
2082
2083     if (IN_LEV_FIELD(left_x, left_y) &&
2084         (IS_FREE_OR_PLAYER(left_x, left_y) ||
2085          IS_AMOEBOID(Feld[left_x][left_y])))
2086       can_turn_left = TRUE;
2087     if (IN_LEV_FIELD(right_x, right_y) &&
2088         (IS_FREE_OR_PLAYER(right_x, right_y) ||
2089          IS_AMOEBOID(Feld[right_x][right_y])))
2090       can_turn_right = TRUE;
2091
2092     if (can_turn_left && can_turn_right)
2093       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
2094     else if (can_turn_left)
2095       MovDir[x][y] = (RND(2) ? left_dir : back_dir);
2096     else if (can_turn_right)
2097       MovDir[x][y] = (RND(2) ? right_dir : back_dir);
2098     else
2099       MovDir[x][y] = back_dir;
2100
2101     MovDelay[x][y] = 6+RND(40);
2102   }
2103   else if (element == EL_SCHWEIN)
2104   {
2105     boolean can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE;
2106     boolean should_turn_left = FALSE, should_turn_right = FALSE;
2107     boolean should_move_on = FALSE;
2108     int rnd_value = 24;
2109     int rnd = RND(rnd_value);
2110
2111     if (IN_LEV_FIELD(left_x, left_y) &&
2112         (IS_FREE(left_x, left_y) || IS_GEM(Feld[left_x][left_y])))
2113       can_turn_left = TRUE;
2114     if (IN_LEV_FIELD(right_x, right_y) &&
2115         (IS_FREE(right_x, right_y) || IS_GEM(Feld[right_x][right_y])))
2116       can_turn_right = TRUE;
2117     if (IN_LEV_FIELD(move_x, move_y) &&
2118         (IS_FREE(move_x, move_y) || IS_GEM(Feld[move_x][move_y])))
2119       can_move_on = TRUE;
2120
2121     if (can_turn_left &&
2122         (!can_move_on ||
2123          (IN_LEV_FIELD(x+back_dx+left_dx, y+back_dy+left_dy) &&
2124           !IS_FREE(x+back_dx+left_dx, y+back_dy+left_dy))))
2125       should_turn_left = TRUE;
2126     if (can_turn_right &&
2127         (!can_move_on ||
2128          (IN_LEV_FIELD(x+back_dx+right_dx, y+back_dy+right_dy) &&
2129           !IS_FREE(x+back_dx+right_dx, y+back_dy+right_dy))))
2130       should_turn_right = TRUE;
2131     if (can_move_on &&
2132         (!can_turn_left || !can_turn_right ||
2133          (IN_LEV_FIELD(x+move_dx+left_dx, y+move_dy+left_dy) &&
2134           !IS_FREE(x+move_dx+left_dx, y+move_dy+left_dy)) ||
2135          (IN_LEV_FIELD(x+move_dx+right_dx, y+move_dy+right_dy) &&
2136           !IS_FREE(x+move_dx+right_dx, y+move_dy+right_dy))))
2137       should_move_on = TRUE;
2138
2139     if (should_turn_left || should_turn_right || should_move_on)
2140     {
2141       if (should_turn_left && should_turn_right && should_move_on)
2142         MovDir[x][y] = (rnd < rnd_value/3 ? left_dir :
2143                         rnd < 2*rnd_value/3 ? right_dir :
2144                         old_move_dir);
2145       else if (should_turn_left && should_turn_right)
2146         MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
2147       else if (should_turn_left && should_move_on)
2148         MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : old_move_dir);
2149       else if (should_turn_right && should_move_on)
2150         MovDir[x][y] = (rnd < rnd_value/2 ? right_dir : old_move_dir);
2151       else if (should_turn_left)
2152         MovDir[x][y] = left_dir;
2153       else if (should_turn_right)
2154         MovDir[x][y] = right_dir;
2155       else if (should_move_on)
2156         MovDir[x][y] = old_move_dir;
2157     }
2158     else if (can_move_on && rnd > rnd_value/8)
2159       MovDir[x][y] = old_move_dir;
2160     else if (can_turn_left && can_turn_right)
2161       MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
2162     else if (can_turn_left && rnd > rnd_value/8)
2163       MovDir[x][y] = left_dir;
2164     else if (can_turn_right && rnd > rnd_value/8)
2165       MovDir[x][y] = right_dir;
2166     else
2167       MovDir[x][y] = back_dir;
2168
2169     if (!IS_FREE(x+move_xy[MovDir[x][y]].x, y+move_xy[MovDir[x][y]].y) &&
2170         !IS_GEM(Feld[x+move_xy[MovDir[x][y]].x][y+move_xy[MovDir[x][y]].y]))
2171       MovDir[x][y] = old_move_dir;
2172
2173     MovDelay[x][y] = 0;
2174   }
2175   else if (element == EL_DRACHE)
2176   {
2177     boolean can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE;
2178     int rnd_value = 24;
2179     int rnd = RND(rnd_value);
2180
2181     if (IN_LEV_FIELD(left_x, left_y) && IS_FREE(left_x, left_y))
2182       can_turn_left = TRUE;
2183     if (IN_LEV_FIELD(right_x, right_y) && IS_FREE(right_x, right_y))
2184       can_turn_right = TRUE;
2185     if (IN_LEV_FIELD(move_x, move_y) && IS_FREE(move_x, move_y))
2186       can_move_on = TRUE;
2187
2188     if (can_move_on && rnd > rnd_value/8)
2189       MovDir[x][y] = old_move_dir;
2190     else if (can_turn_left && can_turn_right)
2191       MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
2192     else if (can_turn_left && rnd > rnd_value/8)
2193       MovDir[x][y] = left_dir;
2194     else if (can_turn_right && rnd > rnd_value/8)
2195       MovDir[x][y] = right_dir;
2196     else
2197       MovDir[x][y] = back_dir;
2198
2199     if (!IS_FREE(x+move_xy[MovDir[x][y]].x, y+move_xy[MovDir[x][y]].y))
2200       MovDir[x][y] = old_move_dir;
2201
2202     MovDelay[x][y] = 0;
2203   }
2204   else if (element == EL_MOLE)
2205   {
2206     boolean can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE;
2207
2208     if (IN_LEV_FIELD(move_x, move_y) &&
2209         (IS_FREE(move_x, move_y) || IS_AMOEBOID(Feld[move_x][move_y]) ||
2210          Feld[move_x][move_y] == EL_DEAMOEBING))
2211       can_move_on = TRUE;
2212
2213     if (!can_move_on)
2214     {
2215       if (IN_LEV_FIELD(left_x, left_y) &&
2216           (IS_FREE(left_x, left_y) || IS_AMOEBOID(Feld[left_x][left_y])))
2217         can_turn_left = TRUE;
2218       if (IN_LEV_FIELD(right_x, right_y) &&
2219           (IS_FREE(right_x, right_y) || IS_AMOEBOID(Feld[right_x][right_y])))
2220         can_turn_right = TRUE;
2221
2222       if (can_turn_left && can_turn_right)
2223         MovDir[x][y] = (RND(2) ? left_dir : right_dir);
2224       else if (can_turn_left)
2225         MovDir[x][y] = left_dir;
2226       else
2227         MovDir[x][y] = right_dir;
2228     }
2229
2230     if (MovDir[x][y] != old_move_dir)
2231       MovDelay[x][y] = 9;
2232   }
2233   else if (element == EL_BALLOON)
2234   {
2235     MovDir[x][y] = game.balloon_dir;
2236     MovDelay[x][y] = 0;
2237   }
2238   else if (element == EL_ROBOT || element == EL_SONDE || element == EL_PINGUIN)
2239   {
2240     int attr_x = -1, attr_y = -1;
2241
2242     if (AllPlayersGone)
2243     {
2244       attr_x = ExitX;
2245       attr_y = ExitY;
2246     }
2247     else
2248     {
2249       int i;
2250
2251       for (i=0; i<MAX_PLAYERS; i++)
2252       {
2253         struct PlayerInfo *player = &stored_player[i];
2254         int jx = player->jx, jy = player->jy;
2255
2256         if (!player->active)
2257           continue;
2258
2259         if (attr_x == -1 || ABS(jx-x)+ABS(jy-y) < ABS(attr_x-x)+ABS(attr_y-y))
2260         {
2261           attr_x = jx;
2262           attr_y = jy;
2263         }
2264       }
2265     }
2266
2267     if (element == EL_ROBOT && ZX>=0 && ZY>=0)
2268     {
2269       attr_x = ZX;
2270       attr_y = ZY;
2271     }
2272
2273     if (element == EL_PINGUIN)
2274     {
2275       int i;
2276       static int xy[4][2] =
2277       {
2278         { 0, -1 },
2279         { -1, 0 },
2280         { +1, 0 },
2281         { 0, +1 }
2282       };
2283
2284       for (i=0; i<4; i++)
2285       {
2286         int ex = x + xy[i%4][0];
2287         int ey = y + xy[i%4][1];
2288
2289         if (IN_LEV_FIELD(ex, ey) && Feld[ex][ey] == EL_AUSGANG_AUF)
2290         {
2291           attr_x = ex;
2292           attr_y = ey;
2293           break;
2294         }
2295       }
2296     }
2297
2298     MovDir[x][y] = MV_NO_MOVING;
2299     if (attr_x<x)
2300       MovDir[x][y] |= (AllPlayersGone ? MV_RIGHT : MV_LEFT);
2301     else if (attr_x>x)
2302       MovDir[x][y] |= (AllPlayersGone ? MV_LEFT : MV_RIGHT);
2303     if (attr_y<y)
2304       MovDir[x][y] |= (AllPlayersGone ? MV_DOWN : MV_UP);
2305     else if (attr_y>y)
2306       MovDir[x][y] |= (AllPlayersGone ? MV_UP : MV_DOWN);
2307
2308     if (element == EL_ROBOT)
2309     {
2310       int newx, newy;
2311
2312       if ((MovDir[x][y]&(MV_LEFT|MV_RIGHT)) && (MovDir[x][y]&(MV_UP|MV_DOWN)))
2313         MovDir[x][y] &= (RND(2) ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
2314       Moving2Blocked(x, y, &newx, &newy);
2315
2316       if (IN_LEV_FIELD(newx, newy) && IS_FREE_OR_PLAYER(newx, newy))
2317         MovDelay[x][y] = 8+8*!RND(3);
2318       else
2319         MovDelay[x][y] = 16;
2320     }
2321     else
2322     {
2323       int newx, newy;
2324
2325       MovDelay[x][y] = 1;
2326
2327       if ((MovDir[x][y]&(MV_LEFT|MV_RIGHT)) && (MovDir[x][y]&(MV_UP|MV_DOWN)))
2328       {
2329         boolean first_horiz = RND(2);
2330         int new_move_dir = MovDir[x][y];
2331
2332         MovDir[x][y] =
2333           new_move_dir & (first_horiz ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
2334         Moving2Blocked(x, y, &newx, &newy);
2335
2336         if (IN_LEV_FIELD(newx, newy) &&
2337             (IS_FREE(newx, newy) ||
2338              Feld[newx][newy] == EL_SALZSAEURE ||
2339              (element == EL_PINGUIN &&
2340               (Feld[newx][newy] == EL_AUSGANG_AUF ||
2341                IS_MAMPF3(Feld[newx][newy])))))
2342           return;
2343
2344         MovDir[x][y] =
2345           new_move_dir & (!first_horiz ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
2346         Moving2Blocked(x, y, &newx, &newy);
2347
2348         if (IN_LEV_FIELD(newx, newy) &&
2349             (IS_FREE(newx, newy) ||
2350              Feld[newx][newy] == EL_SALZSAEURE ||
2351              (element == EL_PINGUIN &&
2352               (Feld[newx][newy] == EL_AUSGANG_AUF ||
2353                IS_MAMPF3(Feld[newx][newy])))))
2354           return;
2355
2356         MovDir[x][y] = old_move_dir;
2357         return;
2358       }
2359     }
2360   }
2361 }
2362
2363 static boolean JustBeingPushed(int x, int y)
2364 {
2365   int i;
2366
2367   for (i=0; i<MAX_PLAYERS; i++)
2368   {
2369     struct PlayerInfo *player = &stored_player[i];
2370
2371     if (player->active && player->Pushing && player->MovPos)
2372     {
2373       int next_jx = player->jx + (player->jx - player->last_jx);
2374       int next_jy = player->jy + (player->jy - player->last_jy);
2375
2376       if (x == next_jx && y == next_jy)
2377         return TRUE;
2378     }
2379   }
2380
2381   return FALSE;
2382 }
2383
2384 void StartMoving(int x, int y)
2385 {
2386   int element = Feld[x][y];
2387
2388   if (Stop[x][y])
2389     return;
2390
2391   if (CAN_FALL(element) && y<lev_fieldy-1)
2392   {
2393     if ((x>0 && IS_PLAYER(x-1, y)) || (x<lev_fieldx-1 && IS_PLAYER(x+1, y)))
2394       if (JustBeingPushed(x, y))
2395         return;
2396
2397     if (element == EL_MORAST_VOLL)
2398     {
2399       if (IS_FREE(x, y+1))
2400       {
2401         InitMovingField(x, y, MV_DOWN);
2402         Feld[x][y] = EL_FELSBROCKEN;
2403         Store[x][y] = EL_MORAST_LEER;
2404       }
2405       else if (Feld[x][y+1] == EL_MORAST_LEER)
2406       {
2407         if (!MovDelay[x][y])
2408           MovDelay[x][y] = TILEY + 1;
2409
2410         if (MovDelay[x][y])
2411         {
2412           MovDelay[x][y]--;
2413           if (MovDelay[x][y])
2414             return;
2415         }
2416
2417         Feld[x][y] = EL_MORAST_LEER;
2418         Feld[x][y+1] = EL_MORAST_VOLL;
2419       }
2420     }
2421     else if (element == EL_FELSBROCKEN && Feld[x][y+1] == EL_MORAST_LEER)
2422     {
2423       InitMovingField(x, y, MV_DOWN);
2424       Store[x][y] = EL_MORAST_VOLL;
2425     }
2426     else if (element == EL_SIEB_VOLL)
2427     {
2428       if (IS_FREE(x, y+1))
2429       {
2430         InitMovingField(x, y, MV_DOWN);
2431         Feld[x][y] = EL_CHANGED(Store2[x][y]);
2432         Store[x][y] = EL_SIEB_LEER;
2433       }
2434       else if (Feld[x][y+1] == EL_SIEB_LEER)
2435       {
2436         if (!MovDelay[x][y])
2437           MovDelay[x][y] = TILEY/4 + 1;
2438
2439         if (MovDelay[x][y])
2440         {
2441           MovDelay[x][y]--;
2442           if (MovDelay[x][y])
2443             return;
2444         }
2445
2446         Feld[x][y] = EL_SIEB_LEER;
2447         Feld[x][y+1] = EL_SIEB_VOLL;
2448         Store2[x][y+1] = EL_CHANGED(Store2[x][y]);
2449         Store2[x][y] = 0;
2450       }
2451     }
2452     else if (element == EL_SIEB2_VOLL)
2453     {
2454       if (IS_FREE(x, y+1))
2455       {
2456         InitMovingField(x, y, MV_DOWN);
2457         Feld[x][y] = EL_CHANGED2(Store2[x][y]);
2458         Store[x][y] = EL_SIEB2_LEER;
2459       }
2460       else if (Feld[x][y+1] == EL_SIEB2_LEER)
2461       {
2462         if (!MovDelay[x][y])
2463           MovDelay[x][y] = TILEY/4 + 1;
2464
2465         if (MovDelay[x][y])
2466         {
2467           MovDelay[x][y]--;
2468           if (MovDelay[x][y])
2469             return;
2470         }
2471
2472         Feld[x][y] = EL_SIEB2_LEER;
2473         Feld[x][y+1] = EL_SIEB2_VOLL;
2474         Store2[x][y+1] = EL_CHANGED2(Store2[x][y]);
2475         Store2[x][y] = 0;
2476       }
2477     }
2478     else if (CAN_CHANGE(element) &&
2479              (Feld[x][y+1] == EL_SIEB_LEER || Feld[x][y+1] == EL_SIEB2_LEER))
2480     {
2481       InitMovingField(x, y, MV_DOWN);
2482       Store[x][y] =
2483         (Feld[x][y+1] == EL_SIEB_LEER ? EL_SIEB_VOLL : EL_SIEB2_VOLL);
2484       Store2[x][y+1] = element;
2485     }
2486     else if (CAN_SMASH(element) && Feld[x][y+1] == EL_SALZSAEURE)
2487     {
2488       Blurb(x, y);
2489       InitMovingField(x, y, MV_DOWN);
2490       Store[x][y] = EL_SALZSAEURE;
2491     }
2492     else if (CAN_SMASH(element) && Feld[x][y+1] == EL_BLOCKED &&
2493              JustStopped[x][y])
2494     {
2495       Impact(x, y);
2496     }
2497     else if (IS_FREE(x, y+1))
2498     {
2499       InitMovingField(x, y, MV_DOWN);
2500     }
2501     else if (element == EL_TROPFEN)
2502     {
2503       Feld[x][y] = EL_AMOEBING;
2504       Store[x][y] = EL_AMOEBE_NASS;
2505     }
2506 #if OLD_GAME_BEHAVIOUR
2507     else if (IS_SLIPPERY(Feld[x][y+1]) && !Store[x][y+1])
2508 #else
2509     else if (IS_SLIPPERY(Feld[x][y+1]) && !Store[x][y+1] &&
2510              !IS_FALLING(x, y+1) && !JustStopped[x][y+1])
2511 #endif
2512     {
2513       boolean left  = (x>0 && IS_FREE(x-1, y) &&
2514                        (IS_FREE(x-1, y+1) || Feld[x-1][y+1] == EL_SALZSAEURE));
2515       boolean right = (x<lev_fieldx-1 && IS_FREE(x+1, y) &&
2516                        (IS_FREE(x+1, y+1) || Feld[x+1][y+1] == EL_SALZSAEURE));
2517
2518       if (left || right)
2519       {
2520         if (left && right && game.emulation != EMU_BOULDERDASH)
2521           left = !(right = RND(2));
2522
2523         InitMovingField(x, y, left ? MV_LEFT : MV_RIGHT);
2524       }
2525     }
2526     else if (IS_BELT(Feld[x][y+1]))
2527     {
2528       boolean left_is_free  = (x>0 && IS_FREE(x-1, y));
2529       boolean right_is_free = (x<lev_fieldx-1 && IS_FREE(x+1, y));
2530       int belt_nr = getBeltNrFromElement(Feld[x][y+1]);
2531       int belt_dir = game.belt_dir[belt_nr];
2532
2533       if ((belt_dir == MV_LEFT  && left_is_free) ||
2534           (belt_dir == MV_RIGHT && right_is_free))
2535         InitMovingField(x, y, belt_dir);
2536     }
2537   }
2538   else if (CAN_MOVE(element))
2539   {
2540     int newx, newy;
2541
2542     if ((element == EL_SONDE || element == EL_BALLOON)
2543         && JustBeingPushed(x, y))
2544       return;
2545
2546     if (!MovDelay[x][y])        /* start new movement phase */
2547     {
2548       /* all objects that can change their move direction after each step */
2549       /* (MAMPFER, MAMPFER2 and PACMAN go straight until they hit a wall  */
2550
2551       if (element!=EL_MAMPFER && element!=EL_MAMPFER2 && element!=EL_PACMAN)
2552       {
2553         TurnRound(x, y);
2554         if (MovDelay[x][y] && (element == EL_KAEFER ||
2555                                element == EL_FLIEGER ||
2556                                element == EL_SP_SNIKSNAK ||
2557                                element == EL_SP_ELECTRON ||
2558                                element == EL_MOLE))
2559           DrawLevelField(x, y);
2560       }
2561     }
2562
2563     if (MovDelay[x][y])         /* wait some time before next movement */
2564     {
2565       MovDelay[x][y]--;
2566
2567       if (element == EL_ROBOT ||
2568           element == EL_MAMPFER || element == EL_MAMPFER2)
2569       {
2570         int phase = MovDelay[x][y] % 8;
2571
2572         if (phase>3)
2573           phase = 7-phase;
2574
2575         if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2576           DrawGraphic(SCREENX(x), SCREENY(y), el2gfx(element)+phase);
2577
2578         if ((element == EL_MAMPFER || element == EL_MAMPFER2)
2579             && MovDelay[x][y]%4 == 3)
2580           PlaySoundLevel(x, y, SND_NJAM);
2581       }
2582       else if (element == EL_SP_ELECTRON)
2583         DrawGraphicAnimation(x, y, GFX2_SP_ELECTRON, 8, 2, ANIM_NORMAL);
2584       else if (element == EL_DRACHE)
2585       {
2586         int i;
2587         int dir = MovDir[x][y];
2588         int dx = (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2589         int dy = (dir == MV_UP   ? -1 : dir == MV_DOWN  ? +1 : 0);
2590         int graphic = (dir == MV_LEFT   ? GFX_FLAMMEN_LEFT :
2591                        dir == MV_RIGHT  ? GFX_FLAMMEN_RIGHT :
2592                        dir == MV_UP     ? GFX_FLAMMEN_UP :
2593                        dir == MV_DOWN   ? GFX_FLAMMEN_DOWN : GFX_LEERRAUM);
2594         int phase = FrameCounter % 2;
2595
2596         for (i=1; i<=3; i++)
2597         {
2598           int xx = x + i*dx, yy = y + i*dy;
2599           int sx = SCREENX(xx), sy = SCREENY(yy);
2600
2601           if (!IN_LEV_FIELD(xx, yy) ||
2602               IS_SOLID(Feld[xx][yy]) || Feld[xx][yy] == EL_EXPLODING)
2603             break;
2604
2605           if (MovDelay[x][y])
2606           {
2607             int flamed = MovingOrBlocked2Element(xx, yy);
2608
2609             if (IS_ENEMY(flamed) || IS_EXPLOSIVE(flamed))
2610               Bang(xx, yy);
2611             else
2612               RemoveMovingField(xx, yy);
2613
2614             Feld[xx][yy] = EL_BURNING;
2615             if (IN_SCR_FIELD(sx, sy))
2616               DrawGraphic(sx, sy, graphic + phase*3 + i-1);
2617           }
2618           else
2619           {
2620             if (Feld[xx][yy] == EL_BURNING)
2621               Feld[xx][yy] = EL_LEERRAUM;
2622             DrawLevelField(xx, yy);
2623           }
2624         }
2625       }
2626
2627       if (MovDelay[x][y])
2628         return;
2629     }
2630
2631     if (element == EL_KAEFER || element == EL_BUTTERFLY)
2632     {
2633       PlaySoundLevel(x, y, SND_KLAPPER);
2634     }
2635     else if (element == EL_FLIEGER || element == EL_FIREFLY)
2636     {
2637       PlaySoundLevel(x, y, SND_ROEHR);
2638     }
2639
2640     /* now make next step */
2641
2642     Moving2Blocked(x, y, &newx, &newy); /* get next screen position */
2643
2644     if (IS_ENEMY(element) && IS_PLAYER(newx, newy) &&
2645         !PLAYER_PROTECTED(newx, newy))
2646     {
2647
2648 #if 1
2649       TestIfBadThingHitsHero(x, y);
2650       return;
2651 #else
2652       /* enemy got the player */
2653       MovDir[x][y] = 0;
2654       KillHero(PLAYERINFO(newx, newy));
2655       return;
2656 #endif
2657
2658     }
2659     else if ((element == EL_PINGUIN || element == EL_ROBOT ||
2660               element == EL_SONDE || element == EL_BALLOON) &&
2661              IN_LEV_FIELD(newx, newy) &&
2662              MovDir[x][y] == MV_DOWN && Feld[newx][newy] == EL_SALZSAEURE)
2663     {
2664       Blurb(x, y);
2665       Store[x][y] = EL_SALZSAEURE;
2666     }
2667     else if (element == EL_PINGUIN && IN_LEV_FIELD(newx, newy))
2668     {
2669       if (Feld[newx][newy] == EL_AUSGANG_AUF)
2670       {
2671         Feld[x][y] = EL_LEERRAUM;
2672         DrawLevelField(x, y);
2673
2674         PlaySoundLevel(newx, newy, SND_BUING);
2675         if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2676           DrawGraphicThruMask(SCREENX(newx), SCREENY(newy), el2gfx(element));
2677
2678         local_player->friends_still_needed--;
2679         if (!local_player->friends_still_needed &&
2680             !local_player->GameOver && AllPlayersGone)
2681           local_player->LevelSolved = local_player->GameOver = TRUE;
2682
2683         return;
2684       }
2685       else if (IS_MAMPF3(Feld[newx][newy]))
2686       {
2687         if (DigField(local_player, newx, newy, 0, 0, DF_DIG) == MF_MOVING)
2688           DrawLevelField(newx, newy);
2689         else
2690           MovDir[x][y] = MV_NO_MOVING;
2691       }
2692       else if (!IS_FREE(newx, newy))
2693       {
2694         if (IS_PLAYER(x, y))
2695           DrawPlayerField(x, y);
2696         else
2697           DrawLevelField(x, y);
2698         return;
2699       }
2700     }
2701     else if (element == EL_SCHWEIN && IN_LEV_FIELD(newx, newy))
2702     {
2703       if (IS_GEM(Feld[newx][newy]))
2704       {
2705         if (IS_MOVING(newx, newy))
2706           RemoveMovingField(newx, newy);
2707         else
2708         {
2709           Feld[newx][newy] = EL_LEERRAUM;
2710           DrawLevelField(newx, newy);
2711         }
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_DRACHE && IN_LEV_FIELD(newx, newy))
2723     {
2724       if (!IS_FREE(newx, newy))
2725       {
2726         if (IS_PLAYER(x, y))
2727           DrawPlayerField(x, y);
2728         else
2729           DrawLevelField(x, y);
2730         return;
2731       }
2732       else
2733       {
2734         boolean wanna_flame = !RND(10);
2735         int dx = newx - x, dy = newy - y;
2736         int newx1 = newx+1*dx, newy1 = newy+1*dy;
2737         int newx2 = newx+2*dx, newy2 = newy+2*dy;
2738         int element1 = (IN_LEV_FIELD(newx1, newy1) ?
2739                         MovingOrBlocked2Element(newx1, newy1) : EL_BETON);
2740         int element2 = (IN_LEV_FIELD(newx2, newy2) ?
2741                         MovingOrBlocked2Element(newx2, newy2) : EL_BETON);
2742
2743         if ((wanna_flame || IS_ENEMY(element1) || IS_ENEMY(element2)) &&
2744             element1 != EL_DRACHE && element2 != EL_DRACHE &&
2745             element1 != EL_BURNING && element2 != EL_BURNING)
2746         {
2747           if (IS_PLAYER(x, y))
2748             DrawPlayerField(x, y);
2749           else
2750             DrawLevelField(x, y);
2751
2752           MovDelay[x][y] = 50;
2753           Feld[newx][newy] = EL_BURNING;
2754           if (IN_LEV_FIELD(newx1, newy1) && Feld[newx1][newy1] == EL_LEERRAUM)
2755             Feld[newx1][newy1] = EL_BURNING;
2756           if (IN_LEV_FIELD(newx2, newy2) && Feld[newx2][newy2] == EL_LEERRAUM)
2757             Feld[newx2][newy2] = EL_BURNING;
2758           return;
2759         }
2760       }
2761     }
2762     else if (element == EL_MAMPFER && IN_LEV_FIELD(newx, newy) &&
2763              Feld[newx][newy] == EL_DIAMANT)
2764     {
2765       if (IS_MOVING(newx, newy))
2766         RemoveMovingField(newx, newy);
2767       else
2768       {
2769         Feld[newx][newy] = EL_LEERRAUM;
2770         DrawLevelField(newx, newy);
2771       }
2772     }
2773     else if (element == EL_MAMPFER2 && IN_LEV_FIELD(newx, newy) &&
2774              IS_MAMPF2(Feld[newx][newy]))
2775     {
2776       if (AmoebaNr[newx][newy])
2777       {
2778         AmoebaCnt2[AmoebaNr[newx][newy]]--;
2779         if (Feld[newx][newy] == EL_AMOEBE_VOLL ||
2780             Feld[newx][newy] == EL_AMOEBE_BD)
2781           AmoebaCnt[AmoebaNr[newx][newy]]--;
2782       }
2783
2784       if (IS_MOVING(newx, newy))
2785         RemoveMovingField(newx, newy);
2786       else
2787       {
2788         Feld[newx][newy] = EL_LEERRAUM;
2789         DrawLevelField(newx, newy);
2790       }
2791     }
2792     else if ((element == EL_PACMAN || element == EL_MOLE)
2793              && IN_LEV_FIELD(newx, newy) && IS_AMOEBOID(Feld[newx][newy]))
2794     {
2795       if (AmoebaNr[newx][newy])
2796       {
2797         AmoebaCnt2[AmoebaNr[newx][newy]]--;
2798         if (Feld[newx][newy] == EL_AMOEBE_VOLL ||
2799             Feld[newx][newy] == EL_AMOEBE_BD)
2800           AmoebaCnt[AmoebaNr[newx][newy]]--;
2801       }
2802
2803       if (element == EL_MOLE)
2804       {
2805         Feld[newx][newy] = EL_DEAMOEBING;
2806         MovDelay[newx][newy] = 0;       /* start amoeba shrinking delay */
2807         return;                         /* wait for shrinking amoeba */
2808       }
2809       else      /* element == EL_PACMAN */
2810       {
2811         Feld[newx][newy] = EL_LEERRAUM;
2812         DrawLevelField(newx, newy);
2813       }
2814     }
2815     else if (element == EL_MOLE && IN_LEV_FIELD(newx, newy) &&
2816              (Feld[newx][newy] == EL_DEAMOEBING ||
2817               (Feld[newx][newy] == EL_LEERRAUM && Stop[newx][newy])))
2818     {
2819       /* wait for shrinking amoeba to completely disappear */
2820       return;
2821     }
2822     else if (!IN_LEV_FIELD(newx, newy) || !IS_FREE(newx, newy))
2823     {
2824       /* object was running against a wall */
2825
2826       TurnRound(x, y);
2827
2828       if (element == EL_KAEFER || element == EL_FLIEGER ||
2829           element == EL_SP_SNIKSNAK || element == EL_MOLE)
2830         DrawLevelField(x, y);
2831       else if (element == EL_BUTTERFLY || element == EL_FIREFLY)
2832         DrawGraphicAnimation(x, y, el2gfx(element), 2, 4, ANIM_NORMAL);
2833       else if (element == EL_SONDE)
2834         DrawGraphicAnimation(x, y, GFX_SONDE_START, 8, 2, ANIM_NORMAL);
2835       else if (element == EL_SP_ELECTRON)
2836         DrawGraphicAnimation(x, y, GFX2_SP_ELECTRON, 8, 2, ANIM_NORMAL);
2837
2838       if (DONT_TOUCH(element))
2839         TestIfBadThingHitsHero(x, y);
2840
2841       return;
2842     }
2843
2844     if (element == EL_ROBOT && IN_SCR_FIELD(x, y))
2845       PlaySoundLevel(x, y, SND_SCHLURF);
2846
2847     InitMovingField(x, y, MovDir[x][y]);
2848   }
2849
2850   if (MovDir[x][y])
2851     ContinueMoving(x, y);
2852 }
2853
2854 void ContinueMoving(int x, int y)
2855 {
2856   int element = Feld[x][y];
2857   int direction = MovDir[x][y];
2858   int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
2859   int dy = (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
2860   int horiz_move = (dx!=0);
2861   int newx = x + dx, newy = y + dy;
2862   int step = (horiz_move ? dx : dy) * TILEX / 8;
2863
2864   if (element == EL_TROPFEN)
2865     step /= 2;
2866   else if (Store[x][y] == EL_MORAST_VOLL || Store[x][y] == EL_MORAST_LEER)
2867     step /= 4;
2868   else if (CAN_FALL(element) && horiz_move &&
2869            y < lev_fieldy-1 && IS_BELT(Feld[x][y+1]))
2870     step /= 2;
2871
2872 #if OLD_GAME_BEHAVIOUR
2873   else if (CAN_FALL(element) && horiz_move && !IS_SP_ELEMENT(element))
2874     step*=2;
2875 #endif
2876
2877   MovPos[x][y] += step;
2878
2879   if (ABS(MovPos[x][y])>=TILEX)         /* object reached its destination */
2880   {
2881     Feld[x][y] = EL_LEERRAUM;
2882     Feld[newx][newy] = element;
2883
2884     if (element == EL_MOLE)
2885     {
2886       int i;
2887       static int xy[4][2] =
2888       {
2889         { 0, -1 },
2890         { -1, 0 },
2891         { +1, 0 },
2892         { 0, +1 }
2893       };
2894
2895       Feld[x][y] = EL_ERDREICH;
2896       DrawLevelField(x, y);
2897
2898       for(i=0; i<4; i++)
2899       {
2900         int xx, yy;
2901
2902         xx = x + xy[i][0];
2903         yy = y + xy[i][1];
2904
2905         if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == EL_ERDREICH)
2906           DrawLevelField(xx, yy);       /* for "ErdreichAnbroeckeln()" */
2907       }
2908     }
2909
2910     if (Store[x][y] == EL_MORAST_VOLL)
2911     {
2912       Store[x][y] = 0;
2913       Feld[newx][newy] = EL_MORAST_VOLL;
2914       element = EL_MORAST_VOLL;
2915     }
2916     else if (Store[x][y] == EL_MORAST_LEER)
2917     {
2918       Store[x][y] = 0;
2919       Feld[x][y] = EL_MORAST_LEER;
2920     }
2921     else if (Store[x][y] == EL_SIEB_VOLL)
2922     {
2923       Store[x][y] = 0;
2924       element = Feld[newx][newy] =
2925         (game.magic_wall_active ? EL_SIEB_VOLL : EL_SIEB_TOT);
2926     }
2927     else if (Store[x][y] == EL_SIEB_LEER)
2928     {
2929       Store[x][y] = Store2[x][y] = 0;
2930       Feld[x][y] = (game.magic_wall_active ? EL_SIEB_LEER : EL_SIEB_TOT);
2931     }
2932     else if (Store[x][y] == EL_SIEB2_VOLL)
2933     {
2934       Store[x][y] = 0;
2935       element = Feld[newx][newy] =
2936         (game.magic_wall_active ? EL_SIEB2_VOLL : EL_SIEB2_TOT);
2937     }
2938     else if (Store[x][y] == EL_SIEB2_LEER)
2939     {
2940       Store[x][y] = Store2[x][y] = 0;
2941       Feld[x][y] = (game.magic_wall_active ? EL_SIEB2_LEER : EL_SIEB2_TOT);
2942     }
2943     else if (Store[x][y] == EL_SALZSAEURE)
2944     {
2945       Store[x][y] = 0;
2946       Feld[newx][newy] = EL_SALZSAEURE;
2947       element = EL_SALZSAEURE;
2948     }
2949     else if (Store[x][y] == EL_AMOEBE_NASS)
2950     {
2951       Store[x][y] = 0;
2952       Feld[x][y] = EL_AMOEBE_NASS;
2953     }
2954
2955     MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
2956     MovDelay[newx][newy] = 0;
2957
2958     if (!CAN_MOVE(element))
2959       MovDir[newx][newy] = 0;
2960
2961     DrawLevelField(x, y);
2962     DrawLevelField(newx, newy);
2963
2964     Stop[newx][newy] = TRUE;
2965     JustStopped[newx][newy] = 3;
2966
2967     if (DONT_TOUCH(element))    /* object may be nasty to player or others */
2968     {
2969       TestIfBadThingHitsHero(newx, newy);
2970       TestIfBadThingHitsFriend(newx, newy);
2971       TestIfBadThingHitsOtherBadThing(newx, newy);
2972     }
2973     else if (element == EL_PINGUIN)
2974       TestIfFriendHitsBadThing(newx, newy);
2975
2976     if (CAN_SMASH(element) && direction == MV_DOWN &&
2977         (newy == lev_fieldy-1 || !IS_FREE(x, newy+1)))
2978       Impact(x, newy);
2979   }
2980   else                          /* still moving on */
2981     DrawLevelField(x, y);
2982 }
2983
2984 int AmoebeNachbarNr(int ax, int ay)
2985 {
2986   int i;
2987   int element = Feld[ax][ay];
2988   int group_nr = 0;
2989   static int xy[4][2] =
2990   {
2991     { 0, -1 },
2992     { -1, 0 },
2993     { +1, 0 },
2994     { 0, +1 }
2995   };
2996
2997   for (i=0; i<4; i++)
2998   {
2999     int x = ax + xy[i][0];
3000     int y = ay + xy[i][1];
3001
3002     if (!IN_LEV_FIELD(x, y))
3003       continue;
3004
3005     if (Feld[x][y] == element && AmoebaNr[x][y] > 0)
3006       group_nr = AmoebaNr[x][y];
3007   }
3008
3009   return group_nr;
3010 }
3011
3012 void AmoebenVereinigen(int ax, int ay)
3013 {
3014   int i, x, y, xx, yy;
3015   int new_group_nr = AmoebaNr[ax][ay];
3016   static int xy[4][2] =
3017   {
3018     { 0, -1 },
3019     { -1, 0 },
3020     { +1, 0 },
3021     { 0, +1 }
3022   };
3023
3024   if (new_group_nr == 0)
3025     return;
3026
3027   for (i=0; i<4; i++)
3028   {
3029     x = ax + xy[i][0];
3030     y = ay + xy[i][1];
3031
3032     if (!IN_LEV_FIELD(x, y))
3033       continue;
3034
3035     if ((Feld[x][y] == EL_AMOEBE_VOLL ||
3036          Feld[x][y] == EL_AMOEBE_BD ||
3037          Feld[x][y] == EL_AMOEBE_TOT) &&
3038         AmoebaNr[x][y] != new_group_nr)
3039     {
3040       int old_group_nr = AmoebaNr[x][y];
3041
3042       if (old_group_nr == 0)
3043         return;
3044
3045       AmoebaCnt[new_group_nr] += AmoebaCnt[old_group_nr];
3046       AmoebaCnt[old_group_nr] = 0;
3047       AmoebaCnt2[new_group_nr] += AmoebaCnt2[old_group_nr];
3048       AmoebaCnt2[old_group_nr] = 0;
3049
3050       for (yy=0; yy<lev_fieldy; yy++)
3051       {
3052         for (xx=0; xx<lev_fieldx; xx++)
3053         {
3054           if (AmoebaNr[xx][yy] == old_group_nr)
3055             AmoebaNr[xx][yy] = new_group_nr;
3056         }
3057       }
3058     }
3059   }
3060 }
3061
3062 void AmoebeUmwandeln(int ax, int ay)
3063 {
3064   int i, x, y;
3065
3066   if (Feld[ax][ay] == EL_AMOEBE_TOT)
3067   {
3068     int group_nr = AmoebaNr[ax][ay];
3069
3070 #ifdef DEBUG
3071     if (group_nr == 0)
3072     {
3073       printf("AmoebeUmwandeln(): ax = %d, ay = %d\n", ax, ay);
3074       printf("AmoebeUmwandeln(): This should never happen!\n");
3075       return;
3076     }
3077 #endif
3078
3079     for (y=0; y<lev_fieldy; y++)
3080     {
3081       for (x=0; x<lev_fieldx; x++)
3082       {
3083         if (Feld[x][y] == EL_AMOEBE_TOT && AmoebaNr[x][y] == group_nr)
3084         {
3085           AmoebaNr[x][y] = 0;
3086           Feld[x][y] = EL_AMOEBA2DIAM;
3087         }
3088       }
3089     }
3090     Bang(ax, ay);
3091   }
3092   else
3093   {
3094     static int xy[4][2] =
3095     {
3096       { 0, -1 },
3097       { -1, 0 },
3098       { +1, 0 },
3099       { 0, +1 }
3100     };
3101
3102     for (i=0; i<4; i++)
3103     {
3104       x = ax + xy[i][0];
3105       y = ay + xy[i][1];
3106
3107       if (!IN_LEV_FIELD(x, y))
3108         continue;
3109
3110       if (Feld[x][y] == EL_AMOEBA2DIAM)
3111         Bang(x, y);
3112     }
3113   }
3114 }
3115
3116 void AmoebeUmwandelnBD(int ax, int ay, int new_element)
3117 {
3118   int x, y;
3119   int group_nr = AmoebaNr[ax][ay];
3120   boolean done = FALSE;
3121
3122 #ifdef DEBUG
3123   if (group_nr == 0)
3124   {
3125     printf("AmoebeUmwandelnBD(): ax = %d, ay = %d\n", ax, ay);
3126     printf("AmoebeUmwandelnBD(): This should never happen!\n");
3127     return;
3128   }
3129 #endif
3130
3131   for (y=0; y<lev_fieldy; y++)
3132   {
3133     for (x=0; x<lev_fieldx; x++)
3134     {
3135       if (AmoebaNr[x][y] == group_nr &&
3136           (Feld[x][y] == EL_AMOEBE_TOT ||
3137            Feld[x][y] == EL_AMOEBE_BD ||
3138            Feld[x][y] == EL_AMOEBING))
3139       {
3140         AmoebaNr[x][y] = 0;
3141         Feld[x][y] = new_element;
3142         InitField(x, y, FALSE);
3143         DrawLevelField(x, y);
3144         done = TRUE;
3145       }
3146     }
3147   }
3148
3149   if (done)
3150     PlaySoundLevel(ax, ay,
3151                    (new_element == EL_FELSBROCKEN ? SND_KLOPF : SND_PLING));
3152 }
3153
3154 void AmoebeWaechst(int x, int y)
3155 {
3156   static unsigned long sound_delay = 0;
3157   static unsigned long sound_delay_value = 0;
3158
3159   if (!MovDelay[x][y])          /* start new growing cycle */
3160   {
3161     MovDelay[x][y] = 7;
3162
3163     if (DelayReached(&sound_delay, sound_delay_value))
3164     {
3165       PlaySoundLevel(x, y, SND_AMOEBE);
3166       sound_delay_value = 30;
3167     }
3168   }
3169
3170   if (MovDelay[x][y])           /* wait some time before growing bigger */
3171   {
3172     MovDelay[x][y]--;
3173     if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3174       DrawGraphic(SCREENX(x), SCREENY(y), GFX_AMOEBING + 3 - MovDelay[x][y]/2);
3175
3176     if (!MovDelay[x][y])
3177     {
3178       Feld[x][y] = Store[x][y];
3179       Store[x][y] = 0;
3180       DrawLevelField(x, y);
3181     }
3182   }
3183 }
3184
3185 void AmoebeSchrumpft(int x, int y)
3186 {
3187   static unsigned long sound_delay = 0;
3188   static unsigned long sound_delay_value = 0;
3189
3190   if (!MovDelay[x][y])          /* start new shrinking cycle */
3191   {
3192     MovDelay[x][y] = 7;
3193
3194     if (DelayReached(&sound_delay, sound_delay_value))
3195     {
3196       PlaySoundLevel(x, y, SND_BLURB);
3197       sound_delay_value = 30;
3198     }
3199   }
3200
3201   if (MovDelay[x][y])           /* wait some time before shrinking */
3202   {
3203     MovDelay[x][y]--;
3204     if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3205       DrawGraphic(SCREENX(x), SCREENY(y), GFX_AMOEBING + MovDelay[x][y]/2);
3206
3207     if (!MovDelay[x][y])
3208     {
3209       Feld[x][y] = EL_LEERRAUM;
3210       DrawLevelField(x, y);
3211
3212       /* don't let mole enter this field in this cycle;
3213          (give priority to objects falling to this field from above) */
3214       Stop[x][y] = TRUE;
3215     }
3216   }
3217 }
3218
3219 void AmoebeAbleger(int ax, int ay)
3220 {
3221   int i;
3222   int element = Feld[ax][ay];
3223   int newax = ax, neway = ay;
3224   static int xy[4][2] =
3225   {
3226     { 0, -1 },
3227     { -1, 0 },
3228     { +1, 0 },
3229     { 0, +1 }
3230   };
3231
3232   if (!level.amoeba_speed)
3233   {
3234     Feld[ax][ay] = EL_AMOEBE_TOT;
3235     DrawLevelField(ax, ay);
3236     return;
3237   }
3238
3239   if (!MovDelay[ax][ay])        /* start making new amoeba field */
3240     MovDelay[ax][ay] = RND(FRAMES_PER_SECOND * 25 / (1 + level.amoeba_speed));
3241
3242   if (MovDelay[ax][ay])         /* wait some time before making new amoeba */
3243   {
3244     MovDelay[ax][ay]--;
3245     if (MovDelay[ax][ay])
3246       return;
3247   }
3248
3249   if (element == EL_AMOEBE_NASS)        /* object is an acid / amoeba drop */
3250   {
3251     int start = RND(4);
3252     int x = ax + xy[start][0];
3253     int y = ay + xy[start][1];
3254
3255     if (!IN_LEV_FIELD(x, y))
3256       return;
3257
3258     if (IS_FREE(x, y) ||
3259         Feld[x][y] == EL_ERDREICH || Feld[x][y] == EL_MORAST_LEER)
3260     {
3261       newax = x;
3262       neway = y;
3263     }
3264
3265     if (newax == ax && neway == ay)
3266       return;
3267   }
3268   else                          /* normal or "filled" (BD style) amoeba */
3269   {
3270     int start = RND(4);
3271     boolean waiting_for_player = FALSE;
3272
3273     for (i=0; i<4; i++)
3274     {
3275       int j = (start + i) % 4;
3276       int x = ax + xy[j][0];
3277       int y = ay + xy[j][1];
3278
3279       if (!IN_LEV_FIELD(x, y))
3280         continue;
3281
3282       if (IS_FREE(x, y) ||
3283           Feld[x][y] == EL_ERDREICH || Feld[x][y] == EL_MORAST_LEER)
3284       {
3285         newax = x;
3286         neway = y;
3287         break;
3288       }
3289       else if (IS_PLAYER(x, y))
3290         waiting_for_player = TRUE;
3291     }
3292
3293     if (newax == ax && neway == ay)             /* amoeba cannot grow */
3294     {
3295       if (i == 4 && (!waiting_for_player || game.emulation == EMU_BOULDERDASH))
3296       {
3297         Feld[ax][ay] = EL_AMOEBE_TOT;
3298         DrawLevelField(ax, ay);
3299         AmoebaCnt[AmoebaNr[ax][ay]]--;
3300
3301         if (AmoebaCnt[AmoebaNr[ax][ay]] <= 0)   /* amoeba is completely dead */
3302         {
3303           if (element == EL_AMOEBE_VOLL)
3304             AmoebeUmwandeln(ax, ay);
3305           else if (element == EL_AMOEBE_BD)
3306             AmoebeUmwandelnBD(ax, ay, level.amoeba_content);
3307         }
3308       }
3309       return;
3310     }
3311     else if (element == EL_AMOEBE_VOLL || element == EL_AMOEBE_BD)
3312     {
3313       /* amoeba gets larger by growing in some direction */
3314
3315       int new_group_nr = AmoebaNr[ax][ay];
3316
3317 #ifdef DEBUG
3318   if (new_group_nr == 0)
3319   {
3320     printf("AmoebeAbleger(): newax = %d, neway = %d\n", newax, neway);
3321     printf("AmoebeAbleger(): This should never happen!\n");
3322     return;
3323   }
3324 #endif
3325
3326       AmoebaNr[newax][neway] = new_group_nr;
3327       AmoebaCnt[new_group_nr]++;
3328       AmoebaCnt2[new_group_nr]++;
3329
3330       /* if amoeba touches other amoeba(s) after growing, unify them */
3331       AmoebenVereinigen(newax, neway);
3332
3333       if (element == EL_AMOEBE_BD && AmoebaCnt2[new_group_nr] >= 200)
3334       {
3335         AmoebeUmwandelnBD(newax, neway, EL_FELSBROCKEN);
3336         return;
3337       }
3338     }
3339   }
3340
3341   if (element != EL_AMOEBE_NASS || neway < ay || !IS_FREE(newax, neway) ||
3342       (neway == lev_fieldy - 1 && newax != ax))
3343   {
3344     Feld[newax][neway] = EL_AMOEBING;
3345     Store[newax][neway] = element;
3346   }
3347   else if (neway == ay)
3348     Feld[newax][neway] = EL_TROPFEN;
3349   else
3350   {
3351     InitMovingField(ax, ay, MV_DOWN);
3352     Feld[ax][ay] = EL_TROPFEN;
3353     Store[ax][ay] = EL_AMOEBE_NASS;
3354     ContinueMoving(ax, ay);
3355     return;
3356   }
3357
3358   DrawLevelField(newax, neway);
3359 }
3360
3361 void Life(int ax, int ay)
3362 {
3363   int x1, y1, x2, y2;
3364   static int life[4] = { 2, 3, 3, 3 };  /* parameters for "game of life" */
3365   int life_time = 40;
3366   int element = Feld[ax][ay];
3367
3368   if (Stop[ax][ay])
3369     return;
3370
3371   if (!MovDelay[ax][ay])        /* start new "game of life" cycle */
3372     MovDelay[ax][ay] = life_time;
3373
3374   if (MovDelay[ax][ay])         /* wait some time before next cycle */
3375   {
3376     MovDelay[ax][ay]--;
3377     if (MovDelay[ax][ay])
3378       return;
3379   }
3380
3381   for (y1=-1; y1<2; y1++) for(x1=-1; x1<2; x1++)
3382   {
3383     int xx = ax+x1, yy = ay+y1;
3384     int nachbarn = 0;
3385
3386     if (!IN_LEV_FIELD(xx, yy))
3387       continue;
3388
3389     for (y2=-1; y2<2; y2++) for (x2=-1; x2<2; x2++)
3390     {
3391       int x = xx+x2, y = yy+y2;
3392
3393       if (!IN_LEV_FIELD(x, y) || (x == xx && y == yy))
3394         continue;
3395
3396       if (((Feld[x][y] == element ||
3397             (element == EL_LIFE && IS_PLAYER(x, y))) &&
3398            !Stop[x][y]) ||
3399           (IS_FREE(x, y) && Stop[x][y]))
3400         nachbarn++;
3401     }
3402
3403     if (xx == ax && yy == ay)           /* field in the middle */
3404     {
3405       if (nachbarn<life[0] || nachbarn>life[1])
3406       {
3407         Feld[xx][yy] = EL_LEERRAUM;
3408         if (!Stop[xx][yy])
3409           DrawLevelField(xx, yy);
3410         Stop[xx][yy] = TRUE;
3411       }
3412     }
3413     else if (IS_FREE(xx, yy) || Feld[xx][yy] == EL_ERDREICH)
3414     {                                   /* free border field */
3415       if (nachbarn>=life[2] && nachbarn<=life[3])
3416       {
3417         Feld[xx][yy] = element;
3418         MovDelay[xx][yy] = (element == EL_LIFE ? 0 : life_time-1);
3419         if (!Stop[xx][yy])
3420           DrawLevelField(xx, yy);
3421         Stop[xx][yy] = TRUE;
3422       }
3423     }
3424   }
3425 }
3426
3427 void Ablenk(int x, int y)
3428 {
3429   if (!MovDelay[x][y])          /* next animation frame */
3430     MovDelay[x][y] = level.time_wheel * FRAMES_PER_SECOND;
3431
3432   if (MovDelay[x][y])           /* wait some time before next frame */
3433   {
3434     MovDelay[x][y]--;
3435     if (MovDelay[x][y])
3436     {
3437       if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3438         DrawGraphic(SCREENX(x), SCREENY(y), GFX_ABLENK+MovDelay[x][y]%4);
3439       if (!(MovDelay[x][y]%4))
3440         PlaySoundLevel(x, y, SND_MIEP);
3441       return;
3442     }
3443   }
3444
3445   Feld[x][y] = EL_ABLENK_AUS;
3446   DrawLevelField(x, y);
3447   if (ZX == x && ZY == y)
3448     ZX = ZY = -1;
3449 }
3450
3451 void TimegateWheel(int x, int y)
3452 {
3453   if (!MovDelay[x][y])          /* next animation frame */
3454     MovDelay[x][y] = level.time_wheel * FRAMES_PER_SECOND;
3455
3456   if (MovDelay[x][y])           /* wait some time before next frame */
3457   {
3458     MovDelay[x][y]--;
3459     if (MovDelay[x][y])
3460     {
3461       if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3462         DrawGraphic(SCREENX(x), SCREENY(y),
3463                     GFX_TIMEGATE_SWITCH + MovDelay[x][y]%4);
3464       if (!(MovDelay[x][y]%4))
3465         PlaySoundLevel(x, y, SND_MIEP);
3466       return;
3467     }
3468   }
3469
3470   Feld[x][y] = EL_TIMEGATE_SWITCH_OFF;
3471   DrawLevelField(x, y);
3472   if (ZX == x && ZY == y)
3473     ZX = ZY = -1;
3474 }
3475
3476 void Birne(int x, int y)
3477 {
3478   if (!MovDelay[x][y])          /* next animation frame */
3479     MovDelay[x][y] = 800;
3480
3481   if (MovDelay[x][y])           /* wait some time before next frame */
3482   {
3483     MovDelay[x][y]--;
3484     if (MovDelay[x][y])
3485     {
3486       if (!(MovDelay[x][y]%5))
3487       {
3488         if (!(MovDelay[x][y]%10))
3489           Feld[x][y]=EL_ABLENK_EIN;
3490         else
3491           Feld[x][y]=EL_ABLENK_AUS;
3492         DrawLevelField(x, y);
3493         Feld[x][y]=EL_ABLENK_EIN;
3494       }
3495       return;
3496     }
3497   }
3498
3499   Feld[x][y]=EL_ABLENK_AUS;
3500   DrawLevelField(x, y);
3501   if (ZX == x && ZY == y)
3502     ZX=ZY=-1;
3503 }
3504
3505 void Blubber(int x, int y)
3506 {
3507   if (y > 0 && IS_MOVING(x, y-1) && MovDir[x][y-1] == MV_DOWN)
3508     DrawLevelField(x, y-1);
3509   else
3510     DrawGraphicAnimation(x, y, GFX_GEBLUBBER, 4, 10, ANIM_NORMAL);
3511 }
3512
3513 void NussKnacken(int x, int y)
3514 {
3515   if (!MovDelay[x][y])          /* next animation frame */
3516     MovDelay[x][y] = 7;
3517
3518   if (MovDelay[x][y])           /* wait some time before next frame */
3519   {
3520     MovDelay[x][y]--;
3521     if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3522       DrawGraphic(SCREENX(x), SCREENY(y),
3523                   GFX_CRACKINGNUT + 3 - MovDelay[x][y]/2);
3524
3525     if (!MovDelay[x][y])
3526     {
3527       Feld[x][y] = EL_EDELSTEIN;
3528       DrawLevelField(x, y);
3529     }
3530   }
3531 }
3532
3533 void BreakingPearl(int x, int y)
3534 {
3535   if (!MovDelay[x][y])          /* next animation frame */
3536     MovDelay[x][y] = 9;
3537
3538   if (MovDelay[x][y])           /* wait some time before next frame */
3539   {
3540     MovDelay[x][y]--;
3541     if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3542       DrawGraphic(SCREENX(x), SCREENY(y),
3543                   GFX_PEARL_BREAKING + 4 - MovDelay[x][y]/2);
3544
3545     if (!MovDelay[x][y])
3546     {
3547       Feld[x][y] = EL_LEERRAUM;
3548       DrawLevelField(x, y);
3549     }
3550   }
3551 }
3552
3553 void SiebAktivieren(int x, int y, int typ)
3554 {
3555   int graphic = (typ == 1 ? GFX_SIEB_VOLL : GFX_SIEB2_VOLL) + 3;
3556
3557   DrawGraphicAnimation(x, y, graphic, 4, 4, ANIM_REVERSE);
3558 }
3559
3560 void AusgangstuerPruefen(int x, int y)
3561 {
3562   if (!local_player->gems_still_needed &&
3563       !local_player->sokobanfields_still_needed &&
3564       !local_player->lights_still_needed)
3565   {
3566     Feld[x][y] = EL_AUSGANG_ACT;
3567
3568     PlaySoundLevel(x < LEVELX(BX1) ? LEVELX(BX1) :
3569                    (x > LEVELX(BX2) ? LEVELX(BX2) : x),
3570                    y < LEVELY(BY1) ? LEVELY(BY1) :
3571                    (y > LEVELY(BY2) ? LEVELY(BY2) : y),
3572                    SND_OEFFNEN);
3573   }
3574 }
3575
3576 void AusgangstuerOeffnen(int x, int y)
3577 {
3578   int delay = 6;
3579
3580   if (!MovDelay[x][y])          /* next animation frame */
3581     MovDelay[x][y] = 5*delay;
3582
3583   if (MovDelay[x][y])           /* wait some time before next frame */
3584   {
3585     int tuer;
3586
3587     MovDelay[x][y]--;
3588     tuer = MovDelay[x][y]/delay;
3589     if (!(MovDelay[x][y]%delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3590       DrawGraphic(SCREENX(x), SCREENY(y), GFX_AUSGANG_AUF-tuer);
3591
3592     if (!MovDelay[x][y])
3593     {
3594       Feld[x][y] = EL_AUSGANG_AUF;
3595       DrawLevelField(x, y);
3596     }
3597   }
3598 }
3599
3600 void AusgangstuerBlinken(int x, int y)
3601 {
3602   DrawGraphicAnimation(x, y, GFX_AUSGANG_AUF, 4, 4, ANIM_OSCILLATE);
3603 }
3604
3605 void OpenSwitchgate(int x, int y)
3606 {
3607   int delay = 6;
3608
3609   if (!MovDelay[x][y])          /* next animation frame */
3610     MovDelay[x][y] = 5 * delay;
3611
3612   if (MovDelay[x][y])           /* wait some time before next frame */
3613   {
3614     int phase;
3615
3616     MovDelay[x][y]--;
3617     phase = MovDelay[x][y] / delay;
3618     if (!(MovDelay[x][y] % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3619       DrawGraphic(SCREENX(x), SCREENY(y), GFX_SWITCHGATE_OPEN - phase);
3620
3621     if (!MovDelay[x][y])
3622     {
3623       Feld[x][y] = EL_SWITCHGATE_OPEN;
3624       DrawLevelField(x, y);
3625     }
3626   }
3627 }
3628
3629 void CloseSwitchgate(int x, int y)
3630 {
3631   int delay = 6;
3632
3633   if (!MovDelay[x][y])          /* next animation frame */
3634     MovDelay[x][y] = 5 * delay;
3635
3636   if (MovDelay[x][y])           /* wait some time before next frame */
3637   {
3638     int phase;
3639
3640     MovDelay[x][y]--;
3641     phase = MovDelay[x][y] / delay;
3642     if (!(MovDelay[x][y] % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3643       DrawGraphic(SCREENX(x), SCREENY(y), GFX_SWITCHGATE_CLOSED + phase);
3644
3645     if (!MovDelay[x][y])
3646     {
3647       Feld[x][y] = EL_SWITCHGATE_CLOSED;
3648       DrawLevelField(x, y);
3649     }
3650   }
3651 }
3652
3653 void OpenTimegate(int x, int y)
3654 {
3655   int delay = 6;
3656
3657   if (!MovDelay[x][y])          /* next animation frame */
3658     MovDelay[x][y] = 5 * delay;
3659
3660   if (MovDelay[x][y])           /* wait some time before next frame */
3661   {
3662     int phase;
3663
3664     MovDelay[x][y]--;
3665     phase = MovDelay[x][y] / delay;
3666     if (!(MovDelay[x][y] % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3667       DrawGraphic(SCREENX(x), SCREENY(y), GFX_TIMEGATE_OPEN - phase);
3668
3669     if (!MovDelay[x][y])
3670     {
3671       Feld[x][y] = EL_TIMEGATE_OPEN;
3672       DrawLevelField(x, y);
3673     }
3674   }
3675 }
3676
3677 void CloseTimegate(int x, int y)
3678 {
3679   int delay = 6;
3680
3681   if (!MovDelay[x][y])          /* next animation frame */
3682     MovDelay[x][y] = 5 * delay;
3683
3684   if (MovDelay[x][y])           /* wait some time before next frame */
3685   {
3686     int phase;
3687
3688     MovDelay[x][y]--;
3689     phase = MovDelay[x][y] / delay;
3690     if (!(MovDelay[x][y] % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3691       DrawGraphic(SCREENX(x), SCREENY(y), GFX_TIMEGATE_CLOSED + phase);
3692
3693     if (!MovDelay[x][y])
3694     {
3695       Feld[x][y] = EL_TIMEGATE_CLOSED;
3696       DrawLevelField(x, y);
3697     }
3698   }
3699 }
3700
3701 static void CloseAllOpenTimegates()
3702 {
3703   int x, y;
3704
3705   for (y=0; y<lev_fieldy; y++)
3706   {
3707     for (x=0; x<lev_fieldx; x++)
3708     {
3709       int element = Feld[x][y];
3710
3711       if (element == EL_TIMEGATE_OPEN || element == EL_TIMEGATE_OPENING)
3712       {
3713         Feld[x][y] = EL_TIMEGATE_CLOSING;
3714         PlaySoundLevel(x, y, SND_OEFFNEN);
3715       }
3716     }
3717   }
3718 }
3719
3720 void EdelsteinFunkeln(int x, int y)
3721 {
3722   if (!IN_SCR_FIELD(SCREENX(x), SCREENY(y)) || IS_MOVING(x, y))
3723     return;
3724
3725   if (Feld[x][y] == EL_EDELSTEIN_BD)
3726     DrawGraphicAnimation(x, y, GFX_EDELSTEIN_BD, 4, 4, ANIM_REVERSE);
3727   else
3728   {
3729     if (!MovDelay[x][y])        /* next animation frame */
3730       MovDelay[x][y] = 11 * !SimpleRND(500);
3731
3732     if (MovDelay[x][y])         /* wait some time before next frame */
3733     {
3734       MovDelay[x][y]--;
3735
3736       if (setup.direct_draw && MovDelay[x][y])
3737         SetDrawtoField(DRAW_BUFFERED);
3738
3739       DrawGraphic(SCREENX(x), SCREENY(y), el2gfx(Feld[x][y]));
3740
3741       if (MovDelay[x][y])
3742       {
3743         int phase = (MovDelay[x][y]-1)/2;
3744
3745         if (phase > 2)
3746           phase = 4-phase;
3747
3748         DrawGraphicThruMask(SCREENX(x), SCREENY(y), GFX_FUNKELN_WEISS + phase);
3749
3750         if (setup.direct_draw)
3751         {
3752           int dest_x, dest_y;
3753
3754           dest_x = FX + SCREENX(x)*TILEX;
3755           dest_y = FY + SCREENY(y)*TILEY;
3756
3757           XCopyArea(display, drawto_field, window, gc,
3758                     dest_x, dest_y, TILEX, TILEY, dest_x, dest_y);
3759           SetDrawtoField(DRAW_DIRECT);
3760         }
3761       }
3762     }
3763   }
3764 }
3765
3766 void MauerWaechst(int x, int y)
3767 {
3768   int delay = 6;
3769
3770   if (!MovDelay[x][y])          /* next animation frame */
3771     MovDelay[x][y] = 3*delay;
3772
3773   if (MovDelay[x][y])           /* wait some time before next frame */
3774   {
3775     int phase;
3776
3777     MovDelay[x][y]--;
3778     phase = 2-MovDelay[x][y]/delay;
3779     if (!(MovDelay[x][y]%delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3780       DrawGraphic(SCREENX(x), SCREENY(y),
3781                   (MovDir[x][y] == MV_LEFT  ? GFX_MAUER_LEFT  :
3782                    MovDir[x][y] == MV_RIGHT ? GFX_MAUER_RIGHT :
3783                    MovDir[x][y] == MV_UP    ? GFX_MAUER_UP    :
3784                                               GFX_MAUER_DOWN  ) + phase);
3785
3786     if (!MovDelay[x][y])
3787     {
3788       if (MovDir[x][y] == MV_LEFT)
3789       {
3790         if (IN_LEV_FIELD(x-1, y) && IS_MAUER(Feld[x-1][y]))
3791           DrawLevelField(x-1, y);
3792       }
3793       else if (MovDir[x][y] == MV_RIGHT)
3794       {
3795         if (IN_LEV_FIELD(x+1, y) && IS_MAUER(Feld[x+1][y]))
3796           DrawLevelField(x+1, y);
3797       }
3798       else if (MovDir[x][y] == MV_UP)
3799       {
3800         if (IN_LEV_FIELD(x, y-1) && IS_MAUER(Feld[x][y-1]))
3801           DrawLevelField(x, y-1);
3802       }
3803       else
3804       {
3805         if (IN_LEV_FIELD(x, y+1) && IS_MAUER(Feld[x][y+1]))
3806           DrawLevelField(x, y+1);
3807       }
3808
3809       Feld[x][y] = Store[x][y];
3810       Store[x][y] = 0;
3811       MovDir[x][y] = MV_NO_MOVING;
3812       DrawLevelField(x, y);
3813     }
3814   }
3815 }
3816
3817 void MauerAbleger(int ax, int ay)
3818 {
3819   int element = Feld[ax][ay];
3820   boolean oben_frei = FALSE, unten_frei = FALSE;
3821   boolean links_frei = FALSE, rechts_frei = FALSE;
3822   boolean oben_massiv = FALSE, unten_massiv = FALSE;
3823   boolean links_massiv = FALSE, rechts_massiv = FALSE;
3824
3825   if (!MovDelay[ax][ay])        /* start building new wall */
3826     MovDelay[ax][ay] = 6;
3827
3828   if (MovDelay[ax][ay])         /* wait some time before building new wall */
3829   {
3830     MovDelay[ax][ay]--;
3831     if (MovDelay[ax][ay])
3832       return;
3833   }
3834
3835   if (IN_LEV_FIELD(ax, ay-1) && IS_FREE(ax, ay-1))
3836     oben_frei = TRUE;
3837   if (IN_LEV_FIELD(ax, ay+1) && IS_FREE(ax, ay+1))
3838     unten_frei = TRUE;
3839   if (IN_LEV_FIELD(ax-1, ay) && IS_FREE(ax-1, ay))
3840     links_frei = TRUE;
3841   if (IN_LEV_FIELD(ax+1, ay) && IS_FREE(ax+1, ay))
3842     rechts_frei = TRUE;
3843
3844   if (element == EL_MAUER_Y || element == EL_MAUER_XY)
3845   {
3846     if (oben_frei)
3847     {
3848       Feld[ax][ay-1] = EL_MAUERND;
3849       Store[ax][ay-1] = element;
3850       MovDir[ax][ay-1] = MV_UP;
3851       if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay-1)))
3852         DrawGraphic(SCREENX(ax), SCREENY(ay-1), GFX_MAUER_UP);
3853     }
3854     if (unten_frei)
3855     {
3856       Feld[ax][ay+1] = EL_MAUERND;
3857       Store[ax][ay+1] = element;
3858       MovDir[ax][ay+1] = MV_DOWN;
3859       if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay+1)))
3860         DrawGraphic(SCREENX(ax), SCREENY(ay+1), GFX_MAUER_DOWN);
3861     }
3862   }
3863
3864   if (element == EL_MAUER_X || element == EL_MAUER_XY ||
3865       element == EL_MAUER_LEBT)
3866   {
3867     if (links_frei)
3868     {
3869       Feld[ax-1][ay] = EL_MAUERND;
3870       Store[ax-1][ay] = element;
3871       MovDir[ax-1][ay] = MV_LEFT;
3872       if (IN_SCR_FIELD(SCREENX(ax-1), SCREENY(ay)))
3873         DrawGraphic(SCREENX(ax-1), SCREENY(ay), GFX_MAUER_LEFT);
3874     }
3875     if (rechts_frei)
3876     {
3877       Feld[ax+1][ay] = EL_MAUERND;
3878       Store[ax+1][ay] = element;
3879       MovDir[ax+1][ay] = MV_RIGHT;
3880       if (IN_SCR_FIELD(SCREENX(ax+1), SCREENY(ay)))
3881         DrawGraphic(SCREENX(ax+1), SCREENY(ay), GFX_MAUER_RIGHT);
3882     }
3883   }
3884
3885   if (element == EL_MAUER_LEBT && (links_frei || rechts_frei))
3886     DrawLevelField(ax, ay);
3887
3888   if (!IN_LEV_FIELD(ax, ay-1) || IS_MAUER(Feld[ax][ay-1]))
3889     oben_massiv = TRUE;
3890   if (!IN_LEV_FIELD(ax, ay+1) || IS_MAUER(Feld[ax][ay+1]))
3891     unten_massiv = TRUE;
3892   if (!IN_LEV_FIELD(ax-1, ay) || IS_MAUER(Feld[ax-1][ay]))
3893     links_massiv = TRUE;
3894   if (!IN_LEV_FIELD(ax+1, ay) || IS_MAUER(Feld[ax+1][ay]))
3895     rechts_massiv = TRUE;
3896
3897   if (((oben_massiv && unten_massiv) ||
3898        element == EL_MAUER_X || element == EL_MAUER_LEBT) &&
3899       ((links_massiv && rechts_massiv) ||
3900        element == EL_MAUER_Y))
3901     Feld[ax][ay] = EL_MAUERWERK;
3902 }
3903
3904 void CheckForDragon(int x, int y)
3905 {
3906   int i, j;
3907   boolean dragon_found = FALSE;
3908   static int xy[4][2] =
3909   {
3910     { 0, -1 },
3911     { -1, 0 },
3912     { +1, 0 },
3913     { 0, +1 }
3914   };
3915
3916   for (i=0; i<4; i++)
3917   {
3918     for (j=0; j<4; j++)
3919     {
3920       int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
3921
3922       if (IN_LEV_FIELD(xx, yy) &&
3923           (Feld[xx][yy] == EL_BURNING || Feld[xx][yy] == EL_DRACHE))
3924       {
3925         if (Feld[xx][yy] == EL_DRACHE)
3926           dragon_found = TRUE;
3927       }
3928       else
3929         break;
3930     }
3931   }
3932
3933   if (!dragon_found)
3934   {
3935     for (i=0; i<4; i++)
3936     {
3937       for (j=0; j<3; j++)
3938       {
3939         int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
3940   
3941         if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == EL_BURNING)
3942         {
3943           Feld[xx][yy] = EL_LEERRAUM;
3944           DrawLevelField(xx, yy);
3945         }
3946         else
3947           break;
3948       }
3949     }
3950   }
3951 }
3952
3953 static void CheckBuggyBase(int x, int y)
3954 {
3955   int element = Feld[x][y];
3956
3957   if (element == EL_SP_BUG)
3958   {
3959     if (!MovDelay[x][y])        /* wait some time before activating base */
3960       MovDelay[x][y] = 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND);
3961
3962     if (MovDelay[x][y])
3963     {
3964       MovDelay[x][y]--;
3965       if (MovDelay[x][y] < 5 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3966         DrawGraphic(SCREENX(x), SCREENY(y), GFX_SP_BUG_WARNING);
3967       if (MovDelay[x][y])
3968         return;
3969
3970       Feld[x][y] = EL_SP_BUG_ACTIVE;
3971     }
3972   }
3973   else if (element == EL_SP_BUG_ACTIVE)
3974   {
3975     if (!MovDelay[x][y])        /* start activating buggy base */
3976       MovDelay[x][y] = 1 * FRAMES_PER_SECOND + RND(1 * FRAMES_PER_SECOND);
3977
3978     if (MovDelay[x][y])
3979     {
3980       MovDelay[x][y]--;
3981       if (MovDelay[x][y])
3982       {
3983         int i;
3984         static int xy[4][2] =
3985         {
3986           { 0, -1 },
3987           { -1, 0 },
3988           { +1, 0 },
3989           { 0, +1 }
3990         };
3991
3992         if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3993           DrawGraphic(SCREENX(x),SCREENY(y), GFX_SP_BUG_ACTIVE + SimpleRND(4));
3994
3995         for (i=0; i<4; i++)
3996         {
3997           int xx = x + xy[i][0], yy = y + xy[i][1];
3998
3999           if (IS_PLAYER(xx, yy))
4000           {
4001             PlaySoundLevel(x, y, SND_SP_BUG);
4002             break;
4003           }
4004         }
4005
4006         return;
4007       }
4008
4009       Feld[x][y] = EL_SP_BUG;
4010       DrawLevelField(x, y);
4011     }
4012   }
4013 }
4014
4015 static void CheckTrap(int x, int y)
4016 {
4017   int element = Feld[x][y];
4018
4019   if (element == EL_TRAP_INACTIVE)
4020   {
4021     if (!MovDelay[x][y])        /* wait some time before activating trap */
4022       MovDelay[x][y] = 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND);
4023
4024     if (MovDelay[x][y])
4025     {
4026       MovDelay[x][y]--;
4027       if (MovDelay[x][y])
4028         return;
4029
4030       Feld[x][y] = EL_TRAP_ACTIVE;
4031     }
4032   }
4033   else if (element == EL_TRAP_ACTIVE)
4034   {
4035     int delay = 4;
4036     int num_frames = 8;
4037
4038     if (!MovDelay[x][y])        /* start activating trap */
4039       MovDelay[x][y] = num_frames * delay;
4040
4041     if (MovDelay[x][y])
4042     {
4043       MovDelay[x][y]--;
4044
4045       if (MovDelay[x][y])
4046       {
4047         if (!(MovDelay[x][y] % delay))
4048         {
4049           int phase = MovDelay[x][y]/delay;
4050
4051           if (phase >= num_frames/2)
4052             phase = num_frames - phase;
4053
4054           if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
4055           {
4056             DrawGraphic(SCREENX(x),SCREENY(y), GFX_TRAP_INACTIVE + phase - 1);
4057             ErdreichAnbroeckeln(SCREENX(x), SCREENY(y));
4058           }
4059         }
4060
4061         return;
4062       }
4063
4064       Feld[x][y] = EL_TRAP_INACTIVE;
4065       DrawLevelField(x, y);
4066     }
4067   }
4068 }
4069
4070 static void DrawBeltAnimation(int x, int y, int element)
4071 {
4072   int belt_nr = getBeltNrFromElement(element);
4073   int belt_dir = game.belt_dir[belt_nr];
4074
4075   if (belt_dir != MV_NO_MOVING)
4076   {
4077     int delay = 2;
4078     int mode = (belt_dir == MV_LEFT ? ANIM_NORMAL : ANIM_REVERSE);
4079     int graphic = el2gfx(element) + (belt_dir == MV_LEFT ? 0 : 7);
4080
4081     DrawGraphicAnimation(x, y, graphic, 8, delay, mode);
4082   }
4083 }
4084
4085 static void PlayerActions(struct PlayerInfo *player, byte player_action)
4086 {
4087   static byte stored_player_action[MAX_PLAYERS];
4088   static int num_stored_actions = 0;
4089   static boolean save_tape_entry = FALSE;
4090   boolean moved = FALSE, snapped = FALSE, bombed = FALSE;
4091   int jx = player->jx, jy = player->jy;
4092   int left      = player_action & JOY_LEFT;
4093   int right     = player_action & JOY_RIGHT;
4094   int up        = player_action & JOY_UP;
4095   int down      = player_action & JOY_DOWN;
4096   int button1   = player_action & JOY_BUTTON_1;
4097   int button2   = player_action & JOY_BUTTON_2;
4098   int dx        = (left ? -1    : right ? 1     : 0);
4099   int dy        = (up   ? -1    : down  ? 1     : 0);
4100
4101   stored_player_action[player->index_nr] = 0;
4102   num_stored_actions++;
4103
4104   if (!player->active || tape.pausing)
4105     return;
4106
4107   if (player_action)
4108   {
4109     save_tape_entry = TRUE;
4110     player->frame_reset_delay = 0;
4111
4112     if (button1)
4113       snapped = SnapField(player, dx, dy);
4114     else
4115     {
4116       if (button2)
4117         bombed = PlaceBomb(player);
4118       moved = MoveFigure(player, dx, dy);
4119     }
4120
4121     if (tape.recording && (moved || snapped || bombed))
4122     {
4123       if (bombed && !moved)
4124         player_action &= JOY_BUTTON;
4125
4126       stored_player_action[player->index_nr] = player_action;
4127     }
4128     else if (tape.playing && snapped)
4129       SnapField(player, 0, 0);                  /* stop snapping */
4130   }
4131   else
4132   {
4133     /* no actions for this player (no input at player's configured device) */
4134
4135     DigField(player, 0, 0, 0, 0, DF_NO_PUSH);
4136     SnapField(player, 0, 0);
4137     CheckGravityMovement(player);
4138
4139     if (++player->frame_reset_delay > player->move_delay_value)
4140       player->Frame = 0;
4141   }
4142
4143   if (tape.recording && num_stored_actions >= MAX_PLAYERS && save_tape_entry)
4144   {
4145     TapeRecordAction(stored_player_action);
4146     num_stored_actions = 0;
4147     save_tape_entry = FALSE;
4148   }
4149
4150   if (tape.playing && !tape.pausing && !player_action &&
4151       tape.counter < tape.length)
4152   {
4153     int next_joy =
4154       tape.pos[tape.counter].action[player->index_nr] & (JOY_LEFT|JOY_RIGHT);
4155
4156     if ((next_joy == JOY_LEFT || next_joy == JOY_RIGHT) &&
4157         (player->MovDir != JOY_UP && player->MovDir != JOY_DOWN))
4158     {
4159       int dx = (next_joy == JOY_LEFT ? -1 : +1);
4160
4161       if (IN_LEV_FIELD(jx+dx, jy) && IS_PUSHABLE(Feld[jx+dx][jy]))
4162       {
4163         int el = Feld[jx+dx][jy];
4164         int push_delay = (IS_SB_ELEMENT(el) || el == EL_SONDE ? 2 :
4165                           el == EL_BALLOON ? 0 : 10);
4166
4167         if (tape.delay_played + push_delay >= tape.pos[tape.counter].delay)
4168         {
4169           player->MovDir = next_joy;
4170           player->Frame = FrameCounter % 4;
4171           player->Pushing = TRUE;
4172         }
4173       }
4174     }
4175   }
4176 }
4177
4178 void GameActions()
4179 {
4180   static unsigned long action_delay = 0;
4181   unsigned long action_delay_value;
4182   int sieb_x = 0, sieb_y = 0;
4183   int i, x, y, element;
4184   byte *recorded_player_action;
4185   byte summarized_player_action = 0;
4186
4187   if (game_status != PLAYING)
4188     return;
4189
4190   action_delay_value =
4191     (tape.playing && tape.fast_forward ? FfwdFrameDelay : GameFrameDelay);
4192
4193   /* ---------- main game synchronization point ---------- */
4194
4195   WaitUntilDelayReached(&action_delay, action_delay_value);
4196
4197   if (network_playing && !network_player_action_received)
4198   {
4199     /*
4200 #ifdef DEBUG
4201     printf("DEBUG: try to get network player actions in time\n");
4202 #endif
4203     */
4204
4205 #ifndef MSDOS
4206     /* last chance to get network player actions without main loop delay */
4207     HandleNetworking();
4208 #endif
4209
4210     if (game_status != PLAYING)
4211       return;
4212
4213     if (!network_player_action_received)
4214     {
4215       /*
4216 #ifdef DEBUG
4217       printf("DEBUG: failed to get network player actions in time\n");
4218 #endif
4219       */
4220       return;
4221     }
4222   }
4223
4224   if (tape.pausing)
4225     return;
4226
4227   if (tape.playing)
4228     TapePlayDelay();
4229   else if (tape.recording)
4230     TapeRecordDelay();
4231
4232   recorded_player_action = (tape.playing ? TapePlayAction() : NULL);
4233
4234   for (i=0; i<MAX_PLAYERS; i++)
4235   {
4236     summarized_player_action |= stored_player[i].action;
4237
4238     if (!network_playing)
4239       stored_player[i].effective_action = stored_player[i].action;
4240   }
4241
4242 #ifndef MSDOS
4243   if (network_playing)
4244     SendToServer_MovePlayer(summarized_player_action);
4245 #endif
4246
4247   if (!options.network && !setup.team_mode)
4248     local_player->effective_action = summarized_player_action;
4249
4250   for (i=0; i<MAX_PLAYERS; i++)
4251   {
4252     int actual_player_action = stored_player[i].effective_action;
4253
4254     if (stored_player[i].programmed_action)
4255       actual_player_action = stored_player[i].programmed_action;
4256
4257     if (recorded_player_action)
4258       actual_player_action = recorded_player_action[i];
4259
4260     PlayerActions(&stored_player[i], actual_player_action);
4261     ScrollFigure(&stored_player[i], SCROLL_GO_ON);
4262   }
4263
4264   network_player_action_received = FALSE;
4265
4266   ScrollScreen(NULL, SCROLL_GO_ON);
4267
4268
4269
4270 #ifdef DEBUG
4271 #if 0
4272   if (TimeFrames == 0 && local_player->active)
4273   {
4274     extern unsigned int last_RND();
4275
4276     printf("DEBUG: %03d last RND was %d \t [state checksum is %d]\n",
4277            TimePlayed, last_RND(), getStateCheckSum(TimePlayed));
4278   }
4279 #endif
4280 #endif
4281
4282 #ifdef DEBUG
4283 #if 0
4284   if (GameFrameDelay >= 500)
4285     printf("FrameCounter == %d\n", FrameCounter);
4286 #endif
4287 #endif
4288
4289
4290
4291   FrameCounter++;
4292   TimeFrames++;
4293
4294   for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
4295   {
4296     Stop[x][y] = FALSE;
4297     if (JustStopped[x][y] > 0)
4298       JustStopped[x][y]--;
4299
4300 #if DEBUG
4301     if (IS_BLOCKED(x, y))
4302     {
4303       int oldx, oldy;
4304
4305       Blocked2Moving(x, y, &oldx, &oldy);
4306       if (!IS_MOVING(oldx, oldy))
4307       {
4308         printf("GameActions(): (BLOCKED => MOVING) context corrupted!\n");
4309         printf("GameActions(): BLOCKED: x = %d, y = %d\n", x, y);
4310         printf("GameActions(): !MOVING: oldx = %d, oldy = %d\n", oldx, oldy);
4311         printf("GameActions(): This should never happen!\n");
4312       }
4313     }
4314 #endif
4315   }
4316
4317   for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
4318   {
4319     element = Feld[x][y];
4320
4321     if (IS_INACTIVE(element))
4322       continue;
4323
4324     if (!IS_MOVING(x, y) && (CAN_FALL(element) || CAN_MOVE(element)))
4325     {
4326       StartMoving(x, y);
4327
4328       if (IS_GEM(element))
4329         EdelsteinFunkeln(x, y);
4330     }
4331     else if (IS_MOVING(x, y))
4332       ContinueMoving(x, y);
4333     else if (IS_ACTIVE_BOMB(element))
4334       CheckDynamite(x, y);
4335     else if (element == EL_EXPLODING)
4336       Explode(x, y, Frame[x][y], EX_NORMAL);
4337     else if (element == EL_AMOEBING)
4338       AmoebeWaechst(x, y);
4339     else if (element == EL_DEAMOEBING)
4340       AmoebeSchrumpft(x, y);
4341     else if (IS_AMOEBALIVE(element))
4342       AmoebeAbleger(x, y);
4343     else if (element == EL_LIFE || element == EL_LIFE_ASYNC)
4344       Life(x, y);
4345     else if (element == EL_ABLENK_EIN)
4346       Ablenk(x, y);
4347     else if (element == EL_TIMEGATE_SWITCH_ON)
4348       TimegateWheel(x, y);
4349     else if (element == EL_SALZSAEURE)
4350       Blubber(x, y);
4351     else if (element == EL_BLURB_LEFT || element == EL_BLURB_RIGHT)
4352       Blurb(x, y);
4353     else if (element == EL_CRACKINGNUT)
4354       NussKnacken(x, y);
4355     else if (element == EL_PEARL_BREAKING)
4356       BreakingPearl(x, y);
4357     else if (element == EL_AUSGANG_ZU)
4358       AusgangstuerPruefen(x, y);
4359     else if (element == EL_AUSGANG_ACT)
4360       AusgangstuerOeffnen(x, y);
4361     else if (element == EL_AUSGANG_AUF)
4362       AusgangstuerBlinken(x, y);
4363     else if (element == EL_MAUERND)
4364       MauerWaechst(x, y);
4365     else if (element == EL_MAUER_LEBT ||
4366              element == EL_MAUER_X ||
4367              element == EL_MAUER_Y ||
4368              element == EL_MAUER_XY)
4369       MauerAbleger(x, y);
4370     else if (element == EL_BURNING)
4371       CheckForDragon(x, y);
4372     else if (element == EL_SP_BUG || element == EL_SP_BUG_ACTIVE)
4373       CheckBuggyBase(x, y);
4374     else if (element == EL_TRAP_INACTIVE || element == EL_TRAP_ACTIVE)
4375       CheckTrap(x, y);
4376     else if (element == EL_SP_TERMINAL)
4377       DrawGraphicAnimation(x, y, GFX2_SP_TERMINAL, 7, 12, ANIM_NORMAL);
4378     else if (element == EL_SP_TERMINAL_ACTIVE)
4379       DrawGraphicAnimation(x, y, GFX2_SP_TERMINAL_ACTIVE, 7, 4, ANIM_NORMAL);
4380     else if (IS_BELT(element))
4381       DrawBeltAnimation(x, y, element);
4382     else if (element == EL_SWITCHGATE_OPENING)
4383       OpenSwitchgate(x, y);
4384     else if (element == EL_SWITCHGATE_CLOSING)
4385       CloseSwitchgate(x, y);
4386     else if (element == EL_TIMEGATE_OPENING)
4387       OpenTimegate(x, y);
4388     else if (element == EL_TIMEGATE_CLOSING)
4389       CloseTimegate(x, y);
4390     else if (element == EL_EXTRA_TIME)
4391       DrawGraphicAnimation(x, y, GFX_EXTRA_TIME, 6, 4, ANIM_NORMAL);
4392     else if (element == EL_SHIELD_PASSIVE)
4393       DrawGraphicAnimation(x, y, GFX_SHIELD_PASSIVE, 6, 4, ANIM_NORMAL);
4394     else if (element == EL_SHIELD_ACTIVE)
4395       DrawGraphicAnimation(x, y, GFX_SHIELD_ACTIVE, 6, 4, ANIM_NORMAL);
4396
4397     if (game.magic_wall_active)
4398     {
4399       boolean sieb = FALSE;
4400       int jx = local_player->jx, jy = local_player->jy;
4401
4402       if (element == EL_SIEB_LEER || element == EL_SIEB_VOLL ||
4403           Store[x][y] == EL_SIEB_LEER)
4404       {
4405         SiebAktivieren(x, y, 1);
4406         sieb = TRUE;
4407       }
4408       else if (element == EL_SIEB2_LEER || element == EL_SIEB2_VOLL ||
4409                Store[x][y] == EL_SIEB2_LEER)
4410       {
4411         SiebAktivieren(x, y, 2);
4412         sieb = TRUE;
4413       }
4414
4415       /* play the element sound at the position nearest to the player */
4416       if (sieb && ABS(x-jx)+ABS(y-jy) < ABS(sieb_x-jx)+ABS(sieb_y-jy))
4417       {
4418         sieb_x = x;
4419         sieb_y = y;
4420       }
4421     }
4422   }
4423
4424   if (game.magic_wall_active)
4425   {
4426     if (!(game.magic_wall_time_left % 4))
4427       PlaySoundLevel(sieb_x, sieb_y, SND_MIEP);
4428
4429     if (game.magic_wall_time_left > 0)
4430     {
4431       game.magic_wall_time_left--;
4432       if (!game.magic_wall_time_left)
4433       {
4434         for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
4435         {
4436           element = Feld[x][y];
4437
4438           if (element == EL_SIEB_LEER || element == EL_SIEB_VOLL)
4439           {
4440             Feld[x][y] = EL_SIEB_TOT;
4441             DrawLevelField(x, y);
4442           }
4443           else if (element == EL_SIEB2_LEER || element == EL_SIEB2_VOLL)
4444           {
4445             Feld[x][y] = EL_SIEB2_TOT;
4446             DrawLevelField(x, y);
4447           }
4448         }
4449
4450         game.magic_wall_active = FALSE;
4451       }
4452     }
4453   }
4454
4455   if (game.light_time_left > 0)
4456   {
4457     game.light_time_left--;
4458
4459     if (game.light_time_left == 0)
4460     {
4461       for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
4462       {
4463         element = Feld[x][y];
4464
4465         if (element == EL_LIGHT_SWITCH_ON)
4466         {
4467           Feld[x][y] = EL_LIGHT_SWITCH_OFF;
4468           DrawLevelField(x, y);
4469         }
4470         else if (element == EL_INVISIBLE_STEEL ||
4471                  element == EL_UNSICHTBAR ||
4472                  element == EL_SAND_INVISIBLE)
4473           DrawLevelField(x, y);
4474       }
4475     }
4476   }
4477
4478   if (game.timegate_time_left > 0)
4479   {
4480     game.timegate_time_left--;
4481
4482     if (game.timegate_time_left == 0)
4483       CloseAllOpenTimegates();
4484   }
4485
4486   if (TimeFrames >= (1000 / GameFrameDelay))
4487   {
4488     TimeFrames = 0;
4489     TimePlayed++;
4490
4491     for (i=0; i<MAX_PLAYERS; i++)
4492     {
4493       if (SHIELD_ON(&stored_player[i]))
4494       {
4495         stored_player[i].shield_passive_time_left--;
4496
4497         if (stored_player[i].shield_active_time_left > 0)
4498           stored_player[i].shield_active_time_left--;
4499       }
4500     }
4501
4502     if (tape.recording || tape.playing)
4503       DrawVideoDisplay(VIDEO_STATE_TIME_ON, TimePlayed);
4504
4505     if (TimeLeft > 0)
4506     {
4507       TimeLeft--;
4508
4509       if (TimeLeft <= 10 && setup.time_limit)
4510         PlaySoundStereo(SND_GONG, PSND_MAX_RIGHT);
4511
4512       DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
4513
4514       if (!TimeLeft && setup.time_limit)
4515         for (i=0; i<MAX_PLAYERS; i++)
4516           KillHero(&stored_player[i]);
4517     }
4518     else if (level.time == 0)           /* level without time limit */
4519       DrawText(DX_TIME, DY_TIME, int2str(TimePlayed, 3), FS_SMALL, FC_YELLOW);
4520   }
4521
4522   DrawAllPlayers();
4523 }
4524
4525 static boolean AllPlayersInSight(struct PlayerInfo *player, int x, int y)
4526 {
4527   int min_x = x, min_y = y, max_x = x, max_y = y;
4528   int i;
4529
4530   for (i=0; i<MAX_PLAYERS; i++)
4531   {
4532     int jx = stored_player[i].jx, jy = stored_player[i].jy;
4533
4534     if (!stored_player[i].active || &stored_player[i] == player)
4535       continue;
4536
4537     min_x = MIN(min_x, jx);
4538     min_y = MIN(min_y, jy);
4539     max_x = MAX(max_x, jx);
4540     max_y = MAX(max_y, jy);
4541   }
4542
4543   return (max_x - min_x < SCR_FIELDX && max_y - min_y < SCR_FIELDY);
4544 }
4545
4546 static boolean AllPlayersInVisibleScreen()
4547 {
4548   int i;
4549
4550   for (i=0; i<MAX_PLAYERS; i++)
4551   {
4552     int jx = stored_player[i].jx, jy = stored_player[i].jy;
4553
4554     if (!stored_player[i].active)
4555       continue;
4556
4557     if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
4558       return FALSE;
4559   }
4560
4561   return TRUE;
4562 }
4563
4564 void ScrollLevel(int dx, int dy)
4565 {
4566   int softscroll_offset = (setup.soft_scrolling ? TILEX : 0);
4567   int x, y;
4568
4569   XCopyArea(display, drawto_field, drawto_field, gc,
4570             FX + TILEX*(dx == -1) - softscroll_offset,
4571             FY + TILEY*(dy == -1) - softscroll_offset,
4572             SXSIZE - TILEX*(dx!=0) + 2*softscroll_offset,
4573             SYSIZE - TILEY*(dy!=0) + 2*softscroll_offset,
4574             FX + TILEX*(dx == 1) - softscroll_offset,
4575             FY + TILEY*(dy == 1) - softscroll_offset);
4576
4577   if (dx)
4578   {
4579     x = (dx == 1 ? BX1 : BX2);
4580     for (y=BY1; y<=BY2; y++)
4581       DrawScreenField(x, y);
4582   }
4583   if (dy)
4584   {
4585     y = (dy == 1 ? BY1 : BY2);
4586     for (x=BX1; x<=BX2; x++)
4587       DrawScreenField(x, y);
4588   }
4589
4590   redraw_mask |= REDRAW_FIELD;
4591 }
4592
4593 static void CheckGravityMovement(struct PlayerInfo *player)
4594 {
4595   if (level.gravity && !player->programmed_action)
4596   {
4597     int move_dir_vertical = player->action & (MV_UP | MV_DOWN);
4598     int move_dir_horizontal = player->action & (MV_LEFT | MV_RIGHT);
4599     int move_dir =
4600       (player->last_move_dir & (MV_LEFT | MV_RIGHT) ?
4601        (move_dir_vertical ? move_dir_vertical : move_dir_horizontal) :
4602        (move_dir_horizontal ? move_dir_horizontal : move_dir_vertical));
4603     int jx = player->jx, jy = player->jy;
4604     int dx = (move_dir & MV_LEFT ? -1 : move_dir & MV_RIGHT ? +1 : 0);
4605     int dy = (move_dir & MV_UP ? -1 : move_dir & MV_DOWN ? +1 : 0);
4606     int new_jx = jx + dx, new_jy = jy + dy;
4607     boolean field_under_player_is_free =
4608       (IN_LEV_FIELD(jx, jy + 1) && IS_FREE(jx, jy + 1));
4609     boolean player_is_moving_to_valid_field =
4610       (IN_LEV_FIELD(new_jx, new_jy) &&
4611        (Feld[new_jx][new_jy] == EL_SP_BASE ||
4612         Feld[new_jx][new_jy] == EL_ERDREICH));
4613
4614     if (field_under_player_is_free && !player_is_moving_to_valid_field)
4615       player->programmed_action = MV_DOWN;
4616   }
4617 }
4618
4619 boolean MoveFigureOneStep(struct PlayerInfo *player,
4620                           int dx, int dy, int real_dx, int real_dy)
4621 {
4622   int jx = player->jx, jy = player->jy;
4623   int new_jx = jx+dx, new_jy = jy+dy;
4624   int element;
4625   int can_move;
4626
4627   if (!player->active || (!dx && !dy))
4628     return MF_NO_ACTION;
4629
4630   player->MovDir = (dx < 0 ? MV_LEFT :
4631                     dx > 0 ? MV_RIGHT :
4632                     dy < 0 ? MV_UP :
4633                     dy > 0 ? MV_DOWN :  MV_NO_MOVING);
4634
4635   if (!IN_LEV_FIELD(new_jx, new_jy))
4636     return MF_NO_ACTION;
4637
4638   if (!options.network && !AllPlayersInSight(player, new_jx, new_jy))
4639     return MF_NO_ACTION;
4640
4641 #if 0
4642   element = MovingOrBlocked2Element(new_jx, new_jy);
4643 #else
4644   element = MovingOrBlocked2ElementIfNotLeaving(new_jx, new_jy);
4645 #endif
4646
4647   if (DONT_GO_TO(element))
4648   {
4649     if (element == EL_SALZSAEURE && dx == 0 && dy == 1)
4650     {
4651       Blurb(jx, jy);
4652       Feld[jx][jy] = EL_SPIELFIGUR;
4653       InitMovingField(jx, jy, MV_DOWN);
4654       Store[jx][jy] = EL_SALZSAEURE;
4655       ContinueMoving(jx, jy);
4656       BuryHero(player);
4657     }
4658     else
4659       TestIfBadThingHitsHero(new_jx, new_jy);
4660
4661     return MF_MOVING;
4662   }
4663
4664   can_move = DigField(player, new_jx, new_jy, real_dx, real_dy, DF_DIG);
4665   if (can_move != MF_MOVING)
4666     return can_move;
4667
4668   StorePlayer[jx][jy] = 0;
4669   player->last_jx = jx;
4670   player->last_jy = jy;
4671   jx = player->jx = new_jx;
4672   jy = player->jy = new_jy;
4673   StorePlayer[jx][jy] = player->element_nr;
4674
4675   player->MovPos =
4676     (dx > 0 || dy > 0 ? -1 : 1) * (TILEX - TILEX / player->move_delay_value);
4677
4678   ScrollFigure(player, SCROLL_INIT);
4679
4680   return MF_MOVING;
4681 }
4682
4683 boolean MoveFigure(struct PlayerInfo *player, int dx, int dy)
4684 {
4685   int jx = player->jx, jy = player->jy;
4686   int old_jx = jx, old_jy = jy;
4687   int moved = MF_NO_ACTION;
4688
4689   if (!player->active || (!dx && !dy))
4690     return FALSE;
4691
4692   if (!FrameReached(&player->move_delay, player->move_delay_value) &&
4693       !tape.playing)
4694     return FALSE;
4695
4696   /* remove the last programmed player action */
4697   player->programmed_action = 0;
4698
4699   if (player->MovPos)
4700   {
4701     /* should only happen if pre-1.2 tape recordings are played */
4702     /* this is only for backward compatibility */
4703
4704     int original_move_delay_value = player->move_delay_value;
4705
4706 #if DEBUG
4707     printf("THIS SHOULD ONLY HAPPEN WITH PRE-1.2 LEVEL TAPES.\n");
4708 #endif
4709
4710     /* scroll remaining steps with finest movement resolution */
4711     player->move_delay_value = MOVE_DELAY_NORMAL_SPEED;
4712
4713     while (player->MovPos)
4714     {
4715       ScrollFigure(player, SCROLL_GO_ON);
4716       ScrollScreen(NULL, SCROLL_GO_ON);
4717       FrameCounter++;
4718       DrawAllPlayers();
4719       BackToFront();
4720     }
4721
4722     player->move_delay_value = original_move_delay_value;
4723   }
4724
4725   if (player->last_move_dir & (MV_LEFT | MV_RIGHT))
4726   {
4727     if (!(moved |= MoveFigureOneStep(player, 0, dy, dx, dy)))
4728       moved |= MoveFigureOneStep(player, dx, 0, dx, dy);
4729   }
4730   else
4731   {
4732     if (!(moved |= MoveFigureOneStep(player, dx, 0, dx, dy)))
4733       moved |= MoveFigureOneStep(player, 0, dy, dx, dy);
4734   }
4735
4736   jx = player->jx;
4737   jy = player->jy;
4738
4739   if (moved & MF_MOVING && !ScreenMovPos &&
4740       (player == local_player || !options.network))
4741   {
4742     int old_scroll_x = scroll_x, old_scroll_y = scroll_y;
4743     int offset = (setup.scroll_delay ? 3 : 0);
4744
4745     if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
4746     {
4747       /* actual player has left the screen -- scroll in that direction */
4748       if (jx != old_jx)         /* player has moved horizontally */
4749         scroll_x += (jx - old_jx);
4750       else                      /* player has moved vertically */
4751         scroll_y += (jy - old_jy);
4752     }
4753     else
4754     {
4755       if (jx != old_jx)         /* player has moved horizontally */
4756       {
4757         if ((player->MovDir == MV_LEFT && scroll_x > jx - MIDPOSX + offset) ||
4758             (player->MovDir == MV_RIGHT && scroll_x < jx - MIDPOSX - offset))
4759           scroll_x = jx-MIDPOSX + (scroll_x < jx-MIDPOSX ? -offset : +offset);
4760
4761         /* don't scroll over playfield boundaries */
4762         if (scroll_x < SBX_Left || scroll_x > SBX_Right)
4763           scroll_x = (scroll_x < SBX_Left ? SBX_Left : SBX_Right);
4764
4765         /* don't scroll more than one field at a time */
4766         scroll_x = old_scroll_x + SIGN(scroll_x - old_scroll_x);
4767
4768         /* don't scroll against the player's moving direction */
4769         if ((player->MovDir == MV_LEFT && scroll_x > old_scroll_x) ||
4770             (player->MovDir == MV_RIGHT && scroll_x < old_scroll_x))
4771           scroll_x = old_scroll_x;
4772       }
4773       else                      /* player has moved vertically */
4774       {
4775         if ((player->MovDir == MV_UP && scroll_y > jy - MIDPOSY + offset) ||
4776             (player->MovDir == MV_DOWN && scroll_y < jy - MIDPOSY - offset))
4777           scroll_y = jy-MIDPOSY + (scroll_y < jy-MIDPOSY ? -offset : +offset);
4778
4779         /* don't scroll over playfield boundaries */
4780         if (scroll_y < SBY_Upper || scroll_y > SBY_Lower)
4781           scroll_y = (scroll_y < SBY_Upper ? SBY_Upper : SBY_Lower);
4782
4783         /* don't scroll more than one field at a time */
4784         scroll_y = old_scroll_y + SIGN(scroll_y - old_scroll_y);
4785
4786         /* don't scroll against the player's moving direction */
4787         if ((player->MovDir == MV_UP && scroll_y > old_scroll_y) ||
4788             (player->MovDir == MV_DOWN && scroll_y < old_scroll_y))
4789           scroll_y = old_scroll_y;
4790       }
4791     }
4792
4793     if (scroll_x != old_scroll_x || scroll_y != old_scroll_y)
4794     {
4795       if (!options.network && !AllPlayersInVisibleScreen())
4796       {
4797         scroll_x = old_scroll_x;
4798         scroll_y = old_scroll_y;
4799       }
4800       else
4801       {
4802         ScrollScreen(player, SCROLL_INIT);
4803         ScrollLevel(old_scroll_x - scroll_x, old_scroll_y - scroll_y);
4804       }
4805     }
4806   }
4807
4808   if (!(moved & MF_MOVING) && !player->Pushing)
4809     player->Frame = 0;
4810   else
4811     player->Frame = (player->Frame + 1) % 4;
4812
4813   if (moved & MF_MOVING)
4814   {
4815     if (old_jx != jx && old_jy == jy)
4816       player->MovDir = (old_jx < jx ? MV_RIGHT : MV_LEFT);
4817     else if (old_jx == jx && old_jy != jy)
4818       player->MovDir = (old_jy < jy ? MV_DOWN : MV_UP);
4819
4820     DrawLevelField(jx, jy);     /* for "ErdreichAnbroeckeln()" */
4821
4822     player->last_move_dir = player->MovDir;
4823   }
4824   else
4825   {
4826     CheckGravityMovement(player);
4827
4828     player->last_move_dir = MV_NO_MOVING;
4829   }
4830
4831   TestIfHeroHitsBadThing(jx, jy);
4832
4833   if (!player->active)
4834     RemoveHero(player);
4835
4836   return moved;
4837 }
4838
4839 void ScrollFigure(struct PlayerInfo *player, int mode)
4840 {
4841   int jx = player->jx, jy = player->jy;
4842   int last_jx = player->last_jx, last_jy = player->last_jy;
4843   int move_stepsize = TILEX / player->move_delay_value;
4844
4845   if (!player->active || !player->MovPos)
4846     return;
4847
4848   if (mode == SCROLL_INIT)
4849   {
4850     player->actual_frame_counter = FrameCounter;
4851     player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
4852
4853     if (Feld[last_jx][last_jy] == EL_LEERRAUM)
4854       Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING;
4855
4856     DrawPlayer(player);
4857     return;
4858   }
4859   else if (!FrameReached(&player->actual_frame_counter, 1))
4860     return;
4861
4862   player->MovPos += (player->MovPos > 0 ? -1 : 1) * move_stepsize;
4863   player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
4864
4865   if (Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING)
4866     Feld[last_jx][last_jy] = EL_LEERRAUM;
4867
4868   /* before DrawPlayer() to draw correct player graphic for this case */
4869   if (player->MovPos == 0)
4870     CheckGravityMovement(player);
4871
4872   DrawPlayer(player);
4873
4874   if (player->MovPos == 0)
4875   {
4876     if (IS_QUICK_GATE(Feld[last_jx][last_jy]))
4877     {
4878       /* continue with normal speed after quickly moving through gate */
4879       HALVE_PLAYER_SPEED(player);
4880
4881       /* be able to make the next move without delay */
4882       player->move_delay = 0;
4883     }
4884
4885     player->last_jx = jx;
4886     player->last_jy = jy;
4887
4888     if (Feld[jx][jy] == EL_AUSGANG_AUF)
4889     {
4890       RemoveHero(player);
4891
4892       if (!local_player->friends_still_needed)
4893         player->LevelSolved = player->GameOver = TRUE;
4894     }
4895   }
4896 }
4897
4898 void ScrollScreen(struct PlayerInfo *player, int mode)
4899 {
4900   static unsigned long screen_frame_counter = 0;
4901
4902   if (mode == SCROLL_INIT)
4903   {
4904     /* set scrolling step size according to actual player's moving speed */
4905     ScrollStepSize = TILEX / player->move_delay_value;
4906
4907     screen_frame_counter = FrameCounter;
4908     ScreenMovDir = player->MovDir;
4909     ScreenMovPos = player->MovPos;
4910     ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
4911     return;
4912   }
4913   else if (!FrameReached(&screen_frame_counter, 1))
4914     return;
4915
4916   if (ScreenMovPos)
4917   {
4918     ScreenMovPos += (ScreenMovPos > 0 ? -1 : 1) * ScrollStepSize;
4919     ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
4920     redraw_mask |= REDRAW_FIELD;
4921   }
4922   else
4923     ScreenMovDir = MV_NO_MOVING;
4924 }
4925
4926 void TestIfGoodThingHitsBadThing(int goodx, int goody)
4927 {
4928   int i, killx = goodx, killy = goody;
4929   static int xy[4][2] =
4930   {
4931     { 0, -1 },
4932     { -1, 0 },
4933     { +1, 0 },
4934     { 0, +1 }
4935   };
4936   static int harmless[4] =
4937   {
4938     MV_UP,
4939     MV_LEFT,
4940     MV_RIGHT,
4941     MV_DOWN
4942   };
4943
4944   for (i=0; i<4; i++)
4945   {
4946     int x, y, element;
4947
4948     x = goodx + xy[i][0];
4949     y = goody + xy[i][1];
4950     if (!IN_LEV_FIELD(x, y))
4951       continue;
4952
4953 #if 0
4954     element = Feld[x][y];
4955 #else
4956     element = MovingOrBlocked2ElementIfNotLeaving(x, y);
4957 #endif
4958
4959     if (DONT_TOUCH(element))
4960     {
4961       if (MovDir[x][y] == harmless[i])
4962         continue;
4963
4964       killx = x;
4965       killy = y;
4966       break;
4967     }
4968   }
4969
4970   if (killx != goodx || killy != goody)
4971   {
4972     if (IS_PLAYER(goodx, goody))
4973     {
4974       struct PlayerInfo *player = PLAYERINFO(goodx, goody);
4975
4976       if (player->shield_active_time_left > 0)
4977         Bang(killx, killy);
4978       else if (!PLAYER_PROTECTED(goodx, goody))
4979         KillHero(player);
4980     }
4981     else
4982       Bang(goodx, goody);
4983   }
4984 }
4985
4986 void TestIfBadThingHitsGoodThing(int badx, int bady)
4987 {
4988   int i, killx = badx, killy = bady;
4989   static int xy[4][2] =
4990   {
4991     { 0, -1 },
4992     { -1, 0 },
4993     { +1, 0 },
4994     { 0, +1 }
4995   };
4996   static int harmless[4] =
4997   {
4998     MV_UP,
4999     MV_LEFT,
5000     MV_RIGHT,
5001     MV_DOWN
5002   };
5003
5004   if (Feld[badx][bady] == EL_EXPLODING) /* skip just exploding bad things */
5005     return;
5006
5007   for (i=0; i<4; i++)
5008   {
5009     int x, y, element;
5010
5011     x = badx + xy[i][0];
5012     y = bady + xy[i][1];
5013     if (!IN_LEV_FIELD(x, y))
5014       continue;
5015
5016     element = Feld[x][y];
5017
5018     if (IS_PLAYER(x, y))
5019     {
5020       killx = x;
5021       killy = y;
5022       break;
5023     }
5024     else if (element == EL_PINGUIN)
5025     {
5026       if (MovDir[x][y] == harmless[i] && IS_MOVING(x, y))
5027         continue;
5028
5029       killx = x;
5030       killy = y;
5031       break;
5032     }
5033   }
5034
5035   if (killx != badx || killy != bady)
5036   {
5037     if (IS_PLAYER(killx, killy))
5038     {
5039       struct PlayerInfo *player = PLAYERINFO(killx, killy);
5040
5041       if (player->shield_active_time_left > 0)
5042         Bang(badx, bady);
5043       else if (!PLAYER_PROTECTED(killx, killy))
5044         KillHero(player);
5045     }
5046     else
5047       Bang(killx, killy);
5048   }
5049 }
5050
5051 void TestIfHeroHitsBadThing(int x, int y)
5052 {
5053   TestIfGoodThingHitsBadThing(x, y);
5054 }
5055
5056 void TestIfBadThingHitsHero(int x, int y)
5057 {
5058   TestIfBadThingHitsGoodThing(x, y);
5059 }
5060
5061 void TestIfFriendHitsBadThing(int x, int y)
5062 {
5063   TestIfGoodThingHitsBadThing(x, y);
5064 }
5065
5066 void TestIfBadThingHitsFriend(int x, int y)
5067 {
5068   TestIfBadThingHitsGoodThing(x, y);
5069 }
5070
5071 void TestIfBadThingHitsOtherBadThing(int badx, int bady)
5072 {
5073   int i, killx = badx, killy = bady;
5074   static int xy[4][2] =
5075   {
5076     { 0, -1 },
5077     { -1, 0 },
5078     { +1, 0 },
5079     { 0, +1 }
5080   };
5081
5082   for (i=0; i<4; i++)
5083   {
5084     int x, y, element;
5085
5086     x=badx + xy[i][0];
5087     y=bady + xy[i][1];
5088     if (!IN_LEV_FIELD(x, y))
5089       continue;
5090
5091     element = Feld[x][y];
5092     if (IS_AMOEBOID(element) || element == EL_LIFE ||
5093         element == EL_AMOEBING || element == EL_TROPFEN)
5094     {
5095       killx = x;
5096       killy = y;
5097       break;
5098     }
5099   }
5100
5101   if (killx != badx || killy != bady)
5102     Bang(badx, bady);
5103 }
5104
5105 void KillHero(struct PlayerInfo *player)
5106 {
5107   int jx = player->jx, jy = player->jy;
5108
5109   if (!player->active)
5110     return;
5111
5112   if (IS_PFORTE(Feld[jx][jy]))
5113     Feld[jx][jy] = EL_LEERRAUM;
5114
5115   /* deactivate shield (else Bang()/Explode() would not work right) */
5116   player->shield_passive_time_left = 0;
5117   player->shield_active_time_left = 0;
5118
5119   Bang(jx, jy);
5120   BuryHero(player);
5121 }
5122
5123 static void KillHeroUnlessProtected(int x, int y)
5124 {
5125   if (!PLAYER_PROTECTED(x, y))
5126     KillHero(PLAYERINFO(x, y));
5127 }
5128
5129 void BuryHero(struct PlayerInfo *player)
5130 {
5131   int jx = player->jx, jy = player->jy;
5132
5133   if (!player->active)
5134     return;
5135
5136   PlaySoundLevel(jx, jy, SND_AUTSCH);
5137   PlaySoundLevel(jx, jy, SND_LACHEN);
5138
5139   player->GameOver = TRUE;
5140   RemoveHero(player);
5141 }
5142
5143 void RemoveHero(struct PlayerInfo *player)
5144 {
5145   int jx = player->jx, jy = player->jy;
5146   int i, found = FALSE;
5147
5148   player->present = FALSE;
5149   player->active = FALSE;
5150
5151   StorePlayer[jx][jy] = 0;
5152
5153   for (i=0; i<MAX_PLAYERS; i++)
5154     if (stored_player[i].active)
5155       found = TRUE;
5156
5157   if (!found)
5158     AllPlayersGone = TRUE;
5159
5160   ExitX = ZX = jx;
5161   ExitY = ZY = jy;
5162 }
5163
5164 int DigField(struct PlayerInfo *player,
5165              int x, int y, int real_dx, int real_dy, int mode)
5166 {
5167   int jx = player->jx, jy = player->jy;
5168   int dx = x - jx, dy = y - jy;
5169   int move_direction = (dx == -1 ? MV_LEFT :
5170                         dx == +1 ? MV_RIGHT :
5171                         dy == -1 ? MV_UP :
5172                         dy == +1 ? MV_DOWN : MV_NO_MOVING);
5173   int element;
5174
5175   if (!player->MovPos)
5176     player->Pushing = FALSE;
5177
5178   if (mode == DF_NO_PUSH)
5179   {
5180     player->Switching = FALSE;
5181     player->push_delay = 0;
5182     return MF_NO_ACTION;
5183   }
5184
5185   if (IS_MOVING(x, y) || IS_PLAYER(x, y))
5186     return MF_NO_ACTION;
5187
5188   if (IS_TUBE(Feld[jx][jy]))
5189   {
5190     int i = 0;
5191     int tube_leave_directions[][2] =
5192     {
5193       { EL_TUBE_CROSS,          MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN },
5194       { EL_TUBE_VERTICAL,                            MV_UP | MV_DOWN },
5195       { EL_TUBE_HORIZONTAL,     MV_LEFT | MV_RIGHT                   },
5196       { EL_TUBE_VERT_LEFT,      MV_LEFT |            MV_UP | MV_DOWN },
5197       { EL_TUBE_VERT_RIGHT,               MV_RIGHT | MV_UP | MV_DOWN },
5198       { EL_TUBE_HORIZ_UP,       MV_LEFT | MV_RIGHT | MV_UP           },
5199       { EL_TUBE_HORIZ_DOWN,     MV_LEFT | MV_RIGHT |         MV_DOWN },
5200       { EL_TUBE_LEFT_UP,        MV_LEFT |            MV_UP           },
5201       { EL_TUBE_LEFT_DOWN,      MV_LEFT |                    MV_DOWN },
5202       { EL_TUBE_RIGHT_UP,                 MV_RIGHT | MV_UP           },
5203       { EL_TUBE_RIGHT_DOWN,               MV_RIGHT |         MV_DOWN },
5204       { -1,                     MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN }
5205     };
5206
5207     while (tube_leave_directions[i][0] != Feld[jx][jy])
5208     {
5209       i++;
5210       if (tube_leave_directions[i][0] == -1)    /* should not happen */
5211         break;
5212     }
5213
5214     if (!(tube_leave_directions[i][1] & move_direction))
5215       return MF_NO_ACTION;      /* tube has no opening in this direction */
5216   }
5217
5218   element = Feld[x][y];
5219
5220   switch (element)
5221   {
5222     case EL_LEERRAUM:
5223       PlaySoundLevel(x, y, SND_EMPTY);
5224       break;
5225
5226     case EL_ERDREICH:
5227     case EL_SAND_INVISIBLE:
5228     case EL_TRAP_INACTIVE:
5229       Feld[x][y] = EL_LEERRAUM;
5230       PlaySoundLevel(x, y, SND_SCHLURF);
5231       break;
5232
5233     case EL_SP_BASE:
5234     case EL_SP_BUG:
5235       Feld[x][y] = EL_LEERRAUM;
5236       PlaySoundLevel(x, y, SND_SP_BASE);
5237       break;
5238
5239     case EL_EDELSTEIN:
5240     case EL_EDELSTEIN_BD:
5241     case EL_EDELSTEIN_GELB:
5242     case EL_EDELSTEIN_ROT:
5243     case EL_EDELSTEIN_LILA:
5244     case EL_DIAMANT:
5245     case EL_SP_INFOTRON:
5246     case EL_PEARL:
5247     case EL_CRYSTAL:
5248       RemoveField(x, y);
5249       local_player->gems_still_needed -= (element == EL_DIAMANT ? 3 :
5250                                           element == EL_PEARL ? 5 :
5251                                           element == EL_CRYSTAL ? 8 : 1);
5252       if (local_player->gems_still_needed < 0)
5253         local_player->gems_still_needed = 0;
5254       RaiseScoreElement(element);
5255       DrawText(DX_EMERALDS, DY_EMERALDS,
5256                int2str(local_player->gems_still_needed, 3),
5257                FS_SMALL, FC_YELLOW);
5258       if (element == EL_SP_INFOTRON)
5259         PlaySoundLevel(x, y, SND_SP_INFOTRON);
5260       else
5261         PlaySoundLevel(x, y, SND_PONG);
5262       break;
5263
5264     case EL_SPEED_PILL:
5265       RemoveField(x, y);
5266       player->move_delay_value = MOVE_DELAY_HIGH_SPEED;
5267       PlaySoundLevel(x, y, SND_PONG);
5268       break;
5269
5270     case EL_ENVELOPE:
5271       Feld[x][y] = EL_LEERRAUM;
5272       PlaySoundLevel(x, y, SND_PONG);
5273       break;
5274
5275     case EL_EXTRA_TIME:
5276       RemoveField(x, y);
5277       if (level.time > 0)
5278       {
5279         TimeLeft += 10;
5280         DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
5281       }
5282       PlaySoundStereo(SND_GONG, PSND_MAX_RIGHT);
5283       break;
5284
5285     case EL_SHIELD_PASSIVE:
5286       RemoveField(x, y);
5287       player->shield_passive_time_left += 10;
5288       PlaySoundLevel(x, y, SND_PONG);
5289       break;
5290
5291     case EL_SHIELD_ACTIVE:
5292       RemoveField(x, y);
5293       player->shield_passive_time_left += 10;
5294       player->shield_active_time_left += 10;
5295       PlaySoundLevel(x, y, SND_PONG);
5296       break;
5297
5298     case EL_DYNAMITE_INACTIVE:
5299     case EL_SP_DISK_RED:
5300       RemoveField(x, y);
5301       player->dynamite++;
5302       RaiseScoreElement(EL_DYNAMITE_INACTIVE);
5303       DrawText(DX_DYNAMITE, DY_DYNAMITE,
5304                int2str(local_player->dynamite, 3),
5305                FS_SMALL, FC_YELLOW);
5306       if (element == EL_SP_DISK_RED)
5307         PlaySoundLevel(x, y, SND_SP_INFOTRON);
5308       else
5309         PlaySoundLevel(x, y, SND_PONG);
5310       break;
5311
5312     case EL_DYNABOMB_NR:
5313       RemoveField(x, y);
5314       player->dynabomb_count++;
5315       player->dynabombs_left++;
5316       RaiseScoreElement(EL_DYNAMITE_INACTIVE);
5317       PlaySoundLevel(x, y, SND_PONG);
5318       break;
5319
5320     case EL_DYNABOMB_SZ:
5321       RemoveField(x, y);
5322       player->dynabomb_size++;
5323       RaiseScoreElement(EL_DYNAMITE_INACTIVE);
5324       PlaySoundLevel(x, y, SND_PONG);
5325       break;
5326
5327     case EL_DYNABOMB_XL:
5328       RemoveField(x, y);
5329       player->dynabomb_xl = TRUE;
5330       RaiseScoreElement(EL_DYNAMITE_INACTIVE);
5331       PlaySoundLevel(x, y, SND_PONG);
5332       break;
5333
5334     case EL_SCHLUESSEL1:
5335     case EL_SCHLUESSEL2:
5336     case EL_SCHLUESSEL3:
5337     case EL_SCHLUESSEL4:
5338     {
5339       int key_nr = element - EL_SCHLUESSEL1;
5340
5341       RemoveField(x, y);
5342       player->key[key_nr] = TRUE;
5343       RaiseScoreElement(EL_SCHLUESSEL);
5344       DrawMiniGraphicExt(drawto, gc,
5345                          DX_KEYS+key_nr*MINI_TILEX, DY_KEYS,
5346                          GFX_SCHLUESSEL1+key_nr);
5347       DrawMiniGraphicExt(window, gc,
5348                          DX_KEYS+key_nr*MINI_TILEX, DY_KEYS,
5349                          GFX_SCHLUESSEL1+key_nr);
5350       PlaySoundLevel(x, y, SND_PONG);
5351       break;
5352     }
5353
5354     case EL_EM_KEY_1:
5355     case EL_EM_KEY_2:
5356     case EL_EM_KEY_3:
5357     case EL_EM_KEY_4:
5358     {
5359       int key_nr = element - EL_EM_KEY_1;
5360
5361       RemoveField(x, y);
5362       player->key[key_nr] = TRUE;
5363       RaiseScoreElement(EL_SCHLUESSEL);
5364       DrawMiniGraphicExt(drawto, gc,
5365                          DX_KEYS+key_nr*MINI_TILEX, DY_KEYS,
5366                          GFX_SCHLUESSEL1+key_nr);
5367       DrawMiniGraphicExt(window, gc,
5368                          DX_KEYS+key_nr*MINI_TILEX, DY_KEYS,
5369                          GFX_SCHLUESSEL1+key_nr);
5370       PlaySoundLevel(x, y, SND_PONG);
5371       break;
5372     }
5373
5374     case EL_ABLENK_AUS:
5375       Feld[x][y] = EL_ABLENK_EIN;
5376       ZX = x;
5377       ZY = y;
5378       DrawLevelField(x, y);
5379       return MF_ACTION;
5380       break;
5381
5382     case EL_SP_TERMINAL:
5383       {
5384         int xx, yy;
5385
5386         for (yy=0; yy<lev_fieldy; yy++)
5387         {
5388           for (xx=0; xx<lev_fieldx; xx++)
5389           {
5390             if (Feld[xx][yy] == EL_SP_DISK_YELLOW)
5391               Bang(xx, yy);
5392             else if (Feld[xx][yy] == EL_SP_TERMINAL)
5393               Feld[xx][yy] = EL_SP_TERMINAL_ACTIVE;
5394           }
5395         }
5396
5397         return MF_ACTION;
5398       }
5399       break;
5400
5401     case EL_BELT1_SWITCH_LEFT:
5402     case EL_BELT1_SWITCH_MIDDLE:
5403     case EL_BELT1_SWITCH_RIGHT:
5404     case EL_BELT2_SWITCH_LEFT:
5405     case EL_BELT2_SWITCH_MIDDLE:
5406     case EL_BELT2_SWITCH_RIGHT:
5407     case EL_BELT3_SWITCH_LEFT:
5408     case EL_BELT3_SWITCH_MIDDLE:
5409     case EL_BELT3_SWITCH_RIGHT:
5410     case EL_BELT4_SWITCH_LEFT:
5411     case EL_BELT4_SWITCH_MIDDLE:
5412     case EL_BELT4_SWITCH_RIGHT:
5413       if (!player->Switching)
5414       {
5415         player->Switching = TRUE;
5416         ToggleBeltSwitch(x, y);
5417       }
5418       return MF_ACTION;
5419       break;
5420
5421     case EL_SWITCHGATE_SWITCH_1:
5422     case EL_SWITCHGATE_SWITCH_2:
5423       if (!player->Switching)
5424       {
5425         player->Switching = TRUE;
5426         ToggleSwitchgateSwitch(x, y);
5427       }
5428       return MF_ACTION;
5429       break;
5430
5431     case EL_LIGHT_SWITCH_OFF:
5432     case EL_LIGHT_SWITCH_ON:
5433       if (!player->Switching)
5434       {
5435         player->Switching = TRUE;
5436         ToggleLightSwitch(x, y);
5437       }
5438       return MF_ACTION;
5439       break;
5440
5441     case EL_TIMEGATE_SWITCH_OFF:
5442       ActivateTimegateSwitch(x, y);
5443
5444       return MF_ACTION;
5445       break;
5446
5447     case EL_BALLOON_SEND_LEFT:
5448     case EL_BALLOON_SEND_RIGHT:
5449     case EL_BALLOON_SEND_UP:
5450     case EL_BALLOON_SEND_DOWN:
5451     case EL_BALLOON_SEND_ANY:
5452       if (element == EL_BALLOON_SEND_ANY)
5453         game.balloon_dir = move_direction;
5454       else
5455         game.balloon_dir = (element == EL_BALLOON_SEND_LEFT  ? MV_LEFT :
5456                             element == EL_BALLOON_SEND_RIGHT ? MV_RIGHT :
5457                             element == EL_BALLOON_SEND_UP    ? MV_UP :
5458                             element == EL_BALLOON_SEND_DOWN  ? MV_DOWN :
5459                             MV_NO_MOVING);
5460
5461       return MF_ACTION;
5462       break;
5463
5464     case EL_SP_EXIT:
5465       if (local_player->gems_still_needed > 0)
5466         return MF_NO_ACTION;
5467
5468       player->LevelSolved = player->GameOver = TRUE;
5469       PlaySoundStereo(SND_SP_EXIT, PSND_MAX_RIGHT);
5470       break;
5471
5472     case EL_FELSBROCKEN:
5473     case EL_BOMBE:
5474     case EL_KOKOSNUSS:
5475     case EL_ZEIT_LEER:
5476     case EL_SP_ZONK:
5477     case EL_SP_DISK_ORANGE:
5478       if (dy || mode == DF_SNAP)
5479         return MF_NO_ACTION;
5480
5481       player->Pushing = TRUE;
5482
5483       if (!IN_LEV_FIELD(x+dx, y+dy) || !IS_FREE(x+dx, y+dy))
5484         return MF_NO_ACTION;
5485
5486       if (real_dy)
5487       {
5488         if (IN_LEV_FIELD(jx, jy+real_dy) && !IS_SOLID(Feld[jx][jy+real_dy]))
5489           return MF_NO_ACTION;
5490       }
5491
5492       if (player->push_delay == 0)
5493         player->push_delay = FrameCounter;
5494       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
5495           !tape.playing)
5496         return MF_NO_ACTION;
5497
5498       RemoveField(x, y);
5499       Feld[x+dx][y+dy] = element;
5500
5501       player->push_delay_value = 2+RND(8);
5502
5503       DrawLevelField(x+dx, y+dy);
5504       if (element == EL_FELSBROCKEN)
5505         PlaySoundLevel(x+dx, y+dy, SND_PUSCH);
5506       else if (element == EL_KOKOSNUSS)
5507         PlaySoundLevel(x+dx, y+dy, SND_KNURK);
5508       else if (IS_SP_ELEMENT(element))
5509         PlaySoundLevel(x+dx, y+dy, SND_SP_ZONKPUSH);
5510       else
5511         PlaySoundLevel(x+dx, y+dy, SND_PUSCH);  /* better than "SND_KLOPF" */
5512       break;
5513
5514     case EL_PFORTE1:
5515     case EL_PFORTE2:
5516     case EL_PFORTE3:
5517     case EL_PFORTE4:
5518       if (!player->key[element - EL_PFORTE1])
5519         return MF_NO_ACTION;
5520       break;
5521
5522     case EL_PFORTE1X:
5523     case EL_PFORTE2X:
5524     case EL_PFORTE3X:
5525     case EL_PFORTE4X:
5526       if (!player->key[element - EL_PFORTE1X])
5527         return MF_NO_ACTION;
5528       break;
5529
5530     case EL_EM_GATE_1:
5531     case EL_EM_GATE_2:
5532     case EL_EM_GATE_3:
5533     case EL_EM_GATE_4:
5534       if (!player->key[element - EL_EM_GATE_1])
5535         return MF_NO_ACTION;
5536       if (!IN_LEV_FIELD(x + dx, y + dy) || !IS_FREE(x + dx, y + dy))
5537         return MF_NO_ACTION;
5538
5539       /* automatically move to the next field with double speed */
5540       player->programmed_action = move_direction;
5541       DOUBLE_PLAYER_SPEED(player);
5542
5543       PlaySoundLevel(x, y, SND_GATE);
5544
5545       break;
5546
5547     case EL_EM_GATE_1X:
5548     case EL_EM_GATE_2X:
5549     case EL_EM_GATE_3X:
5550     case EL_EM_GATE_4X:
5551       if (!player->key[element - EL_EM_GATE_1X])
5552         return MF_NO_ACTION;
5553       if (!IN_LEV_FIELD(x + dx, y + dy) || !IS_FREE(x + dx, y + dy))
5554         return MF_NO_ACTION;
5555
5556       /* automatically move to the next field with double speed */
5557       player->programmed_action = move_direction;
5558       DOUBLE_PLAYER_SPEED(player);
5559
5560       PlaySoundLevel(x, y, SND_GATE);
5561
5562       break;
5563
5564     case EL_SWITCHGATE_OPEN:
5565     case EL_TIMEGATE_OPEN:
5566       if (!IN_LEV_FIELD(x + dx, y + dy) || !IS_FREE(x + dx, y + dy))
5567         return MF_NO_ACTION;
5568
5569       /* automatically move to the next field with double speed */
5570       player->programmed_action = move_direction;
5571       DOUBLE_PLAYER_SPEED(player);
5572
5573       PlaySoundLevel(x, y, SND_GATE);
5574
5575       break;
5576
5577     case EL_SP_PORT1_LEFT:
5578     case EL_SP_PORT2_LEFT:
5579     case EL_SP_PORT1_RIGHT:
5580     case EL_SP_PORT2_RIGHT:
5581     case EL_SP_PORT1_UP:
5582     case EL_SP_PORT2_UP:
5583     case EL_SP_PORT1_DOWN:
5584     case EL_SP_PORT2_DOWN:
5585     case EL_SP_PORT_X:
5586     case EL_SP_PORT_Y:
5587     case EL_SP_PORT_XY:
5588       if ((dx == -1 &&
5589            element != EL_SP_PORT1_LEFT &&
5590            element != EL_SP_PORT2_LEFT &&
5591            element != EL_SP_PORT_X &&
5592            element != EL_SP_PORT_XY) ||
5593           (dx == +1 &&
5594            element != EL_SP_PORT1_RIGHT &&
5595            element != EL_SP_PORT2_RIGHT &&
5596            element != EL_SP_PORT_X &&
5597            element != EL_SP_PORT_XY) ||
5598           (dy == -1 &&
5599            element != EL_SP_PORT1_UP &&
5600            element != EL_SP_PORT2_UP &&
5601            element != EL_SP_PORT_Y &&
5602            element != EL_SP_PORT_XY) ||
5603           (dy == +1 &&
5604            element != EL_SP_PORT1_DOWN &&
5605            element != EL_SP_PORT2_DOWN &&
5606            element != EL_SP_PORT_Y &&
5607            element != EL_SP_PORT_XY) ||
5608           !IN_LEV_FIELD(x + dx, y + dy) ||
5609           !IS_FREE(x + dx, y + dy))
5610         return MF_NO_ACTION;
5611
5612       /* automatically move to the next field with double speed */
5613       player->programmed_action = move_direction;
5614       DOUBLE_PLAYER_SPEED(player);
5615
5616       PlaySoundLevel(x, y, SND_GATE);
5617       break;
5618
5619     case EL_TUBE_CROSS:
5620     case EL_TUBE_VERTICAL:
5621     case EL_TUBE_HORIZONTAL:
5622     case EL_TUBE_VERT_LEFT:
5623     case EL_TUBE_VERT_RIGHT:
5624     case EL_TUBE_HORIZ_UP:
5625     case EL_TUBE_HORIZ_DOWN:
5626     case EL_TUBE_LEFT_UP:
5627     case EL_TUBE_LEFT_DOWN:
5628     case EL_TUBE_RIGHT_UP:
5629     case EL_TUBE_RIGHT_DOWN:
5630       {
5631         int i = 0;
5632         int tube_enter_directions[][2] =
5633         {
5634           { EL_TUBE_CROSS,      MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN },
5635           { EL_TUBE_VERTICAL,                        MV_UP | MV_DOWN },
5636           { EL_TUBE_HORIZONTAL, MV_LEFT | MV_RIGHT                   },
5637           { EL_TUBE_VERT_LEFT,            MV_RIGHT | MV_UP | MV_DOWN },
5638           { EL_TUBE_VERT_RIGHT, MV_LEFT            | MV_UP | MV_DOWN },
5639           { EL_TUBE_HORIZ_UP,   MV_LEFT | MV_RIGHT |         MV_DOWN },
5640           { EL_TUBE_HORIZ_DOWN, MV_LEFT | MV_RIGHT | MV_UP           },
5641           { EL_TUBE_LEFT_UP,              MV_RIGHT |         MV_DOWN },
5642           { EL_TUBE_LEFT_DOWN,            MV_RIGHT | MV_UP           },
5643           { EL_TUBE_RIGHT_UP,   MV_LEFT |                    MV_DOWN },
5644           { EL_TUBE_RIGHT_DOWN, MV_LEFT |            MV_UP           },
5645           { -1,                 MV_NO_MOVING                         }
5646         };
5647
5648         while (tube_enter_directions[i][0] != element)
5649         {
5650           i++;
5651           if (tube_enter_directions[i][0] == -1)        /* should not happen */
5652             break;
5653         }
5654
5655         if (!(tube_enter_directions[i][1] & move_direction))
5656           return MF_NO_ACTION;  /* tube has no opening in this direction */
5657       }
5658       break;
5659
5660     case EL_AUSGANG_ZU:
5661     case EL_AUSGANG_ACT:
5662       /* door is not (yet) open */
5663       return MF_NO_ACTION;
5664       break;
5665
5666     case EL_AUSGANG_AUF:
5667       if (mode == DF_SNAP)
5668         return MF_NO_ACTION;
5669
5670       PlaySoundLevel(x, y, SND_BUING);
5671
5672       break;
5673
5674     case EL_BIRNE_AUS:
5675       Feld[x][y] = EL_BIRNE_EIN;
5676       local_player->lights_still_needed--;
5677       DrawLevelField(x, y);
5678       PlaySoundLevel(x, y, SND_DENG);
5679       return MF_ACTION;
5680       break;
5681
5682     case EL_ZEIT_VOLL:
5683       Feld[x][y] = EL_ZEIT_LEER;
5684       TimeLeft += 10;
5685       DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
5686       DrawLevelField(x, y);
5687       PlaySoundStereo(SND_GONG, PSND_MAX_RIGHT);
5688       return MF_ACTION;
5689       break;
5690
5691     case EL_SOKOBAN_FELD_LEER:
5692       break;
5693
5694     case EL_SOKOBAN_FELD_VOLL:
5695     case EL_SOKOBAN_OBJEKT:
5696     case EL_SONDE:
5697     case EL_SP_DISK_YELLOW:
5698     case EL_BALLOON:
5699     case EL_SPRING:
5700       if (mode == DF_SNAP)
5701         return MF_NO_ACTION;
5702
5703       player->Pushing = TRUE;
5704
5705       if (!IN_LEV_FIELD(x+dx, y+dy)
5706           || (!IS_FREE(x+dx, y+dy)
5707               && (Feld[x+dx][y+dy] != EL_SOKOBAN_FELD_LEER
5708                   || !IS_SB_ELEMENT(element))))
5709         return MF_NO_ACTION;
5710
5711       if (dx && real_dy)
5712       {
5713         if (IN_LEV_FIELD(jx, jy+real_dy) && !IS_SOLID(Feld[jx][jy+real_dy]))
5714           return MF_NO_ACTION;
5715       }
5716       else if (dy && real_dx)
5717       {
5718         if (IN_LEV_FIELD(jx+real_dx, jy) && !IS_SOLID(Feld[jx+real_dx][jy]))
5719           return MF_NO_ACTION;
5720       }
5721
5722       if (player->push_delay == 0)
5723         player->push_delay = FrameCounter;
5724       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
5725           !tape.playing && element != EL_BALLOON)
5726         return MF_NO_ACTION;
5727
5728       if (IS_SB_ELEMENT(element))
5729       {
5730         if (element == EL_SOKOBAN_FELD_VOLL)
5731         {
5732           Feld[x][y] = EL_SOKOBAN_FELD_LEER;
5733           local_player->sokobanfields_still_needed++;
5734         }
5735         else
5736           RemoveField(x, y);
5737
5738         if (Feld[x+dx][y+dy] == EL_SOKOBAN_FELD_LEER)
5739         {
5740           Feld[x+dx][y+dy] = EL_SOKOBAN_FELD_VOLL;
5741           local_player->sokobanfields_still_needed--;
5742           if (element == EL_SOKOBAN_OBJEKT)
5743             PlaySoundLevel(x, y, SND_DENG);
5744         }
5745         else
5746           Feld[x+dx][y+dy] = EL_SOKOBAN_OBJEKT;
5747       }
5748       else
5749       {
5750         RemoveField(x, y);
5751         Feld[x+dx][y+dy] = element;
5752       }
5753
5754       player->push_delay_value = (element == EL_BALLOON ? 0 : 2);
5755
5756       DrawLevelField(x, y);
5757       DrawLevelField(x+dx, y+dy);
5758       if (element == EL_BALLOON)
5759         PlaySoundLevel(x+dx, y+dy, SND_SCHLURF);
5760       else
5761         PlaySoundLevel(x+dx, y+dy, SND_PUSCH);
5762
5763       if (IS_SB_ELEMENT(element) &&
5764           local_player->sokobanfields_still_needed == 0 &&
5765           game.emulation == EMU_SOKOBAN)
5766       {
5767         player->LevelSolved = player->GameOver = TRUE;
5768         PlaySoundLevel(x, y, SND_BUING);
5769       }
5770
5771       break;
5772
5773     case EL_PINGUIN:
5774     case EL_SCHWEIN:
5775     case EL_DRACHE:
5776       break;
5777
5778     default:
5779       return MF_NO_ACTION;
5780   }
5781
5782   player->push_delay = 0;
5783
5784   return MF_MOVING;
5785 }
5786
5787 boolean SnapField(struct PlayerInfo *player, int dx, int dy)
5788 {
5789   int jx = player->jx, jy = player->jy;
5790   int x = jx + dx, y = jy + dy;
5791
5792   if (!player->active || !IN_LEV_FIELD(x, y))
5793     return FALSE;
5794
5795   if (dx && dy)
5796     return FALSE;
5797
5798   if (!dx && !dy)
5799   {
5800     player->snapped = FALSE;
5801     return FALSE;
5802   }
5803
5804   if (player->snapped)
5805     return FALSE;
5806
5807   player->MovDir = (dx < 0 ? MV_LEFT :
5808                     dx > 0 ? MV_RIGHT :
5809                     dy < 0 ? MV_UP :
5810                     dy > 0 ? MV_DOWN :  MV_NO_MOVING);
5811
5812   if (!DigField(player, x, y, 0, 0, DF_SNAP))
5813     return FALSE;
5814
5815   player->snapped = TRUE;
5816   DrawLevelField(x, y);
5817   BackToFront();
5818
5819   return TRUE;
5820 }
5821
5822 boolean PlaceBomb(struct PlayerInfo *player)
5823 {
5824   int jx = player->jx, jy = player->jy;
5825   int element;
5826
5827   if (!player->active || player->MovPos)
5828     return FALSE;
5829
5830   element = Feld[jx][jy];
5831
5832   if ((player->dynamite == 0 && player->dynabombs_left == 0) ||
5833       IS_ACTIVE_BOMB(element) || element == EL_EXPLODING)
5834     return FALSE;
5835
5836   if (element != EL_LEERRAUM)
5837     Store[jx][jy] = element;
5838
5839   if (player->dynamite)
5840   {
5841     Feld[jx][jy] = EL_DYNAMITE_ACTIVE;
5842     MovDelay[jx][jy] = 96;
5843     player->dynamite--;
5844     DrawText(DX_DYNAMITE, DY_DYNAMITE, int2str(local_player->dynamite, 3),
5845              FS_SMALL, FC_YELLOW);
5846     if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy)))
5847     {
5848       if (game.emulation == EMU_SUPAPLEX)
5849         DrawGraphic(SCREENX(jx), SCREENY(jy), GFX_SP_DISK_RED);
5850       else
5851         DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), GFX_DYNAMIT);
5852     }
5853   }
5854   else
5855   {
5856     Feld[jx][jy] = EL_DYNABOMB_ACTIVE_1 + (player->element_nr - EL_SPIELER1);
5857     MovDelay[jx][jy] = 96;
5858     player->dynabombs_left--;
5859     if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy)))
5860       DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), GFX_DYNABOMB);
5861   }
5862
5863   return TRUE;
5864 }
5865
5866 void PlaySoundLevel(int x, int y, int sound_nr)
5867 {
5868   int sx = SCREENX(x), sy = SCREENY(y);
5869   int volume, stereo;
5870   int silence_distance = 8;
5871
5872   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound_nr)) ||
5873       (!setup.sound_loops && IS_LOOP_SOUND(sound_nr)))
5874     return;
5875
5876   if (!IN_LEV_FIELD(x, y) ||
5877       sx < -silence_distance || sx >= SCR_FIELDX+silence_distance ||
5878       sy < -silence_distance || sy >= SCR_FIELDY+silence_distance)
5879     return;
5880
5881   volume = PSND_MAX_VOLUME;
5882
5883 #ifndef MSDOS
5884   stereo = (sx - SCR_FIELDX/2) * 12;
5885 #else
5886   stereo = PSND_MIDDLE + (2 * sx - (SCR_FIELDX - 1)) * 5;
5887   if (stereo > PSND_MAX_RIGHT)
5888     stereo = PSND_MAX_RIGHT;
5889   if (stereo < PSND_MAX_LEFT)
5890     stereo = PSND_MAX_LEFT;
5891 #endif
5892
5893   if (!IN_SCR_FIELD(sx, sy))
5894   {
5895     int dx = ABS(sx - SCR_FIELDX/2) - SCR_FIELDX/2;
5896     int dy = ABS(sy - SCR_FIELDY/2) - SCR_FIELDY/2;
5897
5898     volume -= volume * (dx > dy ? dx : dy) / silence_distance;
5899   }
5900
5901   PlaySoundExt(sound_nr, volume, stereo, PSND_NO_LOOP);
5902 }
5903
5904 void RaiseScore(int value)
5905 {
5906   local_player->score += value;
5907   DrawText(DX_SCORE, DY_SCORE, int2str(local_player->score, 5),
5908            FS_SMALL, FC_YELLOW);
5909 }
5910
5911 void RaiseScoreElement(int element)
5912 {
5913   switch(element)
5914   {
5915     case EL_EDELSTEIN:
5916     case EL_EDELSTEIN_BD:
5917     case EL_EDELSTEIN_GELB:
5918     case EL_EDELSTEIN_ROT:
5919     case EL_EDELSTEIN_LILA:
5920       RaiseScore(level.score[SC_EDELSTEIN]);
5921       break;
5922     case EL_DIAMANT:
5923       RaiseScore(level.score[SC_DIAMANT]);
5924       break;
5925     case EL_KAEFER:
5926     case EL_BUTTERFLY:
5927       RaiseScore(level.score[SC_KAEFER]);
5928       break;
5929     case EL_FLIEGER:
5930     case EL_FIREFLY:
5931       RaiseScore(level.score[SC_FLIEGER]);
5932       break;
5933     case EL_MAMPFER:
5934     case EL_MAMPFER2:
5935       RaiseScore(level.score[SC_MAMPFER]);
5936       break;
5937     case EL_ROBOT:
5938       RaiseScore(level.score[SC_ROBOT]);
5939       break;
5940     case EL_PACMAN:
5941       RaiseScore(level.score[SC_PACMAN]);
5942       break;
5943     case EL_KOKOSNUSS:
5944       RaiseScore(level.score[SC_KOKOSNUSS]);
5945       break;
5946     case EL_DYNAMITE_INACTIVE:
5947       RaiseScore(level.score[SC_DYNAMIT]);
5948       break;
5949     case EL_SCHLUESSEL:
5950       RaiseScore(level.score[SC_SCHLUESSEL]);
5951       break;
5952     default:
5953       break;
5954   }
5955 }
5956
5957 /* ---------- new game button stuff ---------------------------------------- */
5958
5959 /* graphic position values for game buttons */
5960 #define GAME_BUTTON_XSIZE       30
5961 #define GAME_BUTTON_YSIZE       30
5962 #define GAME_BUTTON_XPOS        5
5963 #define GAME_BUTTON_YPOS        215
5964 #define SOUND_BUTTON_XPOS       5
5965 #define SOUND_BUTTON_YPOS       (GAME_BUTTON_YPOS + GAME_BUTTON_YSIZE)
5966
5967 #define GAME_BUTTON_STOP_XPOS   (GAME_BUTTON_XPOS + 0 * GAME_BUTTON_XSIZE)
5968 #define GAME_BUTTON_PAUSE_XPOS  (GAME_BUTTON_XPOS + 1 * GAME_BUTTON_XSIZE)
5969 #define GAME_BUTTON_PLAY_XPOS   (GAME_BUTTON_XPOS + 2 * GAME_BUTTON_XSIZE)
5970 #define SOUND_BUTTON_MUSIC_XPOS (SOUND_BUTTON_XPOS + 0 * GAME_BUTTON_XSIZE)
5971 #define SOUND_BUTTON_LOOPS_XPOS (SOUND_BUTTON_XPOS + 1 * GAME_BUTTON_XSIZE)
5972 #define SOUND_BUTTON_SIMPLE_XPOS (SOUND_BUTTON_XPOS + 2 * GAME_BUTTON_XSIZE)
5973
5974 static struct
5975 {
5976   int x, y;
5977   int gadget_id;
5978   char *infotext;
5979 } gamebutton_info[NUM_GAME_BUTTONS] =
5980 {
5981   {
5982     GAME_BUTTON_STOP_XPOS,      GAME_BUTTON_YPOS,
5983     GAME_CTRL_ID_STOP,
5984     "stop game"
5985   },
5986   {
5987     GAME_BUTTON_PAUSE_XPOS,     GAME_BUTTON_YPOS,
5988     GAME_CTRL_ID_PAUSE,
5989     "pause game"
5990   },
5991   {
5992     GAME_BUTTON_PLAY_XPOS,      GAME_BUTTON_YPOS,
5993     GAME_CTRL_ID_PLAY,
5994     "play game"
5995   },
5996   {
5997     SOUND_BUTTON_MUSIC_XPOS,    SOUND_BUTTON_YPOS,
5998     SOUND_CTRL_ID_MUSIC,
5999     "background music on/off"
6000   },
6001   {
6002     SOUND_BUTTON_LOOPS_XPOS,    SOUND_BUTTON_YPOS,
6003     SOUND_CTRL_ID_LOOPS,
6004     "sound loops on/off"
6005   },
6006   {
6007     SOUND_BUTTON_SIMPLE_XPOS,   SOUND_BUTTON_YPOS,
6008     SOUND_CTRL_ID_SIMPLE,
6009     "normal sounds on/off"
6010   }
6011 };
6012
6013 void CreateGameButtons()
6014 {
6015   int i;
6016
6017   for (i=0; i<NUM_GAME_BUTTONS; i++)
6018   {
6019     Pixmap gd_pixmap = pix[PIX_DOOR];
6020     struct GadgetInfo *gi;
6021     int button_type;
6022     boolean checked;
6023     unsigned long event_mask;
6024     int gd_xoffset, gd_yoffset;
6025     int gd_x1, gd_x2, gd_y1, gd_y2;
6026     int id = i;
6027
6028     gd_xoffset = gamebutton_info[i].x;
6029     gd_yoffset = gamebutton_info[i].y;
6030     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
6031     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
6032
6033     if (id == GAME_CTRL_ID_STOP ||
6034         id == GAME_CTRL_ID_PAUSE ||
6035         id == GAME_CTRL_ID_PLAY)
6036     {
6037       button_type = GD_TYPE_NORMAL_BUTTON;
6038       checked = FALSE;
6039       event_mask = GD_EVENT_RELEASED;
6040       gd_y1  = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
6041       gd_y2  = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
6042     }
6043     else
6044     {
6045       button_type = GD_TYPE_CHECK_BUTTON;
6046       checked =
6047         ((id == SOUND_CTRL_ID_MUSIC && setup.sound_music) ||
6048          (id == SOUND_CTRL_ID_LOOPS && setup.sound_loops) ||
6049          (id == SOUND_CTRL_ID_SIMPLE && setup.sound_simple) ? TRUE : FALSE);
6050       event_mask = GD_EVENT_PRESSED;
6051       gd_y1  = DOOR_GFX_PAGEY1 + gd_yoffset;
6052       gd_y2  = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
6053     }
6054
6055     gi = CreateGadget(GDI_CUSTOM_ID, id,
6056                       GDI_INFO_TEXT, gamebutton_info[i].infotext,
6057                       GDI_X, DX + gd_xoffset,
6058                       GDI_Y, DY + gd_yoffset,
6059                       GDI_WIDTH, GAME_BUTTON_XSIZE,
6060                       GDI_HEIGHT, GAME_BUTTON_YSIZE,
6061                       GDI_TYPE, button_type,
6062                       GDI_STATE, GD_BUTTON_UNPRESSED,
6063                       GDI_CHECKED, checked,
6064                       GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y1,
6065                       GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y1,
6066                       GDI_ALT_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y2,
6067                       GDI_ALT_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y2,
6068                       GDI_EVENT_MASK, event_mask,
6069                       GDI_CALLBACK_ACTION, HandleGameButtons,
6070                       GDI_END);
6071
6072     if (gi == NULL)
6073       Error(ERR_EXIT, "cannot create gadget");
6074
6075     game_gadget[id] = gi;
6076   }
6077 }
6078
6079 static void MapGameButtons()
6080 {
6081   int i;
6082
6083   for (i=0; i<NUM_GAME_BUTTONS; i++)
6084     MapGadget(game_gadget[i]);
6085 }
6086
6087 void UnmapGameButtons()
6088 {
6089   int i;
6090
6091   for (i=0; i<NUM_GAME_BUTTONS; i++)
6092     UnmapGadget(game_gadget[i]);
6093 }
6094
6095 static void HandleGameButtons(struct GadgetInfo *gi)
6096 {
6097   int id = gi->custom_id;
6098
6099   if (game_status != PLAYING)
6100     return;
6101
6102   switch (id)
6103   {
6104     case GAME_CTRL_ID_STOP:
6105       if (AllPlayersGone)
6106       {
6107         CloseDoor(DOOR_CLOSE_1);
6108         game_status = MAINMENU;
6109         DrawMainMenu();
6110         break;
6111       }
6112
6113       if (level_editor_test_game ||
6114           Request("Do you really want to quit the game ?",
6115                   REQ_ASK | REQ_STAY_CLOSED))
6116       { 
6117 #ifndef MSDOS
6118         if (options.network)
6119           SendToServer_StopPlaying();
6120         else
6121 #endif
6122         {
6123           game_status = MAINMENU;
6124           DrawMainMenu();
6125         }
6126       }
6127       else
6128         OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
6129       break;
6130
6131     case GAME_CTRL_ID_PAUSE:
6132       if (options.network)
6133       {
6134 #ifndef MSDOS
6135         if (tape.pausing)
6136           SendToServer_ContinuePlaying();
6137         else
6138           SendToServer_PausePlaying();
6139 #endif
6140       }
6141       else
6142         TapeTogglePause();
6143       break;
6144
6145     case GAME_CTRL_ID_PLAY:
6146       if (tape.pausing)
6147       {
6148 #ifndef MSDOS
6149         if (options.network)
6150           SendToServer_ContinuePlaying();
6151         else
6152 #endif
6153         {
6154           tape.pausing = FALSE;
6155           DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0);
6156         }
6157       }
6158       break;
6159
6160     case SOUND_CTRL_ID_MUSIC:
6161       if (setup.sound_music)
6162       { 
6163         setup.sound_music = FALSE;
6164         FadeSound(background_loop[level_nr % num_bg_loops]);
6165       }
6166       else if (sound_loops_allowed)
6167       { 
6168         setup.sound = setup.sound_music = TRUE;
6169         PlaySoundLoop(background_loop[level_nr % num_bg_loops]);
6170       }
6171       break;
6172
6173     case SOUND_CTRL_ID_LOOPS:
6174       if (setup.sound_loops)
6175         setup.sound_loops = FALSE;
6176       else if (sound_loops_allowed)
6177         setup.sound = setup.sound_loops = TRUE;
6178       break;
6179
6180     case SOUND_CTRL_ID_SIMPLE:
6181       if (setup.sound_simple)
6182         setup.sound_simple = FALSE;
6183       else if (sound_status==SOUND_AVAILABLE)
6184         setup.sound = setup.sound_simple = TRUE;
6185       break;
6186
6187     default:
6188       break;
6189   }
6190 }