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