rnd-19980828
[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] = 96;
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 = (96-MovDelay[x][y])/12) > 6)
601       phase = 6;
602   }
603   else
604   {
605     if ((phase = ((96-MovDelay[x][y])/6) % 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] % 12))
623         PlaySoundLevel(x,y,SND_ZISCH);
624
625       if (Feld[x][y]==EL_DYNAMIT && !(MovDelay[x][y] % 12))
626         DrawDynamite(x,y);
627       else if (Feld[x][y]==EL_DYNABOMB && !(MovDelay[x][y] % 6))
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 = 2;
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] = 9;
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]/2);
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] = 9;
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] = 9;
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] = 16+16*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] = 16+16*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] = 6+RND(40);
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] = 8+8*!RND(3);
1350       else
1351         MovDelay[x][y] = 16;
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] = TILEY + 1;
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] = TILEY/4 + 1;
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] = TILEY/4 + 1;
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] = 50;
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, 4, ANIM_NORMAL);
1791       else if (element==EL_SONDE)
1792         DrawGraphicAnimation(x,y, GFX_SONDE_START, 8, 2, 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] = 7;
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]/2);
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 = 40;
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] = 800;
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, 10, 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] = 7;
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]/2);
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 delay = 6;
2362
2363   if (!MovDelay[x][y])          /* neue Phase / noch nicht gewartet */
2364     MovDelay[x][y] = 5*delay;
2365
2366   if (MovDelay[x][y])           /* neue Phase / in Wartezustand */
2367   {
2368     int tuer;
2369
2370     MovDelay[x][y]--;
2371     tuer = MovDelay[x][y]/delay;
2372     if (!(MovDelay[x][y]%delay) && 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, 4, 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     DrawGraphicAnimation(x,y, GFX_EDELSTEIN_BD, 4, 4, ANIM_REVERSE);
2395   else
2396   {
2397     if (!MovDelay[x][y])        /* neue Phase / noch nicht gewartet */
2398       MovDelay[x][y] = 11 * !SimpleRND(500);
2399
2400     if (MovDelay[x][y])         /* neue Phase / in Wartezustand */
2401     {
2402       MovDelay[x][y]--;
2403
2404       if (direct_draw_on && MovDelay[x][y])
2405         SetDrawtoField(DRAW_BUFFERED);
2406
2407       DrawGraphic(SCROLLX(x),SCROLLY(y), el2gfx(Feld[x][y]));
2408
2409       if (MovDelay[x][y])
2410       {
2411         int src_x,src_y, dest_x,dest_y;
2412         int phase = (MovDelay[x][y]-1)/2;
2413
2414         src_x  = SX+GFX_PER_LINE*TILEX;
2415         src_y  = SY+(phase > 2 ? 4-phase : phase)*TILEY;
2416         dest_x = FX+SCROLLX(x)*TILEX;
2417         dest_y = FY+SCROLLY(y)*TILEY;
2418
2419         XSetClipOrigin(display,clip_gc[PIX_BACK],dest_x-src_x,dest_y-src_y);
2420         XCopyArea(display,pix[PIX_BACK],drawto_field,clip_gc[PIX_BACK],
2421                   src_x,src_y, TILEX,TILEY, dest_x,dest_y);
2422
2423         if (direct_draw_on)
2424         {
2425           XCopyArea(display,drawto_field,window,gc,
2426                     dest_x,dest_y, TILEX,TILEY, dest_x,dest_y);
2427           SetDrawtoField(DRAW_DIRECT);
2428         }
2429       }
2430     }
2431   }
2432 }
2433
2434 void MauerWaechst(int x, int y)
2435 {
2436   int delay = 6;
2437
2438   if (!MovDelay[x][y])          /* neue Phase / noch nicht gewartet */
2439     MovDelay[x][y] = 3*delay;
2440
2441   if (MovDelay[x][y])           /* neue Phase / in Wartezustand */
2442   {
2443     int phase;
2444
2445     MovDelay[x][y]--;
2446     phase = 2-MovDelay[x][y]/delay;
2447     if (!(MovDelay[x][y]%delay) && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
2448       DrawGraphic(SCROLLX(x),SCROLLY(y),
2449                   (Store[x][y]==MV_LEFT ? GFX_MAUER_L1 : GFX_MAUER_R1)+phase);
2450
2451     if (!MovDelay[x][y])
2452     {
2453       if (Store[x][y]==MV_LEFT)
2454       {
2455         if (IN_LEV_FIELD(x-1,y) && IS_MAUER(Feld[x-1][y]))
2456           DrawLevelField(x-1,y);
2457       }
2458       else
2459       {
2460         if (IN_LEV_FIELD(x+1,y) && IS_MAUER(Feld[x+1][y]))
2461           DrawLevelField(x+1,y);
2462       }
2463
2464       Feld[x][y] = EL_MAUER_LEBT;
2465       Store[x][y] = 0;
2466       DrawLevelField(x,y);
2467     }
2468   }
2469 }
2470
2471 void MauerAbleger(int ax, int ay)
2472 {
2473   BOOL links_frei = FALSE, rechts_frei = FALSE;
2474   BOOL links_massiv = FALSE, rechts_massiv = FALSE;
2475
2476   if (!MovDelay[ax][ay])        /* neue Mauer / noch nicht gewartet */
2477     MovDelay[ax][ay] = 6;
2478
2479   if (MovDelay[ax][ay])         /* neue Mauer / in Wartezustand */
2480   {
2481     MovDelay[ax][ay]--;
2482     if (MovDelay[ax][ay])
2483       return;
2484   }
2485
2486   if (IN_LEV_FIELD(ax-1,ay) && IS_FREE(ax-1,ay))
2487     links_frei = TRUE;
2488   if (IN_LEV_FIELD(ax+1,ay) && IS_FREE(ax+1,ay))
2489     rechts_frei = TRUE;
2490
2491   if (links_frei)
2492   {
2493     Feld[ax-1][ay] = EL_MAUERND;
2494     Store[ax-1][ay] = MV_LEFT;
2495     if (IN_SCR_FIELD(SCROLLX(ax-1),SCROLLY(ay)))
2496       DrawGraphic(SCROLLX(ax-1),SCROLLY(ay),GFX_MAUER_L1);
2497   }
2498   if (rechts_frei)
2499   {
2500     Feld[ax+1][ay] = EL_MAUERND;
2501     Store[ax+1][ay] = MV_RIGHT;
2502     if (IN_SCR_FIELD(SCROLLX(ax+1),SCROLLY(ay)))
2503       DrawGraphic(SCROLLX(ax+1),SCROLLY(ay),GFX_MAUER_R1);
2504   }
2505
2506   if (links_frei || rechts_frei)
2507     DrawLevelField(ax,ay);
2508
2509   if (!IN_LEV_FIELD(ax-1,ay) || IS_MAUER(Feld[ax-1][ay]))
2510     links_massiv = TRUE;
2511   if (!IN_LEV_FIELD(ax+1,ay) || IS_MAUER(Feld[ax+1][ay]))
2512     rechts_massiv = TRUE;
2513
2514   if (links_massiv && rechts_massiv)
2515     Feld[ax][ay] = EL_MAUERWERK;
2516 }
2517
2518 void CheckForDragon(int x, int y)
2519 {
2520   int i,j;
2521   BOOL dragon_found = FALSE;
2522   static int xy[4][2] =
2523   {
2524     { 0,-1 },
2525     { -1,0 },
2526     { +1,0 },
2527     { 0,+1 }
2528   };
2529
2530   for(i=0;i<4;i++)
2531   {
2532     for(j=0;j<4;j++)
2533     {
2534       int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
2535
2536       if (IN_LEV_FIELD(xx,yy) &&
2537           (Feld[xx][yy] == EL_BURNING || Feld[xx][yy] == EL_DRACHE))
2538       {
2539         if (Feld[xx][yy] == EL_DRACHE)
2540           dragon_found = TRUE;
2541       }
2542       else
2543         break;
2544     }
2545   }
2546
2547   if (!dragon_found)
2548   {
2549     for(i=0;i<4;i++)
2550     {
2551       for(j=0;j<3;j++)
2552       {
2553         int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
2554   
2555         if (IN_LEV_FIELD(xx,yy) && Feld[xx][yy] == EL_BURNING)
2556         {
2557           Feld[xx][yy] = EL_LEERRAUM;
2558           DrawLevelField(xx,yy);
2559         }
2560         else
2561           break;
2562       }
2563     }
2564   }
2565 }
2566
2567 void GameActions()
2568 {
2569   static long action_delay = 0;
2570   long action_delay_value;
2571
2572   if (game_status != PLAYING)
2573     return;
2574
2575 /*
2576   action_delay_value =
2577     (tape.playing && tape.fast_forward ? FFWD_FRAME_DELAY : GAME_FRAME_DELAY);
2578 */
2579
2580   action_delay_value =
2581     (tape.playing && tape.fast_forward ? FFWD_FRAME_DELAY : GameSpeed);
2582
2583   /*
2584   if (DelayReached(&action_delay, action_delay_value))
2585   */
2586
2587
2588
2589   if (PlayerMovPos)
2590     ScrollFigure(0);
2591
2592   DrawPlayerField();
2593
2594
2595
2596
2597   tst++;
2598
2599   if (0)
2600   {
2601     static long last_Counter = 0;
2602     long new_Counter = Counter();
2603
2604     printf("--> %ld / %ld [%d]\n",
2605            new_Counter - last_Counter,
2606            new_Counter,
2607            FrameCounter);
2608     last_Counter = new_Counter;
2609   }
2610
2611
2612
2613
2614   /*
2615   if (!DelayReached(&action_delay, action_delay_value))
2616     return;
2617     */
2618
2619
2620   while(!DelayReached(&action_delay, action_delay_value))
2621     Delay(1000);
2622
2623
2624
2625
2626   /*
2627   printf("-----------\n");
2628   */
2629
2630
2631
2632   FrameCounter++;
2633
2634
2635
2636   /*
2637   if (PlayerMovPos)
2638     ScrollFigure(0);
2639
2640   DrawPlayerField();
2641   */
2642
2643
2644   tst2 = tst;
2645   tst = 0;
2646
2647
2648
2649   if (0)
2650   {
2651     static long last_Counter = 0;
2652     long new_Counter = Counter();
2653
2654     printf("--> %ld / %ld [%d]\n",
2655            new_Counter - last_Counter,
2656            new_Counter,
2657            FrameCounter);
2658     last_Counter = new_Counter;
2659   }
2660
2661
2662   /*
2663   printf("--> %ld / ", Counter());
2664   */
2665
2666
2667   {
2668     int x,y,element;
2669     int sieb_x = 0, sieb_y = 0;
2670
2671     if (tape.pausing || (tape.playing && !TapePlayDelay()))
2672       return;
2673     else if (tape.recording)
2674       TapeRecordDelay();
2675
2676
2677     /*
2678     FrameCounter++;
2679     */
2680
2681
2682     TimeFrames++;
2683
2684     for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
2685     {
2686       Stop[x][y] = FALSE;
2687       if (JustHit[x][y]>0)
2688         JustHit[x][y]--;
2689
2690 #if DEBUG
2691       if (IS_BLOCKED(x,y))
2692       {
2693         int oldx,oldy;
2694
2695         Blocked2Moving(x,y,&oldx,&oldy);
2696         if (!IS_MOVING(oldx,oldy))
2697         {
2698           printf("GameActions(): (BLOCKED=>MOVING) context corrupted!\n");
2699           printf("GameActions(): BLOCKED: x = %d, y = %d\n",x,y);
2700           printf("GameActions(): !MOVING: oldx = %d, oldy = %d\n",oldx,oldy);
2701           printf("GameActions(): This should never happen!\n");
2702         }
2703       }
2704 #endif
2705
2706     }
2707
2708     for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
2709     {
2710       element = Feld[x][y];
2711
2712       if (IS_INACTIVE(element))
2713         continue;
2714
2715       if (!IS_MOVING(x,y) && (CAN_FALL(element) || CAN_MOVE(element)))
2716       {
2717         StartMoving(x,y);
2718
2719         if (IS_GEM(element))
2720           EdelsteinFunkeln(x,y);
2721       }
2722       else if (IS_MOVING(x,y))
2723         ContinueMoving(x,y);
2724       else if (element==EL_DYNAMIT || element==EL_DYNABOMB)
2725         CheckDynamite(x,y);
2726       else if (element==EL_EXPLODING)
2727         Explode(x,y,Frame[x][y],EX_NORMAL);
2728       else if (element==EL_AMOEBING)
2729         AmoebeWaechst(x,y);
2730       else if (IS_AMOEBALIVE(element))
2731         AmoebeAbleger(x,y);
2732       else if (element==EL_LIFE || element==EL_LIFE_ASYNC)
2733         Life(x,y);
2734       else if (element==EL_ABLENK_EIN)
2735         Ablenk(x,y);
2736       else if (element==EL_SALZSAEURE)
2737         Blubber(x,y);
2738       else if (element==EL_BLURB_LEFT || element==EL_BLURB_RIGHT)
2739         Blurb(x,y);
2740       else if (element==EL_CRACKINGNUT)
2741         NussKnacken(x,y);
2742       else if (element==EL_AUSGANG_ZU)
2743         AusgangstuerPruefen(x,y);
2744       else if (element==EL_AUSGANG_ACT)
2745         AusgangstuerOeffnen(x,y);
2746       else if (element==EL_AUSGANG_AUF)
2747         AusgangstuerBlinken(x,y);
2748       else if (element==EL_MAUERND)
2749         MauerWaechst(x,y);
2750       else if (element==EL_MAUER_LEBT)
2751         MauerAbleger(x,y);
2752       else if (element==EL_BURNING)
2753         CheckForDragon(x,y);
2754
2755       if (SiebAktiv)
2756       {
2757         BOOL sieb = FALSE;
2758
2759         if (element==EL_SIEB_LEER || element==EL_SIEB_VOLL ||
2760             Store[x][y]==EL_SIEB_LEER)
2761         {
2762           SiebAktivieren(x, y, 1);
2763           sieb = TRUE;
2764         }
2765         else if (element==EL_SIEB2_LEER || element==EL_SIEB2_VOLL ||
2766                  Store[x][y]==EL_SIEB2_LEER)
2767         {
2768           SiebAktivieren(x, y, 2);
2769           sieb = TRUE;
2770         }
2771
2772         if (sieb && ABS(x-JX)+ABS(y-JY) < ABS(sieb_x-JX)+ABS(sieb_y-JY))
2773         {
2774           sieb_x = x;
2775           sieb_y = y;
2776         }
2777       }
2778     }
2779
2780     if (SiebAktiv)
2781     {
2782       if (!(SiebAktiv%4))
2783         PlaySoundLevel(sieb_x,sieb_y,SND_MIEP);
2784       SiebAktiv--;
2785       if (!SiebAktiv)
2786       {
2787         for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
2788         {
2789           element = Feld[x][y];
2790           if (element==EL_SIEB_LEER || element==EL_SIEB_VOLL)
2791           {
2792             Feld[x][y] = EL_SIEB_TOT;
2793             DrawLevelField(x,y);
2794           }
2795           else if (element==EL_SIEB2_LEER || element==EL_SIEB2_VOLL)
2796           {
2797             Feld[x][y] = EL_SIEB2_TOT;
2798             DrawLevelField(x,y);
2799           }
2800         }
2801       }
2802     }
2803   }
2804
2805
2806   /*
2807   printf("%ld\n", Counter());
2808   */
2809
2810
2811   if (TimeLeft>0 && TimeFrames>=(100/GameSpeed) && !tape.pausing)
2812   {
2813     TimeFrames = 0;
2814     TimeLeft--;
2815
2816     if (tape.recording || tape.playing)
2817       DrawVideoDisplay(VIDEO_STATE_TIME_ON,level.time-TimeLeft);
2818
2819     if (TimeLeft<=10)
2820       PlaySoundStereo(SND_GONG,PSND_MAX_RIGHT);
2821
2822     DrawText(DX_TIME,DY_TIME,int2str(TimeLeft,3),FS_SMALL,FC_YELLOW);
2823
2824     if (!TimeLeft)
2825       KillHero();
2826   }
2827
2828   DrawPlayerField();
2829
2830   BackToFront();
2831 }
2832
2833 void ScrollLevel(int dx, int dy)
2834 {
2835   int softscroll_offset = (soft_scrolling_on ? TILEX : 0);
2836   int x,y;
2837
2838   ScreenMovPos = PlayerGfxPos;
2839
2840   XCopyArea(display,drawto_field,drawto_field,gc,
2841             FX + TILEX*(dx==-1) - softscroll_offset,
2842             FY + TILEY*(dy==-1) - softscroll_offset,
2843             SXSIZE - TILEX*(dx!=0) + 2*softscroll_offset,
2844             SYSIZE - TILEY*(dy!=0) + 2*softscroll_offset,
2845             FX + TILEX*(dx==1) - softscroll_offset,
2846             FY + TILEY*(dy==1) - softscroll_offset);
2847
2848   if (dx)
2849   {
2850     x = (dx==1 ? BX1 : BX2);
2851     for(y=BY1; y<=BY2; y++)
2852       DrawScreenField(x,y);
2853   }
2854   if (dy)
2855   {
2856     y = (dy==1 ? BY1 : BY2);
2857     for(x=BX1; x<=BX2; x++)
2858       DrawScreenField(x,y);
2859   }
2860
2861   redraw_mask |= REDRAW_FIELD;
2862 }
2863
2864 BOOL MoveFigureOneStep(int dx, int dy, int real_dx, int real_dy)
2865 {
2866   int newJX = JX+dx, newJY = JY+dy;
2867   int element;
2868   int can_move;
2869
2870   if (PlayerGone || (!dx && !dy))
2871     return(MF_NO_ACTION);
2872
2873   PlayerMovDir = (dx < 0 ? MV_LEFT :
2874                   dx > 0 ? MV_RIGHT :
2875                   dy < 0 ? MV_UP :
2876                   dy > 0 ? MV_DOWN :    MV_NO_MOVING);
2877
2878   if (!IN_LEV_FIELD(newJX,newJY))
2879     return(MF_NO_ACTION);
2880
2881   element = MovingOrBlocked2Element(newJX,newJY);
2882
2883   if (DONT_GO_TO(element))
2884   {
2885     if (element==EL_SALZSAEURE && dx==0 && dy==1)
2886     {
2887       Blurb(JX,JY);
2888       Feld[JX][JY] = EL_SPIELFIGUR;
2889       InitMovingField(JX,JY,MV_DOWN);
2890       Store[JX][JY] = EL_SALZSAEURE;
2891       ContinueMoving(JX,JY);
2892       BuryHero();
2893     }
2894     else
2895       KillHero();
2896
2897     return(MF_MOVING);
2898   }
2899
2900   can_move = DigField(newJX,newJY, real_dx,real_dy, DF_DIG);
2901   if (can_move != MF_MOVING)
2902     return(can_move);
2903
2904   lastJX = JX;
2905   lastJY = JY;
2906   JX = newJX;
2907   JY = newJY;
2908
2909   PlayerMovPos = (dx > 0 || dy > 0 ? -1 : 1) * 7*TILEX/8;
2910
2911   ScrollFigure(-1);
2912
2913   return(MF_MOVING);
2914 }
2915
2916 BOOL MoveFigure(int dx, int dy)
2917 {
2918   static long move_delay = 0;
2919   static int last_move_dir = MV_NO_MOVING;
2920   int moved = MF_NO_ACTION;
2921   int oldJX = JX, oldJY = JY;
2922
2923   if (PlayerGone || (!dx && !dy))
2924     return(FALSE);
2925
2926   if (!FrameReached(&move_delay,MoveSpeed) && !tape.playing)
2927     return(FALSE);
2928
2929   if (last_move_dir & (MV_LEFT | MV_RIGHT))
2930   {
2931     if (!(moved |= MoveFigureOneStep(0,dy, dx,dy)))
2932       moved |= MoveFigureOneStep(dx,0, dx,dy);
2933   }
2934   else
2935   {
2936     if (!(moved |= MoveFigureOneStep(dx,0, dx,dy)))
2937       moved |= MoveFigureOneStep(0,dy, dx,dy);
2938   }
2939
2940   last_move_dir = MV_NO_MOVING;
2941
2942   if (moved & MF_MOVING)
2943   {
2944     int old_scroll_x = scroll_x, old_scroll_y = scroll_y;
2945     int offset = (scroll_delay_on ? 3 : 0);
2946
2947     if ((scroll_x < JX-MIDPOSX-offset || scroll_x > JX-MIDPOSX+offset) &&
2948         JX >= MIDPOSX-1-offset && JX <= lev_fieldx-(MIDPOSX-offset))
2949       scroll_x = JX-MIDPOSX + (scroll_x < JX-MIDPOSX ? -offset : offset);
2950     if ((scroll_y < JY-MIDPOSY-offset || scroll_y > JY-MIDPOSY+offset) &&
2951         JY >= MIDPOSY-1-offset && JY <= lev_fieldy-(MIDPOSY-offset))
2952       scroll_y = JY-MIDPOSY + (scroll_y < JY-MIDPOSY ? -offset : offset);
2953
2954     if (scroll_x != old_scroll_x || scroll_y != old_scroll_y)
2955       ScrollLevel(old_scroll_x - scroll_x, old_scroll_y - scroll_y);
2956   }
2957
2958   if (!(moved & MF_MOVING) && !PlayerPushing)
2959     PlayerFrame = 0;
2960   else
2961     PlayerFrame = (PlayerFrame + 1) % 4;
2962
2963   if (moved & MF_MOVING)
2964   {
2965     if (oldJX != JX && oldJY == JY)
2966       PlayerMovDir = (oldJX < JX ? MV_RIGHT : MV_LEFT);
2967     else if (oldJX == JX && oldJY != JY)
2968       PlayerMovDir = (oldJY < JY ? MV_DOWN : MV_UP);
2969
2970     DrawLevelField(JX,JY);      /* für "ErdreichAnbroeckeln()" */
2971
2972     last_move_dir = PlayerMovDir;
2973   }
2974
2975   TestIfHeroHitsBadThing();
2976
2977   if (PlayerGone)
2978     RemoveHero();
2979
2980   return(moved);
2981 }
2982
2983 void ScrollFigure(int init)
2984 {
2985   static long actual_frame_counter = 0;
2986   static int oldJX = -1, oldJY = -1;
2987
2988   if (init)
2989   {
2990
2991
2992
2993     PlayerGfxPos = ScrollStepSize * (PlayerMovPos / ScrollStepSize);
2994
2995
2996
2997     /*
2998     ScreenMovPos = PlayerGfxPos;
2999     redraw_mask |= REDRAW_FIELD;
3000     */
3001
3002
3003
3004     if (0)
3005     {
3006       static long last_Counter = 0;
3007       long new_Counter = Counter();
3008
3009       printf("--> %ld / %ld [%d, %d]\n",
3010              new_Counter - last_Counter,
3011              new_Counter,
3012              FrameCounter,
3013              tst2);
3014       last_Counter = new_Counter;
3015     }
3016
3017
3018
3019
3020     if (oldJX != -1 && oldJY != -1)
3021       DrawLevelElement(oldJX,oldJY, Feld[oldJX][oldJY]);
3022
3023     if (Feld[lastJX][lastJY] == EL_LEERRAUM &&
3024         IN_LEV_FIELD(lastJX,lastJY-1) &&
3025         CAN_FALL(Feld[lastJX][lastJY-1]))
3026       Feld[lastJX][lastJY] = EL_PLAYER_IS_LEAVING;
3027     DrawLevelElement(lastJX,lastJY, Feld[lastJX][lastJY]);
3028     DrawPlayerField();
3029
3030     oldJX = lastJX;
3031     oldJY = lastJY;
3032     actual_frame_counter = FrameCounter;
3033
3034     if (PlayerPushing)
3035     {
3036       int nextJX = JX + (JX - lastJX);
3037       int nextJY = JY + (JY - lastJY);
3038
3039       if (Feld[nextJX][nextJY] == EL_SOKOBAN_FELD_VOLL)
3040         DrawLevelElement(nextJX,nextJY, EL_SOKOBAN_FELD_LEER);
3041       else
3042         DrawLevelElement(nextJX,nextJY, EL_LEERRAUM);
3043     }
3044
3045     DrawPlayerField();
3046
3047     if (Store[lastJX][lastJY])
3048     {
3049       DrawGraphic(SCROLLX(lastJX),SCROLLY(lastJY),
3050                   el2gfx(Store[lastJX][lastJY]));
3051       DrawGraphicThruMask(SCROLLX(lastJX),SCROLLY(lastJY),
3052                           el2gfx(Feld[lastJX][lastJY]));
3053     }
3054     else if (Feld[lastJX][lastJY]==EL_DYNAMIT)
3055       DrawDynamite(lastJX,lastJY);
3056     else
3057       DrawLevelField(lastJX,lastJY);
3058
3059     return;
3060   }
3061   else if (!FrameReached(&actual_frame_counter,1))
3062     return;
3063
3064   PlayerMovPos += (PlayerMovPos > 0 ? -1 : 1) * TILEX/8;
3065   PlayerGfxPos = ScrollStepSize * (PlayerMovPos / ScrollStepSize);
3066
3067
3068   /*
3069   printf("PlayerGfxPos = %d\n", PlayerGfxPos);
3070   */
3071
3072
3073   if (ScreenMovPos && ScreenMovPos != PlayerGfxPos)
3074   {
3075     ScreenMovPos = PlayerGfxPos;
3076     redraw_mask |= REDRAW_FIELD;
3077   }
3078
3079   if (Feld[oldJX][oldJY] == EL_PLAYER_IS_LEAVING)
3080     Feld[oldJX][oldJY] = EL_LEERRAUM;
3081
3082   DrawLevelElement(oldJX,oldJY, Feld[oldJX][oldJY]);
3083   DrawPlayerField();
3084
3085
3086
3087   if (Store[oldJX][oldJY])
3088   {
3089     DrawGraphic(SCROLLX(oldJX),SCROLLY(oldJY),el2gfx(Store[oldJX][oldJY]));
3090     DrawGraphicThruMask(SCROLLX(oldJX),SCROLLY(oldJY),
3091                         el2gfx(Feld[oldJX][oldJY]));
3092   }
3093   else if (Feld[oldJX][oldJY]==EL_DYNAMIT)
3094     DrawDynamite(oldJX,oldJY);
3095   else
3096     DrawLevelField(oldJX,oldJY);
3097
3098   if (PlayerPushing)
3099   {
3100     int nextJX = JX + (JX - lastJX);
3101     int nextJY = JY + (JY - lastJY);
3102
3103     if (PlayerGfxPos)
3104     {
3105       if (Feld[nextJX][nextJY] == EL_SOKOBAN_FELD_VOLL)
3106         DrawLevelElement(nextJX,nextJY, EL_SOKOBAN_FELD_LEER);
3107       else
3108         DrawLevelElement(nextJX,nextJY, EL_LEERRAUM);
3109     }
3110     else
3111       DrawLevelElement(nextJX,nextJY, Feld[nextJX][nextJY]);
3112   }
3113
3114   if (!PlayerMovPos)
3115   {
3116     lastJX = JX;
3117     lastJY = JY;
3118
3119     oldJX = oldJY = -1;
3120   }
3121 }
3122
3123 void TestIfGoodThingHitsBadThing(int goodx, int goody)
3124 {
3125   int i, killx = goodx, killy = goody;
3126   static int xy[4][2] =
3127   {
3128     { 0,-1 },
3129     { -1,0 },
3130     { +1,0 },
3131     { 0,+1 }
3132   };
3133   static int harmless[4] =
3134   {
3135     MV_UP,
3136     MV_LEFT,
3137     MV_RIGHT,
3138     MV_DOWN
3139   };
3140
3141   for(i=0;i<4;i++)
3142   {
3143     int x,y,element;
3144
3145     x = goodx+xy[i][0];
3146     y = goody+xy[i][1];
3147     if (!IN_LEV_FIELD(x,y))
3148       continue;
3149
3150     element = Feld[x][y];
3151
3152     if (DONT_TOUCH(element))
3153     {
3154       if (MovDir[x][y]==harmless[i])
3155         continue;
3156
3157       killx = x;
3158       killy = y;
3159       break;
3160     }
3161   }
3162
3163   if (killx!=goodx || killy!=goody)
3164   {
3165     if (IS_PLAYER(goodx,goody))
3166       KillHero();
3167     else
3168       Bang(goodx,goody);
3169   }
3170 }
3171
3172 void TestIfBadThingHitsGoodThing(int badx, int bady)
3173 {
3174   int i, killx = badx, killy = bady;
3175   static int xy[4][2] =
3176   {
3177     { 0,-1 },
3178     { -1,0 },
3179     { +1,0 },
3180     { 0,+1 }
3181   };
3182   static int harmless[4] =
3183   {
3184     MV_UP,
3185     MV_LEFT,
3186     MV_RIGHT,
3187     MV_DOWN
3188   };
3189
3190   for(i=0;i<4;i++)
3191   {
3192     int x,y,element;
3193
3194     x = badx+xy[i][0];
3195     y = bady+xy[i][1];
3196     if (!IN_LEV_FIELD(x,y))
3197       continue;
3198
3199     element = Feld[x][y];
3200
3201     if (element==EL_PINGUIN)
3202     {
3203       if (MovDir[x][y]==harmless[i] && IS_MOVING(x,y))
3204         continue;
3205
3206       killx = x;
3207       killy = y;
3208       break;
3209     }
3210   }
3211
3212   if (killx!=badx || killy!=bady)
3213     Bang(killx,killy);
3214 }
3215
3216 void TestIfHeroHitsBadThing()
3217 {
3218   TestIfGoodThingHitsBadThing(JX,JY);
3219 }
3220
3221 void TestIfBadThingHitsHero()
3222 {
3223   TestIfGoodThingHitsBadThing(JX,JY);
3224   /* (no typo!) */
3225 }
3226
3227 void TestIfFriendHitsBadThing(int x, int y)
3228 {
3229   TestIfGoodThingHitsBadThing(x,y);
3230 }
3231
3232 void TestIfBadThingHitsFriend(int x, int y)
3233 {
3234   TestIfBadThingHitsGoodThing(x,y);
3235 }
3236
3237 void TestIfBadThingHitsOtherBadThing(int badx, int bady)
3238 {
3239   int i, killx=badx, killy=bady;
3240   static int xy[4][2] =
3241   {
3242     { 0,-1 },
3243     { -1,0 },
3244     { +1,0 },
3245     { 0,+1 }
3246   };
3247
3248   for(i=0;i<4;i++)
3249   {
3250     int x,y,element;
3251
3252     x=badx+xy[i][0];
3253     y=bady+xy[i][1];
3254     if (!IN_LEV_FIELD(x,y))
3255       continue;
3256
3257     element=Feld[x][y];
3258     if (IS_AMOEBOID(element) || element==EL_LIFE ||
3259         element==EL_AMOEBING || element==EL_TROPFEN)
3260     {
3261       killx=x;
3262       killy=y;
3263       break;
3264     }
3265   }
3266
3267   if (killx!=badx || killy!=bady)
3268     Bang(badx,bady);
3269 }
3270
3271 void KillHero()
3272 {
3273   if (PlayerGone)
3274     return;
3275
3276   if (IS_PFORTE(Feld[JX][JY]))
3277     Feld[JX][JY] = EL_LEERRAUM;
3278
3279   Bang(JX,JY);
3280   BuryHero();
3281 }
3282
3283 void BuryHero()
3284 {
3285   if (PlayerGone)
3286     return;
3287
3288   PlaySoundLevel(JX,JY,SND_AUTSCH);
3289   PlaySoundLevel(JX,JY,SND_LACHEN);
3290
3291   GameOver = TRUE;
3292   RemoveHero();
3293 }
3294
3295 void RemoveHero()
3296 {
3297   PlayerGone = TRUE;
3298
3299   ExitX = ZX = JX;
3300   ExitY = ZY = JY;
3301   JX = JY = -1;
3302 }
3303
3304 int DigField(int x, int y, int real_dx, int real_dy, int mode)
3305 {
3306   int dx = x-JX, dy = y-JY;
3307   int element;
3308   static long push_delay = 0;
3309   static int push_delay_value = 5;
3310
3311   if (!PlayerMovPos)
3312     PlayerPushing = FALSE;
3313
3314   if (mode == DF_NO_PUSH)
3315   {
3316     push_delay = 0;
3317     return(MF_NO_ACTION);
3318   }
3319
3320   if (IS_MOVING(x,y))
3321     return(MF_NO_ACTION);
3322
3323   element = Feld[x][y];
3324
3325   switch(element)
3326   {
3327     case EL_LEERRAUM:
3328       break;
3329
3330     case EL_ERDREICH:
3331       Feld[x][y] = EL_LEERRAUM;
3332       break;
3333
3334     case EL_EDELSTEIN:
3335     case EL_EDELSTEIN_BD:
3336     case EL_EDELSTEIN_GELB:
3337     case EL_EDELSTEIN_ROT:
3338     case EL_EDELSTEIN_LILA:
3339       Feld[x][y] = EL_LEERRAUM;
3340       MovDelay[x][y] = 0;       /* wegen EDELSTEIN_BD-Funkeln! */
3341       if (Gems>0)
3342         Gems--;
3343       RaiseScoreElement(EL_EDELSTEIN);
3344       DrawText(DX_EMERALDS,DY_EMERALDS,int2str(Gems,3),FS_SMALL,FC_YELLOW);
3345       PlaySoundLevel(x,y,SND_PONG);
3346       break;
3347
3348     case EL_DIAMANT:
3349       Feld[x][y] = EL_LEERRAUM;
3350       Gems -= 3;
3351       if (Gems<0)
3352         Gems=0;
3353       RaiseScoreElement(EL_DIAMANT);
3354       DrawText(DX_EMERALDS,DY_EMERALDS,int2str(Gems,3),FS_SMALL,FC_YELLOW);
3355       PlaySoundLevel(x,y,SND_PONG);
3356       break;
3357
3358     case EL_DYNAMIT_AUS:
3359       Feld[x][y] = EL_LEERRAUM;
3360       Dynamite++;
3361       RaiseScoreElement(EL_DYNAMIT);
3362       DrawText(DX_DYNAMITE,DY_DYNAMITE,int2str(Dynamite,3),FS_SMALL,FC_YELLOW);
3363       PlaySoundLevel(x,y,SND_PONG);
3364       break;
3365
3366     case EL_DYNABOMB_NR:
3367       Feld[x][y] = EL_LEERRAUM;
3368       DynaBombCount++;
3369       DynaBombsLeft++;
3370       RaiseScoreElement(EL_DYNAMIT);
3371       PlaySoundLevel(x,y,SND_PONG);
3372       break;
3373     case EL_DYNABOMB_SZ:
3374
3375       Feld[x][y] = EL_LEERRAUM;
3376       DynaBombSize++;
3377       RaiseScoreElement(EL_DYNAMIT);
3378       PlaySoundLevel(x,y,SND_PONG);
3379       break;
3380
3381     case EL_DYNABOMB_XL:
3382       Feld[x][y] = EL_LEERRAUM;
3383       DynaBombXL = TRUE;
3384       RaiseScoreElement(EL_DYNAMIT);
3385       PlaySoundLevel(x,y,SND_PONG);
3386       break;
3387
3388     case EL_SCHLUESSEL1:
3389     case EL_SCHLUESSEL2:
3390     case EL_SCHLUESSEL3:
3391     case EL_SCHLUESSEL4:
3392     {
3393       int key_nr = element-EL_SCHLUESSEL1;
3394
3395       Feld[x][y] = EL_LEERRAUM;
3396       Key[key_nr] = TRUE;
3397       RaiseScoreElement(EL_SCHLUESSEL);
3398       DrawMiniGraphicExtHiRes(drawto,gc,
3399                               DX_KEYS+key_nr*MINI_TILEX,DY_KEYS,
3400                               GFX_SCHLUESSEL1+key_nr);
3401       DrawMiniGraphicExtHiRes(window,gc,
3402                               DX_KEYS+key_nr*MINI_TILEX,DY_KEYS,
3403                               GFX_SCHLUESSEL1+key_nr);
3404       PlaySoundLevel(x,y,SND_PONG);
3405       break;
3406     }
3407
3408     case EL_ABLENK_AUS:
3409       Feld[x][y] = EL_ABLENK_EIN;
3410       ZX = x;
3411       ZY = y;
3412       DrawLevelField(x,y);
3413       return(MF_ACTION);
3414       break;
3415
3416     case EL_FELSBROCKEN:
3417     case EL_BOMBE:
3418     case EL_KOKOSNUSS:
3419     case EL_ZEIT_LEER:
3420       if (dy || mode==DF_SNAP)
3421         return(MF_NO_ACTION);
3422
3423       PlayerPushing = TRUE;
3424
3425       if (!IN_LEV_FIELD(x+dx,y+dy) || Feld[x+dx][y+dy] != EL_LEERRAUM)
3426         return(MF_NO_ACTION);
3427
3428       if (real_dy)
3429       {
3430         if (IN_LEV_FIELD(JX,JY+real_dy) && !IS_SOLID(Feld[JX][JY+real_dy]))
3431           return(MF_NO_ACTION);
3432       }
3433
3434       if (push_delay == 0)
3435         push_delay = FrameCounter;
3436       if (!FrameReached(&push_delay,push_delay_value) && !tape.playing)
3437         return(MF_NO_ACTION);
3438
3439       Feld[x][y] = EL_LEERRAUM;
3440       Feld[x+dx][y+dy] = element;
3441
3442       push_delay_value = 2+RND(8);
3443
3444       DrawLevelField(x+dx,y+dy);
3445       if (element==EL_FELSBROCKEN)
3446         PlaySoundLevel(x+dx,y+dy,SND_PUSCH);
3447       else if (element==EL_KOKOSNUSS)
3448         PlaySoundLevel(x+dx,y+dy,SND_KNURK);
3449       else
3450         PlaySoundLevel(x+dx,y+dy,SND_KLOPF);
3451       break;
3452
3453     case EL_PFORTE1:
3454     case EL_PFORTE2:
3455     case EL_PFORTE3:
3456     case EL_PFORTE4:
3457       if (!Key[element-EL_PFORTE1])
3458         return(MF_NO_ACTION);
3459       break;
3460
3461     case EL_PFORTE1X:
3462     case EL_PFORTE2X:
3463     case EL_PFORTE3X:
3464     case EL_PFORTE4X:
3465       if (!Key[element-EL_PFORTE1X])
3466         return(MF_NO_ACTION);
3467       break;
3468
3469     case EL_AUSGANG_ZU:
3470     case EL_AUSGANG_ACT:
3471       /* Tür ist (noch) nicht offen! */
3472       return(MF_NO_ACTION);
3473       break;
3474
3475     case EL_AUSGANG_AUF:
3476       if (mode==DF_SNAP)
3477         return(MF_NO_ACTION);
3478
3479       PlayerGone = TRUE;
3480       PlaySoundLevel(x,y,SND_BUING);
3481
3482       if (!Friends)
3483         LevelSolved = GameOver = TRUE;
3484
3485       break;
3486
3487     case EL_BIRNE_AUS:
3488       Feld[x][y] = EL_BIRNE_EIN;
3489       Lights--;
3490       DrawLevelField(x,y);
3491       PlaySoundLevel(x,y,SND_DENG);
3492       return(MF_ACTION);
3493       break;
3494
3495     case EL_ZEIT_VOLL:
3496       Feld[x][y] = EL_ZEIT_LEER;
3497       TimeLeft += 10;
3498       DrawText(DX_TIME,DY_TIME,int2str(TimeLeft,3),FS_SMALL,FC_YELLOW);
3499       DrawLevelField(x,y);
3500       PlaySoundStereo(SND_GONG,PSND_MAX_RIGHT);
3501       return(MF_ACTION);
3502       break;
3503
3504     case EL_SOKOBAN_FELD_LEER:
3505       break;
3506
3507     case EL_SOKOBAN_FELD_VOLL:
3508     case EL_SOKOBAN_OBJEKT:
3509     case EL_SONDE:
3510       if (mode==DF_SNAP)
3511         return(MF_NO_ACTION);
3512
3513       PlayerPushing = TRUE;
3514
3515       if (!IN_LEV_FIELD(x+dx,y+dy)
3516           || (Feld[x+dx][y+dy] != EL_LEERRAUM
3517               && (Feld[x+dx][y+dy] != EL_SOKOBAN_FELD_LEER
3518                   || !IS_SB_ELEMENT(element))))
3519         return(MF_NO_ACTION);
3520
3521       if (dx && real_dy)
3522       {
3523         if (IN_LEV_FIELD(JX,JY+real_dy) && !IS_SOLID(Feld[JX][JY+real_dy]))
3524           return(MF_NO_ACTION);
3525       }
3526       else if (dy && real_dx)
3527       {
3528         if (IN_LEV_FIELD(JX+real_dx,JY) && !IS_SOLID(Feld[JX+real_dx][JY]))
3529           return(MF_NO_ACTION);
3530       }
3531
3532       if (push_delay == 0)
3533         push_delay = FrameCounter;
3534       if (!FrameReached(&push_delay,push_delay_value) && !tape.playing)
3535         return(MF_NO_ACTION);
3536
3537       if (IS_SB_ELEMENT(element))
3538       {
3539         if (element == EL_SOKOBAN_FELD_VOLL)
3540         {
3541           Feld[x][y] = EL_SOKOBAN_FELD_LEER;
3542           SokobanFields++;
3543         }
3544         else
3545           Feld[x][y] = EL_LEERRAUM;
3546
3547         if (Feld[x+dx][y+dy] == EL_SOKOBAN_FELD_LEER)
3548         {
3549           Feld[x+dx][y+dy] = EL_SOKOBAN_FELD_VOLL;
3550           SokobanFields--;
3551           if (element == EL_SOKOBAN_OBJEKT)
3552             PlaySoundLevel(x,y,SND_DENG);
3553         }
3554         else
3555           Feld[x+dx][y+dy] = EL_SOKOBAN_OBJEKT;
3556       }
3557       else
3558       {
3559         Feld[x][y] = EL_LEERRAUM;
3560         Feld[x+dx][y+dy] = element;
3561       }
3562
3563       push_delay_value = 2;
3564
3565       DrawLevelField(x,y);
3566       DrawLevelField(x+dx,y+dy);
3567       PlaySoundLevel(x+dx,y+dy,SND_PUSCH);
3568
3569       if (IS_SB_ELEMENT(element) &&
3570           SokobanFields == 0 && game_emulation == EMU_SOKOBAN)
3571       {
3572         LevelSolved = GameOver = TRUE;
3573         PlaySoundLevel(x,y,SND_BUING);
3574       }
3575
3576       break;
3577
3578     case EL_MAULWURF:
3579     case EL_PINGUIN:
3580     case EL_SCHWEIN:
3581     case EL_DRACHE:
3582       break;
3583
3584     default:
3585       return(MF_NO_ACTION);
3586       break;
3587   }
3588
3589   push_delay = 0;
3590
3591   return(MF_MOVING);
3592 }
3593
3594 BOOL SnapField(int dx, int dy)
3595 {
3596   int x = JX+dx, y = JY+dy;
3597   static int snapped = FALSE;
3598
3599   if (PlayerGone || !IN_LEV_FIELD(x,y))
3600     return(FALSE);
3601   if (dx && dy)
3602     return(FALSE);
3603   if (!dx && !dy)
3604   {
3605     snapped = FALSE;
3606     return(FALSE);
3607   }
3608   if (snapped)
3609     return(FALSE);
3610
3611   PlayerMovDir = (dx < 0 ? MV_LEFT :
3612                   dx > 0 ? MV_RIGHT :
3613                   dy < 0 ? MV_UP :
3614                   dy > 0 ? MV_DOWN :    MV_NO_MOVING);
3615
3616   if (!DigField(x,y, 0,0, DF_SNAP))
3617     return(FALSE);
3618
3619   snapped = TRUE;
3620   DrawLevelField(x,y);
3621   BackToFront();
3622
3623   return(TRUE);
3624 }
3625
3626 BOOL PlaceBomb(void)
3627 {
3628   int element;
3629
3630   if (PlayerGone || PlayerMovPos)
3631     return(FALSE);
3632
3633   element = Feld[JX][JY];
3634
3635   if ((Dynamite==0 && DynaBombsLeft==0) ||
3636       element==EL_DYNAMIT || element==EL_DYNABOMB || element==EL_EXPLODING)
3637     return(FALSE);
3638
3639   if (element != EL_LEERRAUM)
3640     Store[JX][JY] = element;
3641
3642   if (Dynamite)
3643   {
3644     Feld[JX][JY] = EL_DYNAMIT;
3645     MovDelay[JX][JY] = 96;
3646     Dynamite--;
3647     DrawText(DX_DYNAMITE,DY_DYNAMITE,int2str(Dynamite,3),FS_SMALL,FC_YELLOW);
3648     DrawGraphicThruMask(SCROLLX(JX),SCROLLY(JY),GFX_DYNAMIT);
3649   }
3650   else
3651   {
3652     Feld[JX][JY] = EL_DYNABOMB;
3653     MovDelay[JX][JY] = 96;
3654     DynaBombsLeft--;
3655     DrawGraphicThruMask(SCROLLX(JX),SCROLLY(JY),GFX_DYNABOMB);
3656   }
3657
3658   return(TRUE);
3659 }
3660
3661 void PlaySoundLevel(int x, int y, int sound_nr)
3662 {
3663   int sx = SCROLLX(x), sy = SCROLLY(y);
3664   int volume, stereo;
3665   int silence_distance = 8;
3666
3667   if ((!sound_simple_on && !IS_LOOP_SOUND(sound_nr)) ||
3668       (!sound_loops_on && IS_LOOP_SOUND(sound_nr)))
3669     return;
3670
3671   if (!IN_LEV_FIELD(x,y) ||
3672       sx < -silence_distance || sx >= SCR_FIELDX+silence_distance ||
3673       sy < -silence_distance || sy >= SCR_FIELDY+silence_distance)
3674     return;
3675
3676   volume = PSND_MAX_VOLUME;
3677   stereo = (sx-SCR_FIELDX/2)*12;
3678
3679   if (!IN_SCR_FIELD(sx,sy))
3680   {
3681     int dx = ABS(sx-SCR_FIELDX/2)-SCR_FIELDX/2;
3682     int dy = ABS(sy-SCR_FIELDY/2)-SCR_FIELDY/2;
3683
3684     volume -= volume*(dx > dy ? dx : dy)/silence_distance;
3685   }
3686
3687   PlaySoundExt(sound_nr, volume, stereo, PSND_NO_LOOP);
3688 }
3689
3690 void RaiseScore(int value)
3691 {
3692   Score += value;
3693   DrawText(DX_SCORE,DY_SCORE,int2str(Score,5),FS_SMALL,FC_YELLOW);
3694 }
3695
3696 void RaiseScoreElement(int element)
3697 {
3698   switch(element)
3699   {
3700     case EL_EDELSTEIN:
3701       RaiseScore(level.score[SC_EDELSTEIN]);
3702       break;
3703     case EL_DIAMANT:
3704       RaiseScore(level.score[SC_DIAMANT]);
3705       break;
3706     case EL_KAEFER:
3707     case EL_BUTTERFLY:
3708       RaiseScore(level.score[SC_KAEFER]);
3709       break;
3710     case EL_FLIEGER:
3711     case EL_FIREFLY:
3712       RaiseScore(level.score[SC_FLIEGER]);
3713       break;
3714     case EL_MAMPFER:
3715     case EL_MAMPFER2:
3716       RaiseScore(level.score[SC_MAMPFER]);
3717       break;
3718     case EL_ROBOT:
3719       RaiseScore(level.score[SC_ROBOT]);
3720       break;
3721     case EL_PACMAN:
3722       RaiseScore(level.score[SC_PACMAN]);
3723       break;
3724     case EL_KOKOSNUSS:
3725       RaiseScore(level.score[SC_KOKOSNUSS]);
3726       break;
3727     case EL_DYNAMIT:
3728       RaiseScore(level.score[SC_DYNAMIT]);
3729       break;
3730     case EL_SCHLUESSEL:
3731       RaiseScore(level.score[SC_SCHLUESSEL]);
3732       break;
3733     default:
3734       break;
3735   }
3736 }