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