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