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