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