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