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