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