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