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