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