eb64c053d27d23f99731ebf76662efa253c5cfa3
[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         break;
1012       case EL_SCHLUESSEL:
1013       case EL_SCHLUESSEL1:
1014       case EL_SCHLUESSEL2:
1015       case EL_SCHLUESSEL3:
1016       case EL_SCHLUESSEL4:
1017         sound = SND_KINK;
1018         break;
1019       case EL_ZEIT_VOLL:
1020       case EL_ZEIT_LEER:
1021         sound = SND_DENG;
1022         break;
1023       default:
1024         sound = -1;
1025         break;
1026     }
1027
1028     if (sound>=0)
1029       PlaySoundLevel(x,y,sound);
1030   }
1031 }
1032
1033 void TurnRound(int x, int y)
1034 {
1035   static struct
1036   {
1037     int x,y;
1038   } move_xy[] =
1039   {
1040     { 0,0 },
1041     {-1,0 },
1042     {+1,0 },
1043     { 0,0 },
1044     { 0,-1 },
1045     { 0,0 }, { 0,0 }, { 0,0 },
1046     { 0,+1 }
1047   };
1048   static struct
1049   {
1050     int left,right,back;
1051   } turn[] =
1052   {
1053     { 0,        0,              0 },
1054     { MV_DOWN,  MV_UP,          MV_RIGHT },
1055     { MV_UP,    MV_DOWN,        MV_LEFT },
1056     { 0,        0,              0 },
1057     { MV_LEFT,  MV_RIGHT,       MV_DOWN },
1058     { 0,0,0 },  { 0,0,0 },      { 0,0,0 },
1059     { MV_RIGHT, MV_LEFT,        MV_UP }
1060   };
1061
1062   int element = Feld[x][y];
1063   int old_move_dir = MovDir[x][y];
1064   int left_dir = turn[old_move_dir].left;
1065   int right_dir = turn[old_move_dir].right;
1066   int back_dir = turn[old_move_dir].back;
1067
1068   int left_dx = move_xy[left_dir].x, left_dy = move_xy[left_dir].y;
1069   int right_dx = move_xy[right_dir].x, right_dy = move_xy[right_dir].y;
1070   int move_dx = move_xy[old_move_dir].x, move_dy = move_xy[old_move_dir].y;
1071   int back_dx = move_xy[back_dir].x, back_dy = move_xy[back_dir].y;
1072
1073   int left_x = x+left_dx, left_y = y+left_dy;
1074   int right_x = x+right_dx, right_y = y+right_dy;
1075   int move_x = x+move_dx, move_y = y+move_dy;
1076
1077   if (element==EL_KAEFER || element==EL_BUTTERFLY)
1078   {
1079     TestIfBadThingHitsOtherBadThing(x,y);
1080
1081     if (IN_LEV_FIELD(right_x,right_y) &&
1082         IS_FREE_OR_PLAYER(right_x,right_y))
1083       MovDir[x][y] = right_dir;
1084     else if (!IN_LEV_FIELD(move_x,move_y) ||
1085              !IS_FREE_OR_PLAYER(move_x,move_y))
1086       MovDir[x][y] = left_dir;
1087
1088     if (element==EL_KAEFER && MovDir[x][y] != old_move_dir)
1089       MovDelay[x][y] = 5;
1090     else if (element==EL_BUTTERFLY)     /* && MovDir[x][y]==left_dir) */
1091       MovDelay[x][y] = 1;
1092   }
1093   else if (element==EL_FLIEGER || element==EL_FIREFLY)
1094   {
1095     TestIfBadThingHitsOtherBadThing(x,y);
1096
1097     if (IN_LEV_FIELD(left_x,left_y) &&
1098         IS_FREE_OR_PLAYER(left_x,left_y))
1099       MovDir[x][y] = left_dir;
1100     else if (!IN_LEV_FIELD(move_x,move_y) ||
1101              !IS_FREE_OR_PLAYER(move_x,move_y))
1102       MovDir[x][y] = right_dir;
1103
1104     if (element==EL_FLIEGER && MovDir[x][y] != old_move_dir)
1105       MovDelay[x][y] = 5;
1106     else if (element==EL_FIREFLY)       /* && MovDir[x][y]==right_dir) */
1107       MovDelay[x][y] = 1;
1108   }
1109   else if (element==EL_MAMPFER)
1110   {
1111     BOOL can_turn_left = FALSE, can_turn_right = FALSE;
1112
1113     if (IN_LEV_FIELD(left_x,left_y) &&
1114         (IS_FREE_OR_PLAYER(left_x,left_y) ||
1115          Feld[left_x][left_y] == EL_DIAMANT))
1116       can_turn_left = TRUE;
1117     if (IN_LEV_FIELD(right_x,right_y) &&
1118         (IS_FREE_OR_PLAYER(right_x,right_y) ||
1119          Feld[right_x][right_y] == EL_DIAMANT))
1120       can_turn_right = TRUE;
1121
1122     if (can_turn_left && can_turn_right)
1123       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
1124     else if (can_turn_left)
1125       MovDir[x][y] = (RND(2) ? left_dir : back_dir);
1126     else if (can_turn_right)
1127       MovDir[x][y] = (RND(2) ? right_dir : back_dir);
1128     else
1129       MovDir[x][y] = back_dir;
1130
1131     MovDelay[x][y] = 8+8*RND(3);
1132   }
1133   else if (element==EL_MAMPFER2)
1134   {
1135     BOOL can_turn_left = FALSE, can_turn_right = FALSE;
1136
1137     if (IN_LEV_FIELD(left_x,left_y) &&
1138         (IS_FREE_OR_PLAYER(left_x,left_y) ||
1139          IS_MAMPF2(Feld[left_x][left_y])))
1140       can_turn_left = TRUE;
1141     if (IN_LEV_FIELD(right_x,right_y) &&
1142         (IS_FREE_OR_PLAYER(right_x,right_y) ||
1143          IS_MAMPF2(Feld[right_x][right_y])))
1144       can_turn_right = TRUE;
1145
1146     if (can_turn_left && can_turn_right)
1147       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
1148     else if (can_turn_left)
1149       MovDir[x][y] = (RND(2) ? left_dir : back_dir);
1150     else if (can_turn_right)
1151       MovDir[x][y] = (RND(2) ? right_dir : back_dir);
1152     else
1153       MovDir[x][y] = back_dir;
1154
1155     MovDelay[x][y] = 8+8*RND(3);
1156   }
1157   else if (element==EL_PACMAN)
1158   {
1159     BOOL can_turn_left = FALSE, can_turn_right = FALSE;
1160
1161     if (IN_LEV_FIELD(left_x,left_y) &&
1162         (IS_FREE_OR_PLAYER(left_x,left_y) ||
1163          IS_AMOEBOID(Feld[left_x][left_y])))
1164       can_turn_left = TRUE;
1165     if (IN_LEV_FIELD(right_x,right_y) &&
1166         (IS_FREE_OR_PLAYER(right_x,right_y) ||
1167          IS_AMOEBOID(Feld[right_x][right_y])))
1168       can_turn_right = TRUE;
1169
1170     if (can_turn_left && can_turn_right)
1171       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
1172     else if (can_turn_left)
1173       MovDir[x][y] = (RND(2) ? left_dir : back_dir);
1174     else if (can_turn_right)
1175       MovDir[x][y] = (RND(2) ? right_dir : back_dir);
1176     else
1177       MovDir[x][y] = back_dir;
1178
1179     MovDelay[x][y] = 3+RND(20);
1180   }
1181   else if (element==EL_SCHWEIN)
1182   {
1183     BOOL can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE;
1184     BOOL should_turn_left = FALSE, should_turn_right = FALSE;
1185     BOOL should_move_on = FALSE;
1186     int rnd_value = 24;
1187     int rnd = RND(rnd_value);
1188
1189     if (IN_LEV_FIELD(left_x,left_y) &&
1190         (IS_FREE(left_x,left_y) || IS_GEM(Feld[left_x][left_y])))
1191       can_turn_left = TRUE;
1192     if (IN_LEV_FIELD(right_x,right_y) &&
1193         (IS_FREE(right_x,right_y) || IS_GEM(Feld[right_x][right_y])))
1194       can_turn_right = TRUE;
1195     if (IN_LEV_FIELD(move_x,move_y) &&
1196         (IS_FREE(move_x,move_y) || IS_GEM(Feld[move_x][move_y])))
1197       can_move_on = TRUE;
1198
1199     if (can_turn_left &&
1200         (!can_move_on ||
1201          (IN_LEV_FIELD(x+back_dx+left_dx,y+back_dy+left_dy) &&
1202           !IS_FREE(x+back_dx+left_dx,y+back_dy+left_dy))))
1203       should_turn_left = TRUE;
1204     if (can_turn_right &&
1205         (!can_move_on ||
1206          (IN_LEV_FIELD(x+back_dx+right_dx,y+back_dy+right_dy) &&
1207           !IS_FREE(x+back_dx+right_dx,y+back_dy+right_dy))))
1208       should_turn_right = TRUE;
1209     if (can_move_on &&
1210         (!can_turn_left || !can_turn_right ||
1211          (IN_LEV_FIELD(x+move_dx+left_dx,y+move_dy+left_dy) &&
1212           !IS_FREE(x+move_dx+left_dx,y+move_dy+left_dy)) ||
1213          (IN_LEV_FIELD(x+move_dx+right_dx,y+move_dy+right_dy) &&
1214           !IS_FREE(x+move_dx+right_dx,y+move_dy+right_dy))))
1215       should_move_on = TRUE;
1216
1217     if (should_turn_left || should_turn_right || should_move_on)
1218     {
1219       if (should_turn_left && should_turn_right && should_move_on)
1220         MovDir[x][y] = (rnd < rnd_value/3 ? left_dir :
1221                         rnd < 2*rnd_value/3 ? right_dir :
1222                         old_move_dir);
1223       else if (should_turn_left && should_turn_right)
1224         MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
1225       else if (should_turn_left && should_move_on)
1226         MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : old_move_dir);
1227       else if (should_turn_right && should_move_on)
1228         MovDir[x][y] = (rnd < rnd_value/2 ? right_dir : old_move_dir);
1229       else if (should_turn_left)
1230         MovDir[x][y] = left_dir;
1231       else if (should_turn_right)
1232         MovDir[x][y] = right_dir;
1233       else if (should_move_on)
1234         MovDir[x][y] = old_move_dir;
1235     }
1236     else if (can_move_on && rnd > rnd_value/8)
1237       MovDir[x][y] = old_move_dir;
1238     else if (can_turn_left && can_turn_right)
1239       MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
1240     else if (can_turn_left && rnd > rnd_value/8)
1241       MovDir[x][y] = left_dir;
1242     else if (can_turn_right && rnd > rnd_value/8)
1243       MovDir[x][y] = right_dir;
1244     else
1245       MovDir[x][y] = back_dir;
1246
1247     if (!IS_FREE(x+move_xy[MovDir[x][y]].x,y+move_xy[MovDir[x][y]].y) &&
1248         !IS_GEM(Feld[x+move_xy[MovDir[x][y]].x][y+move_xy[MovDir[x][y]].y]))
1249       MovDir[x][y] = old_move_dir;
1250
1251     MovDelay[x][y] = 0;
1252   }
1253   else if (element==EL_DRACHE)
1254   {
1255     BOOL can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE;
1256     int rnd_value = 24;
1257     int rnd = RND(rnd_value);
1258
1259     if (IN_LEV_FIELD(left_x,left_y) && IS_FREE(left_x,left_y))
1260       can_turn_left = TRUE;
1261     if (IN_LEV_FIELD(right_x,right_y) && IS_FREE(right_x,right_y))
1262       can_turn_right = TRUE;
1263     if (IN_LEV_FIELD(move_x,move_y) && IS_FREE(move_x,move_y))
1264       can_move_on = TRUE;
1265
1266     if (can_move_on && rnd > rnd_value/8)
1267       MovDir[x][y] = old_move_dir;
1268     else if (can_turn_left && can_turn_right)
1269       MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
1270     else if (can_turn_left && rnd > rnd_value/8)
1271       MovDir[x][y] = left_dir;
1272     else if (can_turn_right && rnd > rnd_value/8)
1273       MovDir[x][y] = right_dir;
1274     else
1275       MovDir[x][y] = back_dir;
1276
1277     if (!IS_FREE(x+move_xy[MovDir[x][y]].x,y+move_xy[MovDir[x][y]].y))
1278       MovDir[x][y] = old_move_dir;
1279
1280     MovDelay[x][y] = 0;
1281   }
1282   else if (element==EL_ROBOT || element==EL_SONDE ||
1283            element==EL_MAULWURF || element==EL_PINGUIN)
1284   {
1285     int attr_x = JX, attr_y = JY;
1286     int newx, newy;
1287
1288     if (PlayerGone)
1289     {
1290       attr_x = ExitX;
1291       attr_y = ExitY;
1292     }
1293
1294     if (element==EL_ROBOT && ZX>=0 && ZY>=0)
1295     {
1296       attr_x = ZX;
1297       attr_y = ZY;
1298     }
1299
1300     if (element==EL_MAULWURF || element==EL_PINGUIN)
1301     {
1302       int i;
1303       static int xy[4][2] =
1304       {
1305         { 0,-1 },
1306         { -1,0 },
1307         { +1,0 },
1308         { 0,+1 }
1309       };
1310
1311       for(i=0;i<4;i++)
1312       {
1313         int ex = x+xy[i%4][0];
1314         int ey = y+xy[i%4][1];
1315
1316         if (IN_LEV_FIELD(ex,ey) && Feld[ex][ey] == EL_AUSGANG_AUF)
1317         {
1318           attr_x = ex;
1319           attr_y = ey;
1320           break;
1321         }
1322       }
1323     }
1324
1325     MovDir[x][y] = MV_NO_MOVING;
1326     if (attr_x<x)
1327       MovDir[x][y] |= (GameOver ? MV_RIGHT : MV_LEFT);
1328     else if (attr_x>x)
1329       MovDir[x][y] |= (GameOver ? MV_LEFT : MV_RIGHT);
1330     if (attr_y<y)
1331       MovDir[x][y] |= (GameOver ? MV_DOWN : MV_UP);
1332     else if (attr_y>y)
1333       MovDir[x][y] |= (GameOver ? MV_UP : MV_DOWN);
1334
1335     if (element==EL_ROBOT)
1336     {
1337       if ((MovDir[x][y]&(MV_LEFT|MV_RIGHT)) && (MovDir[x][y]&(MV_UP|MV_DOWN)))
1338         MovDir[x][y] &= (RND(2) ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
1339       Moving2Blocked(x,y,&newx,&newy);
1340
1341       if (IN_LEV_FIELD(newx,newy) && IS_FREE_OR_PLAYER(newx,newy))
1342         MovDelay[x][y] = 4+4*!RND(3);
1343       else
1344         MovDelay[x][y] = 8;
1345     }
1346     else
1347     {
1348       MovDelay[x][y] = 1;
1349
1350       if ((MovDir[x][y]&(MV_LEFT|MV_RIGHT)) && (MovDir[x][y]&(MV_UP|MV_DOWN)))
1351       {
1352         BOOL first_horiz = RND(2);
1353         int new_move_dir = MovDir[x][y];
1354
1355         MovDir[x][y] =
1356           new_move_dir & (first_horiz ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
1357         Moving2Blocked(x,y,&newx,&newy);
1358
1359         if (IN_LEV_FIELD(newx,newy) &&
1360             (IS_FREE(newx,newy) ||
1361              Feld[newx][newy] == EL_SALZSAEURE ||
1362              ((element == EL_MAULWURF || element==EL_PINGUIN) &&
1363               (Feld[newx][newy] == EL_AUSGANG_AUF ||
1364                IS_MAMPF3(Feld[newx][newy])))))
1365           return;
1366
1367         MovDir[x][y] =
1368           new_move_dir & (!first_horiz ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
1369         Moving2Blocked(x,y,&newx,&newy);
1370
1371         if (IN_LEV_FIELD(newx,newy) &&
1372             (IS_FREE(newx,newy) ||
1373              Feld[newx][newy] == EL_SALZSAEURE ||
1374              ((element == EL_MAULWURF || element==EL_PINGUIN) &&
1375               (Feld[newx][newy] == EL_AUSGANG_AUF ||
1376                IS_MAMPF3(Feld[newx][newy])))))
1377           return;
1378
1379         MovDir[x][y] = old_move_dir;
1380         return;
1381       }
1382     }
1383   }
1384 }
1385
1386 void StartMoving(int x, int y)
1387 {
1388   int element = Feld[x][y];
1389
1390   if (Stop[x][y])
1391     return;
1392
1393   if (CAN_FALL(element) && y<lev_fieldy-1)
1394   {
1395     if (PlayerPushing && PlayerMovPos)
1396     {
1397       int nextJX = JX + (JX - lastJX);
1398       int nextJY = JY + (JY - lastJY);
1399
1400       if (x == nextJX && y == nextJY)
1401         return;
1402     }
1403
1404     if (element==EL_MORAST_VOLL)
1405     {
1406       if (IS_FREE(x,y+1))
1407       {
1408         InitMovingField(x,y,MV_DOWN);
1409         Feld[x][y] = EL_FELSBROCKEN;
1410         Store[x][y] = EL_MORAST_LEER;
1411       }
1412       else if (Feld[x][y+1]==EL_MORAST_LEER)
1413       {
1414         if (!MovDelay[x][y])
1415           MovDelay[x][y] = 16;
1416
1417         if (MovDelay[x][y])
1418         {
1419           MovDelay[x][y]--;
1420           if (MovDelay[x][y])
1421             return;
1422         }
1423
1424         Feld[x][y] = EL_MORAST_LEER;
1425         Feld[x][y+1] = EL_MORAST_VOLL;
1426       }
1427     }
1428     else if (element==EL_FELSBROCKEN && Feld[x][y+1]==EL_MORAST_LEER)
1429     {
1430       InitMovingField(x,y,MV_DOWN);
1431       Store[x][y] = EL_MORAST_VOLL;
1432     }
1433     else if (element==EL_SIEB_VOLL)
1434     {
1435       if (IS_FREE(x,y+1))
1436       {
1437         InitMovingField(x,y,MV_DOWN);
1438         Feld[x][y] = EL_CHANGED(Store2[x][y]);
1439         Store[x][y] = EL_SIEB_LEER;
1440       }
1441       else if (Feld[x][y+1]==EL_SIEB_LEER)
1442       {
1443         if (!MovDelay[x][y])
1444           MovDelay[x][y] = 2;
1445
1446         if (MovDelay[x][y])
1447         {
1448           MovDelay[x][y]--;
1449           if (MovDelay[x][y])
1450             return;
1451         }
1452
1453         Feld[x][y] = EL_SIEB_LEER;
1454         Feld[x][y+1] = EL_SIEB_VOLL;
1455         Store2[x][y+1] = EL_CHANGED(Store2[x][y]);
1456         Store2[x][y] = 0;
1457       }
1458     }
1459     else if (element==EL_SIEB2_VOLL)
1460     {
1461       if (IS_FREE(x,y+1))
1462       {
1463         InitMovingField(x,y,MV_DOWN);
1464         Feld[x][y] = EL_CHANGED2(Store2[x][y]);
1465         Store[x][y] = EL_SIEB2_LEER;
1466       }
1467       else if (Feld[x][y+1]==EL_SIEB2_LEER)
1468       {
1469         if (!MovDelay[x][y])
1470           MovDelay[x][y] = 2;
1471
1472         if (MovDelay[x][y])
1473         {
1474           MovDelay[x][y]--;
1475           if (MovDelay[x][y])
1476             return;
1477         }
1478
1479         Feld[x][y] = EL_SIEB2_LEER;
1480         Feld[x][y+1] = EL_SIEB2_VOLL;
1481         Store2[x][y+1] = EL_CHANGED2(Store2[x][y]);
1482         Store2[x][y] = 0;
1483       }
1484     }
1485     else if (SiebAktiv && CAN_CHANGE(element) &&
1486              (Feld[x][y+1]==EL_SIEB_LEER || Feld[x][y+1]==EL_SIEB2_LEER))
1487     {
1488       InitMovingField(x,y,MV_DOWN);
1489       Store[x][y] =
1490         (Feld[x][y+1]==EL_SIEB_LEER ? EL_SIEB_VOLL : EL_SIEB2_VOLL);
1491       Store2[x][y+1] = element;
1492     }
1493     else if (CAN_SMASH(element) && Feld[x][y+1]==EL_SALZSAEURE)
1494     {
1495       Blurb(x,y);
1496       InitMovingField(x,y,MV_DOWN);
1497       Store[x][y] = EL_SALZSAEURE;
1498     }
1499     else if (CAN_SMASH(element) && Feld[x][y+1]==EL_BLOCKED && JustHit[x][y])
1500     {
1501       Impact(x,y);
1502     }
1503     else if (IS_FREE(x,y+1))
1504     {
1505       InitMovingField(x,y,MV_DOWN);
1506     }
1507     else if (element==EL_TROPFEN)
1508     {
1509       Feld[x][y] = EL_AMOEBING;
1510       Store[x][y] = EL_AMOEBE_NASS;
1511     }
1512     else if (IS_SLIPPERY(Feld[x][y+1]) && !Store[x][y+1])
1513     {
1514       BOOL left  = (x>0 && IS_FREE(x-1,y) &&
1515                     (IS_FREE(x-1,y+1) || Feld[x-1][y+1]==EL_SALZSAEURE));
1516       BOOL right = (x<lev_fieldx-1 && IS_FREE(x+1,y) &&
1517                     (IS_FREE(x+1,y+1) || Feld[x+1][y+1]==EL_SALZSAEURE));
1518
1519       if (left || right)
1520       {
1521         if (left && right && game_emulation != EMU_BOULDERDASH)
1522           left = !(right = RND(2));
1523
1524         InitMovingField(x,y,left ? MV_LEFT : MV_RIGHT);
1525       }
1526     }
1527   }
1528   else if (CAN_MOVE(element))
1529   {
1530     int newx,newy;
1531
1532     if (!MovDelay[x][y])        /* neuer Schritt / noch nicht gewartet */
1533     {
1534       /* Alle Figuren, die nach jeden Schritt die Richtung wechseln können.
1535        * (MAMPFER, MAMPFER2 und PACMAN laufen bis zur nächsten Wand.)
1536        */
1537
1538       if (element!=EL_MAMPFER && element!=EL_MAMPFER2 && element!=EL_PACMAN)
1539       {
1540         TurnRound(x,y);
1541         if (MovDelay[x][y] && (element == EL_KAEFER || element == EL_FLIEGER))
1542           DrawLevelField(x,y);
1543       }
1544     }
1545
1546     if (MovDelay[x][y])         /* neuer Schritt / in Wartezustand */
1547     {
1548       MovDelay[x][y]--;
1549
1550       if (element==EL_ROBOT || element==EL_MAMPFER || element==EL_MAMPFER2)
1551       {
1552         int phase = MovDelay[x][y] % 8;
1553
1554         if (phase>3)
1555           phase = 7-phase;
1556
1557         if (IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
1558           DrawGraphic(SCROLLX(x),SCROLLY(y), el2gfx(element)+phase);
1559
1560         if ((element==EL_MAMPFER || element==EL_MAMPFER2)
1561             && MovDelay[x][y]%4==3)
1562           PlaySoundLevel(x,y,SND_NJAM);
1563       }
1564       else if (element==EL_DRACHE)
1565       {
1566         int i;
1567         int dir = MovDir[x][y];
1568         int dx = (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1569         int dy = (dir == MV_UP   ? -1 : dir == MV_DOWN  ? +1 : 0);
1570         int graphic = (dir == MV_LEFT   ? GFX_FLAMMEN_LEFT :
1571                        dir == MV_RIGHT  ? GFX_FLAMMEN_RIGHT :
1572                        dir == MV_UP     ? GFX_FLAMMEN_UP :
1573                        dir == MV_DOWN   ? GFX_FLAMMEN_DOWN : GFX_LEERRAUM);
1574         int phase = FrameCounter % 2;
1575
1576         for(i=1;i<=3;i++)
1577         {
1578           int xx = x + i*dx, yy = y + i*dy;
1579           int sx = SCROLLX(xx), sy = SCROLLY(yy);
1580
1581           if (!IN_LEV_FIELD(xx,yy) ||
1582               IS_SOLID(Feld[xx][yy]) || Feld[xx][yy]==EL_EXPLODING)
1583             break;
1584
1585           if (MovDelay[x][y])
1586           {
1587             int flamed = MovingOrBlocked2Element(xx,yy);
1588
1589             if (IS_ENEMY(flamed) || IS_EXPLOSIVE(flamed))
1590               Bang(xx,yy);
1591             else
1592               RemoveMovingField(xx,yy);
1593
1594             Feld[xx][yy] = EL_BURNING;
1595             if (IN_SCR_FIELD(sx,sy))
1596               DrawGraphic(sx,sy, graphic + phase*3 + i-1);
1597           }
1598           else
1599           {
1600             if (Feld[xx][yy] == EL_BURNING)
1601               Feld[xx][yy] = EL_LEERRAUM;
1602             DrawLevelField(xx,yy);
1603           }
1604         }
1605       }
1606
1607       if (MovDelay[x][y])
1608         return;
1609     }
1610
1611     if (element==EL_KAEFER || element==EL_BUTTERFLY)
1612     {
1613       PlaySoundLevel(x,y,SND_KLAPPER);
1614     }
1615     else if (element==EL_FLIEGER || element==EL_FIREFLY)
1616     {
1617       PlaySoundLevel(x,y,SND_ROEHR);
1618     }
1619
1620     /* neuer Schritt / Wartezustand beendet */
1621
1622     Moving2Blocked(x,y,&newx,&newy);    /* wohin soll's gehen? */
1623
1624     if (IS_ENEMY(element) && IS_PLAYER(newx,newy))
1625     {
1626       /* Spieler erwischt */
1627       MovDir[x][y] = 0;
1628       KillHero();
1629       return;
1630     }
1631     else if ((element == EL_MAULWURF || element == EL_PINGUIN ||
1632               element==EL_ROBOT || element==EL_SONDE) &&
1633              IN_LEV_FIELD(newx,newy) &&
1634              MovDir[x][y]==MV_DOWN && Feld[newx][newy]==EL_SALZSAEURE)
1635     {
1636       Blurb(x,y);
1637       Store[x][y] = EL_SALZSAEURE;
1638     }
1639     else if ((element == EL_MAULWURF || element == EL_PINGUIN) &&
1640              IN_LEV_FIELD(newx,newy))
1641     {
1642       if (Feld[newx][newy] == EL_AUSGANG_AUF)
1643       {
1644         Feld[x][y] = EL_LEERRAUM;
1645         DrawLevelField(x,y);
1646
1647         PlaySoundLevel(newx,newy,SND_BUING);
1648         if (IN_SCR_FIELD(SCROLLX(newx),SCROLLY(newy)))
1649           DrawGraphicThruMask(SCROLLX(newx),SCROLLY(newy),el2gfx(element));
1650
1651         Friends--;
1652         if (!Friends && PlayerGone && !GameOver)
1653           LevelSolved = GameOver = TRUE;
1654
1655         return;
1656       }
1657       else if (IS_MAMPF3(Feld[newx][newy]))
1658       {
1659         if (DigField(newx,newy, 0,0, DF_DIG) == MF_MOVING)
1660           DrawLevelField(newx,newy);
1661         else
1662           MovDir[x][y] = MV_NO_MOVING;
1663       }
1664       else if (!IS_FREE(newx,newy))
1665       {
1666         if (IS_PLAYER(x,y))
1667           DrawPlayerField();
1668         else
1669           DrawLevelField(x,y);
1670         return;
1671       }
1672     }
1673     else if (element == EL_SCHWEIN && IN_LEV_FIELD(newx,newy))
1674     {
1675       if (IS_GEM(Feld[newx][newy]))
1676       {
1677         if (IS_MOVING(newx,newy))
1678           RemoveMovingField(newx,newy);
1679         else
1680         {
1681           Feld[newx][newy] = EL_LEERRAUM;
1682           DrawLevelField(newx,newy);
1683         }
1684       }
1685       else if (!IS_FREE(newx,newy))
1686       {
1687         if (IS_PLAYER(x,y))
1688           DrawPlayerField();
1689         else
1690           DrawLevelField(x,y);
1691         return;
1692       }
1693     }
1694     else if (element==EL_DRACHE && IN_LEV_FIELD(newx,newy))
1695     {
1696       if (!IS_FREE(newx,newy))
1697       {
1698         if (IS_PLAYER(x,y))
1699           DrawPlayerField();
1700         else
1701           DrawLevelField(x,y);
1702         return;
1703       }
1704       else
1705       {
1706         BOOL wanna_flame = !RND(10);
1707         int dx = newx - x, dy = newy - y;
1708         int newx1 = newx+1*dx, newy1 = newy+1*dy;
1709         int newx2 = newx+2*dx, newy2 = newy+2*dy;
1710         int element1 = (IN_LEV_FIELD(newx1,newy1) ?
1711                         MovingOrBlocked2Element(newx1,newy1) : EL_BETON);
1712         int element2 = (IN_LEV_FIELD(newx2,newy2) ?
1713                         MovingOrBlocked2Element(newx2,newy2) : EL_BETON);
1714
1715         if ((wanna_flame || IS_ENEMY(element1) || IS_ENEMY(element2)) &&
1716             element1 != EL_DRACHE && element2 != EL_DRACHE &&
1717             element1 != EL_BURNING && element2 != EL_BURNING)
1718         {
1719           if (IS_PLAYER(x,y))
1720             DrawPlayerField();
1721           else
1722             DrawLevelField(x,y);
1723
1724           MovDelay[x][y] = 25;
1725           Feld[newx][newy] = EL_BURNING;
1726           if (IN_LEV_FIELD(newx1,newy1) && Feld[newx1][newy1] == EL_LEERRAUM)
1727             Feld[newx1][newy1] = EL_BURNING;
1728           if (IN_LEV_FIELD(newx2,newy2) && Feld[newx2][newy2] == EL_LEERRAUM)
1729             Feld[newx2][newy2] = EL_BURNING;
1730           return;
1731         }
1732       }
1733     }
1734     else if (element==EL_MAMPFER && IN_LEV_FIELD(newx,newy) &&
1735              Feld[newx][newy]==EL_DIAMANT)
1736     {
1737       if (IS_MOVING(newx,newy))
1738         RemoveMovingField(newx,newy);
1739       else
1740       {
1741         Feld[newx][newy] = EL_LEERRAUM;
1742         DrawLevelField(newx,newy);
1743       }
1744     }
1745     else if (element==EL_MAMPFER2 && IN_LEV_FIELD(newx,newy) &&
1746              IS_MAMPF2(Feld[newx][newy]))
1747     {
1748       if (AmoebaNr[newx][newy])
1749       {
1750         AmoebaCnt2[AmoebaNr[newx][newy]]--;
1751         if (Feld[newx][newy]==EL_AMOEBE_VOLL || Feld[newx][newy]==EL_AMOEBE_BD)
1752           AmoebaCnt[AmoebaNr[newx][newy]]--;
1753       }
1754
1755       if (IS_MOVING(newx,newy))
1756         RemoveMovingField(newx,newy);
1757       else
1758       {
1759         Feld[newx][newy] = EL_LEERRAUM;
1760         DrawLevelField(newx,newy);
1761       }
1762     }
1763     else if (element==EL_PACMAN && IN_LEV_FIELD(newx,newy) &&
1764              IS_AMOEBOID(Feld[newx][newy]))
1765     {
1766       if (AmoebaNr[newx][newy])
1767       {
1768         AmoebaCnt2[AmoebaNr[newx][newy]]--;
1769         if (Feld[newx][newy]==EL_AMOEBE_VOLL || Feld[newx][newy]==EL_AMOEBE_BD)
1770           AmoebaCnt[AmoebaNr[newx][newy]]--;
1771       }
1772
1773       Feld[newx][newy] = EL_LEERRAUM;
1774       DrawLevelField(newx,newy);
1775     }
1776     else if (!IN_LEV_FIELD(newx,newy) || !IS_FREE(newx,newy))
1777     {                                   /* gegen Wand gelaufen */
1778       TurnRound(x,y);
1779
1780       if (element == EL_KAEFER || element == EL_FLIEGER)
1781         DrawLevelField(x,y);
1782       else if (element == EL_BUTTERFLY || element == EL_FIREFLY)
1783         DrawGraphicAnimation(x,y, el2gfx(element), 2, 2, ANIM_NORMAL);
1784       else if (element==EL_SONDE)
1785         DrawGraphicAnimation(x,y, GFX_SONDE_START, 8, 1, ANIM_NORMAL);
1786
1787       return;
1788     }
1789
1790     if (element==EL_ROBOT && IN_SCR_FIELD(x,y))
1791       PlaySoundLevel(x,y,SND_SCHLURF);
1792
1793     InitMovingField(x,y,MovDir[x][y]);
1794   }
1795
1796   if (MovDir[x][y])
1797     ContinueMoving(x,y);
1798 }
1799
1800 void ContinueMoving(int x, int y)
1801 {
1802   int element = Feld[x][y];
1803   int direction = MovDir[x][y];
1804   int dx = (direction==MV_LEFT ? -1 : direction==MV_RIGHT ? +1 : 0);
1805   int dy = (direction==MV_UP   ? -1 : direction==MV_DOWN  ? +1 : 0);
1806   int horiz_move = (dx!=0);
1807   int newx = x + dx, newy = y + dy;
1808   int step = (horiz_move ? dx : dy)*TILEX/4;
1809
1810   if (CAN_FALL(element) && horiz_move)
1811     step*=2;
1812   else if (element==EL_TROPFEN)
1813     step/=2;
1814   else if (Store[x][y]==EL_MORAST_VOLL || Store[x][y]==EL_MORAST_LEER)
1815     step/=4;
1816
1817   MovPos[x][y] += step;
1818
1819   if (ABS(MovPos[x][y])>=TILEX)         /* Zielfeld erreicht */
1820   {
1821     Feld[x][y] = EL_LEERRAUM;
1822     Feld[newx][newy] = element;
1823
1824     if (Store[x][y]==EL_MORAST_VOLL)
1825     {
1826       Store[x][y] = 0;
1827       Feld[newx][newy] = EL_MORAST_VOLL;
1828       element = EL_MORAST_VOLL;
1829     }
1830     else if (Store[x][y]==EL_MORAST_LEER)
1831     {
1832       Store[x][y] = 0;
1833       Feld[x][y] = EL_MORAST_LEER;
1834     }
1835     else if (Store[x][y]==EL_SIEB_VOLL)
1836     {
1837       Store[x][y] = 0;
1838       element = Feld[newx][newy] = (SiebAktiv ? EL_SIEB_VOLL : EL_SIEB_TOT);
1839     }
1840     else if (Store[x][y]==EL_SIEB_LEER)
1841     {
1842       Store[x][y] = Store2[x][y] = 0;
1843       Feld[x][y] = (SiebAktiv ? EL_SIEB_LEER : EL_SIEB_TOT);
1844     }
1845     else if (Store[x][y]==EL_SIEB2_VOLL)
1846     {
1847       Store[x][y] = 0;
1848       element = Feld[newx][newy] = (SiebAktiv ? EL_SIEB2_VOLL : EL_SIEB2_TOT);
1849     }
1850     else if (Store[x][y]==EL_SIEB2_LEER)
1851     {
1852       Store[x][y] = Store2[x][y] = 0;
1853       Feld[x][y] = (SiebAktiv ? EL_SIEB2_LEER : EL_SIEB2_TOT);
1854     }
1855     else if (Store[x][y]==EL_SALZSAEURE)
1856     {
1857       Store[x][y] = 0;
1858       Feld[newx][newy] = EL_SALZSAEURE;
1859       element = EL_SALZSAEURE;
1860     }
1861     else if (Store[x][y]==EL_AMOEBE_NASS)
1862     {
1863       Store[x][y] = 0;
1864       Feld[x][y] = EL_AMOEBE_NASS;
1865     }
1866
1867     MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
1868     MovDelay[newx][newy] = 0;
1869
1870     if (!CAN_MOVE(element))
1871       MovDir[newx][newy] = 0;
1872
1873     DrawLevelField(x,y);
1874     DrawLevelField(newx,newy);
1875
1876     Stop[newx][newy] = TRUE;
1877     JustHit[x][newy] = 3;
1878
1879     if (DONT_TOUCH(element))    /* Käfer oder Flieger */
1880     {
1881       TestIfBadThingHitsHero();
1882       TestIfBadThingHitsFriend(newx,newy);
1883       TestIfBadThingHitsOtherBadThing(newx,newy);
1884     }
1885     else if (element == EL_PINGUIN)
1886       TestIfFriendHitsBadThing(newx,newy);
1887
1888     if (CAN_SMASH(element) && direction==MV_DOWN &&
1889         (newy==lev_fieldy-1 || !IS_FREE(x,newy+1)))
1890       Impact(x,newy);
1891   }
1892   else                          /* noch in Bewegung */
1893     DrawLevelField(x,y);
1894 }
1895
1896 int AmoebeNachbarNr(int ax, int ay)
1897 {
1898   int i;
1899   int element = Feld[ax][ay];
1900   int group_nr = 0;
1901   static int xy[4][2] =
1902   {
1903     { 0,-1 },
1904     { -1,0 },
1905     { +1,0 },
1906     { 0,+1 }
1907   };
1908
1909   for(i=0;i<4;i++)
1910   {
1911     int x = ax+xy[i%4][0];
1912     int y = ay+xy[i%4][1];
1913
1914     if (!IN_LEV_FIELD(x,y))
1915       continue;
1916
1917     if (Feld[x][y]==element && AmoebaNr[x][y]>0)
1918       group_nr = AmoebaNr[x][y];
1919   }
1920
1921   return(group_nr);
1922 }
1923
1924 void AmoebenVereinigen(int ax, int ay)
1925 {
1926   int i,x,y,xx,yy;
1927   int new_group_nr = AmoebaNr[ax][ay];
1928   static int xy[4][2] =
1929   {
1930     { 0,-1 },
1931     { -1,0 },
1932     { +1,0 },
1933     { 0,+1 }
1934   };
1935
1936   if (!new_group_nr)
1937     return;
1938
1939   for(i=0;i<4;i++)
1940   {
1941     x = ax+xy[i%4][0];
1942     y = ay+xy[i%4][1];
1943
1944     if (!IN_LEV_FIELD(x,y))
1945       continue;
1946
1947     if ((Feld[x][y]==EL_AMOEBE_VOLL ||
1948          Feld[x][y]==EL_AMOEBE_BD ||
1949          Feld[x][y]==EL_AMOEBE_TOT) &&
1950         AmoebaNr[x][y] != new_group_nr)
1951     {
1952       int old_group_nr = AmoebaNr[x][y];
1953
1954       AmoebaCnt[new_group_nr] += AmoebaCnt[old_group_nr];
1955       AmoebaCnt[old_group_nr] = 0;
1956       AmoebaCnt2[new_group_nr] += AmoebaCnt2[old_group_nr];
1957       AmoebaCnt2[old_group_nr] = 0;
1958
1959       for(yy=0;yy<lev_fieldy;yy++) for(xx=0;xx<lev_fieldx;xx++)
1960         if (AmoebaNr[xx][yy]==old_group_nr)
1961           AmoebaNr[xx][yy] = new_group_nr;
1962     }
1963   }
1964 }
1965
1966 void AmoebeUmwandeln(int ax, int ay)
1967 {
1968   int i,x,y;
1969   int group_nr = AmoebaNr[ax][ay];
1970   static int xy[4][2] =
1971   {
1972     { 0,-1 },
1973     { -1,0 },
1974     { +1,0 },
1975     { 0,+1 }
1976   };
1977
1978   if (Feld[ax][ay]==EL_AMOEBE_TOT)
1979   {
1980     for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
1981     {
1982       if (Feld[x][y]==EL_AMOEBE_TOT && AmoebaNr[x][y]==group_nr)
1983       {
1984         AmoebaNr[x][y] = 0;
1985         Feld[x][y] = EL_AMOEBA2DIAM;
1986       }
1987     }
1988     Bang(ax,ay);
1989   }
1990   else
1991   {
1992     for(i=0;i<4;i++)
1993     {
1994       x = ax+xy[i%4][0];
1995       y = ay+xy[i%4][1];
1996
1997       if (!IN_LEV_FIELD(x,y))
1998         continue;
1999
2000       if (Feld[x][y]==EL_AMOEBA2DIAM)
2001         Bang(x,y);
2002     }
2003   }
2004 }
2005
2006 void AmoebeUmwandeln2(int ax, int ay, int new_element)
2007 {
2008   int x,y;
2009   int group_nr = AmoebaNr[ax][ay];
2010   BOOL done = FALSE;
2011
2012   for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
2013   {
2014     if (AmoebaNr[x][y]==group_nr &&
2015         (Feld[x][y]==EL_AMOEBE_TOT ||
2016          Feld[x][y]==EL_AMOEBE_BD ||
2017          Feld[x][y]==EL_AMOEBING))
2018     {
2019       AmoebaNr[x][y] = 0;
2020       Feld[x][y] = new_element;
2021       DrawLevelField(x,y);
2022       done = TRUE;
2023     }
2024   }
2025
2026   if (done)
2027     PlaySoundLevel(ax,ay,new_element==EL_FELSBROCKEN ? SND_KLOPF : SND_PLING);
2028 }
2029
2030 void AmoebeWaechst(int x, int y)
2031 {
2032   static long sound_delay = 0;
2033   static int sound_delay_value = 0;
2034
2035   if (!MovDelay[x][y])          /* neue Phase / noch nicht gewartet */
2036   {
2037     MovDelay[x][y] = 4;
2038
2039     if (DelayReached(&sound_delay,sound_delay_value))
2040     {
2041       PlaySoundLevel(x,y,SND_AMOEBE);
2042       sound_delay_value = 30;
2043     }
2044   }
2045
2046   if (MovDelay[x][y])           /* neue Phase / in Wartezustand */
2047   {
2048     MovDelay[x][y]--;
2049     if (MovDelay[x][y] && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
2050       DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_AMOEBING+3-MovDelay[x][y]);
2051
2052     if (!MovDelay[x][y])
2053     {
2054       Feld[x][y] = Store[x][y];
2055       Store[x][y] = 0;
2056       DrawLevelField(x,y);
2057     }
2058   }
2059 }
2060
2061 void AmoebeAbleger(int ax, int ay)
2062 {
2063   int i;
2064   int element = Feld[ax][ay];
2065   int newax = ax, neway = ay;
2066   static int xy[4][2] =
2067   {
2068     { 0,-1 },
2069     { -1,0 },
2070     { +1,0 },
2071     { 0,+1 }
2072   };
2073
2074   if (!level.tempo_amoebe)
2075   {
2076     Feld[ax][ay] = EL_AMOEBE_TOT;
2077     DrawLevelField(ax,ay);
2078     return;
2079   }
2080
2081   if (!MovDelay[ax][ay])        /* neue Amoebe / noch nicht gewartet */
2082     MovDelay[ax][ay] = RND(FRAMES_PER_SECOND * 25/(1+level.tempo_amoebe));
2083
2084   if (MovDelay[ax][ay])         /* neue Amoebe / in Wartezustand */
2085   {
2086     MovDelay[ax][ay]--;
2087     if (MovDelay[ax][ay])
2088       return;
2089   }
2090
2091   if (element==EL_AMOEBE_NASS)  /* tropfende Amöbe */
2092   {
2093     int start = RND(4);
2094     int x = ax+xy[start][0];
2095     int y = ay+xy[start][1];
2096
2097     if (!IN_LEV_FIELD(x,y))
2098       return;
2099
2100     if (IS_FREE(x,y) ||
2101         Feld[x][y]==EL_ERDREICH || Feld[x][y]==EL_MORAST_LEER)
2102     {
2103       newax = x;
2104       neway = y;
2105     }
2106
2107     if (newax==ax && neway==ay)
2108       return;
2109   }
2110   else                          /* normale oder "gefüllte" Amöbe */
2111   {
2112     int start = RND(4);
2113     BOOL waiting_for_player = FALSE;
2114
2115     for(i=0;i<4;i++)
2116     {
2117       int j = (start+i)%4;
2118       int x = ax+xy[j][0];
2119       int y = ay+xy[j][1];
2120
2121       if (!IN_LEV_FIELD(x,y))
2122         continue;
2123
2124       if (IS_FREE(x,y) ||
2125           Feld[x][y]==EL_ERDREICH || Feld[x][y]==EL_MORAST_LEER)
2126       {
2127         newax = x;
2128         neway = y;
2129         break;
2130       }
2131       else if (IS_PLAYER(x,y))
2132         waiting_for_player = TRUE;
2133     }
2134
2135     if (newax==ax && neway==ay)
2136     {
2137       if (i==4 && !waiting_for_player)
2138       {
2139         Feld[ax][ay] = EL_AMOEBE_TOT;
2140         DrawLevelField(ax,ay);
2141         AmoebaCnt[AmoebaNr[ax][ay]]--;
2142
2143         if (AmoebaCnt[AmoebaNr[ax][ay]]<=0)     /* Amöbe vollständig tot */
2144         {
2145           if (element==EL_AMOEBE_VOLL)
2146             AmoebeUmwandeln(ax,ay);
2147           else if (element==EL_AMOEBE_BD)
2148             AmoebeUmwandeln2(ax,ay,level.amoebe_inhalt);
2149         }
2150       }
2151       return;
2152     }
2153     else if (element==EL_AMOEBE_VOLL || element==EL_AMOEBE_BD)
2154     {
2155       int new_group_nr = AmoebaNr[ax][ay];
2156
2157       AmoebaNr[newax][neway] = new_group_nr;
2158       AmoebaCnt[new_group_nr]++;
2159       AmoebaCnt2[new_group_nr]++;
2160       AmoebenVereinigen(newax,neway);
2161
2162       if (AmoebaCnt2[new_group_nr] >= 200 && element==EL_AMOEBE_BD)
2163       {
2164         AmoebeUmwandeln2(newax,neway,EL_FELSBROCKEN);
2165         return;
2166       }
2167     }
2168   }
2169
2170   if (element!=EL_AMOEBE_NASS || neway<ay || !IS_FREE(newax,neway) ||
2171       (neway==lev_fieldy-1 && newax!=ax))
2172   {
2173     Feld[newax][neway] = EL_AMOEBING;
2174     Store[newax][neway] = element;
2175   }
2176   else if (neway==ay)
2177     Feld[newax][neway] = EL_TROPFEN;
2178   else
2179   {
2180     InitMovingField(ax,ay,MV_DOWN);
2181     Feld[ax][ay] = EL_TROPFEN;
2182     Store[ax][ay] = EL_AMOEBE_NASS;
2183     ContinueMoving(ax,ay);
2184     return;
2185   }
2186
2187   DrawLevelField(newax,neway);
2188 }
2189
2190 void Life(int ax, int ay)
2191 {
2192   int x1,y1,x2,y2;
2193   static int life[4] = { 2,3,3,3 };     /* "Life"-Parameter */
2194   int life_time = 20;
2195   int element = Feld[ax][ay];
2196
2197   if (Stop[ax][ay])
2198     return;
2199
2200   if (!MovDelay[ax][ay])        /* neue Phase / noch nicht gewartet */
2201     MovDelay[ax][ay] = life_time;
2202
2203   if (MovDelay[ax][ay])         /* neue Phase / in Wartezustand */
2204   {
2205     MovDelay[ax][ay]--;
2206     if (MovDelay[ax][ay])
2207       return;
2208   }
2209
2210   for(y1=-1;y1<2;y1++) for(x1=-1;x1<2;x1++)
2211   {
2212     int xx = ax+x1, yy = ay+y1;
2213     int nachbarn = 0;
2214
2215     if (!IN_LEV_FIELD(xx,yy))
2216       continue;
2217
2218     for(y2=-1;y2<2;y2++) for(x2=-1;x2<2;x2++)
2219     {
2220       int x = xx+x2, y = yy+y2;
2221
2222       if (!IN_LEV_FIELD(x,y) || (x==xx && y==yy))
2223         continue;
2224
2225       if (((Feld[x][y]==element || (element==EL_LIFE && IS_PLAYER(x,y))) &&
2226            !Stop[x][y]) ||
2227           (IS_FREE(x,y) && Stop[x][y]))
2228         nachbarn++;
2229     }
2230
2231     if (xx==ax && yy==ay)               /* mittleres Feld mit Amoebe */
2232     {
2233       if (nachbarn<life[0] || nachbarn>life[1])
2234       {
2235         Feld[xx][yy] = EL_LEERRAUM;
2236         if (!Stop[xx][yy])
2237           DrawLevelField(xx,yy);
2238         Stop[xx][yy] = TRUE;
2239       }
2240     }
2241     else if (IS_FREE(xx,yy) || Feld[xx][yy]==EL_ERDREICH)
2242     {                                   /* Randfeld ohne Amoebe */
2243       if (nachbarn>=life[2] && nachbarn<=life[3])
2244       {
2245         Feld[xx][yy] = element;
2246         MovDelay[xx][yy] = (element==EL_LIFE ? 0 : life_time-1);
2247         if (!Stop[xx][yy])
2248           DrawLevelField(xx,yy);
2249         Stop[xx][yy] = TRUE;
2250       }
2251     }
2252   }
2253 }
2254
2255 void Ablenk(int x, int y)
2256 {
2257   if (!MovDelay[x][y])          /* neue Phase / noch nicht gewartet */
2258     MovDelay[x][y] = level.dauer_ablenk * FRAMES_PER_SECOND;
2259
2260   if (MovDelay[x][y])           /* neue Phase / in Wartezustand */
2261   {
2262     MovDelay[x][y]--;
2263     if (MovDelay[x][y])
2264     {
2265       if (IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
2266         DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_ABLENK+MovDelay[x][y]%4);
2267       if (!(MovDelay[x][y]%4))
2268         PlaySoundLevel(x,y,SND_MIEP);
2269       return;
2270     }
2271   }
2272
2273   Feld[x][y] = EL_ABLENK_AUS;
2274   DrawLevelField(x,y);
2275   if (ZX==x && ZY==y)
2276     ZX = ZY = -1;
2277 }
2278
2279 void Birne(int x, int y)
2280 {
2281   if (!MovDelay[x][y])          /* neue Phase / noch nicht gewartet */
2282     MovDelay[x][y] = 400;
2283
2284   if (MovDelay[x][y])           /* neue Phase / in Wartezustand */
2285   {
2286     MovDelay[x][y]--;
2287     if (MovDelay[x][y])
2288     {
2289       if (!(MovDelay[x][y]%5))
2290       {
2291         if (!(MovDelay[x][y]%10))
2292           Feld[x][y]=EL_ABLENK_EIN;
2293         else
2294           Feld[x][y]=EL_ABLENK_AUS;
2295         DrawLevelField(x,y);
2296         Feld[x][y]=EL_ABLENK_EIN;
2297       }
2298       return;
2299     }
2300   }
2301
2302   Feld[x][y]=EL_ABLENK_AUS;
2303   DrawLevelField(x,y);
2304   if (ZX==x && ZY==y)
2305     ZX=ZY=-1;
2306 }
2307
2308 void Blubber(int x, int y)
2309 {
2310   DrawGraphicAnimation(x,y, GFX_GEBLUBBER, 4, 5, ANIM_NORMAL);
2311 }
2312
2313 void NussKnacken(int x, int y)
2314 {
2315   if (!MovDelay[x][y])          /* neue Phase / noch nicht gewartet */
2316     MovDelay[x][y] = 4;
2317
2318   if (MovDelay[x][y])           /* neue Phase / in Wartezustand */
2319   {
2320     MovDelay[x][y]--;
2321     if (MovDelay[x][y] && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
2322       DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_CRACKINGNUT+3-MovDelay[x][y]);
2323
2324     if (!MovDelay[x][y])
2325     {
2326       Feld[x][y] = EL_EDELSTEIN;
2327       DrawLevelField(x,y);
2328     }
2329   }
2330 }
2331
2332 void SiebAktivieren(int x, int y, int typ)
2333 {
2334   if (SiebAktiv%2 && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
2335     DrawGraphic(SCROLLX(x),SCROLLY(y),
2336                 (typ==1 ? GFX_SIEB_VOLL : GFX_SIEB2_VOLL)+3-(SiebAktiv%8)/2);
2337 }
2338
2339 void AusgangstuerPruefen(int x, int y)
2340 {
2341   if (!Gems && !SokobanFields && !Lights)
2342   {
2343     Feld[x][y] = EL_AUSGANG_ACT;
2344     PlaySoundLevel(x,y,SND_OEFFNEN);
2345   }
2346 }
2347
2348 void AusgangstuerOeffnen(int x, int y)
2349 {
2350   int speed = 3;
2351
2352   if (!MovDelay[x][y])          /* neue Phase / noch nicht gewartet */
2353     MovDelay[x][y] = 5*speed;
2354
2355   if (MovDelay[x][y])           /* neue Phase / in Wartezustand */
2356   {
2357     int tuer;
2358
2359     MovDelay[x][y]--;
2360     tuer = MovDelay[x][y]/speed;
2361     if (!(MovDelay[x][y]%speed) && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
2362       DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_AUSGANG_AUF-tuer);
2363
2364     if (!MovDelay[x][y])
2365     {
2366       Feld[x][y] = EL_AUSGANG_AUF;
2367       DrawLevelField(x,y);
2368     }
2369   }
2370 }
2371
2372 void AusgangstuerBlinken(int x, int y)
2373 {
2374   DrawGraphicAnimation(x,y, GFX_AUSGANG_AUF, 4, 2, ANIM_OSCILLATE);
2375 }
2376
2377 void EdelsteinFunkeln(int x, int y)
2378 {
2379   if (!IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)) || IS_MOVING(x,y))
2380     return;
2381
2382   if (Feld[x][y] == EL_EDELSTEIN_BD)
2383   {
2384     const int delay = 2;
2385     const int frames = 4;
2386     int phase = (FrameCounter % (delay*frames)) / delay;
2387
2388     if (!(FrameCounter % delay))
2389       DrawGraphic(SCROLLX(x),SCROLLY(y), GFX_EDELSTEIN_BD - phase);
2390   }
2391   else
2392   {
2393     if (!MovDelay[x][y])        /* neue Phase / noch nicht gewartet */
2394       MovDelay[x][y] = 6*!SimpleRND(500);
2395
2396     if (MovDelay[x][y])         /* neue Phase / in Wartezustand */
2397     {
2398       MovDelay[x][y]--;
2399
2400       if (direct_draw_on && MovDelay[x][y])
2401         SetDrawtoField(DRAW_BUFFERED);
2402
2403       DrawGraphic(SCROLLX(x),SCROLLY(y), el2gfx(Feld[x][y]));
2404
2405       if (MovDelay[x][y])
2406       {
2407         int src_x,src_y, dest_x,dest_y;
2408         int phase = MovDelay[x][y]-1;
2409
2410         src_x  = SX+GFX_PER_LINE*TILEX;
2411         src_y  = SY+(phase > 2 ? 4-phase : phase)*TILEY;
2412         dest_x = FX+SCROLLX(x)*TILEX;
2413         dest_y = FY+SCROLLY(y)*TILEY;
2414
2415         XSetClipOrigin(display,clip_gc[PIX_BACK],dest_x-src_x,dest_y-src_y);
2416         XCopyArea(display,pix[PIX_BACK],drawto_field,clip_gc[PIX_BACK],
2417                   src_x,src_y, TILEX,TILEY, dest_x,dest_y);
2418
2419         if (direct_draw_on)
2420         {
2421           XCopyArea(display,drawto_field,window,gc,
2422                     dest_x,dest_y, TILEX,TILEY, dest_x,dest_y);
2423           SetDrawtoField(DRAW_DIRECT);
2424         }
2425       }
2426     }
2427   }
2428 }
2429
2430 void MauerWaechst(int x, int y)
2431 {
2432   int speed = 3;
2433
2434   if (!MovDelay[x][y])          /* neue Phase / noch nicht gewartet */
2435     MovDelay[x][y] = 3*speed;
2436
2437   if (MovDelay[x][y])           /* neue Phase / in Wartezustand */
2438   {
2439     int phase;
2440
2441     MovDelay[x][y]--;
2442     phase = 2-MovDelay[x][y]/speed;
2443     if (!(MovDelay[x][y]%speed) && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
2444       DrawGraphic(SCROLLX(x),SCROLLY(y),
2445                   (Store[x][y]==MV_LEFT ? GFX_MAUER_L1 : GFX_MAUER_R1)+phase);
2446
2447     if (!MovDelay[x][y])
2448     {
2449       if (Store[x][y]==MV_LEFT)
2450       {
2451         if (IN_LEV_FIELD(x-1,y) && IS_MAUER(Feld[x-1][y]))
2452           DrawLevelField(x-1,y);
2453       }
2454       else
2455       {
2456         if (IN_LEV_FIELD(x+1,y) && IS_MAUER(Feld[x+1][y]))
2457           DrawLevelField(x+1,y);
2458       }
2459
2460       Feld[x][y] = EL_MAUER_LEBT;
2461       Store[x][y] = 0;
2462       DrawLevelField(x,y);
2463     }
2464   }
2465 }
2466
2467 void MauerAbleger(int ax, int ay)
2468 {
2469   BOOL links_frei = FALSE, rechts_frei = FALSE;
2470   BOOL links_massiv = FALSE, rechts_massiv = FALSE;
2471
2472   if (!MovDelay[ax][ay])        /* neue Mauer / noch nicht gewartet */
2473     MovDelay[ax][ay] = 3;
2474
2475   if (MovDelay[ax][ay])         /* neue Mauer / in Wartezustand */
2476   {
2477     MovDelay[ax][ay]--;
2478     if (MovDelay[ax][ay])
2479       return;
2480   }
2481
2482   if (IN_LEV_FIELD(ax-1,ay) && IS_FREE(ax-1,ay))
2483     links_frei = TRUE;
2484   if (IN_LEV_FIELD(ax+1,ay) && IS_FREE(ax+1,ay))
2485     rechts_frei = TRUE;
2486
2487   if (links_frei)
2488   {
2489     Feld[ax-1][ay] = EL_MAUERND;
2490     Store[ax-1][ay] = MV_LEFT;
2491     if (IN_SCR_FIELD(SCROLLX(ax-1),SCROLLY(ay)))
2492       DrawGraphic(SCROLLX(ax-1),SCROLLY(ay),GFX_MAUER_L1);
2493   }
2494   if (rechts_frei)
2495   {
2496     Feld[ax+1][ay] = EL_MAUERND;
2497     Store[ax+1][ay] = MV_RIGHT;
2498     if (IN_SCR_FIELD(SCROLLX(ax+1),SCROLLY(ay)))
2499       DrawGraphic(SCROLLX(ax+1),SCROLLY(ay),GFX_MAUER_R1);
2500   }
2501
2502   if (links_frei || rechts_frei)
2503     DrawLevelField(ax,ay);
2504
2505   if (!IN_LEV_FIELD(ax-1,ay) || IS_MAUER(Feld[ax-1][ay]))
2506     links_massiv = TRUE;
2507   if (!IN_LEV_FIELD(ax+1,ay) || IS_MAUER(Feld[ax+1][ay]))
2508     rechts_massiv = TRUE;
2509
2510   if (links_massiv && rechts_massiv)
2511     Feld[ax][ay] = EL_MAUERWERK;
2512 }
2513
2514 void CheckForDragon(int x, int y)
2515 {
2516   int i,j;
2517   BOOL dragon_found = FALSE;
2518   static int xy[4][2] =
2519   {
2520     { 0,-1 },
2521     { -1,0 },
2522     { +1,0 },
2523     { 0,+1 }
2524   };
2525
2526   for(i=0;i<4;i++)
2527   {
2528     for(j=0;j<4;j++)
2529     {
2530       int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
2531
2532       if (IN_LEV_FIELD(xx,yy) &&
2533           (Feld[xx][yy] == EL_BURNING || Feld[xx][yy] == EL_DRACHE))
2534       {
2535         if (Feld[xx][yy] == EL_DRACHE)
2536           dragon_found = TRUE;
2537       }
2538       else
2539         break;
2540     }
2541   }
2542
2543   if (!dragon_found)
2544   {
2545     for(i=0;i<4;i++)
2546     {
2547       for(j=0;j<3;j++)
2548       {
2549         int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
2550   
2551         if (IN_LEV_FIELD(xx,yy) && Feld[xx][yy] == EL_BURNING)
2552         {
2553           Feld[xx][yy] = EL_LEERRAUM;
2554           DrawLevelField(xx,yy);
2555         }
2556         else
2557           break;
2558       }
2559     }
2560   }
2561 }
2562
2563 void GameActions()
2564 {
2565   static long action_delay=0;
2566   long action_delay_value;
2567
2568   if (game_status != PLAYING)
2569     return;
2570
2571 /*
2572   action_delay_value =
2573     (tape.playing && tape.fast_forward ? FFWD_FRAME_DELAY : GAME_FRAME_DELAY);
2574 */
2575
2576   action_delay_value =
2577     (tape.playing && tape.fast_forward ? FFWD_FRAME_DELAY : Gamespeed);
2578
2579   /*
2580   if (DelayReached(&action_delay, action_delay_value))
2581   */
2582
2583
2584
2585   if (PlayerMovPos)
2586     ScrollFigure(0);
2587
2588   DrawPlayerField();
2589
2590
2591
2592
2593   if (!DelayReached(&action_delay, action_delay_value))
2594     return;
2595
2596   {
2597     int x,y,element;
2598     int sieb_x = 0, sieb_y = 0;
2599
2600     if (tape.pausing || (tape.playing && !TapePlayDelay()))
2601       return;
2602     else if (tape.recording)
2603       TapeRecordDelay();
2604
2605     FrameCounter++;
2606     TimeFrames++;
2607
2608     for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
2609     {
2610       Stop[x][y] = FALSE;
2611       if (JustHit[x][y]>0)
2612         JustHit[x][y]--;
2613
2614 #if DEBUG
2615       if (IS_BLOCKED(x,y))
2616       {
2617         int oldx,oldy;
2618
2619         Blocked2Moving(x,y,&oldx,&oldy);
2620         if (!IS_MOVING(oldx,oldy))
2621         {
2622           printf("GameActions(): (BLOCKED=>MOVING) context corrupted!\n");
2623           printf("GameActions(): BLOCKED: x = %d, y = %d\n",x,y);
2624           printf("GameActions(): !MOVING: oldx = %d, oldy = %d\n",oldx,oldy);
2625           printf("GameActions(): This should never happen!\n");
2626         }
2627       }
2628 #endif
2629
2630     }
2631
2632     for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
2633     {
2634       element = Feld[x][y];
2635
2636       if (IS_INACTIVE(element))
2637         continue;
2638
2639       if (!IS_MOVING(x,y) && (CAN_FALL(element) || CAN_MOVE(element)))
2640       {
2641         StartMoving(x,y);
2642
2643         if (IS_GEM(element))
2644           EdelsteinFunkeln(x,y);
2645       }
2646       else if (IS_MOVING(x,y))
2647         ContinueMoving(x,y);
2648       else if (element==EL_DYNAMIT || element==EL_DYNABOMB)
2649         CheckDynamite(x,y);
2650       else if (element==EL_EXPLODING)
2651         Explode(x,y,Frame[x][y],EX_NORMAL);
2652       else if (element==EL_AMOEBING)
2653         AmoebeWaechst(x,y);
2654       else if (IS_AMOEBALIVE(element))
2655         AmoebeAbleger(x,y);
2656       else if (element==EL_LIFE || element==EL_LIFE_ASYNC)
2657         Life(x,y);
2658       else if (element==EL_ABLENK_EIN)
2659         Ablenk(x,y);
2660       else if (element==EL_SALZSAEURE)
2661         Blubber(x,y);
2662       else if (element==EL_BLURB_LEFT || element==EL_BLURB_RIGHT)
2663         Blurb(x,y);
2664       else if (element==EL_CRACKINGNUT)
2665         NussKnacken(x,y);
2666       else if (element==EL_AUSGANG_ZU)
2667         AusgangstuerPruefen(x,y);
2668       else if (element==EL_AUSGANG_ACT)
2669         AusgangstuerOeffnen(x,y);
2670       else if (element==EL_AUSGANG_AUF)
2671         AusgangstuerBlinken(x,y);
2672       else if (element==EL_MAUERND)
2673         MauerWaechst(x,y);
2674       else if (element==EL_MAUER_LEBT)
2675         MauerAbleger(x,y);
2676       else if (element==EL_BURNING)
2677         CheckForDragon(x,y);
2678
2679       if (SiebAktiv)
2680       {
2681         BOOL sieb = FALSE;
2682
2683         if (element==EL_SIEB_LEER || element==EL_SIEB_VOLL ||
2684             Store[x][y]==EL_SIEB_LEER)
2685         {
2686           SiebAktivieren(x, y, 1);
2687           sieb = TRUE;
2688         }
2689         else if (element==EL_SIEB2_LEER || element==EL_SIEB2_VOLL ||
2690                  Store[x][y]==EL_SIEB2_LEER)
2691         {
2692           SiebAktivieren(x, y, 2);
2693           sieb = TRUE;
2694         }
2695
2696         if (sieb && ABS(x-JX)+ABS(y-JY) < ABS(sieb_x-JX)+ABS(sieb_y-JY))
2697         {
2698           sieb_x = x;
2699           sieb_y = y;
2700         }
2701       }
2702     }
2703
2704     if (SiebAktiv)
2705     {
2706       if (!(SiebAktiv%4))
2707         PlaySoundLevel(sieb_x,sieb_y,SND_MIEP);
2708       SiebAktiv--;
2709       if (!SiebAktiv)
2710       {
2711         for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
2712         {
2713           element = Feld[x][y];
2714           if (element==EL_SIEB_LEER || element==EL_SIEB_VOLL)
2715           {
2716             Feld[x][y] = EL_SIEB_TOT;
2717             DrawLevelField(x,y);
2718           }
2719           else if (element==EL_SIEB2_LEER || element==EL_SIEB2_VOLL)
2720           {
2721             Feld[x][y] = EL_SIEB2_TOT;
2722             DrawLevelField(x,y);
2723           }
2724         }
2725       }
2726     }
2727   }
2728
2729   if (TimeLeft>0 && TimeFrames>=25 && !tape.pausing)
2730   {
2731     TimeFrames = 0;
2732     TimeLeft--;
2733
2734     if (tape.recording || tape.playing)
2735       DrawVideoDisplay(VIDEO_STATE_TIME_ON,level.time-TimeLeft);
2736
2737     if (TimeLeft<=10)
2738       PlaySoundStereo(SND_GONG,PSND_MAX_RIGHT);
2739
2740     DrawText(DX_TIME,DY_TIME,int2str(TimeLeft,3),FS_SMALL,FC_YELLOW);
2741
2742     if (!TimeLeft)
2743       KillHero();
2744   }
2745
2746   DrawPlayerField();
2747
2748   BackToFront();
2749 }
2750
2751 void ScrollLevel(int dx, int dy)
2752 {
2753   int softscroll_offset = (soft_scrolling_on ? TILEX : 0);
2754   int x,y;
2755
2756   ScreenMovPos = PlayerMovPos;
2757
2758   XCopyArea(display,drawto_field,drawto_field,gc,
2759             FX + TILEX*(dx==-1) - softscroll_offset,
2760             FY + TILEY*(dy==-1) - softscroll_offset,
2761             SXSIZE - TILEX*(dx!=0) + 2*softscroll_offset,
2762             SYSIZE - TILEY*(dy!=0) + 2*softscroll_offset,
2763             FX + TILEX*(dx==1) - softscroll_offset,
2764             FY + TILEY*(dy==1) - softscroll_offset);
2765
2766   if (dx)
2767   {
2768     x = (dx==1 ? BX1 : BX2);
2769     for(y=BY1; y<=BY2; y++)
2770       DrawScreenField(x,y);
2771   }
2772   if (dy)
2773   {
2774     y = (dy==1 ? BY1 : BY2);
2775     for(x=BX1; x<=BX2; x++)
2776       DrawScreenField(x,y);
2777   }
2778
2779   redraw_mask |= REDRAW_FIELD;
2780 }
2781
2782 BOOL MoveFigureOneStep(int dx, int dy, int real_dx, int real_dy)
2783 {
2784   int oldJX,oldJY, newJX = JX+dx,newJY = JY+dy;
2785   int element;
2786   int can_move;
2787
2788   if (PlayerGone || (!dx && !dy))
2789     return(MF_NO_ACTION);
2790
2791   PlayerMovDir = (dx < 0 ? MV_LEFT :
2792                   dx > 0 ? MV_RIGHT :
2793                   dy < 0 ? MV_UP :
2794                   dy > 0 ? MV_DOWN :    MV_NO_MOVING);
2795
2796   if (!IN_LEV_FIELD(newJX,newJY))
2797     return(MF_NO_ACTION);
2798
2799   element = MovingOrBlocked2Element(newJX,newJY);
2800
2801   if (DONT_GO_TO(element))
2802   {
2803     if (element==EL_SALZSAEURE && dx==0 && dy==1)
2804     {
2805       Blurb(JX,JY);
2806       Feld[JX][JY] = EL_SPIELFIGUR;
2807       InitMovingField(JX,JY,MV_DOWN);
2808       Store[JX][JY] = EL_SALZSAEURE;
2809       ContinueMoving(JX,JY);
2810       BuryHero();
2811     }
2812     else
2813       KillHero();
2814
2815     return(MF_MOVING);
2816   }
2817
2818   can_move = DigField(newJX,newJY, real_dx,real_dy, DF_DIG);
2819   if (can_move != MF_MOVING)
2820     return(can_move);
2821
2822   oldJX = JX;
2823   oldJY = JY;
2824   JX = newJX;
2825   JY = newJY;
2826
2827
2828   lastJX = oldJX;
2829   lastJY = oldJY;
2830
2831   PlayerMovPos = (dx > 0 || dy > 0 ? -1 : 1) * 3*TILEX/4;
2832
2833   ScrollFigure(-1);
2834
2835   if (Store[oldJX][oldJY])
2836   {
2837     DrawGraphic(SCROLLX(oldJX),SCROLLY(oldJY),el2gfx(Store[oldJX][oldJY]));
2838     DrawGraphicThruMask(SCROLLX(oldJX),SCROLLY(oldJY),
2839                         el2gfx(Feld[oldJX][oldJY]));
2840   }
2841   else if (Feld[oldJX][oldJY]==EL_DYNAMIT)
2842     DrawDynamite(oldJX,oldJY);
2843   else
2844     DrawLevelField(oldJX,oldJY);
2845
2846   return(MF_MOVING);
2847 }
2848
2849 BOOL MoveFigure(int dx, int dy)
2850 {
2851   static long move_delay = 0;
2852   static int last_move_dir = MV_NO_MOVING;
2853   int moved = MF_NO_ACTION;
2854   int oldJX = JX, oldJY = JY;
2855
2856   if (PlayerGone || (!dx && !dy))
2857     return(FALSE);
2858
2859   if (Movemethod == 0)
2860   {
2861     if (!DelayReached(&move_delay,Movespeed[0]) && !tape.playing)
2862       return(FALSE);
2863   }
2864   else
2865   {
2866     if (!FrameReached(&move_delay,Movespeed[1]) && !tape.playing)
2867       return(FALSE);
2868   }
2869
2870   if (last_move_dir & (MV_LEFT | MV_RIGHT))
2871   {
2872     if (!(moved |= MoveFigureOneStep(0,dy, dx,dy)))
2873       moved |= MoveFigureOneStep(dx,0, dx,dy);
2874   }
2875   else
2876   {
2877     if (!(moved |= MoveFigureOneStep(dx,0, dx,dy)))
2878       moved |= MoveFigureOneStep(0,dy, dx,dy);
2879   }
2880
2881   last_move_dir = MV_NO_MOVING;
2882
2883   if (moved & MF_MOVING)
2884   {
2885     int old_scroll_x=scroll_x, old_scroll_y=scroll_y;
2886     int offset = (scroll_delay_on ? 3 : 0);
2887
2888     if ((scroll_x < JX-MIDPOSX-offset || scroll_x > JX-MIDPOSX+offset) &&
2889         JX>=MIDPOSX-1-offset && JX<=lev_fieldx-(MIDPOSX-offset))
2890       scroll_x = JX-MIDPOSX + (scroll_x < JX-MIDPOSX ? -offset : offset);
2891     if ((scroll_y < JY-MIDPOSY-offset || scroll_y > JY-MIDPOSY+offset) &&
2892         JY>=MIDPOSY-1-offset && JY<=lev_fieldy-(MIDPOSY-offset))
2893       scroll_y = JY-MIDPOSY + (scroll_y < JY-MIDPOSY ? -offset : offset);
2894
2895     if (scroll_x!=old_scroll_x || scroll_y!=old_scroll_y)
2896       ScrollLevel(old_scroll_x-scroll_x,old_scroll_y-scroll_y);
2897   }
2898
2899   if (!(moved & MF_MOVING) && !PlayerPushing)
2900     PlayerFrame = 0;
2901   else
2902     PlayerFrame = (PlayerFrame + 1) % 4;
2903
2904   if (moved & MF_MOVING)
2905   {
2906     if (oldJX != JX && oldJY == JY)
2907       PlayerMovDir = (oldJX < JX ? MV_RIGHT : MV_LEFT);
2908     else if (oldJX == JX && oldJY != JY)
2909       PlayerMovDir = (oldJY < JY ? MV_DOWN : MV_UP);
2910
2911     DrawLevelField(JX,JY);      /* für "ErdreichAnbroeckeln()" */
2912
2913     last_move_dir = PlayerMovDir;
2914   }
2915
2916   TestIfHeroHitsBadThing();
2917
2918   if (PlayerGone)
2919     RemoveHero();
2920
2921   return(moved);
2922 }
2923
2924 void ScrollFigure(int init)
2925 {
2926   static long actual_frame_counter;
2927   static int oldJX = -1, oldJY = -1;
2928
2929   if (init)
2930   {
2931     if (oldJX != -1 && oldJY != -1)
2932       DrawLevelElement(oldJX,oldJY, Feld[oldJX][oldJY]);
2933
2934     if (Feld[lastJX][lastJY] == EL_LEERRAUM)
2935       Feld[lastJX][lastJY] = EL_PLAYER_IS_LEAVING;
2936     DrawLevelElement(lastJX,lastJY, Feld[lastJX][lastJY]);
2937     DrawPlayerField();
2938
2939     oldJX = lastJX;
2940     oldJY = lastJY;
2941     actual_frame_counter = FrameCounter;
2942
2943     if (PlayerPushing)
2944     {
2945       int nextJX = JX + (JX - lastJX);
2946       int nextJY = JY + (JY - lastJY);
2947
2948       if (Feld[nextJX][nextJY] == EL_SOKOBAN_FELD_VOLL)
2949         DrawLevelElement(nextJX,nextJY, EL_SOKOBAN_FELD_LEER);
2950       else
2951         DrawLevelElement(nextJX,nextJY, EL_LEERRAUM);
2952     }
2953
2954     DrawPlayerField();
2955
2956     return;
2957   }
2958   else if (!FrameReached(&actual_frame_counter,1))
2959     return;
2960
2961   PlayerMovPos += (PlayerMovPos > 0 ? -1 : 1) * TILEX/4;
2962
2963   if (ScreenMovPos)
2964   {
2965     ScreenMovPos = PlayerMovPos;
2966     redraw_mask |= REDRAW_FIELD;
2967   }
2968
2969   if (Feld[oldJX][oldJY] == EL_PLAYER_IS_LEAVING)
2970     Feld[oldJX][oldJY] = EL_LEERRAUM;
2971
2972   DrawLevelElement(oldJX,oldJY, Feld[oldJX][oldJY]);
2973   DrawPlayerField();
2974
2975
2976
2977   if (Store[oldJX][oldJY])
2978   {
2979     DrawGraphic(SCROLLX(oldJX),SCROLLY(oldJY),el2gfx(Store[oldJX][oldJY]));
2980     DrawGraphicThruMask(SCROLLX(oldJX),SCROLLY(oldJY),
2981                         el2gfx(Feld[oldJX][oldJY]));
2982   }
2983   else if (Feld[oldJX][oldJY]==EL_DYNAMIT)
2984     DrawDynamite(oldJX,oldJY);
2985   else
2986     DrawLevelField(oldJX,oldJY);
2987
2988   if (PlayerPushing)
2989   {
2990     int nextJX = JX + (JX - lastJX);
2991     int nextJY = JY + (JY - lastJY);
2992
2993     if (PlayerMovPos)
2994     {
2995       if (Feld[nextJX][nextJY] == EL_SOKOBAN_FELD_VOLL)
2996         DrawLevelElement(nextJX,nextJY, EL_SOKOBAN_FELD_LEER);
2997       else
2998         DrawLevelElement(nextJX,nextJY, EL_LEERRAUM);
2999     }
3000     else
3001       DrawLevelElement(nextJX,nextJY, Feld[nextJX][nextJY]);
3002   }
3003
3004   if (!PlayerMovPos)
3005   {
3006     lastJX = JX;
3007     lastJY = JY;
3008
3009     oldJX = oldJY = -1;
3010   }
3011 }
3012
3013 void TestIfGoodThingHitsBadThing(int goodx, int goody)
3014 {
3015   int i, killx = goodx, killy = goody;
3016   static int xy[4][2] =
3017   {
3018     { 0,-1 },
3019     { -1,0 },
3020     { +1,0 },
3021     { 0,+1 }
3022   };
3023   static int harmless[4] =
3024   {
3025     MV_UP,
3026     MV_LEFT,
3027     MV_RIGHT,
3028     MV_DOWN
3029   };
3030
3031   for(i=0;i<4;i++)
3032   {
3033     int x,y,element;
3034
3035     x = goodx+xy[i][0];
3036     y = goody+xy[i][1];
3037     if (!IN_LEV_FIELD(x,y))
3038       continue;
3039
3040     element = Feld[x][y];
3041
3042     if (DONT_TOUCH(element))
3043     {
3044       if (MovDir[x][y]==harmless[i])
3045         continue;
3046
3047       killx = x;
3048       killy = y;
3049       break;
3050     }
3051   }
3052
3053   if (killx!=goodx || killy!=goody)
3054   {
3055     if (IS_PLAYER(goodx,goody))
3056       KillHero();
3057     else
3058       Bang(goodx,goody);
3059   }
3060 }
3061
3062 void TestIfBadThingHitsGoodThing(int badx, int bady)
3063 {
3064   int i, killx = badx, killy = bady;
3065   static int xy[4][2] =
3066   {
3067     { 0,-1 },
3068     { -1,0 },
3069     { +1,0 },
3070     { 0,+1 }
3071   };
3072   static int harmless[4] =
3073   {
3074     MV_UP,
3075     MV_LEFT,
3076     MV_RIGHT,
3077     MV_DOWN
3078   };
3079
3080   for(i=0;i<4;i++)
3081   {
3082     int x,y,element;
3083
3084     x = badx+xy[i][0];
3085     y = bady+xy[i][1];
3086     if (!IN_LEV_FIELD(x,y))
3087       continue;
3088
3089     element = Feld[x][y];
3090
3091     if (element==EL_PINGUIN)
3092     {
3093       if (MovDir[x][y]==harmless[i] && IS_MOVING(x,y))
3094         continue;
3095
3096       killx = x;
3097       killy = y;
3098       break;
3099     }
3100   }
3101
3102   if (killx!=badx || killy!=bady)
3103     Bang(killx,killy);
3104 }
3105
3106 void TestIfHeroHitsBadThing()
3107 {
3108   TestIfGoodThingHitsBadThing(JX,JY);
3109 }
3110
3111 void TestIfBadThingHitsHero()
3112 {
3113   TestIfGoodThingHitsBadThing(JX,JY);
3114   /* (no typo!) */
3115 }
3116
3117 void TestIfFriendHitsBadThing(int x, int y)
3118 {
3119   TestIfGoodThingHitsBadThing(x,y);
3120 }
3121
3122 void TestIfBadThingHitsFriend(int x, int y)
3123 {
3124   TestIfBadThingHitsGoodThing(x,y);
3125 }
3126
3127 void TestIfBadThingHitsOtherBadThing(int badx, int bady)
3128 {
3129   int i, killx=badx, killy=bady;
3130   static int xy[4][2] =
3131   {
3132     { 0,-1 },
3133     { -1,0 },
3134     { +1,0 },
3135     { 0,+1 }
3136   };
3137
3138   for(i=0;i<4;i++)
3139   {
3140     int x,y,element;
3141
3142     x=badx+xy[i][0];
3143     y=bady+xy[i][1];
3144     if (!IN_LEV_FIELD(x,y))
3145       continue;
3146
3147     element=Feld[x][y];
3148     if (IS_AMOEBOID(element) || element==EL_LIFE ||
3149         element==EL_AMOEBING || element==EL_TROPFEN)
3150     {
3151       killx=x;
3152       killy=y;
3153       break;
3154     }
3155   }
3156
3157   if (killx!=badx || killy!=bady)
3158     Bang(badx,bady);
3159 }
3160
3161 void KillHero()
3162 {
3163   if (PlayerGone)
3164     return;
3165
3166   if (IS_PFORTE(Feld[JX][JY]))
3167     Feld[JX][JY] = EL_LEERRAUM;
3168
3169   Bang(JX,JY);
3170   BuryHero();
3171 }
3172
3173 void BuryHero()
3174 {
3175   if (PlayerGone)
3176     return;
3177
3178   PlaySoundLevel(JX,JY,SND_AUTSCH);
3179   PlaySoundLevel(JX,JY,SND_LACHEN);
3180
3181   GameOver = TRUE;
3182   RemoveHero();
3183 }
3184
3185 void RemoveHero()
3186 {
3187   PlayerGone = TRUE;
3188
3189   ExitX = ZX = JX;
3190   ExitY = ZY = JY;
3191   JX = JY = -1;
3192 }
3193
3194 int DigField(int x, int y, int real_dx, int real_dy, int mode)
3195 {
3196   int dx = x-JX, dy = y-JY;
3197   int element;
3198   static long push_delay = 0;
3199   static int push_delay_value = 5;
3200
3201   if (!PlayerMovPos)
3202     PlayerPushing = FALSE;
3203
3204   if (mode == DF_NO_PUSH)
3205   {
3206     push_delay = 0;
3207     return(MF_NO_ACTION);
3208   }
3209
3210   if (IS_MOVING(x,y))
3211     return(MF_NO_ACTION);
3212
3213   element = Feld[x][y];
3214
3215   switch(element)
3216   {
3217     case EL_LEERRAUM:
3218       break;
3219
3220     case EL_ERDREICH:
3221       Feld[x][y] = EL_LEERRAUM;
3222       break;
3223
3224     case EL_EDELSTEIN:
3225     case EL_EDELSTEIN_BD:
3226     case EL_EDELSTEIN_GELB:
3227     case EL_EDELSTEIN_ROT:
3228     case EL_EDELSTEIN_LILA:
3229       Feld[x][y] = EL_LEERRAUM;
3230       MovDelay[x][y] = 0;       /* wegen EDELSTEIN_BD-Funkeln! */
3231       if (Gems>0)
3232         Gems--;
3233       RaiseScoreElement(EL_EDELSTEIN);
3234       DrawText(DX_EMERALDS,DY_EMERALDS,int2str(Gems,3),FS_SMALL,FC_YELLOW);
3235       PlaySoundLevel(x,y,SND_PONG);
3236       break;
3237
3238     case EL_DIAMANT:
3239       Feld[x][y] = EL_LEERRAUM;
3240       Gems -= 3;
3241       if (Gems<0)
3242         Gems=0;
3243       RaiseScoreElement(EL_DIAMANT);
3244       DrawText(DX_EMERALDS,DY_EMERALDS,int2str(Gems,3),FS_SMALL,FC_YELLOW);
3245       PlaySoundLevel(x,y,SND_PONG);
3246       break;
3247
3248     case EL_DYNAMIT_AUS:
3249       Feld[x][y] = EL_LEERRAUM;
3250       Dynamite++;
3251       RaiseScoreElement(EL_DYNAMIT);
3252       DrawText(DX_DYNAMITE,DY_DYNAMITE,int2str(Dynamite,3),FS_SMALL,FC_YELLOW);
3253       PlaySoundLevel(x,y,SND_PONG);
3254       break;
3255
3256     case EL_DYNABOMB_NR:
3257       Feld[x][y] = EL_LEERRAUM;
3258       DynaBombCount++;
3259       DynaBombsLeft++;
3260       RaiseScoreElement(EL_DYNAMIT);
3261       PlaySoundLevel(x,y,SND_PONG);
3262       break;
3263     case EL_DYNABOMB_SZ:
3264
3265       Feld[x][y] = EL_LEERRAUM;
3266       DynaBombSize++;
3267       RaiseScoreElement(EL_DYNAMIT);
3268       PlaySoundLevel(x,y,SND_PONG);
3269       break;
3270
3271     case EL_DYNABOMB_XL:
3272       Feld[x][y] = EL_LEERRAUM;
3273       DynaBombXL = TRUE;
3274       RaiseScoreElement(EL_DYNAMIT);
3275       PlaySoundLevel(x,y,SND_PONG);
3276       break;
3277
3278     case EL_SCHLUESSEL1:
3279     case EL_SCHLUESSEL2:
3280     case EL_SCHLUESSEL3:
3281     case EL_SCHLUESSEL4:
3282     {
3283       int key_nr = element-EL_SCHLUESSEL1;
3284
3285       Feld[x][y] = EL_LEERRAUM;
3286       Key[key_nr] = TRUE;
3287       RaiseScoreElement(EL_SCHLUESSEL);
3288       DrawMiniGraphicExtHiRes(drawto,gc,
3289                               DX_KEYS+key_nr*MINI_TILEX,DY_KEYS,
3290                               GFX_SCHLUESSEL1+key_nr);
3291       DrawMiniGraphicExtHiRes(window,gc,
3292                               DX_KEYS+key_nr*MINI_TILEX,DY_KEYS,
3293                               GFX_SCHLUESSEL1+key_nr);
3294       PlaySoundLevel(x,y,SND_PONG);
3295       break;
3296     }
3297
3298     case EL_ABLENK_AUS:
3299       Feld[x][y] = EL_ABLENK_EIN;
3300       ZX = x;
3301       ZY = y;
3302       DrawLevelField(x,y);
3303       return(MF_ACTION);
3304       break;
3305
3306     case EL_FELSBROCKEN:
3307     case EL_BOMBE:
3308     case EL_KOKOSNUSS:
3309     case EL_ZEIT_LEER:
3310       if (dy || mode==DF_SNAP)
3311         return(MF_NO_ACTION);
3312
3313       PlayerPushing = TRUE;
3314
3315       if (!IN_LEV_FIELD(x+dx,y+dy) || Feld[x+dx][y+dy] != EL_LEERRAUM)
3316         return(MF_NO_ACTION);
3317
3318       if (real_dy)
3319       {
3320         if (IN_LEV_FIELD(JX,JY+real_dy) && !IS_SOLID(Feld[JX][JY+real_dy]))
3321           return(MF_NO_ACTION);
3322       }
3323
3324       if (push_delay == 0)
3325         push_delay = FrameCounter;
3326       if (!FrameReached(&push_delay,push_delay_value) && !tape.playing)
3327         return(MF_NO_ACTION);
3328
3329       Feld[x][y] = EL_LEERRAUM;
3330       Feld[x+dx][y+dy] = element;
3331
3332       push_delay_value = 2+RND(8);
3333
3334       DrawLevelField(x+dx,y+dy);
3335       if (element==EL_FELSBROCKEN)
3336         PlaySoundLevel(x+dx,y+dy,SND_PUSCH);
3337       else if (element==EL_KOKOSNUSS)
3338         PlaySoundLevel(x+dx,y+dy,SND_KNURK);
3339       else
3340         PlaySoundLevel(x+dx,y+dy,SND_KLOPF);
3341       break;
3342
3343     case EL_PFORTE1:
3344     case EL_PFORTE2:
3345     case EL_PFORTE3:
3346     case EL_PFORTE4:
3347       if (!Key[element-EL_PFORTE1])
3348         return(MF_NO_ACTION);
3349       break;
3350
3351     case EL_PFORTE1X:
3352     case EL_PFORTE2X:
3353     case EL_PFORTE3X:
3354     case EL_PFORTE4X:
3355       if (!Key[element-EL_PFORTE1X])
3356         return(MF_NO_ACTION);
3357       break;
3358
3359     case EL_AUSGANG_ZU:
3360     case EL_AUSGANG_ACT:
3361       /* Tür ist (noch) nicht offen! */
3362       return(MF_NO_ACTION);
3363       break;
3364
3365     case EL_AUSGANG_AUF:
3366       if (mode==DF_SNAP)
3367         return(MF_NO_ACTION);
3368
3369       PlayerGone = TRUE;
3370       PlaySoundLevel(x,y,SND_BUING);
3371
3372       if (!Friends)
3373         LevelSolved = GameOver = TRUE;
3374
3375       break;
3376
3377     case EL_BIRNE_AUS:
3378       Feld[x][y] = EL_BIRNE_EIN;
3379       Lights--;
3380       DrawLevelField(x,y);
3381       PlaySoundLevel(x,y,SND_DENG);
3382       return(MF_ACTION);
3383       break;
3384
3385     case EL_ZEIT_VOLL:
3386       Feld[x][y] = EL_ZEIT_LEER;
3387       TimeLeft += 10;
3388       DrawText(DX_TIME,DY_TIME,int2str(TimeLeft,3),FS_SMALL,FC_YELLOW);
3389       DrawLevelField(x,y);
3390       PlaySoundStereo(SND_GONG,PSND_MAX_RIGHT);
3391       return(MF_ACTION);
3392       break;
3393
3394     case EL_SOKOBAN_FELD_LEER:
3395       break;
3396
3397     case EL_SOKOBAN_FELD_VOLL:
3398     case EL_SOKOBAN_OBJEKT:
3399     case EL_SONDE:
3400       if (mode==DF_SNAP)
3401         return(MF_NO_ACTION);
3402
3403       PlayerPushing = TRUE;
3404
3405       if (!IN_LEV_FIELD(x+dx,y+dy)
3406           || (Feld[x+dx][y+dy] != EL_LEERRAUM
3407               && (Feld[x+dx][y+dy] != EL_SOKOBAN_FELD_LEER
3408                   || !IS_SB_ELEMENT(element))))
3409         return(MF_NO_ACTION);
3410
3411       if (dx && real_dy)
3412       {
3413         if (IN_LEV_FIELD(JX,JY+real_dy) && !IS_SOLID(Feld[JX][JY+real_dy]))
3414           return(MF_NO_ACTION);
3415       }
3416       else if (dy && real_dx)
3417       {
3418         if (IN_LEV_FIELD(JX+real_dx,JY) && !IS_SOLID(Feld[JX+real_dx][JY]))
3419           return(MF_NO_ACTION);
3420       }
3421
3422       if (push_delay == 0)
3423         push_delay = FrameCounter;
3424       if (!FrameReached(&push_delay,push_delay_value) && !tape.playing)
3425         return(MF_NO_ACTION);
3426
3427       if (IS_SB_ELEMENT(element))
3428       {
3429         if (element == EL_SOKOBAN_FELD_VOLL)
3430         {
3431           Feld[x][y] = EL_SOKOBAN_FELD_LEER;
3432           SokobanFields++;
3433         }
3434         else
3435           Feld[x][y] = EL_LEERRAUM;
3436
3437         if (Feld[x+dx][y+dy] == EL_SOKOBAN_FELD_LEER)
3438         {
3439           Feld[x+dx][y+dy] = EL_SOKOBAN_FELD_VOLL;
3440           SokobanFields--;
3441           if (element == EL_SOKOBAN_OBJEKT)
3442             PlaySoundLevel(x,y,SND_DENG);
3443         }
3444         else
3445           Feld[x+dx][y+dy] = EL_SOKOBAN_OBJEKT;
3446       }
3447       else
3448       {
3449         Feld[x][y] = EL_LEERRAUM;
3450         Feld[x+dx][y+dy] = element;
3451       }
3452
3453       push_delay_value = 2;
3454
3455       DrawLevelField(x,y);
3456       DrawLevelField(x+dx,y+dy);
3457       PlaySoundLevel(x+dx,y+dy,SND_PUSCH);
3458
3459       if (IS_SB_ELEMENT(element) &&
3460           SokobanFields == 0 && game_emulation == EMU_SOKOBAN)
3461       {
3462         LevelSolved = GameOver = TRUE;
3463         PlaySoundLevel(x,y,SND_BUING);
3464       }
3465
3466       break;
3467
3468     case EL_MAULWURF:
3469     case EL_PINGUIN:
3470     case EL_SCHWEIN:
3471     case EL_DRACHE:
3472       break;
3473
3474     default:
3475       return(MF_NO_ACTION);
3476       break;
3477   }
3478
3479   push_delay = 0;
3480
3481   return(MF_MOVING);
3482 }
3483
3484 BOOL SnapField(int dx, int dy)
3485 {
3486   int x = JX+dx, y = JY+dy;
3487   static int snapped = FALSE;
3488
3489   if (PlayerGone || !IN_LEV_FIELD(x,y))
3490     return(FALSE);
3491   if (dx && dy)
3492     return(FALSE);
3493   if (!dx && !dy)
3494   {
3495     snapped = FALSE;
3496     return(FALSE);
3497   }
3498   if (snapped)
3499     return(FALSE);
3500
3501   PlayerMovDir = (dx < 0 ? MV_LEFT :
3502                   dx > 0 ? MV_RIGHT :
3503                   dy < 0 ? MV_UP :
3504                   dy > 0 ? MV_DOWN :    MV_NO_MOVING);
3505
3506   if (!DigField(x,y, 0,0, DF_SNAP))
3507     return(FALSE);
3508
3509   snapped = TRUE;
3510   DrawLevelField(x,y);
3511   BackToFront();
3512
3513   return(TRUE);
3514 }
3515
3516 BOOL PlaceBomb(void)
3517 {
3518   int element;
3519
3520   if (PlayerGone || PlayerMovPos)
3521     return(FALSE);
3522
3523   element = Feld[JX][JY];
3524
3525   if ((Dynamite==0 && DynaBombsLeft==0) ||
3526       element==EL_DYNAMIT || element==EL_DYNABOMB || element==EL_EXPLODING)
3527     return(FALSE);
3528
3529   if (element != EL_LEERRAUM)
3530     Store[JX][JY] = element;
3531
3532   if (Dynamite)
3533   {
3534     Feld[JX][JY] = EL_DYNAMIT;
3535     MovDelay[JX][JY] = 48;
3536     Dynamite--;
3537     DrawText(DX_DYNAMITE,DY_DYNAMITE,int2str(Dynamite,3),FS_SMALL,FC_YELLOW);
3538     DrawGraphicThruMask(SCROLLX(JX),SCROLLY(JY),GFX_DYNAMIT);
3539   }
3540   else
3541   {
3542     Feld[JX][JY] = EL_DYNABOMB;
3543     MovDelay[JX][JY] = 48;
3544     DynaBombsLeft--;
3545     DrawGraphicThruMask(SCROLLX(JX),SCROLLY(JY),GFX_DYNABOMB);
3546   }
3547
3548   return(TRUE);
3549 }
3550
3551 void PlaySoundLevel(int x, int y, int sound_nr)
3552 {
3553   int sx = SCROLLX(x), sy = SCROLLY(y);
3554   int volume, stereo;
3555   int silence_distance = 8;
3556
3557   if ((!sound_simple_on && !IS_LOOP_SOUND(sound_nr)) ||
3558       (!sound_loops_on && IS_LOOP_SOUND(sound_nr)))
3559     return;
3560
3561   if (!IN_LEV_FIELD(x,y) ||
3562       sx < -silence_distance || sx >= SCR_FIELDX+silence_distance ||
3563       sy < -silence_distance || sy >= SCR_FIELDY+silence_distance)
3564     return;
3565
3566   volume = PSND_MAX_VOLUME;
3567   stereo = (sx-SCR_FIELDX/2)*12;
3568
3569   if (!IN_SCR_FIELD(sx,sy))
3570   {
3571     int dx = ABS(sx-SCR_FIELDX/2)-SCR_FIELDX/2;
3572     int dy = ABS(sy-SCR_FIELDY/2)-SCR_FIELDY/2;
3573
3574     volume -= volume*(dx > dy ? dx : dy)/silence_distance;
3575   }
3576
3577   PlaySoundExt(sound_nr, volume, stereo, PSND_NO_LOOP);
3578 }
3579
3580 void RaiseScore(int value)
3581 {
3582   Score += value;
3583   DrawText(DX_SCORE,DY_SCORE,int2str(Score,5),FS_SMALL,FC_YELLOW);
3584 }
3585
3586 void RaiseScoreElement(int element)
3587 {
3588   switch(element)
3589   {
3590     case EL_EDELSTEIN:
3591       RaiseScore(level.score[SC_EDELSTEIN]);
3592       break;
3593     case EL_DIAMANT:
3594       RaiseScore(level.score[SC_DIAMANT]);
3595       break;
3596     case EL_KAEFER:
3597     case EL_BUTTERFLY:
3598       RaiseScore(level.score[SC_KAEFER]);
3599       break;
3600     case EL_FLIEGER:
3601     case EL_FIREFLY:
3602       RaiseScore(level.score[SC_FLIEGER]);
3603       break;
3604     case EL_MAMPFER:
3605     case EL_MAMPFER2:
3606       RaiseScore(level.score[SC_MAMPFER]);
3607       break;
3608     case EL_ROBOT:
3609       RaiseScore(level.score[SC_ROBOT]);
3610       break;
3611     case EL_PACMAN:
3612       RaiseScore(level.score[SC_PACMAN]);
3613       break;
3614     case EL_KOKOSNUSS:
3615       RaiseScore(level.score[SC_KOKOSNUSS]);
3616       break;
3617     case EL_DYNAMIT:
3618       RaiseScore(level.score[SC_DYNAMIT]);
3619       break;
3620     case EL_SCHLUESSEL:
3621       RaiseScore(level.score[SC_SCHLUESSEL]);
3622       break;
3623     default:
3624       break;
3625   }
3626 }