e1977faf19ecae71ff9d8d5944e2cfc9686cb0c6
[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 /* for DigField() */
27 #define DF_NO_PUSH              0
28 #define DF_DIG                  1
29 #define DF_SNAP                 2
30
31 /* for MoveFigure() */
32 #define MF_NO_ACTION            0
33 #define MF_MOVING               1
34 #define MF_ACTION               2
35
36 /* for ScrollFigure() */
37 #define SCROLL_INIT             0
38 #define SCROLL_GO_ON            1
39
40 /* for Explode() */
41 #define EX_PHASE_START          0
42 #define EX_NORMAL               0
43 #define EX_CENTER               1
44 #define EX_BORDER               2
45
46 /* special positions in the game control window (relative to control window) */
47 #define XX_LEVEL                37
48 #define YY_LEVEL                20
49 #define XX_EMERALDS             29
50 #define YY_EMERALDS             54
51 #define XX_DYNAMITE             29
52 #define YY_DYNAMITE             89
53 #define XX_KEYS                 18
54 #define YY_KEYS                 123
55 #define XX_SCORE                15
56 #define YY_SCORE                159
57 #define XX_TIME                 29
58 #define YY_TIME                 194
59
60 /* special positions in the game control window (relative to main window) */
61 #define DX_LEVEL                (DX + XX_LEVEL)
62 #define DY_LEVEL                (DY + YY_LEVEL)
63 #define DX_EMERALDS             (DX + XX_EMERALDS)
64 #define DY_EMERALDS             (DY + YY_EMERALDS)
65 #define DX_DYNAMITE             (DX + XX_DYNAMITE)
66 #define DY_DYNAMITE             (DY + YY_DYNAMITE)
67 #define DX_KEYS                 (DX + XX_KEYS)
68 #define DY_KEYS                 (DY + YY_KEYS)
69 #define DX_SCORE                (DX + XX_SCORE)
70 #define DY_SCORE                (DY + YY_SCORE)
71 #define DX_TIME                 (DX + XX_TIME)
72 #define DY_TIME                 (DY + YY_TIME)
73
74 #define IS_LOOP_SOUND(s)        ((s)==SND_KLAPPER || (s)==SND_ROEHR ||  \
75                                  (s)==SND_NJAM || (s)==SND_MIEP)
76 #define IS_MUSIC_SOUND(s)       ((s)==SND_ALCHEMY || (s)==SND_CHASE || \
77                                  (s)==SND_NETWORK || (s)==SND_CZARDASZ || \
78                                  (s)==SND_TYGER || (s)==SND_VOYAGER || \
79                                  (s)==SND_TWILIGHT)
80
81 /* score for elements */
82 #define SC_EDELSTEIN            0
83 #define SC_DIAMANT              1
84 #define SC_KAEFER               2
85 #define SC_FLIEGER              3
86 #define SC_MAMPFER              4
87 #define SC_ROBOT                5
88 #define SC_PACMAN               6
89 #define SC_KOKOSNUSS            7
90 #define SC_DYNAMIT              8
91 #define SC_SCHLUESSEL           9
92 #define SC_ZEITBONUS            10
93
94 /* values for game_emulation */
95 #define EMU_NONE                0
96 #define EMU_BOULDERDASH         1
97 #define EMU_SOKOBAN             2
98
99 /* to control special behaviour of certain game elements */
100 int game_emulation = EMU_NONE;
101
102
103
104
105 #ifdef DEBUG
106 #if 0
107 static unsigned int getStateCheckSum(int counter)
108 {
109   int x, y;
110   unsigned int mult = 1;
111   unsigned int checksum = 0;
112   /*
113   static short lastFeld[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
114   */
115   static boolean first_game = TRUE;
116
117   for (y=0; y<lev_fieldy; y++) for(x=0; x<lev_fieldx; x++)
118   {
119     /*
120     if (counter == 3)
121     {
122       if (first_game)
123         lastFeld[x][y] = Feld[x][y];
124       else if (lastFeld[x][y] != Feld[x][y])
125         printf("DIFF: [%d][%d]: lastFeld == %d != %d == Feld\n",
126                x, y, lastFeld[x][y], Feld[x][y]);
127     }
128     */
129
130     checksum += mult++ * Ur[x][y];
131     checksum += mult++ * Feld[x][y];
132
133     /*
134     checksum += mult++ * MovPos[x][y];
135     checksum += mult++ * MovDir[x][y];
136     checksum += mult++ * MovDelay[x][y];
137     checksum += mult++ * Store[x][y];
138     checksum += mult++ * Store2[x][y];
139     checksum += mult++ * StorePlayer[x][y];
140     checksum += mult++ * Frame[x][y];
141     checksum += mult++ * AmoebaNr[x][y];
142     checksum += mult++ * JustHit[x][y];
143     checksum += mult++ * Stop[x][y];
144     */
145   }
146
147   if (counter == 3 && first_game)
148     first_game = FALSE;
149
150   return checksum;
151 }
152 #endif
153 #endif
154
155
156
157
158 void GetPlayerConfig()
159 {
160   if (sound_status == SOUND_OFF)
161     setup.sound = FALSE;
162
163   if (!sound_loops_allowed)
164   {
165     setup.sound_loops = FALSE;
166     setup.sound_music = FALSE;
167   }
168
169   setup.sound_simple = setup.sound;
170
171   InitJoysticks();
172 }
173
174 static void InitField(int x, int y, boolean init_game)
175 {
176   switch (Feld[x][y])
177   {
178     case EL_SPIELFIGUR:
179     case EL_SP_MURPHY:
180       if (init_game)
181         Feld[x][y] = EL_SPIELER1;
182       /* no break! */
183     case EL_SPIELER1:
184     case EL_SPIELER2:
185     case EL_SPIELER3:
186     case EL_SPIELER4:
187       if (init_game)
188       {
189         struct PlayerInfo *player = &stored_player[Feld[x][y] - EL_SPIELER1];
190         int jx = player->jx, jy = player->jy;
191
192         player->present = TRUE;
193
194         /*
195         if (!network_playing || player->connected)
196         */
197
198         if (!options.network || player->connected)
199         {
200           player->active = TRUE;
201
202           /* remove potentially duplicate players */
203           if (StorePlayer[jx][jy] == Feld[x][y])
204             StorePlayer[jx][jy] = 0;
205
206           StorePlayer[x][y] = Feld[x][y];
207
208           if (options.verbose)
209           {
210             printf("Player %d activated.\n", player->element_nr);
211             printf("[Local player is %d and currently %s.]\n",
212                    local_player->element_nr,
213                    local_player->active ? "active" : "not active");
214           }
215         }
216
217         Feld[x][y] = EL_LEERRAUM;
218         player->jx = player->last_jx = x;
219         player->jy = player->last_jy = y;
220       }
221       break;
222
223     case EL_BADEWANNE:
224       if (x < lev_fieldx-1 && Feld[x+1][y] == EL_SALZSAEURE)
225         Feld[x][y] = EL_BADEWANNE1;
226       else if (x > 0 && Feld[x-1][y] == EL_SALZSAEURE)
227         Feld[x][y] = EL_BADEWANNE2;
228       else if (y > 0 && Feld[x][y-1] == EL_BADEWANNE1)
229         Feld[x][y] = EL_BADEWANNE3;
230       else if (y > 0 && Feld[x][y-1] == EL_SALZSAEURE)
231         Feld[x][y] = EL_BADEWANNE4;
232       else if (y > 0 && Feld[x][y-1] == EL_BADEWANNE2)
233         Feld[x][y] = EL_BADEWANNE5;
234       break;
235
236     case EL_KAEFER_R:
237     case EL_KAEFER_O:
238     case EL_KAEFER_L:
239     case EL_KAEFER_U:
240     case EL_KAEFER:
241     case EL_FLIEGER_R:
242     case EL_FLIEGER_O:
243     case EL_FLIEGER_L:
244     case EL_FLIEGER_U:
245     case EL_FLIEGER:
246     case EL_BUTTERFLY_R:
247     case EL_BUTTERFLY_O:
248     case EL_BUTTERFLY_L:
249     case EL_BUTTERFLY_U:
250     case EL_BUTTERFLY:
251     case EL_FIREFLY_R:
252     case EL_FIREFLY_O:
253     case EL_FIREFLY_L:
254     case EL_FIREFLY_U:
255     case EL_FIREFLY:
256     case EL_PACMAN_R:
257     case EL_PACMAN_O:
258     case EL_PACMAN_L:
259     case EL_PACMAN_U:
260     case EL_MAMPFER:
261     case EL_MAMPFER2:
262     case EL_ROBOT:
263     case EL_PACMAN:
264       InitMovDir(x, y);
265       break;
266
267     case EL_AMOEBE_VOLL:
268     case EL_AMOEBE_BD:
269       InitAmoebaNr(x, y);
270       break;
271
272     case EL_TROPFEN:
273       if (y == lev_fieldy - 1)
274       {
275         Feld[x][y] = EL_AMOEBING;
276         Store[x][y] = EL_AMOEBE_NASS;
277       }
278       break;
279
280     case EL_DYNAMIT:
281       MovDelay[x][y] = 96;
282       break;
283
284     case EL_BIRNE_AUS:
285       local_player->lights_still_needed++;
286       break;
287
288     case EL_SOKOBAN_FELD_LEER:
289       local_player->sokobanfields_still_needed++;
290       break;
291
292     case EL_MAULWURF:
293     case EL_PINGUIN:
294       local_player->friends_still_needed++;
295       break;
296
297     case EL_SCHWEIN:
298     case EL_DRACHE:
299       MovDir[x][y] = 1 << RND(4);
300       break;
301
302     case EL_SP_EMPTY:
303       Feld[x][y] = EL_LEERRAUM;
304       break;
305
306     default:
307       break;
308   }
309 }
310
311 void InitGame()
312 {
313   int i, j, x, y;
314   boolean emulate_bd = TRUE;    /* unless non-BOULDERDASH elements found */
315   boolean emulate_sb = TRUE;    /* unless non-SOKOBAN     elements found */
316
317   /* don't play tapes over network */
318   network_playing = (options.network && !tape.playing);
319
320   for (i=0; i<MAX_PLAYERS; i++)
321   {
322     struct PlayerInfo *player = &stored_player[i];
323
324     player->index_nr = i;
325     player->element_nr = EL_SPIELER1 + i;
326
327     player->present = FALSE;
328     player->active = FALSE;
329
330     player->action = 0;
331     player->effective_action = 0;
332
333     player->score = 0;
334     player->gems_still_needed = level.edelsteine;
335     player->sokobanfields_still_needed = 0;
336     player->lights_still_needed = 0;
337     player->friends_still_needed = 0;
338
339     for (j=0; j<4; j++)
340       player->key[j] = FALSE;
341
342     player->dynamite = 0;
343     player->dynabomb_count = 0;
344     player->dynabomb_size = 0;
345     player->dynabombs_left = 0;
346     player->dynabomb_xl = FALSE;
347
348     player->MovDir = MV_NO_MOVING;
349     player->MovPos = 0;
350     player->Pushing = FALSE;
351     player->GfxPos = 0;
352     player->Frame = 0;
353
354     player->actual_frame_counter = 0;
355
356     player->frame_reset_delay = 0;
357
358     player->push_delay = 0;
359     player->push_delay_value = 5;
360
361     player->move_delay = 0;
362     player->last_move_dir = MV_NO_MOVING;
363
364     player->snapped = FALSE;
365
366     player->gone = FALSE;
367
368     player->last_jx = player->last_jy = 0;
369     player->jx = player->jy = 0;
370
371     DigField(player, 0, 0, 0, 0, DF_NO_PUSH);
372     SnapField(player, 0, 0);
373
374     player->LevelSolved = FALSE;
375     player->GameOver = FALSE;
376   }
377
378   network_player_action_received = FALSE;
379
380 #ifndef MSDOS
381   /* initial null action */
382   if (network_playing)
383     SendToServer_MovePlayer(MV_NO_MOVING);
384 #endif
385
386   ZX = ZY = -1;
387
388   MampferNr = 0;
389   FrameCounter = 0;
390   TimeFrames = 0;
391   TimeLeft = level.time;
392
393   ScreenMovDir = MV_NO_MOVING;
394   ScreenMovPos = 0;
395   ScreenGfxPos = 0;
396
397   if (level.high_speed)
398   {
399     MoveSpeed = 4;
400     ScrollStepSize = TILEX/4;
401   }
402   else
403   {
404     MoveSpeed = 8;
405     ScrollStepSize = TILEX/8;
406   }
407
408   AllPlayersGone = FALSE;
409   SiebAktiv = FALSE;
410   SiebCount = 0;
411
412   for (i=0; i<MAX_NUM_AMOEBA; i++)
413     AmoebaCnt[i] = AmoebaCnt2[i] = 0;
414
415   for (x=0; x<lev_fieldx; x++)
416   {
417     for (y=0; y<lev_fieldy; y++)
418     {
419       Feld[x][y] = Ur[x][y];
420       MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
421       Store[x][y] = Store2[x][y] = StorePlayer[x][y] = 0;
422       Frame[x][y] = 0;
423       AmoebaNr[x][y] = 0;
424       JustHit[x][y] = 0;
425       Stop[x][y] = FALSE;
426     }
427   }
428
429   for(y=0; y<lev_fieldy; y++) for(x=0; x<lev_fieldx; x++)
430   {
431     if (emulate_bd && !IS_BD_ELEMENT(Feld[x][y]))
432       emulate_bd = FALSE;
433     if (emulate_sb && !IS_SB_ELEMENT(Feld[x][y]))
434       emulate_sb = FALSE;
435
436     InitField(x, y, TRUE);
437   }
438
439   /* check if any connected player was not found in playfield */
440   for (i=0; i<MAX_PLAYERS; i++)
441   {
442     struct PlayerInfo *player = &stored_player[i];
443
444     if (player->connected && !player->present)
445     {
446       for (j=0; j<MAX_PLAYERS; j++)
447       {
448         struct PlayerInfo *some_player = &stored_player[j];
449         int jx = some_player->jx, jy = some_player->jy;
450
451         /* assign first free player found that is present in the playfield */
452         if (some_player->present && !some_player->connected)
453         {
454           player->present = TRUE;
455           player->active = TRUE;
456           some_player->present = FALSE;
457
458           StorePlayer[jx][jy] = player->element_nr;
459           player->jx = player->last_jx = jx;
460           player->jy = player->last_jy = jy;
461
462           break;
463         }
464       }
465     }
466   }
467
468   if (tape.playing)
469   {
470     /* when playing a tape, eliminate all players who do not participate */
471
472     for (i=0; i<MAX_PLAYERS; i++)
473     {
474       if (stored_player[i].active && !tape.player_participates[i])
475       {
476         struct PlayerInfo *player = &stored_player[i];
477         int jx = player->jx, jy = player->jy;
478
479         player->active = FALSE;
480         StorePlayer[jx][jy] = 0;
481         Feld[jx][jy] = EL_LEERRAUM;
482       }
483     }
484   }
485   else if (!options.network && !setup.team_mode)        /* && !tape.playing */
486   {
487     /* when in single player mode, eliminate all but the first active player */
488
489     for (i=0; i<MAX_PLAYERS; i++)
490     {
491       if (stored_player[i].active)
492       {
493         for (j=i+1; j<MAX_PLAYERS; j++)
494         {
495           if (stored_player[j].active)
496           {
497             struct PlayerInfo *player = &stored_player[j];
498             int jx = player->jx, jy = player->jy;
499
500             player->active = FALSE;
501             StorePlayer[jx][jy] = 0;
502             Feld[jx][jy] = EL_LEERRAUM;
503           }
504         }
505       }
506     }
507   }
508
509   /* when recording the game, store which players take part in the game */
510   if (tape.recording)
511   {
512     for (i=0; i<MAX_PLAYERS; i++)
513       if (stored_player[i].active)
514         tape.player_participates[i] = TRUE;
515   }
516
517   if (options.verbose)
518   {
519     for (i=0; i<MAX_PLAYERS; i++)
520     {
521       struct PlayerInfo *player = &stored_player[i];
522
523       printf("Player %d: present == %d, connected == %d, active == %d.\n",
524              i+1,
525              player->present,
526              player->connected,
527              player->active);
528       if (local_player == player)
529         printf("Player  %d is local player.\n", i+1);
530     }
531   }
532
533   game_emulation = (emulate_bd ? EMU_BOULDERDASH :
534                     emulate_sb ? EMU_SOKOBAN : EMU_NONE);
535
536   scroll_x = scroll_y = -1;
537   if (local_player->jx >= MIDPOSX-1)
538     scroll_x = (local_player->jx <= lev_fieldx-MIDPOSX ?
539                 local_player->jx - MIDPOSX :
540                 lev_fieldx - SCR_FIELDX + 1);
541   if (local_player->jy >= MIDPOSY-1)
542     scroll_y = (local_player->jy <= lev_fieldy-MIDPOSY ?
543                 local_player->jy - MIDPOSY :
544                 lev_fieldy - SCR_FIELDY + 1);
545
546   CloseDoor(DOOR_CLOSE_1);
547
548   DrawLevel();
549   DrawAllPlayers();
550   FadeToFront();
551
552   XCopyArea(display, pix[PIX_DOOR], pix[PIX_DB_DOOR], gc,
553             DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
554             DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
555   DrawTextExt(pix[PIX_DB_DOOR], gc,
556               DOOR_GFX_PAGEX1 + XX_LEVEL, DOOR_GFX_PAGEY1 + YY_LEVEL,
557               int2str(level_nr, 2), FS_SMALL, FC_YELLOW);
558   DrawTextExt(pix[PIX_DB_DOOR], gc,
559               DOOR_GFX_PAGEX1 + XX_EMERALDS, DOOR_GFX_PAGEY1 + YY_EMERALDS,
560               int2str(local_player->gems_still_needed,3), FS_SMALL, FC_YELLOW);
561   DrawTextExt(pix[PIX_DB_DOOR], gc,
562               DOOR_GFX_PAGEX1 + XX_DYNAMITE, DOOR_GFX_PAGEY1 + YY_DYNAMITE,
563               int2str(local_player->dynamite, 3), FS_SMALL, FC_YELLOW);
564   DrawTextExt(pix[PIX_DB_DOOR], gc,
565               DOOR_GFX_PAGEX1 + XX_SCORE, DOOR_GFX_PAGEY1 + YY_SCORE,
566               int2str(local_player->score, 5), FS_SMALL, FC_YELLOW);
567   DrawTextExt(pix[PIX_DB_DOOR], gc,
568               DOOR_GFX_PAGEX1 + XX_TIME, DOOR_GFX_PAGEY1 + YY_TIME,
569               int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
570
571   DrawGameButton(BUTTON_GAME_STOP);
572   DrawGameButton(BUTTON_GAME_PAUSE);
573   DrawGameButton(BUTTON_GAME_PLAY);
574   DrawSoundDisplay(BUTTON_SOUND_MUSIC  | (setup.sound_music  ? BUTTON_ON : 0));
575   DrawSoundDisplay(BUTTON_SOUND_LOOPS  | (setup.sound_loops  ? BUTTON_ON : 0));
576   DrawSoundDisplay(BUTTON_SOUND_SIMPLE | (setup.sound_simple ? BUTTON_ON : 0));
577   XCopyArea(display, drawto, pix[PIX_DB_DOOR], gc,
578             DX + GAME_CONTROL_XPOS, DY + GAME_CONTROL_YPOS,
579             GAME_CONTROL_XSIZE, 2 * GAME_CONTROL_YSIZE,
580             DOOR_GFX_PAGEX1 + GAME_CONTROL_XPOS,
581             DOOR_GFX_PAGEY1 + GAME_CONTROL_YPOS);
582
583   OpenDoor(DOOR_OPEN_1);
584
585   if (setup.sound_music)
586     PlaySoundLoop(background_loop[level_nr % num_bg_loops]);
587
588   XAutoRepeatOff(display);
589
590   if (options.verbose)
591   {
592     for (i=0; i<4; i++)
593       printf("Spieler %d %saktiv.\n",
594              i+1, (stored_player[i].active ? "" : "nicht "));
595   }
596 }
597
598 void InitMovDir(int x, int y)
599 {
600   int i, element = Feld[x][y];
601   static int xy[4][2] =
602   {
603     {  0, +1 },
604     { +1,  0 },
605     {  0, -1 },
606     { -1,  0 }
607   };
608   static int direction[2][4] =
609   {
610     { MV_RIGHT, MV_UP,   MV_LEFT,  MV_DOWN },
611     { MV_LEFT,  MV_DOWN, MV_RIGHT, MV_UP }
612   };
613
614   switch(element)
615   {
616     case EL_KAEFER_R:
617     case EL_KAEFER_O:
618     case EL_KAEFER_L:
619     case EL_KAEFER_U:
620       Feld[x][y] = EL_KAEFER;
621       MovDir[x][y] = direction[0][element - EL_KAEFER_R];
622       break;
623     case EL_FLIEGER_R:
624     case EL_FLIEGER_O:
625     case EL_FLIEGER_L:
626     case EL_FLIEGER_U:
627       Feld[x][y] = EL_FLIEGER;
628       MovDir[x][y] = direction[0][element - EL_FLIEGER_R];
629       break;
630     case EL_BUTTERFLY_R:
631     case EL_BUTTERFLY_O:
632     case EL_BUTTERFLY_L:
633     case EL_BUTTERFLY_U:
634       Feld[x][y] = EL_BUTTERFLY;
635       MovDir[x][y] = direction[0][element - EL_BUTTERFLY_R];
636       break;
637     case EL_FIREFLY_R:
638     case EL_FIREFLY_O:
639     case EL_FIREFLY_L:
640     case EL_FIREFLY_U:
641       Feld[x][y] = EL_FIREFLY;
642       MovDir[x][y] = direction[0][element - EL_FIREFLY_R];
643       break;
644     case EL_PACMAN_R:
645     case EL_PACMAN_O:
646     case EL_PACMAN_L:
647     case EL_PACMAN_U:
648       Feld[x][y] = EL_PACMAN;
649       MovDir[x][y] = direction[0][element - EL_PACMAN_R];
650       break;
651     default:
652       MovDir[x][y] = 1 << RND(4);
653       if (element != EL_KAEFER &&
654           element != EL_FLIEGER &&
655           element != EL_BUTTERFLY &&
656           element != EL_FIREFLY)
657         break;
658
659       for (i=0; i<4; i++)
660       {
661         int x1 = x + xy[i][0];
662         int y1 = y + xy[i][1];
663
664         if (!IN_LEV_FIELD(x1, y1) || !IS_FREE(x1, y1))
665         {
666           if (element == EL_KAEFER || element == EL_BUTTERFLY)
667           {
668             MovDir[x][y] = direction[0][i];
669             break;
670           }
671           else if (element == EL_FLIEGER || element == EL_FIREFLY)
672           {
673             MovDir[x][y] = direction[1][i];
674             break;
675           }
676         }
677       }
678       break;
679   }
680 }
681
682 void InitAmoebaNr(int x, int y)
683 {
684   int i;
685   int group_nr = AmoebeNachbarNr(x, y);
686
687   if (group_nr == 0)
688   {
689     for (i=1; i<MAX_NUM_AMOEBA; i++)
690     {
691       if (AmoebaCnt[i] == 0)
692       {
693         group_nr = i;
694         break;
695       }
696     }
697   }
698
699   AmoebaNr[x][y] = group_nr;
700   AmoebaCnt[group_nr]++;
701   AmoebaCnt2[group_nr]++;
702 }
703
704 void GameWon()
705 {
706   int hi_pos;
707   int bumplevel = FALSE;
708
709   if (local_player->MovPos)
710     return;
711
712   local_player->LevelSolved = FALSE;
713
714   if (TimeLeft)
715   {
716     if (setup.sound_loops)
717       PlaySoundExt(SND_SIRR, PSND_MAX_VOLUME, PSND_MAX_RIGHT, PSND_LOOP);
718
719     while(TimeLeft > 0)
720     {
721       if (!setup.sound_loops)
722         PlaySoundStereo(SND_SIRR, PSND_MAX_RIGHT);
723       if (TimeLeft && !(TimeLeft % 10))
724         RaiseScore(level.score[SC_ZEITBONUS]);
725       if (TimeLeft > 100 && !(TimeLeft % 10))
726         TimeLeft -= 10;
727       else
728         TimeLeft--;
729       DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
730       BackToFront();
731       Delay(10);
732     }
733
734     if (setup.sound_loops)
735       StopSound(SND_SIRR);
736   }
737
738   FadeSounds();
739
740   /* Hero disappears */
741   DrawLevelField(ExitX, ExitY);
742   BackToFront();
743
744   if (tape.playing)
745     return;
746
747   CloseDoor(DOOR_CLOSE_1);
748
749   if (tape.recording)
750   {
751     TapeStop();
752     SaveTape(tape.level_nr);            /* Ask to save tape */
753   }
754
755   if ((hi_pos = NewHiScore()) >= 0) 
756   {
757     game_status = HALLOFFAME;
758     DrawHallOfFame(hi_pos);
759     if (bumplevel && TAPE_IS_EMPTY(tape))
760       level_nr++;
761   }
762   else
763   {
764     game_status = MAINMENU;
765     if (bumplevel && TAPE_IS_EMPTY(tape))
766       level_nr++;
767     DrawMainMenu();
768   }
769
770   BackToFront();
771 }
772
773 boolean NewHiScore()
774 {
775   int k, l;
776   int position = -1;
777
778   LoadScore(level_nr);
779
780   if (strcmp(setup.player_name, EMPTY_PLAYER_NAME) == 0 ||
781       local_player->score < highscore[MAX_SCORE_ENTRIES - 1].Score) 
782     return -1;
783
784   for (k=0; k<MAX_SCORE_ENTRIES; k++) 
785   {
786     if (local_player->score > highscore[k].Score)
787     {
788       /* player has made it to the hall of fame */
789
790       if (k < MAX_SCORE_ENTRIES - 1)
791       {
792         int m = MAX_SCORE_ENTRIES - 1;
793
794 #ifdef ONE_PER_NAME
795         for (l=k; l<MAX_SCORE_ENTRIES; l++)
796           if (!strcmp(setup.player_name, highscore[l].Name))
797             m = l;
798         if (m == k)     /* player's new highscore overwrites his old one */
799           goto put_into_list;
800 #endif
801
802         for (l=m; l>k; l--)
803         {
804           strcpy(highscore[l].Name, highscore[l - 1].Name);
805           highscore[l].Score = highscore[l - 1].Score;
806         }
807       }
808
809 #ifdef ONE_PER_NAME
810       put_into_list:
811 #endif
812       strncpy(highscore[k].Name, setup.player_name, MAX_NAMELEN - 1);
813       highscore[k].Name[MAX_NAMELEN - 1] = '\0';
814       highscore[k].Score = local_player->score; 
815       position = k;
816       break;
817     }
818
819 #ifdef ONE_PER_NAME
820     else if (!strncmp(setup.player_name, highscore[k].Name, MAX_NAMELEN - 1))
821       break;    /* player already there with a higher score */
822 #endif
823
824   }
825
826   if (position >= 0) 
827     SaveScore(level_nr);
828
829   return position;
830 }
831
832 void InitMovingField(int x, int y, int direction)
833 {
834   int newx = x + (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
835   int newy = y + (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
836
837   MovDir[x][y] = direction;
838   MovDir[newx][newy] = direction;
839   if (Feld[newx][newy] == EL_LEERRAUM)
840     Feld[newx][newy] = EL_BLOCKED;
841 }
842
843 void Moving2Blocked(int x, int y, int *goes_to_x, int *goes_to_y)
844 {
845   int direction = MovDir[x][y];
846   int newx = x + (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
847   int newy = y + (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
848
849   *goes_to_x = newx;
850   *goes_to_y = newy;
851 }
852
853 void Blocked2Moving(int x, int y, int *comes_from_x, int *comes_from_y)
854 {
855   int oldx = x, oldy = y;
856   int direction = MovDir[x][y];
857
858   if (direction == MV_LEFT)
859     oldx++;
860   else if (direction == MV_RIGHT)
861     oldx--;
862   else if (direction == MV_UP)
863     oldy++;
864   else if (direction == MV_DOWN)
865     oldy--;
866
867   *comes_from_x = oldx;
868   *comes_from_y = oldy;
869 }
870
871 int MovingOrBlocked2Element(int x, int y)
872 {
873   int element = Feld[x][y];
874
875   if (element == EL_BLOCKED)
876   {
877     int oldx, oldy;
878
879     Blocked2Moving(x, y, &oldx, &oldy);
880     return Feld[oldx][oldy];
881   }
882   else
883     return element;
884 }
885
886 static void RemoveField(int x, int y)
887 {
888   Feld[x][y] = EL_LEERRAUM;
889   MovPos[x][y] = 0;
890   MovDir[x][y] = 0;
891   MovDelay[x][y] = 0;
892 }
893
894 void RemoveMovingField(int x, int y)
895 {
896   int oldx = x, oldy = y, newx = x, newy = y;
897
898   if (Feld[x][y] != EL_BLOCKED && !IS_MOVING(x, y))
899     return;
900
901   if (IS_MOVING(x, y))
902   {
903     Moving2Blocked(x, y, &newx, &newy);
904     if (Feld[newx][newy] != EL_BLOCKED)
905       return;
906   }
907   else if (Feld[x][y] == EL_BLOCKED)
908   {
909     Blocked2Moving(x, y, &oldx, &oldy);
910     if (!IS_MOVING(oldx, oldy))
911       return;
912   }
913
914   if (Feld[x][y] == EL_BLOCKED &&
915       (Store[oldx][oldy] == EL_MORAST_LEER ||
916        Store[oldx][oldy] == EL_SIEB_LEER ||
917        Store[oldx][oldy] == EL_SIEB2_LEER ||
918        Store[oldx][oldy] == EL_AMOEBE_NASS))
919   {
920     Feld[oldx][oldy] = Store[oldx][oldy];
921     Store[oldx][oldy] = Store2[oldx][oldy] = 0;
922   }
923   else
924     Feld[oldx][oldy] = EL_LEERRAUM;
925
926   Feld[newx][newy] = EL_LEERRAUM;
927   MovPos[oldx][oldy] = MovDir[oldx][oldy] = MovDelay[oldx][oldy] = 0;
928   MovPos[newx][newy] = MovDir[newx][newy] = MovDelay[newx][newy] = 0;
929
930   DrawLevelField(oldx, oldy);
931   DrawLevelField(newx, newy);
932 }
933
934 void DrawDynamite(int x, int y)
935 {
936   int sx = SCREENX(x), sy = SCREENY(y);
937   int graphic = el2gfx(Feld[x][y]);
938   int phase;
939
940   if (!IN_SCR_FIELD(sx, sy) || IS_PLAYER(x, y))
941     return;
942
943   if (Store[x][y])
944     DrawGraphic(sx, sy, el2gfx(Store[x][y]));
945
946   if (Feld[x][y] == EL_DYNAMIT)
947   {
948     if ((phase = (96 - MovDelay[x][y]) / 12) > 6)
949       phase = 6;
950   }
951   else
952   {
953     if ((phase = ((96 - MovDelay[x][y]) / 6) % 8) > 3)
954       phase = 7 - phase;
955   }
956
957   if (Store[x][y])
958     DrawGraphicThruMask(sx, sy, graphic + phase);
959   else
960     DrawGraphic(sx, sy, graphic + phase);
961 }
962
963 void CheckDynamite(int x, int y)
964 {
965   if (MovDelay[x][y])           /* dynamite is still waiting to explode */
966   {
967     MovDelay[x][y]--;
968     if (MovDelay[x][y])
969     {
970       if (!(MovDelay[x][y] % 12))
971         PlaySoundLevel(x, y, SND_ZISCH);
972
973       if (Feld[x][y] == EL_DYNAMIT && !(MovDelay[x][y] % 12))
974         DrawDynamite(x, y);
975       else if (Feld[x][y] == EL_DYNABOMB && !(MovDelay[x][y] % 6))
976         DrawDynamite(x, y);
977
978       return;
979     }
980   }
981
982   StopSound(SND_ZISCH);
983   Bang(x, y);
984 }
985
986 void Explode(int ex, int ey, int phase, int mode)
987 {
988   int x, y;
989   int num_phase = 9, delay = 2;
990   int last_phase = num_phase * delay;
991   int half_phase = (num_phase / 2) * delay;
992
993   if (phase == EX_PHASE_START)          /* initialize 'Store[][]' field */
994   {
995     int center_element = Feld[ex][ey];
996
997     if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey))
998     {
999       center_element = MovingOrBlocked2Element(ex, ey);
1000       RemoveMovingField(ex, ey);
1001     }
1002
1003     for (y=ey-1; y<ey+2; y++) for(x=ex-1; x<ex+2; x++)
1004     {
1005       int element = Feld[x][y];
1006
1007       if (IS_MOVING(x, y) || IS_BLOCKED(x, y))
1008       {
1009         element = MovingOrBlocked2Element(x, y);
1010         RemoveMovingField(x, y);
1011       }
1012
1013       if (!IN_LEV_FIELD(x, y) || IS_MASSIV(element) || element == EL_BURNING)
1014         continue;
1015
1016       if ((mode!=EX_NORMAL || center_element == EL_AMOEBA2DIAM) &&
1017           (x!=ex || y!=ey))
1018         continue;
1019
1020       if (element == EL_EXPLODING)
1021         element = Store2[x][y];
1022
1023       if (IS_PLAYER(ex, ey))
1024       {
1025         switch(StorePlayer[ex][ey])
1026         {
1027           case EL_SPIELER2:
1028             Store[x][y] = EL_EDELSTEIN_ROT;
1029             break;
1030           case EL_SPIELER3:
1031             Store[x][y] = EL_EDELSTEIN;
1032             break;
1033           case EL_SPIELER4:
1034             Store[x][y] = EL_EDELSTEIN_LILA;
1035             break;
1036           case EL_SPIELER1:
1037           default:
1038             Store[x][y] = EL_EDELSTEIN_GELB;
1039             break;
1040         }
1041       }
1042       else if (center_element == EL_MAULWURF)
1043         Store[x][y] = EL_EDELSTEIN_ROT;
1044       else if (center_element == EL_PINGUIN)
1045         Store[x][y] = EL_EDELSTEIN_LILA;
1046       else if (center_element == EL_KAEFER)
1047         Store[x][y] = ((x == ex && y == ey) ? EL_DIAMANT : EL_EDELSTEIN);
1048       else if (center_element == EL_BUTTERFLY)
1049         Store[x][y] = EL_EDELSTEIN_BD;
1050       else if (center_element == EL_MAMPFER)
1051         Store[x][y] = level.mampfer_inhalt[MampferNr][x-ex+1][y-ey+1];
1052       else if (center_element == EL_AMOEBA2DIAM)
1053         Store[x][y] = level.amoebe_inhalt;
1054       else if (element == EL_ERZ_EDEL)
1055         Store[x][y] = EL_EDELSTEIN;
1056       else if (element == EL_ERZ_DIAM)
1057         Store[x][y] = EL_DIAMANT;
1058       else if (element == EL_ERZ_EDEL_BD)
1059         Store[x][y] = EL_EDELSTEIN_BD;
1060       else if (element == EL_ERZ_EDEL_GELB)
1061         Store[x][y] = EL_EDELSTEIN_GELB;
1062       else if (element == EL_ERZ_EDEL_ROT)
1063         Store[x][y] = EL_EDELSTEIN_ROT;
1064       else if (element == EL_ERZ_EDEL_LILA)
1065         Store[x][y] = EL_EDELSTEIN_LILA;
1066       else if (!IS_PFORTE(Store[x][y]))
1067         Store[x][y] = EL_LEERRAUM;
1068
1069       if (x != ex || y != ey ||
1070           center_element == EL_AMOEBA2DIAM || mode == EX_BORDER)
1071         Store2[x][y] = element;
1072
1073       if (AmoebaNr[x][y] &&
1074           (element == EL_AMOEBE_VOLL ||
1075            element == EL_AMOEBE_BD ||
1076            element == EL_AMOEBING))
1077       {
1078         AmoebaCnt[AmoebaNr[x][y]]--;
1079         AmoebaCnt2[AmoebaNr[x][y]]--;
1080       }
1081
1082       Feld[x][y] = EL_EXPLODING;
1083       MovDir[x][y] = MovPos[x][y] = 0;
1084       AmoebaNr[x][y] = 0;
1085       Frame[x][y] = 1;
1086       Stop[x][y] = TRUE;
1087     }
1088
1089     if (center_element == EL_MAMPFER)
1090       MampferNr = (MampferNr + 1) % MampferMax;
1091
1092     return;
1093   }
1094
1095   if (Stop[ex][ey])
1096     return;
1097
1098   x = ex;
1099   y = ey;
1100
1101   Frame[x][y] = (phase<last_phase ? phase+1 : 0);
1102
1103   if (phase == half_phase)
1104   {
1105     int element = Store2[x][y];
1106
1107     if (IS_PLAYER(x, y))
1108       KillHero(PLAYERINFO(x, y));
1109     else if (IS_EXPLOSIVE(element))
1110     {
1111       Feld[x][y] = Store2[x][y];
1112       Store2[x][y] = 0;
1113       Bang(x, y);
1114     }
1115     else if (element == EL_AMOEBA2DIAM)
1116       AmoebeUmwandeln(x, y);
1117   }
1118
1119   if (phase == last_phase)
1120   {
1121     int element;
1122
1123     element = Feld[x][y] = Store[x][y];
1124     Store[x][y] = Store2[x][y] = 0;
1125     MovDir[x][y] = MovPos[x][y] = MovDelay[x][y] = 0;
1126     InitField(x, y, FALSE);
1127     if (CAN_MOVE(element) || COULD_MOVE(element))
1128       InitMovDir(x, y);
1129     DrawLevelField(x, y);
1130   }
1131   else if (!(phase%delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1132   {
1133     if (phase == delay)
1134       ErdreichAnbroeckeln(SCREENX(x), SCREENY(y));
1135
1136     DrawGraphic(SCREENX(x), SCREENY(y), GFX_EXPLOSION+(phase/delay-1));
1137   }
1138 }
1139
1140 void DynaExplode(int ex, int ey)
1141 {
1142   int i, j;
1143   struct PlayerInfo *player = &stored_player[Store2[ex][ey] - EL_SPIELER1];
1144   static int xy[4][2] =
1145   {
1146     { 0, -1 },
1147     { -1, 0 },
1148     { +1, 0 },
1149     { 0, +1 }
1150   };
1151
1152   Store2[ex][ey] = 0;   /* delete player information */
1153
1154   Explode(ex, ey, EX_PHASE_START, EX_CENTER);
1155
1156   for (i=0; i<4; i++)
1157   {
1158     for (j=1; j<=player->dynabomb_size; j++)
1159     {
1160       int x = ex+j*xy[i%4][0];
1161       int y = ey+j*xy[i%4][1];
1162       int element;
1163
1164       if (!IN_LEV_FIELD(x, y) || IS_MASSIV(Feld[x][y]))
1165         break;
1166
1167       element = Feld[x][y];
1168       Explode(x, y, EX_PHASE_START, EX_BORDER);
1169
1170       if (element != EL_LEERRAUM &&
1171           element != EL_ERDREICH &&
1172           element != EL_EXPLODING &&
1173           !player->dynabomb_xl)
1174         break;
1175     }
1176   }
1177
1178   player->dynabombs_left++;
1179 }
1180
1181 void Bang(int x, int y)
1182 {
1183   int element = Feld[x][y];
1184
1185   PlaySoundLevel(x, y, SND_ROAAAR);
1186
1187   if (IS_PLAYER(x, y))  /* remove objects that might cause smaller explosion */
1188     element = EL_LEERRAUM;
1189
1190   switch(element)
1191   {
1192     case EL_KAEFER:
1193     case EL_FLIEGER:
1194     case EL_BUTTERFLY:
1195     case EL_FIREFLY:
1196     case EL_MAMPFER:
1197     case EL_MAMPFER2:
1198     case EL_ROBOT:
1199     case EL_PACMAN:
1200       RaiseScoreElement(element);
1201       Explode(x, y, EX_PHASE_START, EX_NORMAL);
1202       break;
1203     case EL_DYNABOMB:
1204     case EL_DYNABOMB_NR:
1205     case EL_DYNABOMB_SZ:
1206     case EL_DYNABOMB_XL:
1207       DynaExplode(x, y);
1208       break;
1209     case EL_MAULWURF:
1210     case EL_PINGUIN:
1211     case EL_BIRNE_AUS:
1212     case EL_BIRNE_EIN:
1213       Explode(x, y, EX_PHASE_START, EX_CENTER);
1214       break;
1215     default:
1216       Explode(x, y, EX_PHASE_START, EX_NORMAL);
1217       break;
1218   }
1219 }
1220
1221 void Blurb(int x, int y)
1222 {
1223   int element = Feld[x][y];
1224
1225   if (element != EL_BLURB_LEFT && element != EL_BLURB_RIGHT)    /* start */
1226   {
1227     PlaySoundLevel(x, y, SND_BLURB);
1228     if (IN_LEV_FIELD(x-1, y) && IS_FREE(x-1, y) &&
1229         (!IN_LEV_FIELD(x-1, y-1) ||
1230          !CAN_FALL(MovingOrBlocked2Element(x-1, y-1))))
1231     {
1232       Feld[x-1][y] = EL_BLURB_LEFT;
1233     }
1234     if (IN_LEV_FIELD(x+1, y) && IS_FREE(x+1, y) &&
1235         (!IN_LEV_FIELD(x+1, y-1) ||
1236          !CAN_FALL(MovingOrBlocked2Element(x+1, y-1))))
1237     {
1238       Feld[x+1][y] = EL_BLURB_RIGHT;
1239     }
1240   }
1241   else                                                          /* go on */
1242   {
1243     int graphic = (element==EL_BLURB_LEFT ? GFX_BLURB_LEFT : GFX_BLURB_RIGHT);
1244
1245     if (!MovDelay[x][y])        /* initialize animation counter */
1246       MovDelay[x][y] = 9;
1247
1248     if (MovDelay[x][y])         /* continue animation */
1249     {
1250       MovDelay[x][y]--;
1251       if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1252         DrawGraphic(SCREENX(x), SCREENY(y), graphic+4-MovDelay[x][y]/2);
1253
1254       if (!MovDelay[x][y])
1255       {
1256         Feld[x][y] = EL_LEERRAUM;
1257         DrawLevelField(x, y);
1258       }
1259     }
1260   }
1261 }
1262
1263 void Impact(int x, int y)
1264 {
1265   boolean lastline = (y == lev_fieldy-1);
1266   boolean object_hit = FALSE;
1267   int element = Feld[x][y];
1268   int smashed = 0;
1269
1270   if (!lastline)        /* check if element below was hit */
1271   {
1272     if (Feld[x][y+1] == EL_PLAYER_IS_LEAVING)
1273       return;
1274
1275     object_hit = (!IS_FREE(x, y+1) && (!IS_MOVING(x, y+1) ||
1276                                       MovDir[x][y+1]!=MV_DOWN ||
1277                                       MovPos[x][y+1]<=TILEY/2));
1278     if (object_hit)
1279       smashed = MovingOrBlocked2Element(x, y+1);
1280   }
1281
1282   if (!lastline && smashed == EL_SALZSAEURE)    /* element falls into acid */
1283   {
1284     Blurb(x, y);
1285     return;
1286   }
1287
1288   if (element == EL_BOMBE && (lastline || object_hit))  /* element is bomb */
1289   {
1290     Bang(x, y);
1291     return;
1292   }
1293
1294   if (element == EL_TROPFEN && (lastline || object_hit))        /* acid drop */
1295   {
1296     if (object_hit && IS_PLAYER(x, y+1))
1297       KillHero(PLAYERINFO(x, y+1));
1298     else if (object_hit && (smashed == EL_MAULWURF || smashed == EL_PINGUIN))
1299       Bang(x, y+1);
1300     else
1301     {
1302       Feld[x][y] = EL_AMOEBING;
1303       Store[x][y] = EL_AMOEBE_NASS;
1304     }
1305     return;
1306   }
1307
1308   if (!lastline && object_hit)          /* check which object was hit */
1309   {
1310     if (CAN_CHANGE(element) && 
1311         (smashed == EL_SIEB_INAKTIV || smashed == EL_SIEB2_INAKTIV))
1312     {
1313       int x, y;
1314       int activated_magic_wall =
1315         (smashed == EL_SIEB_INAKTIV ? EL_SIEB_LEER : EL_SIEB2_LEER);
1316
1317       /* activate magic wall / mill */
1318
1319       for (y=0; y<lev_fieldy; y++)
1320         for (x=0; x<lev_fieldx; x++)
1321           if (Feld[x][y] == smashed)
1322             Feld[x][y] = activated_magic_wall;
1323
1324       SiebCount = level.dauer_sieb * FRAMES_PER_SECOND;
1325       SiebAktiv = TRUE;
1326     }
1327
1328     if (IS_PLAYER(x, y+1))
1329     {
1330       KillHero(PLAYERINFO(x, y+1));
1331       return;
1332     }
1333     else if (smashed == EL_MAULWURF || smashed == EL_PINGUIN)
1334     {
1335       Bang(x, y+1);
1336       return;
1337     }
1338     else if (element == EL_EDELSTEIN_BD)
1339     {
1340       if (IS_ENEMY(smashed) && IS_BD_ELEMENT(smashed))
1341       {
1342         Bang(x, y+1);
1343         return;
1344       }
1345     }
1346     else if (element == EL_FELSBROCKEN)
1347     {
1348       if (IS_ENEMY(smashed) || smashed == EL_BOMBE || smashed == EL_SONDE ||
1349           smashed == EL_SCHWEIN || smashed == EL_DRACHE)
1350       {
1351         Bang(x, y+1);
1352         return;
1353       }
1354       else if (!IS_MOVING(x, y+1))
1355       {
1356         if (smashed == EL_BIRNE_AUS || smashed == EL_BIRNE_EIN)
1357         {
1358           Bang(x, y+1);
1359           return;
1360         }
1361         else if (smashed == EL_KOKOSNUSS)
1362         {
1363           Feld[x][y+1] = EL_CRACKINGNUT;
1364           PlaySoundLevel(x, y, SND_KNACK);
1365           RaiseScoreElement(EL_KOKOSNUSS);
1366           return;
1367         }
1368         else if (smashed == EL_DIAMANT)
1369         {
1370           Feld[x][y+1] = EL_LEERRAUM;
1371           PlaySoundLevel(x, y, SND_QUIRK);
1372           return;
1373         }
1374       }
1375     }
1376   }
1377
1378   /* play sound of magic wall / mill */
1379   if (!lastline &&
1380       (Feld[x][y+1] == EL_SIEB_LEER || Feld[x][y+1] == EL_SIEB2_LEER))
1381   {
1382     PlaySoundLevel(x, y, SND_QUIRK);
1383     return;
1384   }
1385
1386   /* play sound of object that hits the ground */
1387   if (lastline || object_hit)
1388   {
1389     int sound;
1390
1391     switch(element)
1392     {
1393       case EL_EDELSTEIN:
1394       case EL_EDELSTEIN_BD:
1395       case EL_EDELSTEIN_GELB:
1396       case EL_EDELSTEIN_ROT:
1397       case EL_EDELSTEIN_LILA:
1398       case EL_DIAMANT:
1399         sound = SND_PLING;
1400         break;
1401       case EL_KOKOSNUSS:
1402         sound = SND_KLUMPF;
1403         break;
1404       case EL_FELSBROCKEN:
1405         sound = SND_KLOPF;
1406         break;
1407       case EL_SCHLUESSEL:
1408       case EL_SCHLUESSEL1:
1409       case EL_SCHLUESSEL2:
1410       case EL_SCHLUESSEL3:
1411       case EL_SCHLUESSEL4:
1412         sound = SND_KINK;
1413         break;
1414       case EL_ZEIT_VOLL:
1415       case EL_ZEIT_LEER:
1416         sound = SND_DENG;
1417         break;
1418       default:
1419         sound = -1;
1420         break;
1421     }
1422
1423     if (sound>=0)
1424       PlaySoundLevel(x, y, sound);
1425   }
1426 }
1427
1428 void TurnRound(int x, int y)
1429 {
1430   static struct
1431   {
1432     int x, y;
1433   } move_xy[] =
1434   {
1435     { 0, 0 },
1436     {-1, 0 },
1437     {+1, 0 },
1438     { 0, 0 },
1439     { 0, -1 },
1440     { 0, 0 }, { 0, 0 }, { 0, 0 },
1441     { 0, +1 }
1442   };
1443   static struct
1444   {
1445     int left, right, back;
1446   } turn[] =
1447   {
1448     { 0,        0,              0 },
1449     { MV_DOWN,  MV_UP,          MV_RIGHT },
1450     { MV_UP,    MV_DOWN,        MV_LEFT },
1451     { 0,        0,              0 },
1452     { MV_LEFT,  MV_RIGHT,       MV_DOWN },
1453     { 0,0,0 },  { 0,0,0 },      { 0,0,0 },
1454     { MV_RIGHT, MV_LEFT,        MV_UP }
1455   };
1456
1457   int element = Feld[x][y];
1458   int old_move_dir = MovDir[x][y];
1459   int left_dir = turn[old_move_dir].left;
1460   int right_dir = turn[old_move_dir].right;
1461   int back_dir = turn[old_move_dir].back;
1462
1463   int left_dx = move_xy[left_dir].x, left_dy = move_xy[left_dir].y;
1464   int right_dx = move_xy[right_dir].x, right_dy = move_xy[right_dir].y;
1465   int move_dx = move_xy[old_move_dir].x, move_dy = move_xy[old_move_dir].y;
1466   int back_dx = move_xy[back_dir].x, back_dy = move_xy[back_dir].y;
1467
1468   int left_x = x+left_dx, left_y = y+left_dy;
1469   int right_x = x+right_dx, right_y = y+right_dy;
1470   int move_x = x+move_dx, move_y = y+move_dy;
1471
1472   if (element == EL_KAEFER || element == EL_BUTTERFLY)
1473   {
1474     TestIfBadThingHitsOtherBadThing(x, y);
1475
1476     if (IN_LEV_FIELD(right_x, right_y) &&
1477         IS_FREE_OR_PLAYER(right_x, right_y))
1478       MovDir[x][y] = right_dir;
1479     else if (!IN_LEV_FIELD(move_x, move_y) ||
1480              !IS_FREE_OR_PLAYER(move_x, move_y))
1481       MovDir[x][y] = left_dir;
1482
1483     if (element == EL_KAEFER && MovDir[x][y] != old_move_dir)
1484       MovDelay[x][y] = 9;
1485     else if (element == EL_BUTTERFLY)   /* && MovDir[x][y] == left_dir) */
1486       MovDelay[x][y] = 1;
1487   }
1488   else if (element == EL_FLIEGER || element == EL_FIREFLY)
1489   {
1490     TestIfBadThingHitsOtherBadThing(x, y);
1491
1492     if (IN_LEV_FIELD(left_x, left_y) &&
1493         IS_FREE_OR_PLAYER(left_x, left_y))
1494       MovDir[x][y] = left_dir;
1495     else if (!IN_LEV_FIELD(move_x, move_y) ||
1496              !IS_FREE_OR_PLAYER(move_x, move_y))
1497       MovDir[x][y] = right_dir;
1498
1499     if (element == EL_FLIEGER && MovDir[x][y] != old_move_dir)
1500       MovDelay[x][y] = 9;
1501     else if (element == EL_FIREFLY)     /* && MovDir[x][y] == right_dir) */
1502       MovDelay[x][y] = 1;
1503   }
1504   else if (element == EL_MAMPFER)
1505   {
1506     boolean can_turn_left = FALSE, can_turn_right = FALSE;
1507
1508     if (IN_LEV_FIELD(left_x, left_y) &&
1509         (IS_FREE_OR_PLAYER(left_x, left_y) ||
1510          Feld[left_x][left_y] == EL_DIAMANT))
1511       can_turn_left = TRUE;
1512     if (IN_LEV_FIELD(right_x, right_y) &&
1513         (IS_FREE_OR_PLAYER(right_x, right_y) ||
1514          Feld[right_x][right_y] == EL_DIAMANT))
1515       can_turn_right = TRUE;
1516
1517     if (can_turn_left && can_turn_right)
1518       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
1519     else if (can_turn_left)
1520       MovDir[x][y] = (RND(2) ? left_dir : back_dir);
1521     else if (can_turn_right)
1522       MovDir[x][y] = (RND(2) ? right_dir : back_dir);
1523     else
1524       MovDir[x][y] = back_dir;
1525
1526     MovDelay[x][y] = 16+16*RND(3);
1527   }
1528   else if (element == EL_MAMPFER2)
1529   {
1530     boolean can_turn_left = FALSE, can_turn_right = FALSE;
1531
1532     if (IN_LEV_FIELD(left_x, left_y) &&
1533         (IS_FREE_OR_PLAYER(left_x, left_y) ||
1534          IS_MAMPF2(Feld[left_x][left_y])))
1535       can_turn_left = TRUE;
1536     if (IN_LEV_FIELD(right_x, right_y) &&
1537         (IS_FREE_OR_PLAYER(right_x, right_y) ||
1538          IS_MAMPF2(Feld[right_x][right_y])))
1539       can_turn_right = TRUE;
1540
1541     if (can_turn_left && can_turn_right)
1542       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
1543     else if (can_turn_left)
1544       MovDir[x][y] = (RND(2) ? left_dir : back_dir);
1545     else if (can_turn_right)
1546       MovDir[x][y] = (RND(2) ? right_dir : back_dir);
1547     else
1548       MovDir[x][y] = back_dir;
1549
1550     MovDelay[x][y] = 16+16*RND(3);
1551   }
1552   else if (element == EL_PACMAN)
1553   {
1554     boolean can_turn_left = FALSE, can_turn_right = FALSE;
1555
1556     if (IN_LEV_FIELD(left_x, left_y) &&
1557         (IS_FREE_OR_PLAYER(left_x, left_y) ||
1558          IS_AMOEBOID(Feld[left_x][left_y])))
1559       can_turn_left = TRUE;
1560     if (IN_LEV_FIELD(right_x, right_y) &&
1561         (IS_FREE_OR_PLAYER(right_x, right_y) ||
1562          IS_AMOEBOID(Feld[right_x][right_y])))
1563       can_turn_right = TRUE;
1564
1565     if (can_turn_left && can_turn_right)
1566       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
1567     else if (can_turn_left)
1568       MovDir[x][y] = (RND(2) ? left_dir : back_dir);
1569     else if (can_turn_right)
1570       MovDir[x][y] = (RND(2) ? right_dir : back_dir);
1571     else
1572       MovDir[x][y] = back_dir;
1573
1574     MovDelay[x][y] = 6+RND(40);
1575   }
1576   else if (element == EL_SCHWEIN)
1577   {
1578     boolean can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE;
1579     boolean should_turn_left = FALSE, should_turn_right = FALSE;
1580     boolean should_move_on = FALSE;
1581     int rnd_value = 24;
1582     int rnd = RND(rnd_value);
1583
1584     if (IN_LEV_FIELD(left_x, left_y) &&
1585         (IS_FREE(left_x, left_y) || IS_GEM(Feld[left_x][left_y])))
1586       can_turn_left = TRUE;
1587     if (IN_LEV_FIELD(right_x, right_y) &&
1588         (IS_FREE(right_x, right_y) || IS_GEM(Feld[right_x][right_y])))
1589       can_turn_right = TRUE;
1590     if (IN_LEV_FIELD(move_x, move_y) &&
1591         (IS_FREE(move_x, move_y) || IS_GEM(Feld[move_x][move_y])))
1592       can_move_on = TRUE;
1593
1594     if (can_turn_left &&
1595         (!can_move_on ||
1596          (IN_LEV_FIELD(x+back_dx+left_dx, y+back_dy+left_dy) &&
1597           !IS_FREE(x+back_dx+left_dx, y+back_dy+left_dy))))
1598       should_turn_left = TRUE;
1599     if (can_turn_right &&
1600         (!can_move_on ||
1601          (IN_LEV_FIELD(x+back_dx+right_dx, y+back_dy+right_dy) &&
1602           !IS_FREE(x+back_dx+right_dx, y+back_dy+right_dy))))
1603       should_turn_right = TRUE;
1604     if (can_move_on &&
1605         (!can_turn_left || !can_turn_right ||
1606          (IN_LEV_FIELD(x+move_dx+left_dx, y+move_dy+left_dy) &&
1607           !IS_FREE(x+move_dx+left_dx, y+move_dy+left_dy)) ||
1608          (IN_LEV_FIELD(x+move_dx+right_dx, y+move_dy+right_dy) &&
1609           !IS_FREE(x+move_dx+right_dx, y+move_dy+right_dy))))
1610       should_move_on = TRUE;
1611
1612     if (should_turn_left || should_turn_right || should_move_on)
1613     {
1614       if (should_turn_left && should_turn_right && should_move_on)
1615         MovDir[x][y] = (rnd < rnd_value/3 ? left_dir :
1616                         rnd < 2*rnd_value/3 ? right_dir :
1617                         old_move_dir);
1618       else if (should_turn_left && should_turn_right)
1619         MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
1620       else if (should_turn_left && should_move_on)
1621         MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : old_move_dir);
1622       else if (should_turn_right && should_move_on)
1623         MovDir[x][y] = (rnd < rnd_value/2 ? right_dir : old_move_dir);
1624       else if (should_turn_left)
1625         MovDir[x][y] = left_dir;
1626       else if (should_turn_right)
1627         MovDir[x][y] = right_dir;
1628       else if (should_move_on)
1629         MovDir[x][y] = old_move_dir;
1630     }
1631     else if (can_move_on && rnd > rnd_value/8)
1632       MovDir[x][y] = old_move_dir;
1633     else if (can_turn_left && can_turn_right)
1634       MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
1635     else if (can_turn_left && rnd > rnd_value/8)
1636       MovDir[x][y] = left_dir;
1637     else if (can_turn_right && rnd > rnd_value/8)
1638       MovDir[x][y] = right_dir;
1639     else
1640       MovDir[x][y] = back_dir;
1641
1642     if (!IS_FREE(x+move_xy[MovDir[x][y]].x, y+move_xy[MovDir[x][y]].y) &&
1643         !IS_GEM(Feld[x+move_xy[MovDir[x][y]].x][y+move_xy[MovDir[x][y]].y]))
1644       MovDir[x][y] = old_move_dir;
1645
1646     MovDelay[x][y] = 0;
1647   }
1648   else if (element == EL_DRACHE)
1649   {
1650     boolean can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE;
1651     int rnd_value = 24;
1652     int rnd = RND(rnd_value);
1653
1654     if (IN_LEV_FIELD(left_x, left_y) && IS_FREE(left_x, left_y))
1655       can_turn_left = TRUE;
1656     if (IN_LEV_FIELD(right_x, right_y) && IS_FREE(right_x, right_y))
1657       can_turn_right = TRUE;
1658     if (IN_LEV_FIELD(move_x, move_y) && IS_FREE(move_x, move_y))
1659       can_move_on = TRUE;
1660
1661     if (can_move_on && rnd > rnd_value/8)
1662       MovDir[x][y] = old_move_dir;
1663     else if (can_turn_left && can_turn_right)
1664       MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
1665     else if (can_turn_left && rnd > rnd_value/8)
1666       MovDir[x][y] = left_dir;
1667     else if (can_turn_right && rnd > rnd_value/8)
1668       MovDir[x][y] = right_dir;
1669     else
1670       MovDir[x][y] = back_dir;
1671
1672     if (!IS_FREE(x+move_xy[MovDir[x][y]].x, y+move_xy[MovDir[x][y]].y))
1673       MovDir[x][y] = old_move_dir;
1674
1675     MovDelay[x][y] = 0;
1676   }
1677   else if (element == EL_ROBOT || element == EL_SONDE ||
1678            element == EL_MAULWURF || element == EL_PINGUIN)
1679   {
1680     int attr_x = -1, attr_y = -1;
1681
1682     if (AllPlayersGone)
1683     {
1684       attr_x = ExitX;
1685       attr_y = ExitY;
1686     }
1687     else
1688     {
1689       int i;
1690
1691       for (i=0; i<MAX_PLAYERS; i++)
1692       {
1693         struct PlayerInfo *player = &stored_player[i];
1694         int jx = player->jx, jy = player->jy;
1695
1696         if (!player->active || player->gone)
1697           continue;
1698
1699         if (attr_x == -1 || ABS(jx-x)+ABS(jy-y) < ABS(attr_x-x)+ABS(attr_y-y))
1700         {
1701           attr_x = jx;
1702           attr_y = jy;
1703         }
1704       }
1705     }
1706
1707     if (element == EL_ROBOT && ZX>=0 && ZY>=0)
1708     {
1709       attr_x = ZX;
1710       attr_y = ZY;
1711     }
1712
1713     if (element == EL_MAULWURF || element == EL_PINGUIN)
1714     {
1715       int i;
1716       static int xy[4][2] =
1717       {
1718         { 0, -1 },
1719         { -1, 0 },
1720         { +1, 0 },
1721         { 0, +1 }
1722       };
1723
1724       for (i=0; i<4; i++)
1725       {
1726         int ex = x + xy[i%4][0];
1727         int ey = y + xy[i%4][1];
1728
1729         if (IN_LEV_FIELD(ex, ey) && Feld[ex][ey] == EL_AUSGANG_AUF)
1730         {
1731           attr_x = ex;
1732           attr_y = ey;
1733           break;
1734         }
1735       }
1736     }
1737
1738     MovDir[x][y] = MV_NO_MOVING;
1739     if (attr_x<x)
1740       MovDir[x][y] |= (AllPlayersGone ? MV_RIGHT : MV_LEFT);
1741     else if (attr_x>x)
1742       MovDir[x][y] |= (AllPlayersGone ? MV_LEFT : MV_RIGHT);
1743     if (attr_y<y)
1744       MovDir[x][y] |= (AllPlayersGone ? MV_DOWN : MV_UP);
1745     else if (attr_y>y)
1746       MovDir[x][y] |= (AllPlayersGone ? MV_UP : MV_DOWN);
1747
1748     if (element == EL_ROBOT)
1749     {
1750       int newx, newy;
1751
1752       if ((MovDir[x][y]&(MV_LEFT|MV_RIGHT)) && (MovDir[x][y]&(MV_UP|MV_DOWN)))
1753         MovDir[x][y] &= (RND(2) ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
1754       Moving2Blocked(x, y, &newx, &newy);
1755
1756       if (IN_LEV_FIELD(newx, newy) && IS_FREE_OR_PLAYER(newx, newy))
1757         MovDelay[x][y] = 8+8*!RND(3);
1758       else
1759         MovDelay[x][y] = 16;
1760     }
1761     else
1762     {
1763       int newx, newy;
1764
1765       MovDelay[x][y] = 1;
1766
1767       if ((MovDir[x][y]&(MV_LEFT|MV_RIGHT)) && (MovDir[x][y]&(MV_UP|MV_DOWN)))
1768       {
1769         boolean first_horiz = RND(2);
1770         int new_move_dir = MovDir[x][y];
1771
1772         MovDir[x][y] =
1773           new_move_dir & (first_horiz ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
1774         Moving2Blocked(x, y, &newx, &newy);
1775
1776         if (IN_LEV_FIELD(newx, newy) &&
1777             (IS_FREE(newx, newy) ||
1778              Feld[newx][newy] == EL_SALZSAEURE ||
1779              ((element == EL_MAULWURF || element == EL_PINGUIN) &&
1780               (Feld[newx][newy] == EL_AUSGANG_AUF ||
1781                IS_MAMPF3(Feld[newx][newy])))))
1782           return;
1783
1784         MovDir[x][y] =
1785           new_move_dir & (!first_horiz ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
1786         Moving2Blocked(x, y, &newx, &newy);
1787
1788         if (IN_LEV_FIELD(newx, newy) &&
1789             (IS_FREE(newx, newy) ||
1790              Feld[newx][newy] == EL_SALZSAEURE ||
1791              ((element == EL_MAULWURF || element == EL_PINGUIN) &&
1792               (Feld[newx][newy] == EL_AUSGANG_AUF ||
1793                IS_MAMPF3(Feld[newx][newy])))))
1794           return;
1795
1796         MovDir[x][y] = old_move_dir;
1797         return;
1798       }
1799     }
1800   }
1801 }
1802
1803 static boolean JustBeingPushed(int x, int y)
1804 {
1805   int i;
1806
1807   for (i=0; i<MAX_PLAYERS; i++)
1808   {
1809     struct PlayerInfo *player = &stored_player[i];
1810
1811     if (player->active && !player->gone &&
1812         player->Pushing && player->MovPos)
1813     {
1814       int next_jx = player->jx + (player->jx - player->last_jx);
1815       int next_jy = player->jy + (player->jy - player->last_jy);
1816
1817       if (x == next_jx && y == next_jy)
1818         return TRUE;
1819     }
1820   }
1821
1822   return FALSE;
1823 }
1824
1825 void StartMoving(int x, int y)
1826 {
1827   int element = Feld[x][y];
1828
1829   if (Stop[x][y])
1830     return;
1831
1832   if (CAN_FALL(element) && y<lev_fieldy-1)
1833   {
1834     if ((x>0 && IS_PLAYER(x-1, y)) || (x<lev_fieldx-1 && IS_PLAYER(x+1, y)))
1835       if (JustBeingPushed(x, y))
1836         return;
1837
1838     if (element == EL_MORAST_VOLL)
1839     {
1840       if (IS_FREE(x, y+1))
1841       {
1842         InitMovingField(x, y, MV_DOWN);
1843         Feld[x][y] = EL_FELSBROCKEN;
1844         Store[x][y] = EL_MORAST_LEER;
1845       }
1846       else if (Feld[x][y+1] == EL_MORAST_LEER)
1847       {
1848         if (!MovDelay[x][y])
1849           MovDelay[x][y] = TILEY + 1;
1850
1851         if (MovDelay[x][y])
1852         {
1853           MovDelay[x][y]--;
1854           if (MovDelay[x][y])
1855             return;
1856         }
1857
1858         Feld[x][y] = EL_MORAST_LEER;
1859         Feld[x][y+1] = EL_MORAST_VOLL;
1860       }
1861     }
1862     else if (element == EL_FELSBROCKEN && Feld[x][y+1] == EL_MORAST_LEER)
1863     {
1864       InitMovingField(x, y, MV_DOWN);
1865       Store[x][y] = EL_MORAST_VOLL;
1866     }
1867     else if (element == EL_SIEB_VOLL)
1868     {
1869       if (IS_FREE(x, y+1))
1870       {
1871         InitMovingField(x, y, MV_DOWN);
1872         Feld[x][y] = EL_CHANGED(Store2[x][y]);
1873         Store[x][y] = EL_SIEB_LEER;
1874       }
1875       else if (Feld[x][y+1] == EL_SIEB_LEER)
1876       {
1877         if (!MovDelay[x][y])
1878           MovDelay[x][y] = TILEY/4 + 1;
1879
1880         if (MovDelay[x][y])
1881         {
1882           MovDelay[x][y]--;
1883           if (MovDelay[x][y])
1884             return;
1885         }
1886
1887         Feld[x][y] = EL_SIEB_LEER;
1888         Feld[x][y+1] = EL_SIEB_VOLL;
1889         Store2[x][y+1] = EL_CHANGED(Store2[x][y]);
1890         Store2[x][y] = 0;
1891       }
1892     }
1893     else if (element == EL_SIEB2_VOLL)
1894     {
1895       if (IS_FREE(x, y+1))
1896       {
1897         InitMovingField(x, y, MV_DOWN);
1898         Feld[x][y] = EL_CHANGED2(Store2[x][y]);
1899         Store[x][y] = EL_SIEB2_LEER;
1900       }
1901       else if (Feld[x][y+1] == EL_SIEB2_LEER)
1902       {
1903         if (!MovDelay[x][y])
1904           MovDelay[x][y] = TILEY/4 + 1;
1905
1906         if (MovDelay[x][y])
1907         {
1908           MovDelay[x][y]--;
1909           if (MovDelay[x][y])
1910             return;
1911         }
1912
1913         Feld[x][y] = EL_SIEB2_LEER;
1914         Feld[x][y+1] = EL_SIEB2_VOLL;
1915         Store2[x][y+1] = EL_CHANGED2(Store2[x][y]);
1916         Store2[x][y] = 0;
1917       }
1918     }
1919     else if (CAN_CHANGE(element) &&
1920              (Feld[x][y+1] == EL_SIEB_LEER || Feld[x][y+1] == EL_SIEB2_LEER))
1921     {
1922       InitMovingField(x, y, MV_DOWN);
1923       Store[x][y] =
1924         (Feld[x][y+1] == EL_SIEB_LEER ? EL_SIEB_VOLL : EL_SIEB2_VOLL);
1925       Store2[x][y+1] = element;
1926     }
1927     else if (CAN_SMASH(element) && Feld[x][y+1] == EL_SALZSAEURE)
1928     {
1929       Blurb(x, y);
1930       InitMovingField(x, y, MV_DOWN);
1931       Store[x][y] = EL_SALZSAEURE;
1932     }
1933     else if (CAN_SMASH(element) && Feld[x][y+1] == EL_BLOCKED && JustHit[x][y])
1934     {
1935       Impact(x, y);
1936     }
1937     else if (IS_FREE(x, y+1))
1938     {
1939       InitMovingField(x, y, MV_DOWN);
1940     }
1941     else if (element == EL_TROPFEN)
1942     {
1943       Feld[x][y] = EL_AMOEBING;
1944       Store[x][y] = EL_AMOEBE_NASS;
1945     }
1946     else if (IS_SLIPPERY(Feld[x][y+1]) && !Store[x][y+1])
1947     {
1948       boolean left  = (x>0 && IS_FREE(x-1, y) &&
1949                        (IS_FREE(x-1, y+1) || Feld[x-1][y+1] == EL_SALZSAEURE));
1950       boolean right = (x<lev_fieldx-1 && IS_FREE(x+1, y) &&
1951                        (IS_FREE(x+1, y+1) || Feld[x+1][y+1] == EL_SALZSAEURE));
1952
1953       if (left || right)
1954       {
1955         if (left && right && game_emulation != EMU_BOULDERDASH)
1956           left = !(right = RND(2));
1957
1958         InitMovingField(x, y, left ? MV_LEFT : MV_RIGHT);
1959       }
1960     }
1961   }
1962   else if (CAN_MOVE(element))
1963   {
1964     int newx, newy;
1965
1966     if (element == EL_SONDE && JustBeingPushed(x, y))
1967       return;
1968
1969     if (!MovDelay[x][y])        /* start new movement phase */
1970     {
1971       /* all objects that can change their move direction after each step */
1972       /* (MAMPFER, MAMPFER2 and PACMAN go straight until they hit a wall  */
1973
1974       if (element!=EL_MAMPFER && element!=EL_MAMPFER2 && element!=EL_PACMAN)
1975       {
1976         TurnRound(x, y);
1977         if (MovDelay[x][y] && (element == EL_KAEFER || element == EL_FLIEGER))
1978           DrawLevelField(x, y);
1979       }
1980     }
1981
1982     if (MovDelay[x][y])         /* wait some time before next movement */
1983     {
1984       MovDelay[x][y]--;
1985
1986       if (element == EL_ROBOT || element == EL_MAMPFER ||
1987           element == EL_MAMPFER2)
1988       {
1989         int phase = MovDelay[x][y] % 8;
1990
1991         if (phase>3)
1992           phase = 7-phase;
1993
1994         if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1995           DrawGraphic(SCREENX(x), SCREENY(y), el2gfx(element)+phase);
1996
1997         if ((element == EL_MAMPFER || element == EL_MAMPFER2)
1998             && MovDelay[x][y]%4 == 3)
1999           PlaySoundLevel(x, y, SND_NJAM);
2000       }
2001       else if (element == EL_DRACHE)
2002       {
2003         int i;
2004         int dir = MovDir[x][y];
2005         int dx = (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2006         int dy = (dir == MV_UP   ? -1 : dir == MV_DOWN  ? +1 : 0);
2007         int graphic = (dir == MV_LEFT   ? GFX_FLAMMEN_LEFT :
2008                        dir == MV_RIGHT  ? GFX_FLAMMEN_RIGHT :
2009                        dir == MV_UP     ? GFX_FLAMMEN_UP :
2010                        dir == MV_DOWN   ? GFX_FLAMMEN_DOWN : GFX_LEERRAUM);
2011         int phase = FrameCounter % 2;
2012
2013         for (i=1; i<=3; i++)
2014         {
2015           int xx = x + i*dx, yy = y + i*dy;
2016           int sx = SCREENX(xx), sy = SCREENY(yy);
2017
2018           if (!IN_LEV_FIELD(xx, yy) ||
2019               IS_SOLID(Feld[xx][yy]) || Feld[xx][yy] == EL_EXPLODING)
2020             break;
2021
2022           if (MovDelay[x][y])
2023           {
2024             int flamed = MovingOrBlocked2Element(xx, yy);
2025
2026             if (IS_ENEMY(flamed) || IS_EXPLOSIVE(flamed))
2027               Bang(xx, yy);
2028             else
2029               RemoveMovingField(xx, yy);
2030
2031             Feld[xx][yy] = EL_BURNING;
2032             if (IN_SCR_FIELD(sx, sy))
2033               DrawGraphic(sx, sy, graphic + phase*3 + i-1);
2034           }
2035           else
2036           {
2037             if (Feld[xx][yy] == EL_BURNING)
2038               Feld[xx][yy] = EL_LEERRAUM;
2039             DrawLevelField(xx, yy);
2040           }
2041         }
2042       }
2043
2044       if (MovDelay[x][y])
2045         return;
2046     }
2047
2048     if (element == EL_KAEFER || element == EL_BUTTERFLY)
2049     {
2050       PlaySoundLevel(x, y, SND_KLAPPER);
2051     }
2052     else if (element == EL_FLIEGER || element == EL_FIREFLY)
2053     {
2054       PlaySoundLevel(x, y, SND_ROEHR);
2055     }
2056
2057     /* now make next step */
2058
2059     Moving2Blocked(x, y, &newx, &newy); /* get next screen position */
2060
2061     if (IS_ENEMY(element) && IS_PLAYER(newx, newy))
2062     {
2063       /* enemy got the player */
2064       MovDir[x][y] = 0;
2065       KillHero(PLAYERINFO(newx, newy));
2066       return;
2067     }
2068     else if ((element == EL_MAULWURF || element == EL_PINGUIN ||
2069               element == EL_ROBOT || element == EL_SONDE) &&
2070              IN_LEV_FIELD(newx, newy) &&
2071              MovDir[x][y] == MV_DOWN && Feld[newx][newy] == EL_SALZSAEURE)
2072     {
2073       Blurb(x, y);
2074       Store[x][y] = EL_SALZSAEURE;
2075     }
2076     else if ((element == EL_MAULWURF || element == EL_PINGUIN) &&
2077              IN_LEV_FIELD(newx, newy))
2078     {
2079       if (Feld[newx][newy] == EL_AUSGANG_AUF)
2080       {
2081         Feld[x][y] = EL_LEERRAUM;
2082         DrawLevelField(x, y);
2083
2084         PlaySoundLevel(newx, newy, SND_BUING);
2085         if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2086           DrawGraphicThruMask(SCREENX(newx), SCREENY(newy), el2gfx(element));
2087
2088         local_player->friends_still_needed--;
2089         if (!local_player->friends_still_needed &&
2090             !local_player->GameOver && AllPlayersGone)
2091           local_player->LevelSolved = local_player->GameOver = TRUE;
2092
2093         return;
2094       }
2095       else if (IS_MAMPF3(Feld[newx][newy]))
2096       {
2097         if (DigField(local_player, newx, newy, 0, 0, DF_DIG) == MF_MOVING)
2098           DrawLevelField(newx, newy);
2099         else
2100           MovDir[x][y] = MV_NO_MOVING;
2101       }
2102       else if (!IS_FREE(newx, newy))
2103       {
2104         if (IS_PLAYER(x, y))
2105           DrawPlayerField(x, y);
2106         else
2107           DrawLevelField(x, y);
2108         return;
2109       }
2110     }
2111     else if (element == EL_SCHWEIN && IN_LEV_FIELD(newx, newy))
2112     {
2113       if (IS_GEM(Feld[newx][newy]))
2114       {
2115         if (IS_MOVING(newx, newy))
2116           RemoveMovingField(newx, newy);
2117         else
2118         {
2119           Feld[newx][newy] = EL_LEERRAUM;
2120           DrawLevelField(newx, newy);
2121         }
2122       }
2123       else if (!IS_FREE(newx, newy))
2124       {
2125         if (IS_PLAYER(x, y))
2126           DrawPlayerField(x, y);
2127         else
2128           DrawLevelField(x, y);
2129         return;
2130       }
2131     }
2132     else if (element == EL_DRACHE && IN_LEV_FIELD(newx, newy))
2133     {
2134       if (!IS_FREE(newx, newy))
2135       {
2136         if (IS_PLAYER(x, y))
2137           DrawPlayerField(x, y);
2138         else
2139           DrawLevelField(x, y);
2140         return;
2141       }
2142       else
2143       {
2144         boolean wanna_flame = !RND(10);
2145         int dx = newx - x, dy = newy - y;
2146         int newx1 = newx+1*dx, newy1 = newy+1*dy;
2147         int newx2 = newx+2*dx, newy2 = newy+2*dy;
2148         int element1 = (IN_LEV_FIELD(newx1, newy1) ?
2149                         MovingOrBlocked2Element(newx1, newy1) : EL_BETON);
2150         int element2 = (IN_LEV_FIELD(newx2, newy2) ?
2151                         MovingOrBlocked2Element(newx2, newy2) : EL_BETON);
2152
2153         if ((wanna_flame || IS_ENEMY(element1) || IS_ENEMY(element2)) &&
2154             element1 != EL_DRACHE && element2 != EL_DRACHE &&
2155             element1 != EL_BURNING && element2 != EL_BURNING)
2156         {
2157           if (IS_PLAYER(x, y))
2158             DrawPlayerField(x, y);
2159           else
2160             DrawLevelField(x, y);
2161
2162           MovDelay[x][y] = 50;
2163           Feld[newx][newy] = EL_BURNING;
2164           if (IN_LEV_FIELD(newx1, newy1) && Feld[newx1][newy1] == EL_LEERRAUM)
2165             Feld[newx1][newy1] = EL_BURNING;
2166           if (IN_LEV_FIELD(newx2, newy2) && Feld[newx2][newy2] == EL_LEERRAUM)
2167             Feld[newx2][newy2] = EL_BURNING;
2168           return;
2169         }
2170       }
2171     }
2172     else if (element == EL_MAMPFER && IN_LEV_FIELD(newx, newy) &&
2173              Feld[newx][newy] == EL_DIAMANT)
2174     {
2175       if (IS_MOVING(newx, newy))
2176         RemoveMovingField(newx, newy);
2177       else
2178       {
2179         Feld[newx][newy] = EL_LEERRAUM;
2180         DrawLevelField(newx, newy);
2181       }
2182     }
2183     else if (element == EL_MAMPFER2 && IN_LEV_FIELD(newx, newy) &&
2184              IS_MAMPF2(Feld[newx][newy]))
2185     {
2186       if (AmoebaNr[newx][newy])
2187       {
2188         AmoebaCnt2[AmoebaNr[newx][newy]]--;
2189         if (Feld[newx][newy] == EL_AMOEBE_VOLL ||
2190             Feld[newx][newy] == EL_AMOEBE_BD)
2191           AmoebaCnt[AmoebaNr[newx][newy]]--;
2192       }
2193
2194       if (IS_MOVING(newx, newy))
2195         RemoveMovingField(newx, newy);
2196       else
2197       {
2198         Feld[newx][newy] = EL_LEERRAUM;
2199         DrawLevelField(newx, newy);
2200       }
2201     }
2202     else if (element == EL_PACMAN && IN_LEV_FIELD(newx, newy) &&
2203              IS_AMOEBOID(Feld[newx][newy]))
2204     {
2205       if (AmoebaNr[newx][newy])
2206       {
2207         AmoebaCnt2[AmoebaNr[newx][newy]]--;
2208         if (Feld[newx][newy] == EL_AMOEBE_VOLL ||
2209             Feld[newx][newy] == EL_AMOEBE_BD)
2210           AmoebaCnt[AmoebaNr[newx][newy]]--;
2211       }
2212
2213       Feld[newx][newy] = EL_LEERRAUM;
2214       DrawLevelField(newx, newy);
2215     }
2216     else if (!IN_LEV_FIELD(newx, newy) || !IS_FREE(newx, newy))
2217     {
2218       /* object was running against a wall */
2219
2220       TurnRound(x, y);
2221
2222       if (element == EL_KAEFER || element == EL_FLIEGER)
2223         DrawLevelField(x, y);
2224       else if (element == EL_BUTTERFLY || element == EL_FIREFLY)
2225         DrawGraphicAnimation(x, y, el2gfx(element), 2, 4, ANIM_NORMAL);
2226       else if (element == EL_SONDE)
2227         DrawGraphicAnimation(x, y, GFX_SONDE_START, 8, 2, ANIM_NORMAL);
2228
2229       return;
2230     }
2231
2232     if (element == EL_ROBOT && IN_SCR_FIELD(x, y))
2233       PlaySoundLevel(x, y, SND_SCHLURF);
2234
2235     InitMovingField(x, y, MovDir[x][y]);
2236   }
2237
2238   if (MovDir[x][y])
2239     ContinueMoving(x, y);
2240 }
2241
2242 void ContinueMoving(int x, int y)
2243 {
2244   int element = Feld[x][y];
2245   int direction = MovDir[x][y];
2246   int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
2247   int dy = (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
2248   int horiz_move = (dx!=0);
2249   int newx = x + dx, newy = y + dy;
2250   int step = (horiz_move ? dx : dy) * TILEX/8;
2251
2252   if (CAN_FALL(element) && horiz_move)
2253     step*=2;
2254   else if (element == EL_TROPFEN)
2255     step/=2;
2256   else if (Store[x][y] == EL_MORAST_VOLL || Store[x][y] == EL_MORAST_LEER)
2257     step/=4;
2258
2259   MovPos[x][y] += step;
2260
2261   if (ABS(MovPos[x][y])>=TILEX)         /* object reached its destination */
2262   {
2263     Feld[x][y] = EL_LEERRAUM;
2264     Feld[newx][newy] = element;
2265
2266     if (Store[x][y] == EL_MORAST_VOLL)
2267     {
2268       Store[x][y] = 0;
2269       Feld[newx][newy] = EL_MORAST_VOLL;
2270       element = EL_MORAST_VOLL;
2271     }
2272     else if (Store[x][y] == EL_MORAST_LEER)
2273     {
2274       Store[x][y] = 0;
2275       Feld[x][y] = EL_MORAST_LEER;
2276     }
2277     else if (Store[x][y] == EL_SIEB_VOLL)
2278     {
2279       Store[x][y] = 0;
2280       element = Feld[newx][newy] = (SiebAktiv ? EL_SIEB_VOLL : EL_SIEB_TOT);
2281     }
2282     else if (Store[x][y] == EL_SIEB_LEER)
2283     {
2284       Store[x][y] = Store2[x][y] = 0;
2285       Feld[x][y] = (SiebAktiv ? EL_SIEB_LEER : EL_SIEB_TOT);
2286     }
2287     else if (Store[x][y] == EL_SIEB2_VOLL)
2288     {
2289       Store[x][y] = 0;
2290       element = Feld[newx][newy] = (SiebAktiv ? EL_SIEB2_VOLL : EL_SIEB2_TOT);
2291     }
2292     else if (Store[x][y] == EL_SIEB2_LEER)
2293     {
2294       Store[x][y] = Store2[x][y] = 0;
2295       Feld[x][y] = (SiebAktiv ? EL_SIEB2_LEER : EL_SIEB2_TOT);
2296     }
2297     else if (Store[x][y] == EL_SALZSAEURE)
2298     {
2299       Store[x][y] = 0;
2300       Feld[newx][newy] = EL_SALZSAEURE;
2301       element = EL_SALZSAEURE;
2302     }
2303     else if (Store[x][y] == EL_AMOEBE_NASS)
2304     {
2305       Store[x][y] = 0;
2306       Feld[x][y] = EL_AMOEBE_NASS;
2307     }
2308
2309     MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
2310     MovDelay[newx][newy] = 0;
2311
2312     if (!CAN_MOVE(element))
2313       MovDir[newx][newy] = 0;
2314
2315     DrawLevelField(x, y);
2316     DrawLevelField(newx, newy);
2317
2318     Stop[newx][newy] = TRUE;
2319     JustHit[x][newy] = 3;
2320
2321     if (DONT_TOUCH(element))    /* object may be nasty to player or others */
2322     {
2323       TestIfBadThingHitsHero(newx, newy);
2324       TestIfBadThingHitsFriend(newx, newy);
2325       TestIfBadThingHitsOtherBadThing(newx, newy);
2326     }
2327     else if (element == EL_PINGUIN)
2328       TestIfFriendHitsBadThing(newx, newy);
2329
2330     if (CAN_SMASH(element) && direction == MV_DOWN &&
2331         (newy == lev_fieldy-1 || !IS_FREE(x, newy+1)))
2332       Impact(x, newy);
2333   }
2334   else                          /* still moving on */
2335     DrawLevelField(x, y);
2336 }
2337
2338 int AmoebeNachbarNr(int ax, int ay)
2339 {
2340   int i;
2341   int element = Feld[ax][ay];
2342   int group_nr = 0;
2343   static int xy[4][2] =
2344   {
2345     { 0, -1 },
2346     { -1, 0 },
2347     { +1, 0 },
2348     { 0, +1 }
2349   };
2350
2351   for (i=0; i<4; i++)
2352   {
2353     int x = ax + xy[i][0];
2354     int y = ay + xy[i][1];
2355
2356     if (!IN_LEV_FIELD(x, y))
2357       continue;
2358
2359     if (Feld[x][y] == element && AmoebaNr[x][y] > 0)
2360       group_nr = AmoebaNr[x][y];
2361   }
2362
2363   return group_nr;
2364 }
2365
2366 void AmoebenVereinigen(int ax, int ay)
2367 {
2368   int i, x, y, xx, yy;
2369   int new_group_nr = AmoebaNr[ax][ay];
2370   static int xy[4][2] =
2371   {
2372     { 0, -1 },
2373     { -1, 0 },
2374     { +1, 0 },
2375     { 0, +1 }
2376   };
2377
2378   if (new_group_nr == 0)
2379     return;
2380
2381   for (i=0; i<4; i++)
2382   {
2383     x = ax + xy[i][0];
2384     y = ay + xy[i][1];
2385
2386     if (!IN_LEV_FIELD(x, y))
2387       continue;
2388
2389     if ((Feld[x][y] == EL_AMOEBE_VOLL ||
2390          Feld[x][y] == EL_AMOEBE_BD ||
2391          Feld[x][y] == EL_AMOEBE_TOT) &&
2392         AmoebaNr[x][y] != new_group_nr)
2393     {
2394       int old_group_nr = AmoebaNr[x][y];
2395
2396       if (old_group_nr == 0)
2397         return;
2398
2399       AmoebaCnt[new_group_nr] += AmoebaCnt[old_group_nr];
2400       AmoebaCnt[old_group_nr] = 0;
2401       AmoebaCnt2[new_group_nr] += AmoebaCnt2[old_group_nr];
2402       AmoebaCnt2[old_group_nr] = 0;
2403
2404       for (yy=0; yy<lev_fieldy; yy++)
2405       {
2406         for (xx=0; xx<lev_fieldx; xx++)
2407         {
2408           if (AmoebaNr[xx][yy] == old_group_nr)
2409             AmoebaNr[xx][yy] = new_group_nr;
2410         }
2411       }
2412     }
2413   }
2414 }
2415
2416 void AmoebeUmwandeln(int ax, int ay)
2417 {
2418   int i, x, y;
2419
2420   if (Feld[ax][ay] == EL_AMOEBE_TOT)
2421   {
2422     int group_nr = AmoebaNr[ax][ay];
2423
2424 #ifdef DEBUG
2425     if (group_nr == 0)
2426     {
2427       printf("AmoebeUmwandeln(): ax = %d, ay = %d\n", ax, ay);
2428       printf("AmoebeUmwandeln(): This should never happen!\n");
2429       return;
2430     }
2431 #endif
2432
2433     for (y=0; y<lev_fieldy; y++)
2434     {
2435       for (x=0; x<lev_fieldx; x++)
2436       {
2437         if (Feld[x][y] == EL_AMOEBE_TOT && AmoebaNr[x][y] == group_nr)
2438         {
2439           AmoebaNr[x][y] = 0;
2440           Feld[x][y] = EL_AMOEBA2DIAM;
2441         }
2442       }
2443     }
2444     Bang(ax, ay);
2445   }
2446   else
2447   {
2448     static int xy[4][2] =
2449     {
2450       { 0, -1 },
2451       { -1, 0 },
2452       { +1, 0 },
2453       { 0, +1 }
2454     };
2455
2456     for (i=0; i<4; i++)
2457     {
2458       x = ax + xy[i][0];
2459       y = ay + xy[i][1];
2460
2461       if (!IN_LEV_FIELD(x, y))
2462         continue;
2463
2464       if (Feld[x][y] == EL_AMOEBA2DIAM)
2465         Bang(x, y);
2466     }
2467   }
2468 }
2469
2470 void AmoebeUmwandelnBD(int ax, int ay, int new_element)
2471 {
2472   int x, y;
2473   int group_nr = AmoebaNr[ax][ay];
2474   boolean done = FALSE;
2475
2476 #ifdef DEBUG
2477   if (group_nr == 0)
2478   {
2479     printf("AmoebeUmwandelnBD(): ax = %d, ay = %d\n", ax, ay);
2480     printf("AmoebeUmwandelnBD(): This should never happen!\n");
2481     return;
2482   }
2483 #endif
2484
2485   for (y=0; y<lev_fieldy; y++)
2486   {
2487     for (x=0; x<lev_fieldx; x++)
2488     {
2489       if (AmoebaNr[x][y] == group_nr &&
2490           (Feld[x][y] == EL_AMOEBE_TOT ||
2491            Feld[x][y] == EL_AMOEBE_BD ||
2492            Feld[x][y] == EL_AMOEBING))
2493       {
2494         AmoebaNr[x][y] = 0;
2495         Feld[x][y] = new_element;
2496         InitField(x, y, FALSE);
2497         DrawLevelField(x, y);
2498         done = TRUE;
2499       }
2500     }
2501   }
2502
2503   if (done)
2504     PlaySoundLevel(ax, ay,
2505                    (new_element == EL_FELSBROCKEN ? SND_KLOPF : SND_PLING));
2506 }
2507
2508 void AmoebeWaechst(int x, int y)
2509 {
2510   static unsigned long sound_delay = 0;
2511   static unsigned long sound_delay_value = 0;
2512
2513   if (!MovDelay[x][y])          /* start new growing cycle */
2514   {
2515     MovDelay[x][y] = 7;
2516
2517     if (DelayReached(&sound_delay, sound_delay_value))
2518     {
2519       PlaySoundLevel(x, y, SND_AMOEBE);
2520       sound_delay_value = 30;
2521     }
2522   }
2523
2524   if (MovDelay[x][y])           /* wait some time before growing bigger */
2525   {
2526     MovDelay[x][y]--;
2527     if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2528       DrawGraphic(SCREENX(x), SCREENY(y), GFX_AMOEBING + 3 - MovDelay[x][y]/2);
2529
2530     if (!MovDelay[x][y])
2531     {
2532       Feld[x][y] = Store[x][y];
2533       Store[x][y] = 0;
2534       DrawLevelField(x, y);
2535     }
2536   }
2537 }
2538
2539 void AmoebeAbleger(int ax, int ay)
2540 {
2541   int i;
2542   int element = Feld[ax][ay];
2543   int newax = ax, neway = ay;
2544   static int xy[4][2] =
2545   {
2546     { 0, -1 },
2547     { -1, 0 },
2548     { +1, 0 },
2549     { 0, +1 }
2550   };
2551
2552   if (!level.tempo_amoebe)
2553   {
2554     Feld[ax][ay] = EL_AMOEBE_TOT;
2555     DrawLevelField(ax, ay);
2556     return;
2557   }
2558
2559   if (!MovDelay[ax][ay])        /* start making new amoeba field */
2560     MovDelay[ax][ay] = RND(FRAMES_PER_SECOND * 25 / (1 + level.tempo_amoebe));
2561
2562   if (MovDelay[ax][ay])         /* wait some time before making new amoeba */
2563   {
2564     MovDelay[ax][ay]--;
2565     if (MovDelay[ax][ay])
2566       return;
2567   }
2568
2569   if (element == EL_AMOEBE_NASS)        /* object is an acid / amoeba drop */
2570   {
2571     int start = RND(4);
2572     int x = ax + xy[start][0];
2573     int y = ay + xy[start][1];
2574
2575     if (!IN_LEV_FIELD(x, y))
2576       return;
2577
2578     if (IS_FREE(x, y) ||
2579         Feld[x][y] == EL_ERDREICH || Feld[x][y] == EL_MORAST_LEER)
2580     {
2581       newax = x;
2582       neway = y;
2583     }
2584
2585     if (newax == ax && neway == ay)
2586       return;
2587   }
2588   else                          /* normal or "filled" (BD style) amoeba */
2589   {
2590     int start = RND(4);
2591     boolean waiting_for_player = FALSE;
2592
2593     for (i=0; i<4; i++)
2594     {
2595       int j = (start + i) % 4;
2596       int x = ax + xy[j][0];
2597       int y = ay + xy[j][1];
2598
2599       if (!IN_LEV_FIELD(x, y))
2600         continue;
2601
2602       if (IS_FREE(x, y) ||
2603           Feld[x][y] == EL_ERDREICH || Feld[x][y] == EL_MORAST_LEER)
2604       {
2605         newax = x;
2606         neway = y;
2607         break;
2608       }
2609       else if (IS_PLAYER(x, y))
2610         waiting_for_player = TRUE;
2611     }
2612
2613     if (newax == ax && neway == ay)             /* amoeba cannot grow */
2614     {
2615       if (i == 4 && !waiting_for_player)
2616       {
2617         Feld[ax][ay] = EL_AMOEBE_TOT;
2618         DrawLevelField(ax, ay);
2619         AmoebaCnt[AmoebaNr[ax][ay]]--;
2620
2621         if (AmoebaCnt[AmoebaNr[ax][ay]] <= 0)   /* amoeba is completely dead */
2622         {
2623           if (element == EL_AMOEBE_VOLL)
2624             AmoebeUmwandeln(ax, ay);
2625           else if (element == EL_AMOEBE_BD)
2626             AmoebeUmwandelnBD(ax, ay, level.amoebe_inhalt);
2627         }
2628       }
2629       return;
2630     }
2631     else if (element == EL_AMOEBE_VOLL || element == EL_AMOEBE_BD)
2632     {
2633       /* amoeba gets larger by growing in some direction */
2634
2635       int new_group_nr = AmoebaNr[ax][ay];
2636
2637 #ifdef DEBUG
2638   if (new_group_nr == 0)
2639   {
2640     printf("AmoebeAbleger(): newax = %d, neway = %d\n", newax, neway);
2641     printf("AmoebeAbleger(): This should never happen!\n");
2642     return;
2643   }
2644 #endif
2645
2646       AmoebaNr[newax][neway] = new_group_nr;
2647       AmoebaCnt[new_group_nr]++;
2648       AmoebaCnt2[new_group_nr]++;
2649
2650       /* if amoeba touches other amoeba(s) after growing, unify them */
2651       AmoebenVereinigen(newax, neway);
2652
2653       if (element == EL_AMOEBE_BD && AmoebaCnt2[new_group_nr] >= 200)
2654       {
2655         AmoebeUmwandelnBD(newax, neway, EL_FELSBROCKEN);
2656         return;
2657       }
2658     }
2659   }
2660
2661   if (element != EL_AMOEBE_NASS || neway < ay || !IS_FREE(newax, neway) ||
2662       (neway == lev_fieldy - 1 && newax != ax))
2663   {
2664     Feld[newax][neway] = EL_AMOEBING;
2665     Store[newax][neway] = element;
2666   }
2667   else if (neway == ay)
2668     Feld[newax][neway] = EL_TROPFEN;
2669   else
2670   {
2671     InitMovingField(ax, ay, MV_DOWN);
2672     Feld[ax][ay] = EL_TROPFEN;
2673     Store[ax][ay] = EL_AMOEBE_NASS;
2674     ContinueMoving(ax, ay);
2675     return;
2676   }
2677
2678   DrawLevelField(newax, neway);
2679 }
2680
2681 void Life(int ax, int ay)
2682 {
2683   int x1, y1, x2, y2;
2684   static int life[4] = { 2, 3, 3, 3 };  /* parameters for "game of life" */
2685   int life_time = 40;
2686   int element = Feld[ax][ay];
2687
2688   if (Stop[ax][ay])
2689     return;
2690
2691   if (!MovDelay[ax][ay])        /* start new "game of life" cycle */
2692     MovDelay[ax][ay] = life_time;
2693
2694   if (MovDelay[ax][ay])         /* wait some time before next cycle */
2695   {
2696     MovDelay[ax][ay]--;
2697     if (MovDelay[ax][ay])
2698       return;
2699   }
2700
2701   for (y1=-1; y1<2; y1++) for(x1=-1; x1<2; x1++)
2702   {
2703     int xx = ax+x1, yy = ay+y1;
2704     int nachbarn = 0;
2705
2706     if (!IN_LEV_FIELD(xx, yy))
2707       continue;
2708
2709     for (y2=-1; y2<2; y2++) for (x2=-1; x2<2; x2++)
2710     {
2711       int x = xx+x2, y = yy+y2;
2712
2713       if (!IN_LEV_FIELD(x, y) || (x == xx && y == yy))
2714         continue;
2715
2716       if (((Feld[x][y] == element ||
2717             (element == EL_LIFE && IS_PLAYER(x, y))) &&
2718            !Stop[x][y]) ||
2719           (IS_FREE(x, y) && Stop[x][y]))
2720         nachbarn++;
2721     }
2722
2723     if (xx == ax && yy == ay)           /* field in the middle */
2724     {
2725       if (nachbarn<life[0] || nachbarn>life[1])
2726       {
2727         Feld[xx][yy] = EL_LEERRAUM;
2728         if (!Stop[xx][yy])
2729           DrawLevelField(xx, yy);
2730         Stop[xx][yy] = TRUE;
2731       }
2732     }
2733     else if (IS_FREE(xx, yy) || Feld[xx][yy] == EL_ERDREICH)
2734     {                                   /* free border field */
2735       if (nachbarn>=life[2] && nachbarn<=life[3])
2736       {
2737         Feld[xx][yy] = element;
2738         MovDelay[xx][yy] = (element == EL_LIFE ? 0 : life_time-1);
2739         if (!Stop[xx][yy])
2740           DrawLevelField(xx, yy);
2741         Stop[xx][yy] = TRUE;
2742       }
2743     }
2744   }
2745 }
2746
2747 void Ablenk(int x, int y)
2748 {
2749   if (!MovDelay[x][y])          /* next animation frame */
2750     MovDelay[x][y] = level.dauer_ablenk * FRAMES_PER_SECOND;
2751
2752   if (MovDelay[x][y])           /* wait some time before next frame */
2753   {
2754     MovDelay[x][y]--;
2755     if (MovDelay[x][y])
2756     {
2757       if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2758         DrawGraphic(SCREENX(x), SCREENY(y), GFX_ABLENK+MovDelay[x][y]%4);
2759       if (!(MovDelay[x][y]%4))
2760         PlaySoundLevel(x, y, SND_MIEP);
2761       return;
2762     }
2763   }
2764
2765   Feld[x][y] = EL_ABLENK_AUS;
2766   DrawLevelField(x, y);
2767   if (ZX == x && ZY == y)
2768     ZX = ZY = -1;
2769 }
2770
2771 void Birne(int x, int y)
2772 {
2773   if (!MovDelay[x][y])          /* next animation frame */
2774     MovDelay[x][y] = 800;
2775
2776   if (MovDelay[x][y])           /* wait some time before next frame */
2777   {
2778     MovDelay[x][y]--;
2779     if (MovDelay[x][y])
2780     {
2781       if (!(MovDelay[x][y]%5))
2782       {
2783         if (!(MovDelay[x][y]%10))
2784           Feld[x][y]=EL_ABLENK_EIN;
2785         else
2786           Feld[x][y]=EL_ABLENK_AUS;
2787         DrawLevelField(x, y);
2788         Feld[x][y]=EL_ABLENK_EIN;
2789       }
2790       return;
2791     }
2792   }
2793
2794   Feld[x][y]=EL_ABLENK_AUS;
2795   DrawLevelField(x, y);
2796   if (ZX == x && ZY == y)
2797     ZX=ZY=-1;
2798 }
2799
2800 void Blubber(int x, int y)
2801 {
2802   if (y > 0 && IS_MOVING(x, y-1) && MovDir[x][y-1] == MV_DOWN)
2803     DrawLevelField(x, y-1);
2804   else
2805     DrawGraphicAnimation(x, y, GFX_GEBLUBBER, 4, 10, ANIM_NORMAL);
2806 }
2807
2808 void NussKnacken(int x, int y)
2809 {
2810   if (!MovDelay[x][y])          /* next animation frame */
2811     MovDelay[x][y] = 7;
2812
2813   if (MovDelay[x][y])           /* wait some time before next frame */
2814   {
2815     MovDelay[x][y]--;
2816     if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2817       DrawGraphic(SCREENX(x), SCREENY(y), GFX_CRACKINGNUT+3-MovDelay[x][y]/2);
2818
2819     if (!MovDelay[x][y])
2820     {
2821       Feld[x][y] = EL_EDELSTEIN;
2822       DrawLevelField(x, y);
2823     }
2824   }
2825 }
2826
2827 void SiebAktivieren(int x, int y, int typ)
2828 {
2829   int graphic = (typ == 1 ? GFX_SIEB_VOLL : GFX_SIEB2_VOLL) + 3;
2830
2831   DrawGraphicAnimation(x, y, graphic, 4, 4, ANIM_REVERSE);
2832 }
2833
2834 void AusgangstuerPruefen(int x, int y)
2835 {
2836   if (!local_player->gems_still_needed &&
2837       !local_player->sokobanfields_still_needed &&
2838       !local_player->lights_still_needed)
2839   {
2840     Feld[x][y] = EL_AUSGANG_ACT;
2841
2842     PlaySoundLevel(x < LEVELX(BX1) ? LEVELX(BX1) :
2843                    (x > LEVELX(BX2) ? LEVELX(BX2) : x),
2844                    y < LEVELY(BY1) ? LEVELY(BY1) :
2845                    (y > LEVELY(BY2) ? LEVELY(BY2) : y),
2846                    SND_OEFFNEN);
2847   }
2848 }
2849
2850 void AusgangstuerOeffnen(int x, int y)
2851 {
2852   int delay = 6;
2853
2854   if (!MovDelay[x][y])          /* next animation frame */
2855     MovDelay[x][y] = 5*delay;
2856
2857   if (MovDelay[x][y])           /* wait some time before next frame */
2858   {
2859     int tuer;
2860
2861     MovDelay[x][y]--;
2862     tuer = MovDelay[x][y]/delay;
2863     if (!(MovDelay[x][y]%delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2864       DrawGraphic(SCREENX(x), SCREENY(y), GFX_AUSGANG_AUF-tuer);
2865
2866     if (!MovDelay[x][y])
2867     {
2868       Feld[x][y] = EL_AUSGANG_AUF;
2869       DrawLevelField(x, y);
2870     }
2871   }
2872 }
2873
2874 void AusgangstuerBlinken(int x, int y)
2875 {
2876   DrawGraphicAnimation(x, y, GFX_AUSGANG_AUF, 4, 4, ANIM_OSCILLATE);
2877 }
2878
2879 void EdelsteinFunkeln(int x, int y)
2880 {
2881   if (!IN_SCR_FIELD(SCREENX(x), SCREENY(y)) || IS_MOVING(x, y))
2882     return;
2883
2884   if (Feld[x][y] == EL_EDELSTEIN_BD)
2885     DrawGraphicAnimation(x, y, GFX_EDELSTEIN_BD, 4, 4, ANIM_REVERSE);
2886   else
2887   {
2888     if (!MovDelay[x][y])        /* next animation frame */
2889       MovDelay[x][y] = 11 * !SimpleRND(500);
2890
2891     if (MovDelay[x][y])         /* wait some time before next frame */
2892     {
2893       MovDelay[x][y]--;
2894
2895       if (setup.direct_draw && MovDelay[x][y])
2896         SetDrawtoField(DRAW_BUFFERED);
2897
2898       DrawGraphic(SCREENX(x), SCREENY(y), el2gfx(Feld[x][y]));
2899
2900       if (MovDelay[x][y])
2901       {
2902         int phase = (MovDelay[x][y]-1)/2;
2903
2904         if (phase > 2)
2905           phase = 4-phase;
2906
2907         DrawGraphicThruMask(SCREENX(x), SCREENY(y), GFX_FUNKELN_WEISS + phase);
2908
2909         if (setup.direct_draw)
2910         {
2911           int dest_x, dest_y;
2912
2913           dest_x = FX + SCREENX(x)*TILEX;
2914           dest_y = FY + SCREENY(y)*TILEY;
2915
2916           XCopyArea(display, drawto_field, window, gc,
2917                     dest_x, dest_y, TILEX, TILEY, dest_x, dest_y);
2918           SetDrawtoField(DRAW_DIRECT);
2919         }
2920       }
2921     }
2922   }
2923 }
2924
2925 void MauerWaechst(int x, int y)
2926 {
2927   int delay = 6;
2928
2929   if (!MovDelay[x][y])          /* next animation frame */
2930     MovDelay[x][y] = 3*delay;
2931
2932   if (MovDelay[x][y])           /* wait some time before next frame */
2933   {
2934     int phase;
2935
2936     MovDelay[x][y]--;
2937     phase = 2-MovDelay[x][y]/delay;
2938     if (!(MovDelay[x][y]%delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2939       DrawGraphic(SCREENX(x), SCREENY(y),
2940                   (MovDir[x][y] == MV_LEFT  ? GFX_MAUER_LEFT  :
2941                    MovDir[x][y] == MV_RIGHT ? GFX_MAUER_RIGHT :
2942                    MovDir[x][y] == MV_UP    ? GFX_MAUER_UP    :
2943                                               GFX_MAUER_DOWN  ) + phase);
2944
2945     if (!MovDelay[x][y])
2946     {
2947       if (MovDir[x][y] == MV_LEFT)
2948       {
2949         if (IN_LEV_FIELD(x-1, y) && IS_MAUER(Feld[x-1][y]))
2950           DrawLevelField(x-1, y);
2951       }
2952       else if (MovDir[x][y] == MV_RIGHT)
2953       {
2954         if (IN_LEV_FIELD(x+1, y) && IS_MAUER(Feld[x+1][y]))
2955           DrawLevelField(x+1, y);
2956       }
2957       else if (MovDir[x][y] == MV_UP)
2958       {
2959         if (IN_LEV_FIELD(x, y-1) && IS_MAUER(Feld[x][y-1]))
2960           DrawLevelField(x, y-1);
2961       }
2962       else
2963       {
2964         if (IN_LEV_FIELD(x, y+1) && IS_MAUER(Feld[x][y+1]))
2965           DrawLevelField(x, y+1);
2966       }
2967
2968       Feld[x][y] = Store[x][y];
2969       Store[x][y] = 0;
2970       MovDir[x][y] = MV_NO_MOVING;
2971       DrawLevelField(x, y);
2972     }
2973   }
2974 }
2975
2976 void MauerAbleger(int ax, int ay)
2977 {
2978   int element = Feld[ax][ay];
2979   boolean oben_frei = FALSE, unten_frei = FALSE;
2980   boolean links_frei = FALSE, rechts_frei = FALSE;
2981   boolean oben_massiv = FALSE, unten_massiv = FALSE;
2982   boolean links_massiv = FALSE, rechts_massiv = FALSE;
2983
2984   if (!MovDelay[ax][ay])        /* start building new wall */
2985     MovDelay[ax][ay] = 6;
2986
2987   if (MovDelay[ax][ay])         /* wait some time before building new wall */
2988   {
2989     MovDelay[ax][ay]--;
2990     if (MovDelay[ax][ay])
2991       return;
2992   }
2993
2994   if (IN_LEV_FIELD(ax, ay-1) && IS_FREE(ax, ay-1))
2995     oben_frei = TRUE;
2996   if (IN_LEV_FIELD(ax, ay+1) && IS_FREE(ax, ay+1))
2997     unten_frei = TRUE;
2998   if (IN_LEV_FIELD(ax-1, ay) && IS_FREE(ax-1, ay))
2999     links_frei = TRUE;
3000   if (IN_LEV_FIELD(ax+1, ay) && IS_FREE(ax+1, ay))
3001     rechts_frei = TRUE;
3002
3003   if (element == EL_MAUER_Y || element == EL_MAUER_XY)
3004   {
3005     if (oben_frei)
3006     {
3007       Feld[ax][ay-1] = EL_MAUERND;
3008       Store[ax][ay-1] = element;
3009       MovDir[ax][ay-1] = MV_UP;
3010       if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay-1)))
3011         DrawGraphic(SCREENX(ax), SCREENY(ay-1), GFX_MAUER_UP);
3012     }
3013     if (unten_frei)
3014     {
3015       Feld[ax][ay+1] = EL_MAUERND;
3016       Store[ax][ay+1] = element;
3017       MovDir[ax][ay+1] = MV_DOWN;
3018       if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay+1)))
3019         DrawGraphic(SCREENX(ax), SCREENY(ay+1), GFX_MAUER_DOWN);
3020     }
3021   }
3022
3023   if (element == EL_MAUER_X || element == EL_MAUER_XY ||
3024       element == EL_MAUER_LEBT)
3025   {
3026     if (links_frei)
3027     {
3028       Feld[ax-1][ay] = EL_MAUERND;
3029       Store[ax-1][ay] = element;
3030       MovDir[ax-1][ay] = MV_LEFT;
3031       if (IN_SCR_FIELD(SCREENX(ax-1), SCREENY(ay)))
3032         DrawGraphic(SCREENX(ax-1), SCREENY(ay), GFX_MAUER_LEFT);
3033     }
3034     if (rechts_frei)
3035     {
3036       Feld[ax+1][ay] = EL_MAUERND;
3037       Store[ax+1][ay] = element;
3038       MovDir[ax+1][ay] = MV_RIGHT;
3039       if (IN_SCR_FIELD(SCREENX(ax+1), SCREENY(ay)))
3040         DrawGraphic(SCREENX(ax+1), SCREENY(ay), GFX_MAUER_RIGHT);
3041     }
3042   }
3043
3044   if (element == EL_MAUER_LEBT && (links_frei || rechts_frei))
3045     DrawLevelField(ax, ay);
3046
3047   if (!IN_LEV_FIELD(ax, ay-1) || IS_MAUER(Feld[ax][ay-1]))
3048     oben_massiv = TRUE;
3049   if (!IN_LEV_FIELD(ax, ay+1) || IS_MAUER(Feld[ax][ay+1]))
3050     unten_massiv = TRUE;
3051   if (!IN_LEV_FIELD(ax-1, ay) || IS_MAUER(Feld[ax-1][ay]))
3052     links_massiv = TRUE;
3053   if (!IN_LEV_FIELD(ax+1, ay) || IS_MAUER(Feld[ax+1][ay]))
3054     rechts_massiv = TRUE;
3055
3056   if (((oben_massiv && unten_massiv) ||
3057        element == EL_MAUER_X || element == EL_MAUER_LEBT) &&
3058       ((links_massiv && rechts_massiv) ||
3059        element == EL_MAUER_Y))
3060     Feld[ax][ay] = EL_MAUERWERK;
3061 }
3062
3063 void CheckForDragon(int x, int y)
3064 {
3065   int i, j;
3066   boolean dragon_found = FALSE;
3067   static int xy[4][2] =
3068   {
3069     { 0, -1 },
3070     { -1, 0 },
3071     { +1, 0 },
3072     { 0, +1 }
3073   };
3074
3075   for (i=0; i<4; i++)
3076   {
3077     for (j=0; j<4; j++)
3078     {
3079       int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
3080
3081       if (IN_LEV_FIELD(xx, yy) &&
3082           (Feld[xx][yy] == EL_BURNING || Feld[xx][yy] == EL_DRACHE))
3083       {
3084         if (Feld[xx][yy] == EL_DRACHE)
3085           dragon_found = TRUE;
3086       }
3087       else
3088         break;
3089     }
3090   }
3091
3092   if (!dragon_found)
3093   {
3094     for (i=0; i<4; i++)
3095     {
3096       for (j=0; j<3; j++)
3097       {
3098         int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
3099   
3100         if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == EL_BURNING)
3101         {
3102           Feld[xx][yy] = EL_LEERRAUM;
3103           DrawLevelField(xx, yy);
3104         }
3105         else
3106           break;
3107       }
3108     }
3109   }
3110 }
3111
3112 static void PlayerActions(struct PlayerInfo *player, byte player_action)
3113 {
3114   static byte stored_player_action[MAX_PLAYERS];
3115   static int num_stored_actions = 0;
3116   static boolean save_tape_entry = FALSE;
3117   boolean moved = FALSE, snapped = FALSE, bombed = FALSE;
3118   int jx = player->jx, jy = player->jy;
3119   int left      = player_action & JOY_LEFT;
3120   int right     = player_action & JOY_RIGHT;
3121   int up        = player_action & JOY_UP;
3122   int down      = player_action & JOY_DOWN;
3123   int button1   = player_action & JOY_BUTTON_1;
3124   int button2   = player_action & JOY_BUTTON_2;
3125   int dx        = (left ? -1    : right ? 1     : 0);
3126   int dy        = (up   ? -1    : down  ? 1     : 0);
3127
3128   stored_player_action[player->index_nr] = 0;
3129   num_stored_actions++;
3130
3131   if (!player->active || player->gone || tape.pausing)
3132     return;
3133
3134   if (player_action)
3135   {
3136     save_tape_entry = TRUE;
3137     player->frame_reset_delay = 0;
3138
3139     if (button1)
3140       snapped = SnapField(player, dx, dy);
3141     else
3142     {
3143       if (button2)
3144         bombed = PlaceBomb(player);
3145       moved = MoveFigure(player, dx, dy);
3146     }
3147
3148     if (tape.recording && (moved || snapped || bombed))
3149     {
3150       if (bombed && !moved)
3151         player_action &= JOY_BUTTON;
3152
3153       stored_player_action[player->index_nr] = player_action;
3154
3155 #if 0
3156       /* this allows cycled sequences of PlayerActions() */
3157       if (num_stored_actions >= MAX_PLAYERS)
3158       {
3159         TapeRecordAction(stored_player_action);
3160         num_stored_actions = 0;
3161       }
3162 #endif
3163
3164     }
3165     else if (tape.playing && snapped)
3166       SnapField(player, 0, 0);                  /* stop snapping */
3167   }
3168   else
3169   {
3170     DigField(player, 0, 0, 0, 0, DF_NO_PUSH);
3171     SnapField(player, 0, 0);
3172     if (++player->frame_reset_delay > MoveSpeed)
3173       player->Frame = 0;
3174   }
3175
3176   if (tape.recording && num_stored_actions >= MAX_PLAYERS && save_tape_entry)
3177   {
3178     TapeRecordAction(stored_player_action);
3179     num_stored_actions = 0;
3180     save_tape_entry = FALSE;
3181   }
3182
3183   if (tape.playing && !tape.pausing && !player_action &&
3184       tape.counter < tape.length)
3185   {
3186     int next_joy =
3187       tape.pos[tape.counter].action[player->index_nr] & (JOY_LEFT|JOY_RIGHT);
3188
3189     if ((next_joy == JOY_LEFT || next_joy == JOY_RIGHT) &&
3190         (player->MovDir != JOY_UP && player->MovDir != JOY_DOWN))
3191     {
3192       int dx = (next_joy == JOY_LEFT ? -1 : +1);
3193
3194       if (IN_LEV_FIELD(jx+dx, jy) && IS_PUSHABLE(Feld[jx+dx][jy]))
3195       {
3196         int el = Feld[jx+dx][jy];
3197         int push_delay = (IS_SB_ELEMENT(el) || el == EL_SONDE ? 2 : 10);
3198
3199         if (tape.delay_played + push_delay >= tape.pos[tape.counter].delay)
3200         {
3201           player->MovDir = next_joy;
3202           player->Frame = FrameCounter % 4;
3203           player->Pushing = TRUE;
3204         }
3205       }
3206     }
3207   }
3208 }
3209
3210 void GameActions()
3211 {
3212   static unsigned long action_delay = 0;
3213   unsigned long action_delay_value;
3214   int sieb_x = 0, sieb_y = 0;
3215   int i, x, y, element;
3216   byte *recorded_player_action;
3217   byte summarized_player_action = 0;
3218
3219   if (game_status != PLAYING)
3220     return;
3221
3222   action_delay_value =
3223     (tape.playing && tape.fast_forward ? FfwdFrameDelay : GameFrameDelay);
3224
3225   /*
3226   if (tape.playing && tape.fast_forward)
3227   {
3228     char buf[100];
3229
3230     sprintf(buf, "FFWD: %ld ms", action_delay_value);
3231     print_debug(buf);
3232   }
3233   */
3234
3235
3236   /* main game synchronization point */
3237
3238
3239
3240
3241 #if 1
3242   WaitUntilDelayReached(&action_delay, action_delay_value);
3243 #else
3244
3245   while (!DelayReached(&action_delay, action_delay_value))
3246   {
3247     char buf[100];
3248
3249     sprintf(buf, "%ld %ld %ld",
3250             Counter(), action_delay, action_delay_value);
3251     print_debug(buf);
3252   }
3253   print_debug("done");
3254
3255 #endif
3256
3257
3258
3259
3260   if (network_playing && !network_player_action_received)
3261   {
3262     /*
3263 #ifdef DEBUG
3264     printf("DEBUG: try to get network player actions in time\n");
3265 #endif
3266     */
3267
3268 #ifndef MSDOS
3269     /* last chance to get network player actions without main loop delay */
3270     HandleNetworking();
3271 #endif
3272
3273     if (game_status != PLAYING)
3274       return;
3275
3276     if (!network_player_action_received)
3277     {
3278       /*
3279 #ifdef DEBUG
3280       printf("DEBUG: failed to get network player actions in time\n");
3281 #endif
3282       */
3283       return;
3284     }
3285   }
3286
3287
3288   /*
3289   if (tape.pausing || (tape.playing && !TapePlayDelay()))
3290     return;
3291   else if (tape.recording)
3292     TapeRecordDelay();
3293   */
3294
3295   if (tape.pausing)
3296     return;
3297
3298   if (tape.playing)
3299     TapePlayDelay();
3300   else if (tape.recording)
3301     TapeRecordDelay();
3302
3303   recorded_player_action = (tape.playing ? TapePlayAction() : NULL);
3304
3305   for (i=0; i<MAX_PLAYERS; i++)
3306   {
3307     summarized_player_action |= stored_player[i].action;
3308
3309     if (!network_playing)
3310       stored_player[i].effective_action = stored_player[i].action;
3311   }
3312
3313 #ifndef MSDOS
3314   if (network_playing)
3315     SendToServer_MovePlayer(summarized_player_action);
3316 #endif
3317
3318   if (!options.network && !setup.team_mode)
3319     local_player->effective_action = summarized_player_action;
3320
3321   for (i=0; i<MAX_PLAYERS; i++)
3322   {
3323     int actual_player_action = stored_player[i].effective_action;
3324
3325     if (recorded_player_action)
3326       actual_player_action = recorded_player_action[i];
3327
3328     PlayerActions(&stored_player[i], actual_player_action);
3329     ScrollFigure(&stored_player[i], SCROLL_GO_ON);
3330   }
3331
3332   network_player_action_received = FALSE;
3333
3334   ScrollScreen(NULL, SCROLL_GO_ON);
3335
3336
3337   /*
3338   if (tape.pausing || (tape.playing && !TapePlayDelay()))
3339     return;
3340   else if (tape.recording)
3341     TapeRecordDelay();
3342   */
3343
3344
3345
3346
3347
3348 #ifdef DEBUG
3349   /*
3350   if (TimeFrames == 0 && !local_player->gone)
3351   {
3352     extern unsigned int last_RND();
3353
3354     printf("DEBUG: %03d last RND was %d \t [state checksum is %d]\n",
3355            level.time - TimeLeft,
3356            last_RND(),
3357            getStateCheckSum(level.time - TimeLeft));
3358   }
3359   */
3360 #endif
3361
3362
3363
3364 #ifdef DEBUG
3365   /*
3366   if (GameFrameDelay >= 500)
3367     printf("FrameCounter == %d\n", FrameCounter);
3368   */
3369 #endif
3370
3371
3372
3373
3374
3375   FrameCounter++;
3376   TimeFrames++;
3377
3378   for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
3379   {
3380     Stop[x][y] = FALSE;
3381     if (JustHit[x][y]>0)
3382       JustHit[x][y]--;
3383
3384 #if DEBUG
3385     if (IS_BLOCKED(x, y))
3386     {
3387       int oldx, oldy;
3388
3389       Blocked2Moving(x, y, &oldx, &oldy);
3390       if (!IS_MOVING(oldx, oldy))
3391       {
3392         printf("GameActions(): (BLOCKED=>MOVING) context corrupted!\n");
3393         printf("GameActions(): BLOCKED: x = %d, y = %d\n", x, y);
3394         printf("GameActions(): !MOVING: oldx = %d, oldy = %d\n", oldx, oldy);
3395         printf("GameActions(): This should never happen!\n");
3396       }
3397     }
3398 #endif
3399   }
3400
3401   for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
3402   {
3403     element = Feld[x][y];
3404
3405     if (IS_INACTIVE(element))
3406       continue;
3407
3408     if (!IS_MOVING(x, y) && (CAN_FALL(element) || CAN_MOVE(element)))
3409     {
3410       StartMoving(x, y);
3411
3412       if (IS_GEM(element))
3413         EdelsteinFunkeln(x, y);
3414     }
3415     else if (IS_MOVING(x, y))
3416       ContinueMoving(x, y);
3417     else if (element == EL_DYNAMIT || element == EL_DYNABOMB)
3418       CheckDynamite(x, y);
3419     else if (element == EL_EXPLODING)
3420       Explode(x, y, Frame[x][y], EX_NORMAL);
3421     else if (element == EL_AMOEBING)
3422       AmoebeWaechst(x, y);
3423     else if (IS_AMOEBALIVE(element))
3424       AmoebeAbleger(x, y);
3425     else if (element == EL_LIFE || element == EL_LIFE_ASYNC)
3426       Life(x, y);
3427     else if (element == EL_ABLENK_EIN)
3428       Ablenk(x, y);
3429     else if (element == EL_SALZSAEURE)
3430       Blubber(x, y);
3431     else if (element == EL_BLURB_LEFT || element == EL_BLURB_RIGHT)
3432       Blurb(x, y);
3433     else if (element == EL_CRACKINGNUT)
3434       NussKnacken(x, y);
3435     else if (element == EL_AUSGANG_ZU)
3436       AusgangstuerPruefen(x, y);
3437     else if (element == EL_AUSGANG_ACT)
3438       AusgangstuerOeffnen(x, y);
3439     else if (element == EL_AUSGANG_AUF)
3440       AusgangstuerBlinken(x, y);
3441     else if (element == EL_MAUERND)
3442       MauerWaechst(x, y);
3443     else if (element == EL_MAUER_LEBT ||
3444              element == EL_MAUER_X ||
3445              element == EL_MAUER_Y ||
3446              element == EL_MAUER_XY)
3447       MauerAbleger(x, y);
3448     else if (element == EL_BURNING)
3449       CheckForDragon(x, y);
3450
3451     if (SiebAktiv)
3452     {
3453       boolean sieb = FALSE;
3454       int jx = local_player->jx, jy = local_player->jy;
3455
3456       if (element == EL_SIEB_LEER || element == EL_SIEB_VOLL ||
3457           Store[x][y] == EL_SIEB_LEER)
3458       {
3459         SiebAktivieren(x, y, 1);
3460         sieb = TRUE;
3461       }
3462       else if (element == EL_SIEB2_LEER || element == EL_SIEB2_VOLL ||
3463                Store[x][y] == EL_SIEB2_LEER)
3464       {
3465         SiebAktivieren(x, y, 2);
3466         sieb = TRUE;
3467       }
3468
3469       /* play the element sound at the position nearest to the player */
3470       if (sieb && ABS(x-jx)+ABS(y-jy) < ABS(sieb_x-jx)+ABS(sieb_y-jy))
3471       {
3472         sieb_x = x;
3473         sieb_y = y;
3474       }
3475     }
3476   }
3477
3478   if (SiebAktiv)
3479   {
3480     if (!(SiebCount % 4))
3481       PlaySoundLevel(sieb_x, sieb_y, SND_MIEP);
3482
3483     if (SiebCount > 0)
3484     {
3485       SiebCount--;
3486       if (!SiebCount)
3487       {
3488         for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
3489         {
3490           element = Feld[x][y];
3491           if (element == EL_SIEB_LEER || element == EL_SIEB_VOLL)
3492           {
3493             Feld[x][y] = EL_SIEB_TOT;
3494             DrawLevelField(x, y);
3495           }
3496           else if (element == EL_SIEB2_LEER || element == EL_SIEB2_VOLL)
3497           {
3498             Feld[x][y] = EL_SIEB2_TOT;
3499             DrawLevelField(x, y);
3500           }
3501         }
3502
3503         SiebAktiv = FALSE;
3504       }
3505     }
3506   }
3507
3508   if (TimeLeft > 0 && TimeFrames >= (1000 / GameFrameDelay) && !tape.pausing)
3509   {
3510     TimeFrames = 0;
3511     TimeLeft--;
3512
3513     if (tape.recording || tape.playing)
3514       DrawVideoDisplay(VIDEO_STATE_TIME_ON, level.time-TimeLeft);
3515
3516     if (TimeLeft<=10)
3517       PlaySoundStereo(SND_GONG, PSND_MAX_RIGHT);
3518
3519     DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
3520
3521     if (!TimeLeft)
3522       for (i=0; i<MAX_PLAYERS; i++)
3523         KillHero(&stored_player[i]);
3524   }
3525
3526   DrawAllPlayers();
3527 }
3528
3529 static boolean AllPlayersInSight(struct PlayerInfo *player, int x, int y)
3530 {
3531   int min_x = x, min_y = y, max_x = x, max_y = y;
3532   int i;
3533
3534   for (i=0; i<MAX_PLAYERS; i++)
3535   {
3536     int jx = stored_player[i].jx, jy = stored_player[i].jy;
3537
3538     if (!stored_player[i].active || stored_player[i].gone ||
3539         &stored_player[i] == player)
3540       continue;
3541
3542     min_x = MIN(min_x, jx);
3543     min_y = MIN(min_y, jy);
3544     max_x = MAX(max_x, jx);
3545     max_y = MAX(max_y, jy);
3546   }
3547
3548   return (max_x - min_x < SCR_FIELDX && max_y - min_y < SCR_FIELDY);
3549 }
3550
3551 static boolean AllPlayersInVisibleScreen()
3552 {
3553   int i;
3554
3555   for (i=0; i<MAX_PLAYERS; i++)
3556   {
3557     int jx = stored_player[i].jx, jy = stored_player[i].jy;
3558
3559     if (!stored_player[i].active || stored_player[i].gone)
3560       continue;
3561
3562     if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
3563       return FALSE;
3564   }
3565
3566   return TRUE;
3567 }
3568
3569 void ScrollLevel(int dx, int dy)
3570 {
3571   int softscroll_offset = (setup.soft_scrolling ? TILEX : 0);
3572   int x, y;
3573
3574   XCopyArea(display, drawto_field, drawto_field, gc,
3575             FX + TILEX*(dx == -1) - softscroll_offset,
3576             FY + TILEY*(dy == -1) - softscroll_offset,
3577             SXSIZE - TILEX*(dx!=0) + 2*softscroll_offset,
3578             SYSIZE - TILEY*(dy!=0) + 2*softscroll_offset,
3579             FX + TILEX*(dx == 1) - softscroll_offset,
3580             FY + TILEY*(dy == 1) - softscroll_offset);
3581
3582   if (dx)
3583   {
3584     x = (dx == 1 ? BX1 : BX2);
3585     for (y=BY1; y<=BY2; y++)
3586       DrawScreenField(x, y);
3587   }
3588   if (dy)
3589   {
3590     y = (dy == 1 ? BY1 : BY2);
3591     for (x=BX1; x<=BX2; x++)
3592       DrawScreenField(x, y);
3593   }
3594
3595   redraw_mask |= REDRAW_FIELD;
3596 }
3597
3598 boolean MoveFigureOneStep(struct PlayerInfo *player,
3599                           int dx, int dy, int real_dx, int real_dy)
3600 {
3601   int jx = player->jx, jy = player->jy;
3602   int new_jx = jx+dx, new_jy = jy+dy;
3603   int element;
3604   int can_move;
3605
3606   if (player->gone || (!dx && !dy))
3607     return MF_NO_ACTION;
3608
3609   player->MovDir = (dx < 0 ? MV_LEFT :
3610                     dx > 0 ? MV_RIGHT :
3611                     dy < 0 ? MV_UP :
3612                     dy > 0 ? MV_DOWN :  MV_NO_MOVING);
3613
3614   if (!IN_LEV_FIELD(new_jx, new_jy))
3615     return MF_NO_ACTION;
3616
3617   if (!options.network && !AllPlayersInSight(player, new_jx, new_jy))
3618     return MF_NO_ACTION;
3619
3620   element = MovingOrBlocked2Element(new_jx, new_jy);
3621
3622   if (DONT_GO_TO(element))
3623   {
3624     if (element == EL_SALZSAEURE && dx == 0 && dy == 1)
3625     {
3626       Blurb(jx, jy);
3627       Feld[jx][jy] = EL_SPIELFIGUR;
3628       InitMovingField(jx, jy, MV_DOWN);
3629       Store[jx][jy] = EL_SALZSAEURE;
3630       ContinueMoving(jx, jy);
3631       BuryHero(player);
3632     }
3633     else
3634       KillHero(player);
3635
3636     return MF_MOVING;
3637   }
3638
3639   can_move = DigField(player, new_jx, new_jy, real_dx, real_dy, DF_DIG);
3640   if (can_move != MF_MOVING)
3641     return can_move;
3642
3643   StorePlayer[jx][jy] = 0;
3644   player->last_jx = jx;
3645   player->last_jy = jy;
3646   jx = player->jx = new_jx;
3647   jy = player->jy = new_jy;
3648   StorePlayer[jx][jy] = player->element_nr;
3649
3650   player->MovPos = (dx > 0 || dy > 0 ? -1 : 1) * (TILEX - TILEX / MoveSpeed);
3651
3652   ScrollFigure(player, SCROLL_INIT);
3653
3654   return MF_MOVING;
3655 }
3656
3657 boolean MoveFigure(struct PlayerInfo *player, int dx, int dy)
3658 {
3659   int jx = player->jx, jy = player->jy;
3660   int old_jx = jx, old_jy = jy;
3661   int moved = MF_NO_ACTION;
3662
3663   if (player->gone || (!dx && !dy))
3664     return FALSE;
3665
3666   if (!FrameReached(&player->move_delay, MoveSpeed) && !tape.playing)
3667     return FALSE;
3668
3669   if (player->MovPos)
3670   {
3671     /* should only happen if pre-1.2 tape recordings are played */
3672     /* this is only for backward compatibility */
3673
3674     int old_move_speed = MoveSpeed;
3675
3676 #if DEBUG
3677     printf("THIS SHOULD ONLY HAPPEN WITH PRE-1.2 LEVEL TAPES.\n");
3678 #endif
3679
3680     /* scroll remaining steps with finest movement resolution */
3681     MoveSpeed = 8;
3682
3683     while (player->MovPos)
3684     {
3685       ScrollFigure(player, SCROLL_GO_ON);
3686       ScrollScreen(NULL, SCROLL_GO_ON);
3687       FrameCounter++;
3688       DrawAllPlayers();
3689       BackToFront();
3690     }
3691
3692     MoveSpeed = old_move_speed;
3693   }
3694
3695   if (player->last_move_dir & (MV_LEFT | MV_RIGHT))
3696   {
3697     if (!(moved |= MoveFigureOneStep(player, 0, dy, dx, dy)))
3698       moved |= MoveFigureOneStep(player, dx, 0, dx, dy);
3699   }
3700   else
3701   {
3702     if (!(moved |= MoveFigureOneStep(player, dx, 0, dx, dy)))
3703       moved |= MoveFigureOneStep(player, 0, dy, dx, dy);
3704   }
3705
3706   jx = player->jx;
3707   jy = player->jy;
3708
3709   if (moved & MF_MOVING && !ScreenMovPos &&
3710       (player == local_player || !options.network))
3711   {
3712     int old_scroll_x = scroll_x, old_scroll_y = scroll_y;
3713     int offset = (setup.scroll_delay ? 3 : 0);
3714
3715     if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
3716     {
3717       /* actual player has left the screen -- scroll in that direction */
3718       if (jx != old_jx)         /* player has moved horizontally */
3719         scroll_x += (jx - old_jx);
3720       else                      /* player has moved vertically */
3721         scroll_y += (jy - old_jy);
3722     }
3723     else
3724     {
3725       if (jx != old_jx)         /* player has moved horizontally */
3726       {
3727         if ((player->MovDir == MV_LEFT && scroll_x > jx-MIDPOSX+offset) ||
3728             (player->MovDir == MV_RIGHT && scroll_x < jx-MIDPOSX-offset))
3729           scroll_x = jx-MIDPOSX + (scroll_x < jx-MIDPOSX ? -offset : +offset);
3730
3731         /* don't scroll over playfield boundaries */
3732         if (scroll_x < -1 || scroll_x > lev_fieldx - SCR_FIELDX + 1)
3733           scroll_x = (scroll_x < -1 ? -1 : lev_fieldx - SCR_FIELDX + 1);
3734
3735         /* don't scroll more than one field at a time */
3736         scroll_x = old_scroll_x + SIGN(scroll_x - old_scroll_x);
3737
3738         /* don't scroll against the player's moving direction */
3739         if ((player->MovDir == MV_LEFT && scroll_x > old_scroll_x) ||
3740             (player->MovDir == MV_RIGHT && scroll_x < old_scroll_x))
3741           scroll_x = old_scroll_x;
3742       }
3743       else                      /* player has moved vertically */
3744       {
3745         if ((player->MovDir == MV_UP && scroll_y > jy-MIDPOSY+offset) ||
3746             (player->MovDir == MV_DOWN && scroll_y < jy-MIDPOSY-offset))
3747           scroll_y = jy-MIDPOSY + (scroll_y < jy-MIDPOSY ? -offset : +offset);
3748
3749         /* don't scroll over playfield boundaries */
3750         if (scroll_y < -1 || scroll_y > lev_fieldy - SCR_FIELDY + 1)
3751           scroll_y = (scroll_y < -1 ? -1 : lev_fieldy - SCR_FIELDY + 1);
3752
3753         /* don't scroll more than one field at a time */
3754         scroll_y = old_scroll_y + SIGN(scroll_y - old_scroll_y);
3755
3756         /* don't scroll against the player's moving direction */
3757         if ((player->MovDir == MV_UP && scroll_y > old_scroll_y) ||
3758             (player->MovDir == MV_DOWN && scroll_y < old_scroll_y))
3759           scroll_y = old_scroll_y;
3760       }
3761     }
3762
3763     if (scroll_x != old_scroll_x || scroll_y != old_scroll_y)
3764     {
3765       if (!options.network && !AllPlayersInVisibleScreen())
3766       {
3767         scroll_x = old_scroll_x;
3768         scroll_y = old_scroll_y;
3769       }
3770       else
3771       {
3772         ScrollScreen(player, SCROLL_INIT);
3773         ScrollLevel(old_scroll_x - scroll_x, old_scroll_y - scroll_y);
3774       }
3775     }
3776   }
3777
3778   if (!(moved & MF_MOVING) && !player->Pushing)
3779     player->Frame = 0;
3780   else
3781     player->Frame = (player->Frame + 1) % 4;
3782
3783   if (moved & MF_MOVING)
3784   {
3785     if (old_jx != jx && old_jy == jy)
3786       player->MovDir = (old_jx < jx ? MV_RIGHT : MV_LEFT);
3787     else if (old_jx == jx && old_jy != jy)
3788       player->MovDir = (old_jy < jy ? MV_DOWN : MV_UP);
3789
3790     DrawLevelField(jx, jy);     /* for "ErdreichAnbroeckeln()" */
3791
3792     player->last_move_dir = player->MovDir;
3793   }
3794   else
3795     player->last_move_dir = MV_NO_MOVING;
3796
3797   TestIfHeroHitsBadThing(jx, jy);
3798
3799   if (player->gone)
3800     RemoveHero(player);
3801
3802   return moved;
3803 }
3804
3805 void ScrollFigure(struct PlayerInfo *player, int mode)
3806 {
3807   int jx = player->jx, jy = player->jy;
3808   int last_jx = player->last_jx, last_jy = player->last_jy;
3809
3810   if (!player->active || player->gone || !player->MovPos)
3811     return;
3812
3813   if (mode == SCROLL_INIT)
3814   {
3815     player->actual_frame_counter = FrameCounter;
3816     player->GfxPos = ScrollStepSize * (player->MovPos / ScrollStepSize);
3817
3818     if (Feld[last_jx][last_jy] == EL_LEERRAUM)
3819       Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING;
3820
3821     DrawPlayer(player);
3822     return;
3823   }
3824   else if (!FrameReached(&player->actual_frame_counter, 1))
3825     return;
3826
3827   player->MovPos += (player->MovPos > 0 ? -1 : 1) * TILEX / MoveSpeed;
3828   player->GfxPos = ScrollStepSize * (player->MovPos / ScrollStepSize);
3829
3830   if (Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING)
3831     Feld[last_jx][last_jy] = EL_LEERRAUM;
3832
3833   DrawPlayer(player);
3834
3835   if (!player->MovPos)
3836   {
3837     player->last_jx = jx;
3838     player->last_jy = jy;
3839
3840     if (Feld[jx][jy] == EL_AUSGANG_AUF)
3841     {
3842       RemoveHero(player);
3843
3844       if (!local_player->friends_still_needed)
3845         player->LevelSolved = player->GameOver = TRUE;
3846     }
3847   }
3848 }
3849
3850 void ScrollScreen(struct PlayerInfo *player, int mode)
3851 {
3852   static unsigned long screen_frame_counter = 0;
3853
3854   if (mode == SCROLL_INIT)
3855   {
3856     screen_frame_counter = FrameCounter;
3857     ScreenMovDir = player->MovDir;
3858     ScreenMovPos = player->MovPos;
3859     ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
3860     return;
3861   }
3862   else if (!FrameReached(&screen_frame_counter, 1))
3863     return;
3864
3865   if (ScreenMovPos)
3866   {
3867     ScreenMovPos += (ScreenMovPos > 0 ? -1 : 1) * TILEX / MoveSpeed;
3868     ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
3869     redraw_mask |= REDRAW_FIELD;
3870   }
3871   else
3872     ScreenMovDir = MV_NO_MOVING;
3873 }
3874
3875 void TestIfGoodThingHitsBadThing(int goodx, int goody)
3876 {
3877   int i, killx = goodx, killy = goody;
3878   static int xy[4][2] =
3879   {
3880     { 0, -1 },
3881     { -1, 0 },
3882     { +1, 0 },
3883     { 0, +1 }
3884   };
3885   static int harmless[4] =
3886   {
3887     MV_UP,
3888     MV_LEFT,
3889     MV_RIGHT,
3890     MV_DOWN
3891   };
3892
3893   for (i=0; i<4; i++)
3894   {
3895     int x, y, element;
3896
3897     x = goodx + xy[i][0];
3898     y = goody + xy[i][1];
3899     if (!IN_LEV_FIELD(x, y))
3900       continue;
3901
3902     element = Feld[x][y];
3903
3904     if (DONT_TOUCH(element))
3905     {
3906       if (MovDir[x][y] == harmless[i])
3907         continue;
3908
3909       killx = x;
3910       killy = y;
3911       break;
3912     }
3913   }
3914
3915   if (killx != goodx || killy != goody)
3916   {
3917     if (IS_PLAYER(goodx, goody))
3918       KillHero(PLAYERINFO(goodx, goody));
3919     else
3920       Bang(goodx, goody);
3921   }
3922 }
3923
3924 void TestIfBadThingHitsGoodThing(int badx, int bady)
3925 {
3926   int i, killx = badx, killy = bady;
3927   static int xy[4][2] =
3928   {
3929     { 0, -1 },
3930     { -1, 0 },
3931     { +1, 0 },
3932     { 0, +1 }
3933   };
3934   static int harmless[4] =
3935   {
3936     MV_UP,
3937     MV_LEFT,
3938     MV_RIGHT,
3939     MV_DOWN
3940   };
3941
3942   for (i=0; i<4; i++)
3943   {
3944     int x, y, element;
3945
3946     x = badx + xy[i][0];
3947     y = bady + xy[i][1];
3948     if (!IN_LEV_FIELD(x, y))
3949       continue;
3950
3951     element = Feld[x][y];
3952
3953     if (IS_PLAYER(x, y))
3954     {
3955       killx = x;
3956       killy = y;
3957       break;
3958     }
3959     else if (element == EL_PINGUIN)
3960     {
3961       if (MovDir[x][y] == harmless[i] && IS_MOVING(x, y))
3962         continue;
3963
3964       killx = x;
3965       killy = y;
3966       break;
3967     }
3968   }
3969
3970   if (killx != badx || killy != bady)
3971   {
3972     if (IS_PLAYER(killx, killy))
3973       KillHero(PLAYERINFO(killx, killy));
3974     else
3975       Bang(killx, killy);
3976   }
3977 }
3978
3979 void TestIfHeroHitsBadThing(int x, int y)
3980 {
3981   TestIfGoodThingHitsBadThing(x, y);
3982 }
3983
3984 void TestIfBadThingHitsHero(int x, int y)
3985 {
3986   TestIfBadThingHitsGoodThing(x, y);
3987 }
3988
3989 void TestIfFriendHitsBadThing(int x, int y)
3990 {
3991   TestIfGoodThingHitsBadThing(x, y);
3992 }
3993
3994 void TestIfBadThingHitsFriend(int x, int y)
3995 {
3996   TestIfBadThingHitsGoodThing(x, y);
3997 }
3998
3999 void TestIfBadThingHitsOtherBadThing(int badx, int bady)
4000 {
4001   int i, killx = badx, killy = bady;
4002   static int xy[4][2] =
4003   {
4004     { 0, -1 },
4005     { -1, 0 },
4006     { +1, 0 },
4007     { 0, +1 }
4008   };
4009
4010   for (i=0; i<4; i++)
4011   {
4012     int x, y, element;
4013
4014     x=badx + xy[i][0];
4015     y=bady + xy[i][1];
4016     if (!IN_LEV_FIELD(x, y))
4017       continue;
4018
4019     element = Feld[x][y];
4020     if (IS_AMOEBOID(element) || element == EL_LIFE ||
4021         element == EL_AMOEBING || element == EL_TROPFEN)
4022     {
4023       killx = x;
4024       killy = y;
4025       break;
4026     }
4027   }
4028
4029   if (killx != badx || killy != bady)
4030     Bang(badx, bady);
4031 }
4032
4033 void KillHero(struct PlayerInfo *player)
4034 {
4035   int jx = player->jx, jy = player->jy;
4036
4037   if (player->gone)
4038     return;
4039
4040   if (IS_PFORTE(Feld[jx][jy]))
4041     Feld[jx][jy] = EL_LEERRAUM;
4042
4043   Bang(jx, jy);
4044   BuryHero(player);
4045 }
4046
4047 void BuryHero(struct PlayerInfo *player)
4048 {
4049   int jx = player->jx, jy = player->jy;
4050
4051   if (player->gone)
4052     return;
4053
4054   PlaySoundLevel(jx, jy, SND_AUTSCH);
4055   PlaySoundLevel(jx, jy, SND_LACHEN);
4056
4057   player->GameOver = TRUE;
4058   RemoveHero(player);
4059 }
4060
4061 void RemoveHero(struct PlayerInfo *player)
4062 {
4063   int jx = player->jx, jy = player->jy;
4064   int i, found = FALSE;
4065
4066   player->gone = TRUE;
4067   StorePlayer[jx][jy] = 0;
4068
4069   for (i=0; i<MAX_PLAYERS; i++)
4070     if (stored_player[i].active && !stored_player[i].gone)
4071       found = TRUE;
4072
4073   if (!found)
4074     AllPlayersGone = TRUE;
4075
4076   ExitX = ZX = jx;
4077   ExitY = ZY = jy;
4078 }
4079
4080 int DigField(struct PlayerInfo *player,
4081              int x, int y, int real_dx, int real_dy, int mode)
4082 {
4083   int jx = player->jx, jy = player->jy;
4084   int dx = x - jx, dy = y - jy;
4085   int element;
4086
4087   if (!player->MovPos)
4088     player->Pushing = FALSE;
4089
4090   if (mode == DF_NO_PUSH)
4091   {
4092     player->push_delay = 0;
4093     return MF_NO_ACTION;
4094   }
4095
4096   if (IS_MOVING(x, y) || IS_PLAYER(x, y))
4097     return MF_NO_ACTION;
4098
4099   element = Feld[x][y];
4100
4101   switch(element)
4102   {
4103     case EL_LEERRAUM:
4104       break;
4105
4106     case EL_ERDREICH:
4107       Feld[x][y] = EL_LEERRAUM;
4108       break;
4109
4110     case EL_EDELSTEIN:
4111     case EL_EDELSTEIN_BD:
4112     case EL_EDELSTEIN_GELB:
4113     case EL_EDELSTEIN_ROT:
4114     case EL_EDELSTEIN_LILA:
4115     case EL_DIAMANT:
4116     case EL_SP_INFOTRON:
4117       RemoveField(x, y);
4118       local_player->gems_still_needed -= (element == EL_DIAMANT ? 3 : 1);
4119       if (local_player->gems_still_needed < 0)
4120         local_player->gems_still_needed = 0;
4121       RaiseScoreElement(element);
4122       DrawText(DX_EMERALDS, DY_EMERALDS,
4123                int2str(local_player->gems_still_needed, 3),
4124                FS_SMALL, FC_YELLOW);
4125       PlaySoundLevel(x, y, SND_PONG);
4126       break;
4127
4128     case EL_SPEED_PILL:
4129       RemoveField(x, y);
4130       MoveSpeed = 4;
4131       ScrollStepSize = TILEX/4;
4132       PlaySoundLevel(x, y, SND_PONG);
4133       break;
4134
4135     case EL_DYNAMIT_AUS:
4136       RemoveField(x, y);
4137       player->dynamite++;
4138       RaiseScoreElement(EL_DYNAMIT);
4139       DrawText(DX_DYNAMITE, DY_DYNAMITE,
4140                int2str(local_player->dynamite, 3),
4141                FS_SMALL, FC_YELLOW);
4142       PlaySoundLevel(x, y, SND_PONG);
4143       break;
4144
4145     case EL_DYNABOMB_NR:
4146       RemoveField(x, y);
4147       player->dynabomb_count++;
4148       player->dynabombs_left++;
4149       RaiseScoreElement(EL_DYNAMIT);
4150       PlaySoundLevel(x, y, SND_PONG);
4151       break;
4152
4153     case EL_DYNABOMB_SZ:
4154       RemoveField(x, y);
4155       player->dynabomb_size++;
4156       RaiseScoreElement(EL_DYNAMIT);
4157       PlaySoundLevel(x, y, SND_PONG);
4158       break;
4159
4160     case EL_DYNABOMB_XL:
4161       RemoveField(x, y);
4162       player->dynabomb_xl = TRUE;
4163       RaiseScoreElement(EL_DYNAMIT);
4164       PlaySoundLevel(x, y, SND_PONG);
4165       break;
4166
4167     case EL_SCHLUESSEL1:
4168     case EL_SCHLUESSEL2:
4169     case EL_SCHLUESSEL3:
4170     case EL_SCHLUESSEL4:
4171     {
4172       int key_nr = element-EL_SCHLUESSEL1;
4173
4174       RemoveField(x, y);
4175       player->key[key_nr] = TRUE;
4176       RaiseScoreElement(EL_SCHLUESSEL);
4177       DrawMiniGraphicExt(drawto, gc,
4178                          DX_KEYS+key_nr*MINI_TILEX, DY_KEYS,
4179                          GFX_SCHLUESSEL1+key_nr);
4180       DrawMiniGraphicExt(window, gc,
4181                          DX_KEYS+key_nr*MINI_TILEX, DY_KEYS,
4182                          GFX_SCHLUESSEL1+key_nr);
4183       PlaySoundLevel(x, y, SND_PONG);
4184       break;
4185     }
4186
4187     case EL_ABLENK_AUS:
4188       Feld[x][y] = EL_ABLENK_EIN;
4189       ZX = x;
4190       ZY = y;
4191       DrawLevelField(x, y);
4192       return MF_ACTION;
4193       break;
4194
4195     case EL_SP_TERMINAL:
4196       {
4197         int xx, yy;
4198
4199         for (yy=0; yy<lev_fieldy; yy++)
4200           for (xx=0; xx<lev_fieldx; xx++)
4201             if (Feld[xx][yy] == EL_SP_DISK_YELLOW)
4202               Bang(xx, yy);
4203
4204         Feld[x][y] = EL_SP_TERMINAL_ACTIVE;
4205         DrawLevelField(x, y);
4206         return MF_ACTION;
4207       }
4208       break;
4209
4210     case EL_SP_EXIT:
4211       if (local_player->gems_still_needed > 0)
4212         return MF_NO_ACTION;
4213
4214       player->LevelSolved = player->GameOver = TRUE;
4215       PlaySoundLevel(x, y, SND_BUING);
4216       break;
4217
4218     case EL_FELSBROCKEN:
4219     case EL_BOMBE:
4220     case EL_KOKOSNUSS:
4221     case EL_ZEIT_LEER:
4222     case EL_SP_ZONK:
4223     case EL_SP_DISK_ORANGE:
4224     case EL_SP_DISK_YELLOW:
4225       if (dy || mode == DF_SNAP)
4226         return MF_NO_ACTION;
4227
4228       player->Pushing = TRUE;
4229
4230       if (!IN_LEV_FIELD(x+dx, y+dy) || !IS_FREE(x+dx, y+dy))
4231         return MF_NO_ACTION;
4232
4233       if (real_dy)
4234       {
4235         if (IN_LEV_FIELD(jx, jy+real_dy) && !IS_SOLID(Feld[jx][jy+real_dy]))
4236           return MF_NO_ACTION;
4237       }
4238
4239       if (player->push_delay == 0)
4240         player->push_delay = FrameCounter;
4241       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
4242           !tape.playing)
4243         return MF_NO_ACTION;
4244
4245       RemoveField(x, y);
4246       Feld[x+dx][y+dy] = element;
4247
4248       player->push_delay_value = 2+RND(8);
4249
4250       DrawLevelField(x+dx, y+dy);
4251       if (element == EL_FELSBROCKEN)
4252         PlaySoundLevel(x+dx, y+dy, SND_PUSCH);
4253       else if (element == EL_KOKOSNUSS)
4254         PlaySoundLevel(x+dx, y+dy, SND_KNURK);
4255       else
4256         PlaySoundLevel(x+dx, y+dy, SND_KLOPF);
4257       break;
4258
4259     case EL_PFORTE1:
4260     case EL_PFORTE2:
4261     case EL_PFORTE3:
4262     case EL_PFORTE4:
4263       if (!player->key[element-EL_PFORTE1])
4264         return MF_NO_ACTION;
4265       break;
4266
4267     case EL_PFORTE1X:
4268     case EL_PFORTE2X:
4269     case EL_PFORTE3X:
4270     case EL_PFORTE4X:
4271       if (!player->key[element-EL_PFORTE1X])
4272         return MF_NO_ACTION;
4273       break;
4274
4275     case EL_AUSGANG_ZU:
4276     case EL_AUSGANG_ACT:
4277       /* door is not (yet) open */
4278       return MF_NO_ACTION;
4279       break;
4280
4281     case EL_AUSGANG_AUF:
4282       if (mode == DF_SNAP)
4283         return MF_NO_ACTION;
4284
4285       PlaySoundLevel(x, y, SND_BUING);
4286
4287       /*
4288       player->gone = TRUE;
4289       PlaySoundLevel(x, y, SND_BUING);
4290
4291       if (!local_player->friends_still_needed)
4292         player->LevelSolved = player->GameOver = TRUE;
4293       */
4294
4295       break;
4296
4297     case EL_BIRNE_AUS:
4298       Feld[x][y] = EL_BIRNE_EIN;
4299       local_player->lights_still_needed--;
4300       DrawLevelField(x, y);
4301       PlaySoundLevel(x, y, SND_DENG);
4302       return MF_ACTION;
4303       break;
4304
4305     case EL_ZEIT_VOLL:
4306       Feld[x][y] = EL_ZEIT_LEER;
4307       TimeLeft += 10;
4308       DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
4309       DrawLevelField(x, y);
4310       PlaySoundStereo(SND_GONG, PSND_MAX_RIGHT);
4311       return MF_ACTION;
4312       break;
4313
4314     case EL_SOKOBAN_FELD_LEER:
4315       break;
4316
4317     case EL_SOKOBAN_FELD_VOLL:
4318     case EL_SOKOBAN_OBJEKT:
4319     case EL_SONDE:
4320       if (mode == DF_SNAP)
4321         return MF_NO_ACTION;
4322
4323       player->Pushing = TRUE;
4324
4325       if (!IN_LEV_FIELD(x+dx, y+dy)
4326           || (!IS_FREE(x+dx, y+dy)
4327               && (Feld[x+dx][y+dy] != EL_SOKOBAN_FELD_LEER
4328                   || !IS_SB_ELEMENT(element))))
4329         return MF_NO_ACTION;
4330
4331       if (dx && real_dy)
4332       {
4333         if (IN_LEV_FIELD(jx, jy+real_dy) && !IS_SOLID(Feld[jx][jy+real_dy]))
4334           return MF_NO_ACTION;
4335       }
4336       else if (dy && real_dx)
4337       {
4338         if (IN_LEV_FIELD(jx+real_dx, jy) && !IS_SOLID(Feld[jx+real_dx][jy]))
4339           return MF_NO_ACTION;
4340       }
4341
4342       if (player->push_delay == 0)
4343         player->push_delay = FrameCounter;
4344       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
4345           !tape.playing)
4346         return MF_NO_ACTION;
4347
4348       if (IS_SB_ELEMENT(element))
4349       {
4350         if (element == EL_SOKOBAN_FELD_VOLL)
4351         {
4352           Feld[x][y] = EL_SOKOBAN_FELD_LEER;
4353           local_player->sokobanfields_still_needed++;
4354         }
4355         else
4356           RemoveField(x, y);
4357
4358         if (Feld[x+dx][y+dy] == EL_SOKOBAN_FELD_LEER)
4359         {
4360           Feld[x+dx][y+dy] = EL_SOKOBAN_FELD_VOLL;
4361           local_player->sokobanfields_still_needed--;
4362           if (element == EL_SOKOBAN_OBJEKT)
4363             PlaySoundLevel(x, y, SND_DENG);
4364         }
4365         else
4366           Feld[x+dx][y+dy] = EL_SOKOBAN_OBJEKT;
4367       }
4368       else
4369       {
4370         RemoveField(x, y);
4371         Feld[x+dx][y+dy] = element;
4372       }
4373
4374       player->push_delay_value = 2;
4375
4376       DrawLevelField(x, y);
4377       DrawLevelField(x+dx, y+dy);
4378       PlaySoundLevel(x+dx, y+dy, SND_PUSCH);
4379
4380       if (IS_SB_ELEMENT(element) &&
4381           local_player->sokobanfields_still_needed == 0 &&
4382           game_emulation == EMU_SOKOBAN)
4383       {
4384         player->LevelSolved = player->GameOver = TRUE;
4385         PlaySoundLevel(x, y, SND_BUING);
4386       }
4387
4388       break;
4389
4390     case EL_MAULWURF:
4391     case EL_PINGUIN:
4392     case EL_SCHWEIN:
4393     case EL_DRACHE:
4394       break;
4395
4396     default:
4397       if (IS_EATABLE(element))          /* other kinds of 'dirt' */
4398         Feld[x][y] = EL_LEERRAUM;
4399       else
4400         return MF_NO_ACTION;
4401
4402       break;
4403   }
4404
4405   player->push_delay = 0;
4406
4407   return MF_MOVING;
4408 }
4409
4410 boolean SnapField(struct PlayerInfo *player, int dx, int dy)
4411 {
4412   int jx = player->jx, jy = player->jy;
4413   int x = jx + dx, y = jy + dy;
4414
4415   if (player->gone || !IN_LEV_FIELD(x, y))
4416     return FALSE;
4417
4418   if (dx && dy)
4419     return FALSE;
4420
4421   if (!dx && !dy)
4422   {
4423     player->snapped = FALSE;
4424     return FALSE;
4425   }
4426
4427   if (player->snapped)
4428     return FALSE;
4429
4430   player->MovDir = (dx < 0 ? MV_LEFT :
4431                     dx > 0 ? MV_RIGHT :
4432                     dy < 0 ? MV_UP :
4433                     dy > 0 ? MV_DOWN :  MV_NO_MOVING);
4434
4435   if (!DigField(player, x, y, 0, 0, DF_SNAP))
4436     return FALSE;
4437
4438   player->snapped = TRUE;
4439   DrawLevelField(x, y);
4440   BackToFront();
4441
4442   return TRUE;
4443 }
4444
4445 boolean PlaceBomb(struct PlayerInfo *player)
4446 {
4447   int jx = player->jx, jy = player->jy;
4448   int element;
4449
4450   if (player->gone || player->MovPos)
4451     return FALSE;
4452
4453   element = Feld[jx][jy];
4454
4455   if ((player->dynamite == 0 && player->dynabombs_left == 0) ||
4456       element == EL_DYNAMIT || element == EL_DYNABOMB ||
4457       element == EL_EXPLODING)
4458     return FALSE;
4459
4460   if (element != EL_LEERRAUM)
4461     Store[jx][jy] = element;
4462
4463   if (player->dynamite)
4464   {
4465     Feld[jx][jy] = EL_DYNAMIT;
4466     MovDelay[jx][jy] = 96;
4467     player->dynamite--;
4468     DrawText(DX_DYNAMITE, DY_DYNAMITE, int2str(local_player->dynamite, 3),
4469              FS_SMALL, FC_YELLOW);
4470     if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy)))
4471       DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), GFX_DYNAMIT);
4472   }
4473   else
4474   {
4475     Feld[jx][jy] = EL_DYNABOMB;
4476     Store2[jx][jy] = player->element_nr;        /* for DynaExplode() */
4477     MovDelay[jx][jy] = 96;
4478     player->dynabombs_left--;
4479     if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy)))
4480       DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), GFX_DYNABOMB);
4481   }
4482
4483   return TRUE;
4484 }
4485
4486 void PlaySoundLevel(int x, int y, int sound_nr)
4487 {
4488   int sx = SCREENX(x), sy = SCREENY(y);
4489   int volume, stereo;
4490   int silence_distance = 8;
4491
4492   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound_nr)) ||
4493       (!setup.sound_loops && IS_LOOP_SOUND(sound_nr)))
4494     return;
4495
4496   if (!IN_LEV_FIELD(x, y) ||
4497       sx < -silence_distance || sx >= SCR_FIELDX+silence_distance ||
4498       sy < -silence_distance || sy >= SCR_FIELDY+silence_distance)
4499     return;
4500
4501   volume = PSND_MAX_VOLUME;
4502
4503 #ifndef MSDOS
4504   stereo = (sx-SCR_FIELDX/2)*12;
4505 #else
4506   stereo = PSND_MIDDLE+(2*sx-(SCR_FIELDX-1))*5;
4507   if(stereo > PSND_MAX_RIGHT) stereo = PSND_MAX_RIGHT;
4508   if(stereo < PSND_MAX_LEFT) stereo = PSND_MAX_LEFT;
4509 #endif
4510
4511   if (!IN_SCR_FIELD(sx, sy))
4512   {
4513     int dx = ABS(sx-SCR_FIELDX/2)-SCR_FIELDX/2;
4514     int dy = ABS(sy-SCR_FIELDY/2)-SCR_FIELDY/2;
4515
4516     volume -= volume*(dx > dy ? dx : dy)/silence_distance;
4517   }
4518
4519   PlaySoundExt(sound_nr, volume, stereo, PSND_NO_LOOP);
4520 }
4521
4522 void RaiseScore(int value)
4523 {
4524   local_player->score += value;
4525   DrawText(DX_SCORE, DY_SCORE, int2str(local_player->score, 5),
4526            FS_SMALL, FC_YELLOW);
4527 }
4528
4529 void RaiseScoreElement(int element)
4530 {
4531   switch(element)
4532   {
4533     case EL_EDELSTEIN:
4534     case EL_EDELSTEIN_BD:
4535     case EL_EDELSTEIN_GELB:
4536     case EL_EDELSTEIN_ROT:
4537     case EL_EDELSTEIN_LILA:
4538       RaiseScore(level.score[SC_EDELSTEIN]);
4539       break;
4540     case EL_DIAMANT:
4541       RaiseScore(level.score[SC_DIAMANT]);
4542       break;
4543     case EL_KAEFER:
4544     case EL_BUTTERFLY:
4545       RaiseScore(level.score[SC_KAEFER]);
4546       break;
4547     case EL_FLIEGER:
4548     case EL_FIREFLY:
4549       RaiseScore(level.score[SC_FLIEGER]);
4550       break;
4551     case EL_MAMPFER:
4552     case EL_MAMPFER2:
4553       RaiseScore(level.score[SC_MAMPFER]);
4554       break;
4555     case EL_ROBOT:
4556       RaiseScore(level.score[SC_ROBOT]);
4557       break;
4558     case EL_PACMAN:
4559       RaiseScore(level.score[SC_PACMAN]);
4560       break;
4561     case EL_KOKOSNUSS:
4562       RaiseScore(level.score[SC_KOKOSNUSS]);
4563       break;
4564     case EL_DYNAMIT:
4565       RaiseScore(level.score[SC_DYNAMIT]);
4566       break;
4567     case EL_SCHLUESSEL:
4568       RaiseScore(level.score[SC_SCHLUESSEL]);
4569       break;
4570     default:
4571       break;
4572   }
4573 }