rnd-19980918
[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(10);
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]/2 && 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]/2 && 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   if (y > 0 && IS_MOVING(x,y-1) && MovDir[x][y-1] == MV_DOWN)
2316     DrawLevelField(x,y-1);
2317   else
2318     DrawGraphicAnimation(x,y, GFX_GEBLUBBER, 4, 10, ANIM_NORMAL);
2319 }
2320
2321 void NussKnacken(int x, int y)
2322 {
2323   if (!MovDelay[x][y])          /* neue Phase / noch nicht gewartet */
2324     MovDelay[x][y] = 7;
2325
2326   if (MovDelay[x][y])           /* neue Phase / in Wartezustand */
2327   {
2328     MovDelay[x][y]--;
2329     if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
2330       DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_CRACKINGNUT+3-MovDelay[x][y]/2);
2331
2332     if (!MovDelay[x][y])
2333     {
2334       Feld[x][y] = EL_EDELSTEIN;
2335       DrawLevelField(x,y);
2336     }
2337   }
2338 }
2339
2340 void SiebAktivieren(int x, int y, int typ)
2341 {
2342   if (!(SiebAktiv % 4) && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
2343     DrawGraphic(SCROLLX(x),SCROLLY(y),
2344                 (typ==1 ? GFX_SIEB_VOLL : GFX_SIEB2_VOLL)+3-(SiebAktiv%16)/4);
2345 }
2346
2347 void AusgangstuerPruefen(int x, int y)
2348 {
2349   if (!Gems && !SokobanFields && !Lights)
2350   {
2351     Feld[x][y] = EL_AUSGANG_ACT;
2352
2353     if (IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
2354       PlaySoundLevel(x,y,SND_OEFFNEN);
2355     else
2356       PlaySoundLevel(JX,JY,SND_OEFFNEN);
2357   }
2358 }
2359
2360 void AusgangstuerOeffnen(int x, int y)
2361 {
2362   int delay = 6;
2363
2364   if (!MovDelay[x][y])          /* neue Phase / noch nicht gewartet */
2365     MovDelay[x][y] = 5*delay;
2366
2367   if (MovDelay[x][y])           /* neue Phase / in Wartezustand */
2368   {
2369     int tuer;
2370
2371     MovDelay[x][y]--;
2372     tuer = MovDelay[x][y]/delay;
2373     if (!(MovDelay[x][y]%delay) && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
2374       DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_AUSGANG_AUF-tuer);
2375
2376     if (!MovDelay[x][y])
2377     {
2378       Feld[x][y] = EL_AUSGANG_AUF;
2379       DrawLevelField(x,y);
2380     }
2381   }
2382 }
2383
2384 void AusgangstuerBlinken(int x, int y)
2385 {
2386   DrawGraphicAnimation(x,y, GFX_AUSGANG_AUF, 4, 4, ANIM_OSCILLATE);
2387 }
2388
2389 void EdelsteinFunkeln(int x, int y)
2390 {
2391   if (!IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)) || IS_MOVING(x,y))
2392     return;
2393
2394   if (Feld[x][y] == EL_EDELSTEIN_BD)
2395     DrawGraphicAnimation(x,y, GFX_EDELSTEIN_BD, 4, 4, ANIM_REVERSE);
2396   else
2397   {
2398     if (!MovDelay[x][y])        /* neue Phase / noch nicht gewartet */
2399       MovDelay[x][y] = 11 * !SimpleRND(500);
2400
2401     if (MovDelay[x][y])         /* neue Phase / in Wartezustand */
2402     {
2403       MovDelay[x][y]--;
2404
2405       if (direct_draw_on && MovDelay[x][y])
2406         SetDrawtoField(DRAW_BUFFERED);
2407
2408       DrawGraphic(SCROLLX(x),SCROLLY(y), el2gfx(Feld[x][y]));
2409
2410       if (MovDelay[x][y])
2411       {
2412         int src_x,src_y, dest_x,dest_y;
2413         int phase = (MovDelay[x][y]-1)/2;
2414
2415         if (phase > 2)
2416           phase = 4-phase;
2417
2418         src_x  = SX + GFX_PER_LINE*TILEX;
2419         src_y  = SY + phase*TILEY;
2420         dest_x = FX + SCROLLX(x)*TILEX;
2421         dest_y = FY + SCROLLY(y)*TILEY;
2422
2423         /*
2424         XSetClipOrigin(display,clip_gc[PIX_BACK],dest_x-src_x,dest_y-src_y);
2425         XCopyArea(display,pix[PIX_BACK],drawto_field,clip_gc[PIX_BACK],
2426                   src_x,src_y, TILEX,TILEY, dest_x,dest_y);
2427                   */
2428
2429         XSetClipMask(display, tile_clip_gc,
2430                      tile_clipmask[GFX_MASK_SPARKLING + phase]);
2431         XSetClipOrigin(display, tile_clip_gc, dest_x,dest_y);
2432         XCopyArea(display, pix[PIX_BACK], drawto_field, tile_clip_gc,
2433                   src_x,src_y, TILEX,TILEY, dest_x,dest_y);
2434
2435         if (direct_draw_on)
2436         {
2437           XCopyArea(display,drawto_field,window,gc,
2438                     dest_x,dest_y, TILEX,TILEY, dest_x,dest_y);
2439           SetDrawtoField(DRAW_DIRECT);
2440         }
2441       }
2442     }
2443   }
2444 }
2445
2446 void MauerWaechst(int x, int y)
2447 {
2448   int delay = 6;
2449
2450   if (!MovDelay[x][y])          /* neue Phase / noch nicht gewartet */
2451     MovDelay[x][y] = 3*delay;
2452
2453   if (MovDelay[x][y])           /* neue Phase / in Wartezustand */
2454   {
2455     int phase;
2456
2457     MovDelay[x][y]--;
2458     phase = 2-MovDelay[x][y]/delay;
2459     if (!(MovDelay[x][y]%delay) && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
2460       DrawGraphic(SCROLLX(x),SCROLLY(y),
2461                   (Store[x][y]==MV_LEFT ? GFX_MAUER_L1 : GFX_MAUER_R1)+phase);
2462
2463     if (!MovDelay[x][y])
2464     {
2465       if (Store[x][y]==MV_LEFT)
2466       {
2467         if (IN_LEV_FIELD(x-1,y) && IS_MAUER(Feld[x-1][y]))
2468           DrawLevelField(x-1,y);
2469       }
2470       else
2471       {
2472         if (IN_LEV_FIELD(x+1,y) && IS_MAUER(Feld[x+1][y]))
2473           DrawLevelField(x+1,y);
2474       }
2475
2476       Feld[x][y] = EL_MAUER_LEBT;
2477       Store[x][y] = 0;
2478       DrawLevelField(x,y);
2479     }
2480   }
2481 }
2482
2483 void MauerAbleger(int ax, int ay)
2484 {
2485   BOOL links_frei = FALSE, rechts_frei = FALSE;
2486   BOOL links_massiv = FALSE, rechts_massiv = FALSE;
2487
2488   if (!MovDelay[ax][ay])        /* neue Mauer / noch nicht gewartet */
2489     MovDelay[ax][ay] = 6;
2490
2491   if (MovDelay[ax][ay])         /* neue Mauer / in Wartezustand */
2492   {
2493     MovDelay[ax][ay]--;
2494     if (MovDelay[ax][ay])
2495       return;
2496   }
2497
2498   if (IN_LEV_FIELD(ax-1,ay) && IS_FREE(ax-1,ay))
2499     links_frei = TRUE;
2500   if (IN_LEV_FIELD(ax+1,ay) && IS_FREE(ax+1,ay))
2501     rechts_frei = TRUE;
2502
2503   if (links_frei)
2504   {
2505     Feld[ax-1][ay] = EL_MAUERND;
2506     Store[ax-1][ay] = MV_LEFT;
2507     if (IN_SCR_FIELD(SCROLLX(ax-1),SCROLLY(ay)))
2508       DrawGraphic(SCROLLX(ax-1),SCROLLY(ay),GFX_MAUER_L1);
2509   }
2510   if (rechts_frei)
2511   {
2512     Feld[ax+1][ay] = EL_MAUERND;
2513     Store[ax+1][ay] = MV_RIGHT;
2514     if (IN_SCR_FIELD(SCROLLX(ax+1),SCROLLY(ay)))
2515       DrawGraphic(SCROLLX(ax+1),SCROLLY(ay),GFX_MAUER_R1);
2516   }
2517
2518   if (links_frei || rechts_frei)
2519     DrawLevelField(ax,ay);
2520
2521   if (!IN_LEV_FIELD(ax-1,ay) || IS_MAUER(Feld[ax-1][ay]))
2522     links_massiv = TRUE;
2523   if (!IN_LEV_FIELD(ax+1,ay) || IS_MAUER(Feld[ax+1][ay]))
2524     rechts_massiv = TRUE;
2525
2526   if (links_massiv && rechts_massiv)
2527     Feld[ax][ay] = EL_MAUERWERK;
2528 }
2529
2530 void CheckForDragon(int x, int y)
2531 {
2532   int i,j;
2533   BOOL dragon_found = FALSE;
2534   static int xy[4][2] =
2535   {
2536     { 0,-1 },
2537     { -1,0 },
2538     { +1,0 },
2539     { 0,+1 }
2540   };
2541
2542   for(i=0;i<4;i++)
2543   {
2544     for(j=0;j<4;j++)
2545     {
2546       int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
2547
2548       if (IN_LEV_FIELD(xx,yy) &&
2549           (Feld[xx][yy] == EL_BURNING || Feld[xx][yy] == EL_DRACHE))
2550       {
2551         if (Feld[xx][yy] == EL_DRACHE)
2552           dragon_found = TRUE;
2553       }
2554       else
2555         break;
2556     }
2557   }
2558
2559   if (!dragon_found)
2560   {
2561     for(i=0;i<4;i++)
2562     {
2563       for(j=0;j<3;j++)
2564       {
2565         int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
2566   
2567         if (IN_LEV_FIELD(xx,yy) && Feld[xx][yy] == EL_BURNING)
2568         {
2569           Feld[xx][yy] = EL_LEERRAUM;
2570           DrawLevelField(xx,yy);
2571         }
2572         else
2573           break;
2574       }
2575     }
2576   }
2577 }
2578
2579 void GameActions()
2580 {
2581   static long action_delay = 0;
2582   long action_delay_value;
2583   int sieb_x = 0, sieb_y = 0;
2584   int x, y, element;
2585
2586   if (game_status != PLAYING)
2587     return;
2588
2589 #ifdef DEBUG
2590   action_delay_value =
2591     (tape.playing && tape.fast_forward ? FFWD_FRAME_DELAY : GameSpeed);
2592 #else
2593   action_delay_value =
2594     (tape.playing && tape.fast_forward ? FFWD_FRAME_DELAY : GAME_FRAME_DELAY);
2595 #endif
2596
2597   if (PlayerMovPos)
2598     ScrollFigure(0);
2599
2600   /* main game synchronization point */
2601   WaitUntilDelayReached(&action_delay, action_delay_value);
2602
2603   if (tape.pausing || (tape.playing && !TapePlayDelay()))
2604     return;
2605   else if (tape.recording)
2606     TapeRecordDelay();
2607
2608   FrameCounter++;
2609   TimeFrames++;
2610
2611   for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
2612   {
2613     Stop[x][y] = FALSE;
2614     if (JustHit[x][y]>0)
2615       JustHit[x][y]--;
2616
2617 #if DEBUG
2618     if (IS_BLOCKED(x,y))
2619     {
2620       int oldx,oldy;
2621
2622       Blocked2Moving(x,y,&oldx,&oldy);
2623       if (!IS_MOVING(oldx,oldy))
2624       {
2625         printf("GameActions(): (BLOCKED=>MOVING) context corrupted!\n");
2626         printf("GameActions(): BLOCKED: x = %d, y = %d\n",x,y);
2627         printf("GameActions(): !MOVING: oldx = %d, oldy = %d\n",oldx,oldy);
2628         printf("GameActions(): This should never happen!\n");
2629       }
2630     }
2631 #endif
2632   }
2633
2634   for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
2635   {
2636     element = Feld[x][y];
2637
2638     if (IS_INACTIVE(element))
2639       continue;
2640
2641     if (!IS_MOVING(x,y) && (CAN_FALL(element) || CAN_MOVE(element)))
2642     {
2643       StartMoving(x,y);
2644
2645       if (IS_GEM(element))
2646         EdelsteinFunkeln(x,y);
2647     }
2648     else if (IS_MOVING(x,y))
2649       ContinueMoving(x,y);
2650     else if (element==EL_DYNAMIT || element==EL_DYNABOMB)
2651       CheckDynamite(x,y);
2652     else if (element==EL_EXPLODING)
2653       Explode(x,y,Frame[x][y],EX_NORMAL);
2654     else if (element==EL_AMOEBING)
2655       AmoebeWaechst(x,y);
2656     else if (IS_AMOEBALIVE(element))
2657       AmoebeAbleger(x,y);
2658     else if (element==EL_LIFE || element==EL_LIFE_ASYNC)
2659       Life(x,y);
2660     else if (element==EL_ABLENK_EIN)
2661       Ablenk(x,y);
2662     else if (element==EL_SALZSAEURE)
2663       Blubber(x,y);
2664     else if (element==EL_BLURB_LEFT || element==EL_BLURB_RIGHT)
2665       Blurb(x,y);
2666     else if (element==EL_CRACKINGNUT)
2667       NussKnacken(x,y);
2668     else if (element==EL_AUSGANG_ZU)
2669       AusgangstuerPruefen(x,y);
2670     else if (element==EL_AUSGANG_ACT)
2671       AusgangstuerOeffnen(x,y);
2672     else if (element==EL_AUSGANG_AUF)
2673       AusgangstuerBlinken(x,y);
2674     else if (element==EL_MAUERND)
2675       MauerWaechst(x,y);
2676     else if (element==EL_MAUER_LEBT)
2677       MauerAbleger(x,y);
2678     else if (element==EL_BURNING)
2679       CheckForDragon(x,y);
2680
2681     if (SiebAktiv)
2682     {
2683       BOOL sieb = FALSE;
2684
2685       if (element==EL_SIEB_LEER || element==EL_SIEB_VOLL ||
2686           Store[x][y]==EL_SIEB_LEER)
2687       {
2688         SiebAktivieren(x, y, 1);
2689         sieb = TRUE;
2690       }
2691       else if (element==EL_SIEB2_LEER || element==EL_SIEB2_VOLL ||
2692                Store[x][y]==EL_SIEB2_LEER)
2693       {
2694         SiebAktivieren(x, y, 2);
2695         sieb = TRUE;
2696       }
2697
2698       if (sieb && ABS(x-JX)+ABS(y-JY) < ABS(sieb_x-JX)+ABS(sieb_y-JY))
2699       {
2700         sieb_x = x;
2701         sieb_y = y;
2702       }
2703     }
2704   }
2705
2706   if (SiebAktiv)
2707   {
2708     if (!(SiebAktiv%4))
2709       PlaySoundLevel(sieb_x,sieb_y,SND_MIEP);
2710     SiebAktiv--;
2711     if (!SiebAktiv)
2712     {
2713       for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
2714       {
2715         element = Feld[x][y];
2716         if (element==EL_SIEB_LEER || element==EL_SIEB_VOLL)
2717         {
2718           Feld[x][y] = EL_SIEB_TOT;
2719           DrawLevelField(x,y);
2720         }
2721         else if (element==EL_SIEB2_LEER || element==EL_SIEB2_VOLL)
2722         {
2723           Feld[x][y] = EL_SIEB2_TOT;
2724           DrawLevelField(x,y);
2725         }
2726       }
2727     }
2728   }
2729
2730   if (TimeLeft>0 && TimeFrames>=(1000/GameSpeed) && !tape.pausing)
2731   {
2732     TimeFrames = 0;
2733     TimeLeft--;
2734
2735     if (tape.recording || tape.playing)
2736       DrawVideoDisplay(VIDEO_STATE_TIME_ON,level.time-TimeLeft);
2737
2738     if (TimeLeft<=10)
2739       PlaySoundStereo(SND_GONG,PSND_MAX_RIGHT);
2740
2741     DrawText(DX_TIME,DY_TIME,int2str(TimeLeft,3),FS_SMALL,FC_YELLOW);
2742
2743     if (!TimeLeft)
2744       KillHero();
2745   }
2746
2747   DrawPlayerField();
2748 }
2749
2750 void ScrollLevel(int dx, int dy)
2751 {
2752   int softscroll_offset = (soft_scrolling_on ? TILEX : 0);
2753   int x,y;
2754
2755   ScreenMovPos = PlayerGfxPos;
2756
2757   XCopyArea(display,drawto_field,drawto_field,gc,
2758             FX + TILEX*(dx==-1) - softscroll_offset,
2759             FY + TILEY*(dy==-1) - softscroll_offset,
2760             SXSIZE - TILEX*(dx!=0) + 2*softscroll_offset,
2761             SYSIZE - TILEY*(dy!=0) + 2*softscroll_offset,
2762             FX + TILEX*(dx==1) - softscroll_offset,
2763             FY + TILEY*(dy==1) - softscroll_offset);
2764
2765   if (dx)
2766   {
2767     x = (dx==1 ? BX1 : BX2);
2768     for(y=BY1; y<=BY2; y++)
2769       DrawScreenField(x,y);
2770   }
2771   if (dy)
2772   {
2773     y = (dy==1 ? BY1 : BY2);
2774     for(x=BX1; x<=BX2; x++)
2775       DrawScreenField(x,y);
2776   }
2777
2778   redraw_mask |= REDRAW_FIELD;
2779 }
2780
2781 BOOL MoveFigureOneStep(int dx, int dy, int real_dx, int real_dy)
2782 {
2783   int newJX = JX+dx, newJY = JY+dy;
2784   int element;
2785   int can_move;
2786
2787   if (PlayerGone || (!dx && !dy))
2788     return(MF_NO_ACTION);
2789
2790   PlayerMovDir = (dx < 0 ? MV_LEFT :
2791                   dx > 0 ? MV_RIGHT :
2792                   dy < 0 ? MV_UP :
2793                   dy > 0 ? MV_DOWN :    MV_NO_MOVING);
2794
2795   if (!IN_LEV_FIELD(newJX,newJY))
2796     return(MF_NO_ACTION);
2797
2798   element = MovingOrBlocked2Element(newJX,newJY);
2799
2800   if (DONT_GO_TO(element))
2801   {
2802     if (element==EL_SALZSAEURE && dx==0 && dy==1)
2803     {
2804       Blurb(JX,JY);
2805       Feld[JX][JY] = EL_SPIELFIGUR;
2806       InitMovingField(JX,JY,MV_DOWN);
2807       Store[JX][JY] = EL_SALZSAEURE;
2808       ContinueMoving(JX,JY);
2809       BuryHero();
2810     }
2811     else
2812       KillHero();
2813
2814     return(MF_MOVING);
2815   }
2816
2817   can_move = DigField(newJX,newJY, real_dx,real_dy, DF_DIG);
2818   if (can_move != MF_MOVING)
2819     return(can_move);
2820
2821   lastJX = JX;
2822   lastJY = JY;
2823   JX = newJX;
2824   JY = newJY;
2825
2826   PlayerMovPos = (dx > 0 || dy > 0 ? -1 : 1) * 7*TILEX/8;
2827
2828   ScrollFigure(-1);
2829
2830   return(MF_MOVING);
2831 }
2832
2833 BOOL MoveFigure(int dx, int dy)
2834 {
2835   static long move_delay = 0;
2836   static int last_move_dir = MV_NO_MOVING;
2837   int moved = MF_NO_ACTION;
2838   int oldJX = JX, oldJY = JY;
2839
2840   if (PlayerGone || (!dx && !dy))
2841     return(FALSE);
2842
2843   if (!FrameReached(&move_delay,MoveSpeed) && !tape.playing)
2844     return(FALSE);
2845
2846   if (last_move_dir & (MV_LEFT | MV_RIGHT))
2847   {
2848     if (!(moved |= MoveFigureOneStep(0,dy, dx,dy)))
2849       moved |= MoveFigureOneStep(dx,0, dx,dy);
2850   }
2851   else
2852   {
2853     if (!(moved |= MoveFigureOneStep(dx,0, dx,dy)))
2854       moved |= MoveFigureOneStep(0,dy, dx,dy);
2855   }
2856
2857   last_move_dir = MV_NO_MOVING;
2858
2859   if (moved & MF_MOVING)
2860   {
2861     int old_scroll_x = scroll_x, old_scroll_y = scroll_y;
2862     int offset = (scroll_delay_on ? 3 : 0);
2863
2864     if ((scroll_x < JX-MIDPOSX-offset || scroll_x > JX-MIDPOSX+offset) &&
2865         JX >= MIDPOSX-1-offset && JX <= lev_fieldx-(MIDPOSX-offset))
2866       scroll_x = JX-MIDPOSX + (scroll_x < JX-MIDPOSX ? -offset : offset);
2867     if ((scroll_y < JY-MIDPOSY-offset || scroll_y > JY-MIDPOSY+offset) &&
2868         JY >= MIDPOSY-1-offset && JY <= lev_fieldy-(MIDPOSY-offset))
2869       scroll_y = JY-MIDPOSY + (scroll_y < JY-MIDPOSY ? -offset : offset);
2870
2871     if (scroll_x != old_scroll_x || scroll_y != old_scroll_y)
2872       ScrollLevel(old_scroll_x - scroll_x, old_scroll_y - scroll_y);
2873   }
2874
2875   if (!(moved & MF_MOVING) && !PlayerPushing)
2876     PlayerFrame = 0;
2877   else
2878     PlayerFrame = (PlayerFrame + 1) % 4;
2879
2880   if (moved & MF_MOVING)
2881   {
2882     if (oldJX != JX && oldJY == JY)
2883       PlayerMovDir = (oldJX < JX ? MV_RIGHT : MV_LEFT);
2884     else if (oldJX == JX && oldJY != JY)
2885       PlayerMovDir = (oldJY < JY ? MV_DOWN : MV_UP);
2886
2887     DrawLevelField(JX,JY);      /* für "ErdreichAnbroeckeln()" */
2888
2889     last_move_dir = PlayerMovDir;
2890   }
2891
2892   TestIfHeroHitsBadThing();
2893
2894   if (PlayerGone)
2895     RemoveHero();
2896
2897   return(moved);
2898 }
2899
2900 void ScrollFigure(int init)
2901 {
2902   static long actual_frame_counter = 0;
2903
2904   if (init)
2905   {
2906     PlayerGfxPos = ScrollStepSize * (PlayerMovPos / ScrollStepSize);
2907     actual_frame_counter = FrameCounter;
2908
2909     /*
2910     if (Feld[lastJX][lastJY] == EL_LEERRAUM &&
2911         IN_LEV_FIELD(lastJX,lastJY-1) &&
2912         CAN_FALL(Feld[lastJX][lastJY-1]))
2913       Feld[lastJX][lastJY] = EL_PLAYER_IS_LEAVING;
2914       */
2915
2916     if (Feld[lastJX][lastJY] == EL_LEERRAUM)
2917       Feld[lastJX][lastJY] = EL_PLAYER_IS_LEAVING;
2918
2919     DrawPlayerField();
2920     return;
2921   }
2922   else if (!FrameReached(&actual_frame_counter,1))
2923     return;
2924
2925   PlayerMovPos += (PlayerMovPos > 0 ? -1 : 1) * TILEX/8;
2926   PlayerGfxPos = ScrollStepSize * (PlayerMovPos / ScrollStepSize);
2927
2928   if (ScreenMovPos && ScreenMovPos != PlayerGfxPos)
2929   {
2930     ScreenMovPos = PlayerGfxPos;
2931     redraw_mask |= REDRAW_FIELD;
2932   }
2933
2934   if (Feld[lastJX][lastJY] == EL_PLAYER_IS_LEAVING)
2935     Feld[lastJX][lastJY] = EL_LEERRAUM;
2936
2937   DrawPlayerField();
2938
2939   if (!PlayerMovPos)
2940   {
2941     lastJX = JX;
2942     lastJY = JY;
2943   }
2944 }
2945
2946 void TestIfGoodThingHitsBadThing(int goodx, int goody)
2947 {
2948   int i, killx = goodx, killy = goody;
2949   static int xy[4][2] =
2950   {
2951     { 0,-1 },
2952     { -1,0 },
2953     { +1,0 },
2954     { 0,+1 }
2955   };
2956   static int harmless[4] =
2957   {
2958     MV_UP,
2959     MV_LEFT,
2960     MV_RIGHT,
2961     MV_DOWN
2962   };
2963
2964   for(i=0;i<4;i++)
2965   {
2966     int x,y,element;
2967
2968     x = goodx+xy[i][0];
2969     y = goody+xy[i][1];
2970     if (!IN_LEV_FIELD(x,y))
2971       continue;
2972
2973     element = Feld[x][y];
2974
2975     if (DONT_TOUCH(element))
2976     {
2977       if (MovDir[x][y]==harmless[i])
2978         continue;
2979
2980       killx = x;
2981       killy = y;
2982       break;
2983     }
2984   }
2985
2986   if (killx!=goodx || killy!=goody)
2987   {
2988     if (IS_PLAYER(goodx,goody))
2989       KillHero();
2990     else
2991       Bang(goodx,goody);
2992   }
2993 }
2994
2995 void TestIfBadThingHitsGoodThing(int badx, int bady)
2996 {
2997   int i, killx = badx, killy = bady;
2998   static int xy[4][2] =
2999   {
3000     { 0,-1 },
3001     { -1,0 },
3002     { +1,0 },
3003     { 0,+1 }
3004   };
3005   static int harmless[4] =
3006   {
3007     MV_UP,
3008     MV_LEFT,
3009     MV_RIGHT,
3010     MV_DOWN
3011   };
3012
3013   for(i=0;i<4;i++)
3014   {
3015     int x,y,element;
3016
3017     x = badx+xy[i][0];
3018     y = bady+xy[i][1];
3019     if (!IN_LEV_FIELD(x,y))
3020       continue;
3021
3022     element = Feld[x][y];
3023
3024     if (element==EL_PINGUIN)
3025     {
3026       if (MovDir[x][y]==harmless[i] && IS_MOVING(x,y))
3027         continue;
3028
3029       killx = x;
3030       killy = y;
3031       break;
3032     }
3033   }
3034
3035   if (killx!=badx || killy!=bady)
3036     Bang(killx,killy);
3037 }
3038
3039 void TestIfHeroHitsBadThing()
3040 {
3041   TestIfGoodThingHitsBadThing(JX,JY);
3042 }
3043
3044 void TestIfBadThingHitsHero()
3045 {
3046   TestIfGoodThingHitsBadThing(JX,JY);
3047   /* (no typo!) */
3048 }
3049
3050 void TestIfFriendHitsBadThing(int x, int y)
3051 {
3052   TestIfGoodThingHitsBadThing(x,y);
3053 }
3054
3055 void TestIfBadThingHitsFriend(int x, int y)
3056 {
3057   TestIfBadThingHitsGoodThing(x,y);
3058 }
3059
3060 void TestIfBadThingHitsOtherBadThing(int badx, int bady)
3061 {
3062   int i, killx=badx, killy=bady;
3063   static int xy[4][2] =
3064   {
3065     { 0,-1 },
3066     { -1,0 },
3067     { +1,0 },
3068     { 0,+1 }
3069   };
3070
3071   for(i=0;i<4;i++)
3072   {
3073     int x,y,element;
3074
3075     x=badx+xy[i][0];
3076     y=bady+xy[i][1];
3077     if (!IN_LEV_FIELD(x,y))
3078       continue;
3079
3080     element=Feld[x][y];
3081     if (IS_AMOEBOID(element) || element==EL_LIFE ||
3082         element==EL_AMOEBING || element==EL_TROPFEN)
3083     {
3084       killx=x;
3085       killy=y;
3086       break;
3087     }
3088   }
3089
3090   if (killx!=badx || killy!=bady)
3091     Bang(badx,bady);
3092 }
3093
3094 void KillHero()
3095 {
3096   if (PlayerGone)
3097     return;
3098
3099   if (IS_PFORTE(Feld[JX][JY]))
3100     Feld[JX][JY] = EL_LEERRAUM;
3101
3102   Bang(JX,JY);
3103   BuryHero();
3104 }
3105
3106 void BuryHero()
3107 {
3108   if (PlayerGone)
3109     return;
3110
3111   PlaySoundLevel(JX,JY,SND_AUTSCH);
3112   PlaySoundLevel(JX,JY,SND_LACHEN);
3113
3114   GameOver = TRUE;
3115   RemoveHero();
3116 }
3117
3118 void RemoveHero()
3119 {
3120   PlayerGone = TRUE;
3121
3122   ExitX = ZX = JX;
3123   ExitY = ZY = JY;
3124   JX = JY = -1;
3125 }
3126
3127 int DigField(int x, int y, int real_dx, int real_dy, int mode)
3128 {
3129   int dx = x-JX, dy = y-JY;
3130   int element;
3131   static long push_delay = 0;
3132   static int push_delay_value = 5;
3133
3134   if (!PlayerMovPos)
3135     PlayerPushing = FALSE;
3136
3137   if (mode == DF_NO_PUSH)
3138   {
3139     push_delay = 0;
3140     return(MF_NO_ACTION);
3141   }
3142
3143   if (IS_MOVING(x,y))
3144     return(MF_NO_ACTION);
3145
3146   element = Feld[x][y];
3147
3148   switch(element)
3149   {
3150     case EL_LEERRAUM:
3151       break;
3152
3153     case EL_ERDREICH:
3154       Feld[x][y] = EL_LEERRAUM;
3155       break;
3156
3157     case EL_EDELSTEIN:
3158     case EL_EDELSTEIN_BD:
3159     case EL_EDELSTEIN_GELB:
3160     case EL_EDELSTEIN_ROT:
3161     case EL_EDELSTEIN_LILA:
3162       Feld[x][y] = EL_LEERRAUM;
3163       MovDelay[x][y] = 0;       /* wegen EDELSTEIN_BD-Funkeln! */
3164       if (Gems>0)
3165         Gems--;
3166       RaiseScoreElement(EL_EDELSTEIN);
3167       DrawText(DX_EMERALDS,DY_EMERALDS,int2str(Gems,3),FS_SMALL,FC_YELLOW);
3168       PlaySoundLevel(x,y,SND_PONG);
3169       break;
3170
3171     case EL_DIAMANT:
3172       Feld[x][y] = EL_LEERRAUM;
3173       Gems -= 3;
3174       if (Gems<0)
3175         Gems=0;
3176       RaiseScoreElement(EL_DIAMANT);
3177       DrawText(DX_EMERALDS,DY_EMERALDS,int2str(Gems,3),FS_SMALL,FC_YELLOW);
3178       PlaySoundLevel(x,y,SND_PONG);
3179       break;
3180
3181     case EL_DYNAMIT_AUS:
3182       Feld[x][y] = EL_LEERRAUM;
3183       Dynamite++;
3184       RaiseScoreElement(EL_DYNAMIT);
3185       DrawText(DX_DYNAMITE,DY_DYNAMITE,int2str(Dynamite,3),FS_SMALL,FC_YELLOW);
3186       PlaySoundLevel(x,y,SND_PONG);
3187       break;
3188
3189     case EL_DYNABOMB_NR:
3190       Feld[x][y] = EL_LEERRAUM;
3191       DynaBombCount++;
3192       DynaBombsLeft++;
3193       RaiseScoreElement(EL_DYNAMIT);
3194       PlaySoundLevel(x,y,SND_PONG);
3195       break;
3196     case EL_DYNABOMB_SZ:
3197
3198       Feld[x][y] = EL_LEERRAUM;
3199       DynaBombSize++;
3200       RaiseScoreElement(EL_DYNAMIT);
3201       PlaySoundLevel(x,y,SND_PONG);
3202       break;
3203
3204     case EL_DYNABOMB_XL:
3205       Feld[x][y] = EL_LEERRAUM;
3206       DynaBombXL = TRUE;
3207       RaiseScoreElement(EL_DYNAMIT);
3208       PlaySoundLevel(x,y,SND_PONG);
3209       break;
3210
3211     case EL_SCHLUESSEL1:
3212     case EL_SCHLUESSEL2:
3213     case EL_SCHLUESSEL3:
3214     case EL_SCHLUESSEL4:
3215     {
3216       int key_nr = element-EL_SCHLUESSEL1;
3217
3218       Feld[x][y] = EL_LEERRAUM;
3219       Key[key_nr] = TRUE;
3220       RaiseScoreElement(EL_SCHLUESSEL);
3221       DrawMiniGraphicExt(drawto,gc,
3222                          DX_KEYS+key_nr*MINI_TILEX,DY_KEYS,
3223                          GFX_SCHLUESSEL1+key_nr);
3224       DrawMiniGraphicExt(window,gc,
3225                          DX_KEYS+key_nr*MINI_TILEX,DY_KEYS,
3226                          GFX_SCHLUESSEL1+key_nr);
3227       PlaySoundLevel(x,y,SND_PONG);
3228       break;
3229     }
3230
3231     case EL_ABLENK_AUS:
3232       Feld[x][y] = EL_ABLENK_EIN;
3233       ZX = x;
3234       ZY = y;
3235       DrawLevelField(x,y);
3236       return(MF_ACTION);
3237       break;
3238
3239     case EL_FELSBROCKEN:
3240     case EL_BOMBE:
3241     case EL_KOKOSNUSS:
3242     case EL_ZEIT_LEER:
3243       if (dy || mode==DF_SNAP)
3244         return(MF_NO_ACTION);
3245
3246       PlayerPushing = TRUE;
3247
3248       if (!IN_LEV_FIELD(x+dx,y+dy) || Feld[x+dx][y+dy] != EL_LEERRAUM)
3249         return(MF_NO_ACTION);
3250
3251       if (real_dy)
3252       {
3253         if (IN_LEV_FIELD(JX,JY+real_dy) && !IS_SOLID(Feld[JX][JY+real_dy]))
3254           return(MF_NO_ACTION);
3255       }
3256
3257       if (push_delay == 0)
3258         push_delay = FrameCounter;
3259       if (!FrameReached(&push_delay,push_delay_value) && !tape.playing)
3260         return(MF_NO_ACTION);
3261
3262       Feld[x][y] = EL_LEERRAUM;
3263       Feld[x+dx][y+dy] = element;
3264
3265       push_delay_value = 2+RND(8);
3266
3267       DrawLevelField(x+dx,y+dy);
3268       if (element==EL_FELSBROCKEN)
3269         PlaySoundLevel(x+dx,y+dy,SND_PUSCH);
3270       else if (element==EL_KOKOSNUSS)
3271         PlaySoundLevel(x+dx,y+dy,SND_KNURK);
3272       else
3273         PlaySoundLevel(x+dx,y+dy,SND_KLOPF);
3274       break;
3275
3276     case EL_PFORTE1:
3277     case EL_PFORTE2:
3278     case EL_PFORTE3:
3279     case EL_PFORTE4:
3280       if (!Key[element-EL_PFORTE1])
3281         return(MF_NO_ACTION);
3282       break;
3283
3284     case EL_PFORTE1X:
3285     case EL_PFORTE2X:
3286     case EL_PFORTE3X:
3287     case EL_PFORTE4X:
3288       if (!Key[element-EL_PFORTE1X])
3289         return(MF_NO_ACTION);
3290       break;
3291
3292     case EL_AUSGANG_ZU:
3293     case EL_AUSGANG_ACT:
3294       /* Tür ist (noch) nicht offen! */
3295       return(MF_NO_ACTION);
3296       break;
3297
3298     case EL_AUSGANG_AUF:
3299       if (mode==DF_SNAP)
3300         return(MF_NO_ACTION);
3301
3302       PlayerGone = TRUE;
3303       PlaySoundLevel(x,y,SND_BUING);
3304
3305       if (!Friends)
3306         LevelSolved = GameOver = TRUE;
3307
3308       break;
3309
3310     case EL_BIRNE_AUS:
3311       Feld[x][y] = EL_BIRNE_EIN;
3312       Lights--;
3313       DrawLevelField(x,y);
3314       PlaySoundLevel(x,y,SND_DENG);
3315       return(MF_ACTION);
3316       break;
3317
3318     case EL_ZEIT_VOLL:
3319       Feld[x][y] = EL_ZEIT_LEER;
3320       TimeLeft += 10;
3321       DrawText(DX_TIME,DY_TIME,int2str(TimeLeft,3),FS_SMALL,FC_YELLOW);
3322       DrawLevelField(x,y);
3323       PlaySoundStereo(SND_GONG,PSND_MAX_RIGHT);
3324       return(MF_ACTION);
3325       break;
3326
3327     case EL_SOKOBAN_FELD_LEER:
3328       break;
3329
3330     case EL_SOKOBAN_FELD_VOLL:
3331     case EL_SOKOBAN_OBJEKT:
3332     case EL_SONDE:
3333       if (mode==DF_SNAP)
3334         return(MF_NO_ACTION);
3335
3336       PlayerPushing = TRUE;
3337
3338       if (!IN_LEV_FIELD(x+dx,y+dy)
3339           || (Feld[x+dx][y+dy] != EL_LEERRAUM
3340               && (Feld[x+dx][y+dy] != EL_SOKOBAN_FELD_LEER
3341                   || !IS_SB_ELEMENT(element))))
3342         return(MF_NO_ACTION);
3343
3344       if (dx && real_dy)
3345       {
3346         if (IN_LEV_FIELD(JX,JY+real_dy) && !IS_SOLID(Feld[JX][JY+real_dy]))
3347           return(MF_NO_ACTION);
3348       }
3349       else if (dy && real_dx)
3350       {
3351         if (IN_LEV_FIELD(JX+real_dx,JY) && !IS_SOLID(Feld[JX+real_dx][JY]))
3352           return(MF_NO_ACTION);
3353       }
3354
3355       if (push_delay == 0)
3356         push_delay = FrameCounter;
3357       if (!FrameReached(&push_delay,push_delay_value) && !tape.playing)
3358         return(MF_NO_ACTION);
3359
3360       if (IS_SB_ELEMENT(element))
3361       {
3362         if (element == EL_SOKOBAN_FELD_VOLL)
3363         {
3364           Feld[x][y] = EL_SOKOBAN_FELD_LEER;
3365           SokobanFields++;
3366         }
3367         else
3368           Feld[x][y] = EL_LEERRAUM;
3369
3370         if (Feld[x+dx][y+dy] == EL_SOKOBAN_FELD_LEER)
3371         {
3372           Feld[x+dx][y+dy] = EL_SOKOBAN_FELD_VOLL;
3373           SokobanFields--;
3374           if (element == EL_SOKOBAN_OBJEKT)
3375             PlaySoundLevel(x,y,SND_DENG);
3376         }
3377         else
3378           Feld[x+dx][y+dy] = EL_SOKOBAN_OBJEKT;
3379       }
3380       else
3381       {
3382         Feld[x][y] = EL_LEERRAUM;
3383         Feld[x+dx][y+dy] = element;
3384       }
3385
3386       push_delay_value = 2;
3387
3388       DrawLevelField(x,y);
3389       DrawLevelField(x+dx,y+dy);
3390       PlaySoundLevel(x+dx,y+dy,SND_PUSCH);
3391
3392       if (IS_SB_ELEMENT(element) &&
3393           SokobanFields == 0 && game_emulation == EMU_SOKOBAN)
3394       {
3395         LevelSolved = GameOver = TRUE;
3396         PlaySoundLevel(x,y,SND_BUING);
3397       }
3398
3399       break;
3400
3401     case EL_MAULWURF:
3402     case EL_PINGUIN:
3403     case EL_SCHWEIN:
3404     case EL_DRACHE:
3405       break;
3406
3407     default:
3408       return(MF_NO_ACTION);
3409       break;
3410   }
3411
3412   push_delay = 0;
3413
3414   return(MF_MOVING);
3415 }
3416
3417 BOOL SnapField(int dx, int dy)
3418 {
3419   int x = JX+dx, y = JY+dy;
3420   static int snapped = FALSE;
3421
3422   if (PlayerGone || !IN_LEV_FIELD(x,y))
3423     return(FALSE);
3424   if (dx && dy)
3425     return(FALSE);
3426   if (!dx && !dy)
3427   {
3428     snapped = FALSE;
3429     return(FALSE);
3430   }
3431   if (snapped)
3432     return(FALSE);
3433
3434   PlayerMovDir = (dx < 0 ? MV_LEFT :
3435                   dx > 0 ? MV_RIGHT :
3436                   dy < 0 ? MV_UP :
3437                   dy > 0 ? MV_DOWN :    MV_NO_MOVING);
3438
3439   if (!DigField(x,y, 0,0, DF_SNAP))
3440     return(FALSE);
3441
3442   snapped = TRUE;
3443   DrawLevelField(x,y);
3444   BackToFront();
3445
3446   return(TRUE);
3447 }
3448
3449 BOOL PlaceBomb(void)
3450 {
3451   int element;
3452
3453   if (PlayerGone || PlayerMovPos)
3454     return(FALSE);
3455
3456   element = Feld[JX][JY];
3457
3458   if ((Dynamite==0 && DynaBombsLeft==0) ||
3459       element==EL_DYNAMIT || element==EL_DYNABOMB || element==EL_EXPLODING)
3460     return(FALSE);
3461
3462   if (element != EL_LEERRAUM)
3463     Store[JX][JY] = element;
3464
3465   if (Dynamite)
3466   {
3467     Feld[JX][JY] = EL_DYNAMIT;
3468     MovDelay[JX][JY] = 96;
3469     Dynamite--;
3470     DrawText(DX_DYNAMITE,DY_DYNAMITE,int2str(Dynamite,3),FS_SMALL,FC_YELLOW);
3471     DrawGraphicThruMask(SCROLLX(JX),SCROLLY(JY),GFX_DYNAMIT);
3472   }
3473   else
3474   {
3475     Feld[JX][JY] = EL_DYNABOMB;
3476     MovDelay[JX][JY] = 96;
3477     DynaBombsLeft--;
3478     DrawGraphicThruMask(SCROLLX(JX),SCROLLY(JY),GFX_DYNABOMB);
3479   }
3480
3481   return(TRUE);
3482 }
3483
3484 void PlaySoundLevel(int x, int y, int sound_nr)
3485 {
3486   int sx = SCROLLX(x), sy = SCROLLY(y);
3487   int volume, stereo;
3488   int silence_distance = 8;
3489
3490   if ((!sound_simple_on && !IS_LOOP_SOUND(sound_nr)) ||
3491       (!sound_loops_on && IS_LOOP_SOUND(sound_nr)))
3492     return;
3493
3494   if (!IN_LEV_FIELD(x,y) ||
3495       sx < -silence_distance || sx >= SCR_FIELDX+silence_distance ||
3496       sy < -silence_distance || sy >= SCR_FIELDY+silence_distance)
3497     return;
3498
3499   volume = PSND_MAX_VOLUME;
3500 #ifndef MSDOS
3501   stereo = (sx-SCR_FIELDX/2)*12;
3502 #else
3503   stereo = PSND_MIDDLE+(2*sx-(SCR_FIELDX-1))*5;
3504   if(stereo > PSND_MAX_RIGHT) stereo = PSND_MAX_RIGHT;
3505   if(stereo < PSND_MAX_LEFT) stereo = PSND_MAX_LEFT;
3506 #endif
3507
3508   if (!IN_SCR_FIELD(sx,sy))
3509   {
3510     int dx = ABS(sx-SCR_FIELDX/2)-SCR_FIELDX/2;
3511     int dy = ABS(sy-SCR_FIELDY/2)-SCR_FIELDY/2;
3512
3513     volume -= volume*(dx > dy ? dx : dy)/silence_distance;
3514   }
3515
3516   PlaySoundExt(sound_nr, volume, stereo, PSND_NO_LOOP);
3517 }
3518
3519 void RaiseScore(int value)
3520 {
3521   Score += value;
3522   DrawText(DX_SCORE,DY_SCORE,int2str(Score,5),FS_SMALL,FC_YELLOW);
3523 }
3524
3525 void RaiseScoreElement(int element)
3526 {
3527   switch(element)
3528   {
3529     case EL_EDELSTEIN:
3530       RaiseScore(level.score[SC_EDELSTEIN]);
3531       break;
3532     case EL_DIAMANT:
3533       RaiseScore(level.score[SC_DIAMANT]);
3534       break;
3535     case EL_KAEFER:
3536     case EL_BUTTERFLY:
3537       RaiseScore(level.score[SC_KAEFER]);
3538       break;
3539     case EL_FLIEGER:
3540     case EL_FIREFLY:
3541       RaiseScore(level.score[SC_FLIEGER]);
3542       break;
3543     case EL_MAMPFER:
3544     case EL_MAMPFER2:
3545       RaiseScore(level.score[SC_MAMPFER]);
3546       break;
3547     case EL_ROBOT:
3548       RaiseScore(level.score[SC_ROBOT]);
3549       break;
3550     case EL_PACMAN:
3551       RaiseScore(level.score[SC_PACMAN]);
3552       break;
3553     case EL_KOKOSNUSS:
3554       RaiseScore(level.score[SC_KOKOSNUSS]);
3555       break;
3556     case EL_DYNAMIT:
3557       RaiseScore(level.score[SC_DYNAMIT]);
3558       break;
3559     case EL_SCHLUESSEL:
3560       RaiseScore(level.score[SC_SCHLUESSEL]);
3561       break;
3562     default:
3563       break;
3564   }
3565 }