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