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