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