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