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