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