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