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