rnd-19980907
[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       {
1795         int nextJX = JX + (JX - lastJX);
1796         int nextJY = JY + (JY - lastJY);
1797
1798         if (!(PlayerPushing && PlayerGfxPos && x == nextJX && y == nextJY))
1799           DrawGraphicAnimation(x,y, GFX_SONDE_START, 8, 2, ANIM_NORMAL);
1800       }
1801
1802       return;
1803     }
1804
1805     if (element==EL_ROBOT && IN_SCR_FIELD(x,y))
1806       PlaySoundLevel(x,y,SND_SCHLURF);
1807
1808     InitMovingField(x,y,MovDir[x][y]);
1809   }
1810
1811   if (MovDir[x][y])
1812     ContinueMoving(x,y);
1813 }
1814
1815 void ContinueMoving(int x, int y)
1816 {
1817   int element = Feld[x][y];
1818   int direction = MovDir[x][y];
1819   int dx = (direction==MV_LEFT ? -1 : direction==MV_RIGHT ? +1 : 0);
1820   int dy = (direction==MV_UP   ? -1 : direction==MV_DOWN  ? +1 : 0);
1821   int horiz_move = (dx!=0);
1822   int newx = x + dx, newy = y + dy;
1823   int step = (horiz_move ? dx : dy) * TILEX/8;
1824
1825   if (CAN_FALL(element) && horiz_move)
1826     step*=2;
1827   else if (element==EL_TROPFEN)
1828     step/=2;
1829   else if (Store[x][y]==EL_MORAST_VOLL || Store[x][y]==EL_MORAST_LEER)
1830     step/=4;
1831
1832   MovPos[x][y] += step;
1833
1834   if (ABS(MovPos[x][y])>=TILEX)         /* Zielfeld erreicht */
1835   {
1836     Feld[x][y] = EL_LEERRAUM;
1837     Feld[newx][newy] = element;
1838
1839     if (Store[x][y]==EL_MORAST_VOLL)
1840     {
1841       Store[x][y] = 0;
1842       Feld[newx][newy] = EL_MORAST_VOLL;
1843       element = EL_MORAST_VOLL;
1844     }
1845     else if (Store[x][y]==EL_MORAST_LEER)
1846     {
1847       Store[x][y] = 0;
1848       Feld[x][y] = EL_MORAST_LEER;
1849     }
1850     else if (Store[x][y]==EL_SIEB_VOLL)
1851     {
1852       Store[x][y] = 0;
1853       element = Feld[newx][newy] = (SiebAktiv ? EL_SIEB_VOLL : EL_SIEB_TOT);
1854     }
1855     else if (Store[x][y]==EL_SIEB_LEER)
1856     {
1857       Store[x][y] = Store2[x][y] = 0;
1858       Feld[x][y] = (SiebAktiv ? EL_SIEB_LEER : EL_SIEB_TOT);
1859     }
1860     else if (Store[x][y]==EL_SIEB2_VOLL)
1861     {
1862       Store[x][y] = 0;
1863       element = Feld[newx][newy] = (SiebAktiv ? EL_SIEB2_VOLL : EL_SIEB2_TOT);
1864     }
1865     else if (Store[x][y]==EL_SIEB2_LEER)
1866     {
1867       Store[x][y] = Store2[x][y] = 0;
1868       Feld[x][y] = (SiebAktiv ? EL_SIEB2_LEER : EL_SIEB2_TOT);
1869     }
1870     else if (Store[x][y]==EL_SALZSAEURE)
1871     {
1872       Store[x][y] = 0;
1873       Feld[newx][newy] = EL_SALZSAEURE;
1874       element = EL_SALZSAEURE;
1875     }
1876     else if (Store[x][y]==EL_AMOEBE_NASS)
1877     {
1878       Store[x][y] = 0;
1879       Feld[x][y] = EL_AMOEBE_NASS;
1880     }
1881
1882     MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
1883     MovDelay[newx][newy] = 0;
1884
1885     if (!CAN_MOVE(element))
1886       MovDir[newx][newy] = 0;
1887
1888     DrawLevelField(x,y);
1889     DrawLevelField(newx,newy);
1890
1891     Stop[newx][newy] = TRUE;
1892     JustHit[x][newy] = 3;
1893
1894     if (DONT_TOUCH(element))    /* Käfer oder Flieger */
1895     {
1896       TestIfBadThingHitsHero();
1897       TestIfBadThingHitsFriend(newx,newy);
1898       TestIfBadThingHitsOtherBadThing(newx,newy);
1899     }
1900     else if (element == EL_PINGUIN)
1901       TestIfFriendHitsBadThing(newx,newy);
1902
1903     if (CAN_SMASH(element) && direction==MV_DOWN &&
1904         (newy==lev_fieldy-1 || !IS_FREE(x,newy+1)))
1905       Impact(x,newy);
1906   }
1907   else                          /* noch in Bewegung */
1908     DrawLevelField(x,y);
1909 }
1910
1911 int AmoebeNachbarNr(int ax, int ay)
1912 {
1913   int i;
1914   int element = Feld[ax][ay];
1915   int group_nr = 0;
1916   static int xy[4][2] =
1917   {
1918     { 0,-1 },
1919     { -1,0 },
1920     { +1,0 },
1921     { 0,+1 }
1922   };
1923
1924   for(i=0;i<4;i++)
1925   {
1926     int x = ax+xy[i%4][0];
1927     int y = ay+xy[i%4][1];
1928
1929     if (!IN_LEV_FIELD(x,y))
1930       continue;
1931
1932     if (Feld[x][y]==element && AmoebaNr[x][y]>0)
1933       group_nr = AmoebaNr[x][y];
1934   }
1935
1936   return(group_nr);
1937 }
1938
1939 void AmoebenVereinigen(int ax, int ay)
1940 {
1941   int i,x,y,xx,yy;
1942   int new_group_nr = AmoebaNr[ax][ay];
1943   static int xy[4][2] =
1944   {
1945     { 0,-1 },
1946     { -1,0 },
1947     { +1,0 },
1948     { 0,+1 }
1949   };
1950
1951   if (!new_group_nr)
1952     return;
1953
1954   for(i=0;i<4;i++)
1955   {
1956     x = ax+xy[i%4][0];
1957     y = ay+xy[i%4][1];
1958
1959     if (!IN_LEV_FIELD(x,y))
1960       continue;
1961
1962     if ((Feld[x][y]==EL_AMOEBE_VOLL ||
1963          Feld[x][y]==EL_AMOEBE_BD ||
1964          Feld[x][y]==EL_AMOEBE_TOT) &&
1965         AmoebaNr[x][y] != new_group_nr)
1966     {
1967       int old_group_nr = AmoebaNr[x][y];
1968
1969       AmoebaCnt[new_group_nr] += AmoebaCnt[old_group_nr];
1970       AmoebaCnt[old_group_nr] = 0;
1971       AmoebaCnt2[new_group_nr] += AmoebaCnt2[old_group_nr];
1972       AmoebaCnt2[old_group_nr] = 0;
1973
1974       for(yy=0;yy<lev_fieldy;yy++) for(xx=0;xx<lev_fieldx;xx++)
1975         if (AmoebaNr[xx][yy]==old_group_nr)
1976           AmoebaNr[xx][yy] = new_group_nr;
1977     }
1978   }
1979 }
1980
1981 void AmoebeUmwandeln(int ax, int ay)
1982 {
1983   int i,x,y;
1984   int group_nr = AmoebaNr[ax][ay];
1985   static int xy[4][2] =
1986   {
1987     { 0,-1 },
1988     { -1,0 },
1989     { +1,0 },
1990     { 0,+1 }
1991   };
1992
1993   if (Feld[ax][ay]==EL_AMOEBE_TOT)
1994   {
1995     for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
1996     {
1997       if (Feld[x][y]==EL_AMOEBE_TOT && AmoebaNr[x][y]==group_nr)
1998       {
1999         AmoebaNr[x][y] = 0;
2000         Feld[x][y] = EL_AMOEBA2DIAM;
2001       }
2002     }
2003     Bang(ax,ay);
2004   }
2005   else
2006   {
2007     for(i=0;i<4;i++)
2008     {
2009       x = ax+xy[i%4][0];
2010       y = ay+xy[i%4][1];
2011
2012       if (!IN_LEV_FIELD(x,y))
2013         continue;
2014
2015       if (Feld[x][y]==EL_AMOEBA2DIAM)
2016         Bang(x,y);
2017     }
2018   }
2019 }
2020
2021 void AmoebeUmwandeln2(int ax, int ay, int new_element)
2022 {
2023   int x,y;
2024   int group_nr = AmoebaNr[ax][ay];
2025   BOOL done = FALSE;
2026
2027   for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
2028   {
2029     if (AmoebaNr[x][y]==group_nr &&
2030         (Feld[x][y]==EL_AMOEBE_TOT ||
2031          Feld[x][y]==EL_AMOEBE_BD ||
2032          Feld[x][y]==EL_AMOEBING))
2033     {
2034       AmoebaNr[x][y] = 0;
2035       Feld[x][y] = new_element;
2036       DrawLevelField(x,y);
2037       done = TRUE;
2038     }
2039   }
2040
2041   if (done)
2042     PlaySoundLevel(ax,ay,new_element==EL_FELSBROCKEN ? SND_KLOPF : SND_PLING);
2043 }
2044
2045 void AmoebeWaechst(int x, int y)
2046 {
2047   static long sound_delay = 0;
2048   static int sound_delay_value = 0;
2049
2050   if (!MovDelay[x][y])          /* neue Phase / noch nicht gewartet */
2051   {
2052     MovDelay[x][y] = 7;
2053
2054     if (DelayReached(&sound_delay,sound_delay_value))
2055     {
2056       PlaySoundLevel(x,y,SND_AMOEBE);
2057       sound_delay_value = 30;
2058     }
2059   }
2060
2061   if (MovDelay[x][y])           /* neue Phase / in Wartezustand */
2062   {
2063     MovDelay[x][y]--;
2064     if (MovDelay[x][y] && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
2065       DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_AMOEBING+3-MovDelay[x][y]/2);
2066
2067     if (!MovDelay[x][y])
2068     {
2069       Feld[x][y] = Store[x][y];
2070       Store[x][y] = 0;
2071       DrawLevelField(x,y);
2072     }
2073   }
2074 }
2075
2076 void AmoebeAbleger(int ax, int ay)
2077 {
2078   int i;
2079   int element = Feld[ax][ay];
2080   int newax = ax, neway = ay;
2081   static int xy[4][2] =
2082   {
2083     { 0,-1 },
2084     { -1,0 },
2085     { +1,0 },
2086     { 0,+1 }
2087   };
2088
2089   if (!level.tempo_amoebe)
2090   {
2091     Feld[ax][ay] = EL_AMOEBE_TOT;
2092     DrawLevelField(ax,ay);
2093     return;
2094   }
2095
2096   if (!MovDelay[ax][ay])        /* neue Amoebe / noch nicht gewartet */
2097     MovDelay[ax][ay] = RND(FRAMES_PER_SECOND * 25/(1+level.tempo_amoebe));
2098
2099   if (MovDelay[ax][ay])         /* neue Amoebe / in Wartezustand */
2100   {
2101     MovDelay[ax][ay]--;
2102     if (MovDelay[ax][ay])
2103       return;
2104   }
2105
2106   if (element==EL_AMOEBE_NASS)  /* tropfende Amöbe */
2107   {
2108     int start = RND(4);
2109     int x = ax+xy[start][0];
2110     int y = ay+xy[start][1];
2111
2112     if (!IN_LEV_FIELD(x,y))
2113       return;
2114
2115     if (IS_FREE(x,y) ||
2116         Feld[x][y]==EL_ERDREICH || Feld[x][y]==EL_MORAST_LEER)
2117     {
2118       newax = x;
2119       neway = y;
2120     }
2121
2122     if (newax==ax && neway==ay)
2123       return;
2124   }
2125   else                          /* normale oder "gefüllte" Amöbe */
2126   {
2127     int start = RND(4);
2128     BOOL waiting_for_player = FALSE;
2129
2130     for(i=0;i<4;i++)
2131     {
2132       int j = (start+i)%4;
2133       int x = ax+xy[j][0];
2134       int y = ay+xy[j][1];
2135
2136       if (!IN_LEV_FIELD(x,y))
2137         continue;
2138
2139       if (IS_FREE(x,y) ||
2140           Feld[x][y]==EL_ERDREICH || Feld[x][y]==EL_MORAST_LEER)
2141       {
2142         newax = x;
2143         neway = y;
2144         break;
2145       }
2146       else if (IS_PLAYER(x,y))
2147         waiting_for_player = TRUE;
2148     }
2149
2150     if (newax==ax && neway==ay)
2151     {
2152       if (i==4 && !waiting_for_player)
2153       {
2154         Feld[ax][ay] = EL_AMOEBE_TOT;
2155         DrawLevelField(ax,ay);
2156         AmoebaCnt[AmoebaNr[ax][ay]]--;
2157
2158         if (AmoebaCnt[AmoebaNr[ax][ay]]<=0)     /* Amöbe vollständig tot */
2159         {
2160           if (element==EL_AMOEBE_VOLL)
2161             AmoebeUmwandeln(ax,ay);
2162           else if (element==EL_AMOEBE_BD)
2163             AmoebeUmwandeln2(ax,ay,level.amoebe_inhalt);
2164         }
2165       }
2166       return;
2167     }
2168     else if (element==EL_AMOEBE_VOLL || element==EL_AMOEBE_BD)
2169     {
2170       int new_group_nr = AmoebaNr[ax][ay];
2171
2172       AmoebaNr[newax][neway] = new_group_nr;
2173       AmoebaCnt[new_group_nr]++;
2174       AmoebaCnt2[new_group_nr]++;
2175       AmoebenVereinigen(newax,neway);
2176
2177       if (AmoebaCnt2[new_group_nr] >= 200 && element==EL_AMOEBE_BD)
2178       {
2179         AmoebeUmwandeln2(newax,neway,EL_FELSBROCKEN);
2180         return;
2181       }
2182     }
2183   }
2184
2185   if (element!=EL_AMOEBE_NASS || neway<ay || !IS_FREE(newax,neway) ||
2186       (neway==lev_fieldy-1 && newax!=ax))
2187   {
2188     Feld[newax][neway] = EL_AMOEBING;
2189     Store[newax][neway] = element;
2190   }
2191   else if (neway==ay)
2192     Feld[newax][neway] = EL_TROPFEN;
2193   else
2194   {
2195     InitMovingField(ax,ay,MV_DOWN);
2196     Feld[ax][ay] = EL_TROPFEN;
2197     Store[ax][ay] = EL_AMOEBE_NASS;
2198     ContinueMoving(ax,ay);
2199     return;
2200   }
2201
2202   DrawLevelField(newax,neway);
2203 }
2204
2205 void Life(int ax, int ay)
2206 {
2207   int x1,y1,x2,y2;
2208   static int life[4] = { 2,3,3,3 };     /* "Life"-Parameter */
2209   int life_time = 40;
2210   int element = Feld[ax][ay];
2211
2212   if (Stop[ax][ay])
2213     return;
2214
2215   if (!MovDelay[ax][ay])        /* neue Phase / noch nicht gewartet */
2216     MovDelay[ax][ay] = life_time;
2217
2218   if (MovDelay[ax][ay])         /* neue Phase / in Wartezustand */
2219   {
2220     MovDelay[ax][ay]--;
2221     if (MovDelay[ax][ay])
2222       return;
2223   }
2224
2225   for(y1=-1;y1<2;y1++) for(x1=-1;x1<2;x1++)
2226   {
2227     int xx = ax+x1, yy = ay+y1;
2228     int nachbarn = 0;
2229
2230     if (!IN_LEV_FIELD(xx,yy))
2231       continue;
2232
2233     for(y2=-1;y2<2;y2++) for(x2=-1;x2<2;x2++)
2234     {
2235       int x = xx+x2, y = yy+y2;
2236
2237       if (!IN_LEV_FIELD(x,y) || (x==xx && y==yy))
2238         continue;
2239
2240       if (((Feld[x][y]==element || (element==EL_LIFE && IS_PLAYER(x,y))) &&
2241            !Stop[x][y]) ||
2242           (IS_FREE(x,y) && Stop[x][y]))
2243         nachbarn++;
2244     }
2245
2246     if (xx==ax && yy==ay)               /* mittleres Feld mit Amoebe */
2247     {
2248       if (nachbarn<life[0] || nachbarn>life[1])
2249       {
2250         Feld[xx][yy] = EL_LEERRAUM;
2251         if (!Stop[xx][yy])
2252           DrawLevelField(xx,yy);
2253         Stop[xx][yy] = TRUE;
2254       }
2255     }
2256     else if (IS_FREE(xx,yy) || Feld[xx][yy]==EL_ERDREICH)
2257     {                                   /* Randfeld ohne Amoebe */
2258       if (nachbarn>=life[2] && nachbarn<=life[3])
2259       {
2260         Feld[xx][yy] = element;
2261         MovDelay[xx][yy] = (element==EL_LIFE ? 0 : life_time-1);
2262         if (!Stop[xx][yy])
2263           DrawLevelField(xx,yy);
2264         Stop[xx][yy] = TRUE;
2265       }
2266     }
2267   }
2268 }
2269
2270 void Ablenk(int x, int y)
2271 {
2272   if (!MovDelay[x][y])          /* neue Phase / noch nicht gewartet */
2273     MovDelay[x][y] = level.dauer_ablenk * FRAMES_PER_SECOND;
2274
2275   if (MovDelay[x][y])           /* neue Phase / in Wartezustand */
2276   {
2277     MovDelay[x][y]--;
2278     if (MovDelay[x][y])
2279     {
2280       if (IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
2281         DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_ABLENK+MovDelay[x][y]%4);
2282       if (!(MovDelay[x][y]%4))
2283         PlaySoundLevel(x,y,SND_MIEP);
2284       return;
2285     }
2286   }
2287
2288   Feld[x][y] = EL_ABLENK_AUS;
2289   DrawLevelField(x,y);
2290   if (ZX==x && ZY==y)
2291     ZX = ZY = -1;
2292 }
2293
2294 void Birne(int x, int y)
2295 {
2296   if (!MovDelay[x][y])          /* neue Phase / noch nicht gewartet */
2297     MovDelay[x][y] = 800;
2298
2299   if (MovDelay[x][y])           /* neue Phase / in Wartezustand */
2300   {
2301     MovDelay[x][y]--;
2302     if (MovDelay[x][y])
2303     {
2304       if (!(MovDelay[x][y]%5))
2305       {
2306         if (!(MovDelay[x][y]%10))
2307           Feld[x][y]=EL_ABLENK_EIN;
2308         else
2309           Feld[x][y]=EL_ABLENK_AUS;
2310         DrawLevelField(x,y);
2311         Feld[x][y]=EL_ABLENK_EIN;
2312       }
2313       return;
2314     }
2315   }
2316
2317   Feld[x][y]=EL_ABLENK_AUS;
2318   DrawLevelField(x,y);
2319   if (ZX==x && ZY==y)
2320     ZX=ZY=-1;
2321 }
2322
2323 void Blubber(int x, int y)
2324 {
2325   DrawGraphicAnimation(x,y, GFX_GEBLUBBER, 4, 10, ANIM_NORMAL);
2326 }
2327
2328 void NussKnacken(int x, int y)
2329 {
2330   if (!MovDelay[x][y])          /* neue Phase / noch nicht gewartet */
2331     MovDelay[x][y] = 7;
2332
2333   if (MovDelay[x][y])           /* neue Phase / in Wartezustand */
2334   {
2335     MovDelay[x][y]--;
2336     if (MovDelay[x][y] && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
2337       DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_CRACKINGNUT+3-MovDelay[x][y]/2);
2338
2339     if (!MovDelay[x][y])
2340     {
2341       Feld[x][y] = EL_EDELSTEIN;
2342       DrawLevelField(x,y);
2343     }
2344   }
2345 }
2346
2347 void SiebAktivieren(int x, int y, int typ)
2348 {
2349   if (SiebAktiv%2 && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
2350     DrawGraphic(SCROLLX(x),SCROLLY(y),
2351                 (typ==1 ? GFX_SIEB_VOLL : GFX_SIEB2_VOLL)+3-(SiebAktiv%8)/2);
2352 }
2353
2354 void AusgangstuerPruefen(int x, int y)
2355 {
2356   if (!Gems && !SokobanFields && !Lights)
2357   {
2358     Feld[x][y] = EL_AUSGANG_ACT;
2359
2360     if (IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
2361       PlaySoundLevel(x,y,SND_OEFFNEN);
2362     else
2363       PlaySoundLevel(JX,JY,SND_OEFFNEN);
2364   }
2365 }
2366
2367 void AusgangstuerOeffnen(int x, int y)
2368 {
2369   int delay = 6;
2370
2371   if (!MovDelay[x][y])          /* neue Phase / noch nicht gewartet */
2372     MovDelay[x][y] = 5*delay;
2373
2374   if (MovDelay[x][y])           /* neue Phase / in Wartezustand */
2375   {
2376     int tuer;
2377
2378     MovDelay[x][y]--;
2379     tuer = MovDelay[x][y]/delay;
2380     if (!(MovDelay[x][y]%delay) && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
2381       DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_AUSGANG_AUF-tuer);
2382
2383     if (!MovDelay[x][y])
2384     {
2385       Feld[x][y] = EL_AUSGANG_AUF;
2386       DrawLevelField(x,y);
2387     }
2388   }
2389 }
2390
2391 void AusgangstuerBlinken(int x, int y)
2392 {
2393   DrawGraphicAnimation(x,y, GFX_AUSGANG_AUF, 4, 4, ANIM_OSCILLATE);
2394 }
2395
2396 void EdelsteinFunkeln(int x, int y)
2397 {
2398   if (!IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)) || IS_MOVING(x,y))
2399     return;
2400
2401   if (Feld[x][y] == EL_EDELSTEIN_BD)
2402     DrawGraphicAnimation(x,y, GFX_EDELSTEIN_BD, 4, 4, ANIM_REVERSE);
2403   else
2404   {
2405     if (!MovDelay[x][y])        /* neue Phase / noch nicht gewartet */
2406       MovDelay[x][y] = 11 * !SimpleRND(500);
2407
2408     if (MovDelay[x][y])         /* neue Phase / in Wartezustand */
2409     {
2410       MovDelay[x][y]--;
2411
2412       if (direct_draw_on && MovDelay[x][y])
2413         SetDrawtoField(DRAW_BUFFERED);
2414
2415       DrawGraphic(SCROLLX(x),SCROLLY(y), el2gfx(Feld[x][y]));
2416
2417       if (MovDelay[x][y])
2418       {
2419         int src_x,src_y, dest_x,dest_y;
2420         int phase = (MovDelay[x][y]-1)/2;
2421
2422         src_x  = SX+GFX_PER_LINE*TILEX;
2423         src_y  = SY+(phase > 2 ? 4-phase : phase)*TILEY;
2424         dest_x = FX+SCROLLX(x)*TILEX;
2425         dest_y = FY+SCROLLY(y)*TILEY;
2426
2427         XSetClipOrigin(display,clip_gc[PIX_BACK],dest_x-src_x,dest_y-src_y);
2428         XCopyArea(display,pix[PIX_BACK],drawto_field,clip_gc[PIX_BACK],
2429                   src_x,src_y, TILEX,TILEY, dest_x,dest_y);
2430
2431         if (direct_draw_on)
2432         {
2433           XCopyArea(display,drawto_field,window,gc,
2434                     dest_x,dest_y, TILEX,TILEY, dest_x,dest_y);
2435           SetDrawtoField(DRAW_DIRECT);
2436         }
2437       }
2438     }
2439   }
2440 }
2441
2442 void MauerWaechst(int x, int y)
2443 {
2444   int delay = 6;
2445
2446   if (!MovDelay[x][y])          /* neue Phase / noch nicht gewartet */
2447     MovDelay[x][y] = 3*delay;
2448
2449   if (MovDelay[x][y])           /* neue Phase / in Wartezustand */
2450   {
2451     int phase;
2452
2453     MovDelay[x][y]--;
2454     phase = 2-MovDelay[x][y]/delay;
2455     if (!(MovDelay[x][y]%delay) && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
2456       DrawGraphic(SCROLLX(x),SCROLLY(y),
2457                   (Store[x][y]==MV_LEFT ? GFX_MAUER_L1 : GFX_MAUER_R1)+phase);
2458
2459     if (!MovDelay[x][y])
2460     {
2461       if (Store[x][y]==MV_LEFT)
2462       {
2463         if (IN_LEV_FIELD(x-1,y) && IS_MAUER(Feld[x-1][y]))
2464           DrawLevelField(x-1,y);
2465       }
2466       else
2467       {
2468         if (IN_LEV_FIELD(x+1,y) && IS_MAUER(Feld[x+1][y]))
2469           DrawLevelField(x+1,y);
2470       }
2471
2472       Feld[x][y] = EL_MAUER_LEBT;
2473       Store[x][y] = 0;
2474       DrawLevelField(x,y);
2475     }
2476   }
2477 }
2478
2479 void MauerAbleger(int ax, int ay)
2480 {
2481   BOOL links_frei = FALSE, rechts_frei = FALSE;
2482   BOOL links_massiv = FALSE, rechts_massiv = FALSE;
2483
2484   if (!MovDelay[ax][ay])        /* neue Mauer / noch nicht gewartet */
2485     MovDelay[ax][ay] = 6;
2486
2487   if (MovDelay[ax][ay])         /* neue Mauer / in Wartezustand */
2488   {
2489     MovDelay[ax][ay]--;
2490     if (MovDelay[ax][ay])
2491       return;
2492   }
2493
2494   if (IN_LEV_FIELD(ax-1,ay) && IS_FREE(ax-1,ay))
2495     links_frei = TRUE;
2496   if (IN_LEV_FIELD(ax+1,ay) && IS_FREE(ax+1,ay))
2497     rechts_frei = TRUE;
2498
2499   if (links_frei)
2500   {
2501     Feld[ax-1][ay] = EL_MAUERND;
2502     Store[ax-1][ay] = MV_LEFT;
2503     if (IN_SCR_FIELD(SCROLLX(ax-1),SCROLLY(ay)))
2504       DrawGraphic(SCROLLX(ax-1),SCROLLY(ay),GFX_MAUER_L1);
2505   }
2506   if (rechts_frei)
2507   {
2508     Feld[ax+1][ay] = EL_MAUERND;
2509     Store[ax+1][ay] = MV_RIGHT;
2510     if (IN_SCR_FIELD(SCROLLX(ax+1),SCROLLY(ay)))
2511       DrawGraphic(SCROLLX(ax+1),SCROLLY(ay),GFX_MAUER_R1);
2512   }
2513
2514   if (links_frei || rechts_frei)
2515     DrawLevelField(ax,ay);
2516
2517   if (!IN_LEV_FIELD(ax-1,ay) || IS_MAUER(Feld[ax-1][ay]))
2518     links_massiv = TRUE;
2519   if (!IN_LEV_FIELD(ax+1,ay) || IS_MAUER(Feld[ax+1][ay]))
2520     rechts_massiv = TRUE;
2521
2522   if (links_massiv && rechts_massiv)
2523     Feld[ax][ay] = EL_MAUERWERK;
2524 }
2525
2526 void CheckForDragon(int x, int y)
2527 {
2528   int i,j;
2529   BOOL dragon_found = FALSE;
2530   static int xy[4][2] =
2531   {
2532     { 0,-1 },
2533     { -1,0 },
2534     { +1,0 },
2535     { 0,+1 }
2536   };
2537
2538   for(i=0;i<4;i++)
2539   {
2540     for(j=0;j<4;j++)
2541     {
2542       int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
2543
2544       if (IN_LEV_FIELD(xx,yy) &&
2545           (Feld[xx][yy] == EL_BURNING || Feld[xx][yy] == EL_DRACHE))
2546       {
2547         if (Feld[xx][yy] == EL_DRACHE)
2548           dragon_found = TRUE;
2549       }
2550       else
2551         break;
2552     }
2553   }
2554
2555   if (!dragon_found)
2556   {
2557     for(i=0;i<4;i++)
2558     {
2559       for(j=0;j<3;j++)
2560       {
2561         int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
2562   
2563         if (IN_LEV_FIELD(xx,yy) && Feld[xx][yy] == EL_BURNING)
2564         {
2565           Feld[xx][yy] = EL_LEERRAUM;
2566           DrawLevelField(xx,yy);
2567         }
2568         else
2569           break;
2570       }
2571     }
2572   }
2573 }
2574
2575 void GameActions()
2576 {
2577   static long action_delay = 0;
2578   long action_delay_value;
2579
2580   if (game_status != PLAYING)
2581     return;
2582
2583 /*
2584   action_delay_value =
2585     (tape.playing && tape.fast_forward ? FFWD_FRAME_DELAY : GAME_FRAME_DELAY);
2586 */
2587
2588   action_delay_value =
2589     (tape.playing && tape.fast_forward ? FFWD_FRAME_DELAY : GameSpeed);
2590
2591   /*
2592   if (DelayReached(&action_delay, action_delay_value))
2593   */
2594
2595
2596
2597   if (PlayerMovPos)
2598     ScrollFigure(0);
2599
2600   DrawPlayerField();
2601
2602
2603
2604
2605   tst++;
2606
2607   if (0)
2608   {
2609     static long last_Counter = 0;
2610     long new_Counter = Counter();
2611
2612     printf("--> %ld / %ld [%d]\n",
2613            new_Counter - last_Counter,
2614            new_Counter,
2615            FrameCounter);
2616     last_Counter = new_Counter;
2617   }
2618
2619
2620
2621
2622   /*
2623   if (!DelayReached(&action_delay, action_delay_value))
2624     return;
2625     */
2626
2627
2628   while(!DelayReached(&action_delay, action_delay_value))
2629     Delay(1000);
2630
2631
2632
2633
2634   /*
2635   printf("-----------\n");
2636   */
2637
2638
2639
2640   FrameCounter++;
2641
2642
2643
2644   /*
2645   if (PlayerMovPos)
2646     ScrollFigure(0);
2647
2648   DrawPlayerField();
2649   */
2650
2651
2652   tst2 = tst;
2653   tst = 0;
2654
2655
2656
2657   if (0)
2658   {
2659     static long last_Counter = 0;
2660     long new_Counter = Counter();
2661
2662     printf("--> %ld / %ld [%d]\n",
2663            new_Counter - last_Counter,
2664            new_Counter,
2665            FrameCounter);
2666     last_Counter = new_Counter;
2667   }
2668
2669
2670   /*
2671   printf("--> %ld / ", Counter());
2672   */
2673
2674
2675   {
2676     int x,y,element;
2677     int sieb_x = 0, sieb_y = 0;
2678
2679     if (tape.pausing || (tape.playing && !TapePlayDelay()))
2680       return;
2681     else if (tape.recording)
2682       TapeRecordDelay();
2683
2684
2685     /*
2686     FrameCounter++;
2687     */
2688
2689
2690     TimeFrames++;
2691
2692     for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
2693     {
2694       Stop[x][y] = FALSE;
2695       if (JustHit[x][y]>0)
2696         JustHit[x][y]--;
2697
2698 #if DEBUG
2699       if (IS_BLOCKED(x,y))
2700       {
2701         int oldx,oldy;
2702
2703         Blocked2Moving(x,y,&oldx,&oldy);
2704         if (!IS_MOVING(oldx,oldy))
2705         {
2706           printf("GameActions(): (BLOCKED=>MOVING) context corrupted!\n");
2707           printf("GameActions(): BLOCKED: x = %d, y = %d\n",x,y);
2708           printf("GameActions(): !MOVING: oldx = %d, oldy = %d\n",oldx,oldy);
2709           printf("GameActions(): This should never happen!\n");
2710         }
2711       }
2712 #endif
2713
2714     }
2715
2716     for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
2717     {
2718       element = Feld[x][y];
2719
2720       if (IS_INACTIVE(element))
2721         continue;
2722
2723       if (!IS_MOVING(x,y) && (CAN_FALL(element) || CAN_MOVE(element)))
2724       {
2725         StartMoving(x,y);
2726
2727         if (IS_GEM(element))
2728           EdelsteinFunkeln(x,y);
2729       }
2730       else if (IS_MOVING(x,y))
2731         ContinueMoving(x,y);
2732       else if (element==EL_DYNAMIT || element==EL_DYNABOMB)
2733         CheckDynamite(x,y);
2734       else if (element==EL_EXPLODING)
2735         Explode(x,y,Frame[x][y],EX_NORMAL);
2736       else if (element==EL_AMOEBING)
2737         AmoebeWaechst(x,y);
2738       else if (IS_AMOEBALIVE(element))
2739         AmoebeAbleger(x,y);
2740       else if (element==EL_LIFE || element==EL_LIFE_ASYNC)
2741         Life(x,y);
2742       else if (element==EL_ABLENK_EIN)
2743         Ablenk(x,y);
2744       else if (element==EL_SALZSAEURE)
2745         Blubber(x,y);
2746       else if (element==EL_BLURB_LEFT || element==EL_BLURB_RIGHT)
2747         Blurb(x,y);
2748       else if (element==EL_CRACKINGNUT)
2749         NussKnacken(x,y);
2750       else if (element==EL_AUSGANG_ZU)
2751         AusgangstuerPruefen(x,y);
2752       else if (element==EL_AUSGANG_ACT)
2753         AusgangstuerOeffnen(x,y);
2754       else if (element==EL_AUSGANG_AUF)
2755         AusgangstuerBlinken(x,y);
2756       else if (element==EL_MAUERND)
2757         MauerWaechst(x,y);
2758       else if (element==EL_MAUER_LEBT)
2759         MauerAbleger(x,y);
2760       else if (element==EL_BURNING)
2761         CheckForDragon(x,y);
2762
2763       if (SiebAktiv)
2764       {
2765         BOOL sieb = FALSE;
2766
2767         if (element==EL_SIEB_LEER || element==EL_SIEB_VOLL ||
2768             Store[x][y]==EL_SIEB_LEER)
2769         {
2770           SiebAktivieren(x, y, 1);
2771           sieb = TRUE;
2772         }
2773         else if (element==EL_SIEB2_LEER || element==EL_SIEB2_VOLL ||
2774                  Store[x][y]==EL_SIEB2_LEER)
2775         {
2776           SiebAktivieren(x, y, 2);
2777           sieb = TRUE;
2778         }
2779
2780         if (sieb && ABS(x-JX)+ABS(y-JY) < ABS(sieb_x-JX)+ABS(sieb_y-JY))
2781         {
2782           sieb_x = x;
2783           sieb_y = y;
2784         }
2785       }
2786     }
2787
2788     if (SiebAktiv)
2789     {
2790       if (!(SiebAktiv%4))
2791         PlaySoundLevel(sieb_x,sieb_y,SND_MIEP);
2792       SiebAktiv--;
2793       if (!SiebAktiv)
2794       {
2795         for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
2796         {
2797           element = Feld[x][y];
2798           if (element==EL_SIEB_LEER || element==EL_SIEB_VOLL)
2799           {
2800             Feld[x][y] = EL_SIEB_TOT;
2801             DrawLevelField(x,y);
2802           }
2803           else if (element==EL_SIEB2_LEER || element==EL_SIEB2_VOLL)
2804           {
2805             Feld[x][y] = EL_SIEB2_TOT;
2806             DrawLevelField(x,y);
2807           }
2808         }
2809       }
2810     }
2811   }
2812
2813
2814   /*
2815   printf("%ld\n", Counter());
2816   */
2817
2818
2819   if (TimeLeft>0 && TimeFrames>=(100/GameSpeed) && !tape.pausing)
2820   {
2821     TimeFrames = 0;
2822     TimeLeft--;
2823
2824     if (tape.recording || tape.playing)
2825       DrawVideoDisplay(VIDEO_STATE_TIME_ON,level.time-TimeLeft);
2826
2827     if (TimeLeft<=10)
2828       PlaySoundStereo(SND_GONG,PSND_MAX_RIGHT);
2829
2830     DrawText(DX_TIME,DY_TIME,int2str(TimeLeft,3),FS_SMALL,FC_YELLOW);
2831
2832     if (!TimeLeft)
2833       KillHero();
2834   }
2835
2836   DrawPlayerField();
2837
2838   BackToFront();
2839 }
2840
2841 void ScrollLevel(int dx, int dy)
2842 {
2843   int softscroll_offset = (soft_scrolling_on ? TILEX : 0);
2844   int x,y;
2845
2846   ScreenMovPos = PlayerGfxPos;
2847
2848   XCopyArea(display,drawto_field,drawto_field,gc,
2849             FX + TILEX*(dx==-1) - softscroll_offset,
2850             FY + TILEY*(dy==-1) - softscroll_offset,
2851             SXSIZE - TILEX*(dx!=0) + 2*softscroll_offset,
2852             SYSIZE - TILEY*(dy!=0) + 2*softscroll_offset,
2853             FX + TILEX*(dx==1) - softscroll_offset,
2854             FY + TILEY*(dy==1) - softscroll_offset);
2855
2856   if (dx)
2857   {
2858     x = (dx==1 ? BX1 : BX2);
2859     for(y=BY1; y<=BY2; y++)
2860       DrawScreenField(x,y);
2861   }
2862   if (dy)
2863   {
2864     y = (dy==1 ? BY1 : BY2);
2865     for(x=BX1; x<=BX2; x++)
2866       DrawScreenField(x,y);
2867   }
2868
2869   redraw_mask |= REDRAW_FIELD;
2870 }
2871
2872 BOOL MoveFigureOneStep(int dx, int dy, int real_dx, int real_dy)
2873 {
2874   int newJX = JX+dx, newJY = JY+dy;
2875   int element;
2876   int can_move;
2877
2878   if (PlayerGone || (!dx && !dy))
2879     return(MF_NO_ACTION);
2880
2881   PlayerMovDir = (dx < 0 ? MV_LEFT :
2882                   dx > 0 ? MV_RIGHT :
2883                   dy < 0 ? MV_UP :
2884                   dy > 0 ? MV_DOWN :    MV_NO_MOVING);
2885
2886   if (!IN_LEV_FIELD(newJX,newJY))
2887     return(MF_NO_ACTION);
2888
2889   element = MovingOrBlocked2Element(newJX,newJY);
2890
2891   if (DONT_GO_TO(element))
2892   {
2893     if (element==EL_SALZSAEURE && dx==0 && dy==1)
2894     {
2895       Blurb(JX,JY);
2896       Feld[JX][JY] = EL_SPIELFIGUR;
2897       InitMovingField(JX,JY,MV_DOWN);
2898       Store[JX][JY] = EL_SALZSAEURE;
2899       ContinueMoving(JX,JY);
2900       BuryHero();
2901     }
2902     else
2903       KillHero();
2904
2905     return(MF_MOVING);
2906   }
2907
2908   can_move = DigField(newJX,newJY, real_dx,real_dy, DF_DIG);
2909   if (can_move != MF_MOVING)
2910     return(can_move);
2911
2912   lastJX = JX;
2913   lastJY = JY;
2914   JX = newJX;
2915   JY = newJY;
2916
2917   PlayerMovPos = (dx > 0 || dy > 0 ? -1 : 1) * 7*TILEX/8;
2918
2919   ScrollFigure(-1);
2920
2921   return(MF_MOVING);
2922 }
2923
2924 BOOL MoveFigure(int dx, int dy)
2925 {
2926   static long move_delay = 0;
2927   static int last_move_dir = MV_NO_MOVING;
2928   int moved = MF_NO_ACTION;
2929   int oldJX = JX, oldJY = JY;
2930
2931   if (PlayerGone || (!dx && !dy))
2932     return(FALSE);
2933
2934   if (!FrameReached(&move_delay,MoveSpeed) && !tape.playing)
2935     return(FALSE);
2936
2937   if (last_move_dir & (MV_LEFT | MV_RIGHT))
2938   {
2939     if (!(moved |= MoveFigureOneStep(0,dy, dx,dy)))
2940       moved |= MoveFigureOneStep(dx,0, dx,dy);
2941   }
2942   else
2943   {
2944     if (!(moved |= MoveFigureOneStep(dx,0, dx,dy)))
2945       moved |= MoveFigureOneStep(0,dy, dx,dy);
2946   }
2947
2948   last_move_dir = MV_NO_MOVING;
2949
2950   if (moved & MF_MOVING)
2951   {
2952     int old_scroll_x = scroll_x, old_scroll_y = scroll_y;
2953     int offset = (scroll_delay_on ? 3 : 0);
2954
2955     if ((scroll_x < JX-MIDPOSX-offset || scroll_x > JX-MIDPOSX+offset) &&
2956         JX >= MIDPOSX-1-offset && JX <= lev_fieldx-(MIDPOSX-offset))
2957       scroll_x = JX-MIDPOSX + (scroll_x < JX-MIDPOSX ? -offset : offset);
2958     if ((scroll_y < JY-MIDPOSY-offset || scroll_y > JY-MIDPOSY+offset) &&
2959         JY >= MIDPOSY-1-offset && JY <= lev_fieldy-(MIDPOSY-offset))
2960       scroll_y = JY-MIDPOSY + (scroll_y < JY-MIDPOSY ? -offset : offset);
2961
2962     if (scroll_x != old_scroll_x || scroll_y != old_scroll_y)
2963       ScrollLevel(old_scroll_x - scroll_x, old_scroll_y - scroll_y);
2964   }
2965
2966   if (!(moved & MF_MOVING) && !PlayerPushing)
2967     PlayerFrame = 0;
2968   else
2969     PlayerFrame = (PlayerFrame + 1) % 4;
2970
2971   if (moved & MF_MOVING)
2972   {
2973     if (oldJX != JX && oldJY == JY)
2974       PlayerMovDir = (oldJX < JX ? MV_RIGHT : MV_LEFT);
2975     else if (oldJX == JX && oldJY != JY)
2976       PlayerMovDir = (oldJY < JY ? MV_DOWN : MV_UP);
2977
2978     DrawLevelField(JX,JY);      /* für "ErdreichAnbroeckeln()" */
2979
2980     last_move_dir = PlayerMovDir;
2981   }
2982
2983   TestIfHeroHitsBadThing();
2984
2985   if (PlayerGone)
2986     RemoveHero();
2987
2988   return(moved);
2989 }
2990
2991 void ScrollFigure(int init)
2992 {
2993   static long actual_frame_counter = 0;
2994   static int oldJX = -1, oldJY = -1;
2995
2996   if (init)
2997   {
2998
2999
3000
3001     PlayerGfxPos = ScrollStepSize * (PlayerMovPos / ScrollStepSize);
3002
3003
3004
3005     /*
3006     ScreenMovPos = PlayerGfxPos;
3007     redraw_mask |= REDRAW_FIELD;
3008     */
3009
3010
3011
3012     if (0)
3013     {
3014       static long last_Counter = 0;
3015       long new_Counter = Counter();
3016
3017       printf("--> %ld / %ld [%d, %d]\n",
3018              new_Counter - last_Counter,
3019              new_Counter,
3020              FrameCounter,
3021              tst2);
3022       last_Counter = new_Counter;
3023     }
3024
3025
3026
3027
3028     if (oldJX != -1 && oldJY != -1)
3029       DrawLevelElement(oldJX,oldJY, Feld[oldJX][oldJY]);
3030
3031     if (Feld[lastJX][lastJY] == EL_LEERRAUM &&
3032         IN_LEV_FIELD(lastJX,lastJY-1) &&
3033         CAN_FALL(Feld[lastJX][lastJY-1]))
3034       Feld[lastJX][lastJY] = EL_PLAYER_IS_LEAVING;
3035     DrawLevelElement(lastJX,lastJY, Feld[lastJX][lastJY]);
3036     DrawPlayerField();
3037
3038     oldJX = lastJX;
3039     oldJY = lastJY;
3040     actual_frame_counter = FrameCounter;
3041
3042     if (PlayerPushing)
3043     {
3044       int nextJX = JX + (JX - lastJX);
3045       int nextJY = JY + (JY - lastJY);
3046
3047       if (Feld[nextJX][nextJY] == EL_SOKOBAN_FELD_VOLL)
3048         DrawLevelElement(nextJX,nextJY, EL_SOKOBAN_FELD_LEER);
3049       else
3050         DrawLevelElement(nextJX,nextJY, EL_LEERRAUM);
3051     }
3052
3053     DrawPlayerField();
3054
3055     if (Store[lastJX][lastJY])
3056     {
3057       DrawGraphic(SCROLLX(lastJX),SCROLLY(lastJY),
3058                   el2gfx(Store[lastJX][lastJY]));
3059       DrawGraphicThruMask(SCROLLX(lastJX),SCROLLY(lastJY),
3060                           el2gfx(Feld[lastJX][lastJY]));
3061     }
3062     else if (Feld[lastJX][lastJY]==EL_DYNAMIT)
3063       DrawDynamite(lastJX,lastJY);
3064     else
3065       DrawLevelField(lastJX,lastJY);
3066
3067     return;
3068   }
3069   else if (!FrameReached(&actual_frame_counter,1))
3070     return;
3071
3072   PlayerMovPos += (PlayerMovPos > 0 ? -1 : 1) * TILEX/8;
3073   PlayerGfxPos = ScrollStepSize * (PlayerMovPos / ScrollStepSize);
3074
3075
3076   /*
3077   printf("PlayerGfxPos = %d\n", PlayerGfxPos);
3078   */
3079
3080
3081   if (ScreenMovPos && ScreenMovPos != PlayerGfxPos)
3082   {
3083     ScreenMovPos = PlayerGfxPos;
3084     redraw_mask |= REDRAW_FIELD;
3085   }
3086
3087   if (Feld[oldJX][oldJY] == EL_PLAYER_IS_LEAVING)
3088     Feld[oldJX][oldJY] = EL_LEERRAUM;
3089
3090   DrawLevelElement(oldJX,oldJY, Feld[oldJX][oldJY]);
3091   DrawPlayerField();
3092
3093
3094
3095   if (Store[oldJX][oldJY])
3096   {
3097     DrawGraphic(SCROLLX(oldJX),SCROLLY(oldJY),el2gfx(Store[oldJX][oldJY]));
3098     DrawGraphicThruMask(SCROLLX(oldJX),SCROLLY(oldJY),
3099                         el2gfx(Feld[oldJX][oldJY]));
3100   }
3101   else if (Feld[oldJX][oldJY]==EL_DYNAMIT)
3102     DrawDynamite(oldJX,oldJY);
3103   else
3104     DrawLevelField(oldJX,oldJY);
3105
3106   if (PlayerPushing)
3107   {
3108     int nextJX = JX + (JX - lastJX);
3109     int nextJY = JY + (JY - lastJY);
3110
3111     if (PlayerGfxPos)
3112     {
3113       if (Feld[nextJX][nextJY] == EL_SOKOBAN_FELD_VOLL)
3114         DrawLevelElement(nextJX,nextJY, EL_SOKOBAN_FELD_LEER);
3115       else
3116         DrawLevelElement(nextJX,nextJY, EL_LEERRAUM);
3117     }
3118     else
3119       DrawLevelElement(nextJX,nextJY, Feld[nextJX][nextJY]);
3120   }
3121
3122   if (!PlayerMovPos)
3123   {
3124     lastJX = JX;
3125     lastJY = JY;
3126
3127     oldJX = oldJY = -1;
3128   }
3129 }
3130
3131 void TestIfGoodThingHitsBadThing(int goodx, int goody)
3132 {
3133   int i, killx = goodx, killy = goody;
3134   static int xy[4][2] =
3135   {
3136     { 0,-1 },
3137     { -1,0 },
3138     { +1,0 },
3139     { 0,+1 }
3140   };
3141   static int harmless[4] =
3142   {
3143     MV_UP,
3144     MV_LEFT,
3145     MV_RIGHT,
3146     MV_DOWN
3147   };
3148
3149   for(i=0;i<4;i++)
3150   {
3151     int x,y,element;
3152
3153     x = goodx+xy[i][0];
3154     y = goody+xy[i][1];
3155     if (!IN_LEV_FIELD(x,y))
3156       continue;
3157
3158     element = Feld[x][y];
3159
3160     if (DONT_TOUCH(element))
3161     {
3162       if (MovDir[x][y]==harmless[i])
3163         continue;
3164
3165       killx = x;
3166       killy = y;
3167       break;
3168     }
3169   }
3170
3171   if (killx!=goodx || killy!=goody)
3172   {
3173     if (IS_PLAYER(goodx,goody))
3174       KillHero();
3175     else
3176       Bang(goodx,goody);
3177   }
3178 }
3179
3180 void TestIfBadThingHitsGoodThing(int badx, int bady)
3181 {
3182   int i, killx = badx, killy = bady;
3183   static int xy[4][2] =
3184   {
3185     { 0,-1 },
3186     { -1,0 },
3187     { +1,0 },
3188     { 0,+1 }
3189   };
3190   static int harmless[4] =
3191   {
3192     MV_UP,
3193     MV_LEFT,
3194     MV_RIGHT,
3195     MV_DOWN
3196   };
3197
3198   for(i=0;i<4;i++)
3199   {
3200     int x,y,element;
3201
3202     x = badx+xy[i][0];
3203     y = bady+xy[i][1];
3204     if (!IN_LEV_FIELD(x,y))
3205       continue;
3206
3207     element = Feld[x][y];
3208
3209     if (element==EL_PINGUIN)
3210     {
3211       if (MovDir[x][y]==harmless[i] && IS_MOVING(x,y))
3212         continue;
3213
3214       killx = x;
3215       killy = y;
3216       break;
3217     }
3218   }
3219
3220   if (killx!=badx || killy!=bady)
3221     Bang(killx,killy);
3222 }
3223
3224 void TestIfHeroHitsBadThing()
3225 {
3226   TestIfGoodThingHitsBadThing(JX,JY);
3227 }
3228
3229 void TestIfBadThingHitsHero()
3230 {
3231   TestIfGoodThingHitsBadThing(JX,JY);
3232   /* (no typo!) */
3233 }
3234
3235 void TestIfFriendHitsBadThing(int x, int y)
3236 {
3237   TestIfGoodThingHitsBadThing(x,y);
3238 }
3239
3240 void TestIfBadThingHitsFriend(int x, int y)
3241 {
3242   TestIfBadThingHitsGoodThing(x,y);
3243 }
3244
3245 void TestIfBadThingHitsOtherBadThing(int badx, int bady)
3246 {
3247   int i, killx=badx, killy=bady;
3248   static int xy[4][2] =
3249   {
3250     { 0,-1 },
3251     { -1,0 },
3252     { +1,0 },
3253     { 0,+1 }
3254   };
3255
3256   for(i=0;i<4;i++)
3257   {
3258     int x,y,element;
3259
3260     x=badx+xy[i][0];
3261     y=bady+xy[i][1];
3262     if (!IN_LEV_FIELD(x,y))
3263       continue;
3264
3265     element=Feld[x][y];
3266     if (IS_AMOEBOID(element) || element==EL_LIFE ||
3267         element==EL_AMOEBING || element==EL_TROPFEN)
3268     {
3269       killx=x;
3270       killy=y;
3271       break;
3272     }
3273   }
3274
3275   if (killx!=badx || killy!=bady)
3276     Bang(badx,bady);
3277 }
3278
3279 void KillHero()
3280 {
3281   if (PlayerGone)
3282     return;
3283
3284   if (IS_PFORTE(Feld[JX][JY]))
3285     Feld[JX][JY] = EL_LEERRAUM;
3286
3287   Bang(JX,JY);
3288   BuryHero();
3289 }
3290
3291 void BuryHero()
3292 {
3293   if (PlayerGone)
3294     return;
3295
3296   PlaySoundLevel(JX,JY,SND_AUTSCH);
3297   PlaySoundLevel(JX,JY,SND_LACHEN);
3298
3299   GameOver = TRUE;
3300   RemoveHero();
3301 }
3302
3303 void RemoveHero()
3304 {
3305   PlayerGone = TRUE;
3306
3307   ExitX = ZX = JX;
3308   ExitY = ZY = JY;
3309   JX = JY = -1;
3310 }
3311
3312 int DigField(int x, int y, int real_dx, int real_dy, int mode)
3313 {
3314   int dx = x-JX, dy = y-JY;
3315   int element;
3316   static long push_delay = 0;
3317   static int push_delay_value = 5;
3318
3319   if (!PlayerMovPos)
3320     PlayerPushing = FALSE;
3321
3322   if (mode == DF_NO_PUSH)
3323   {
3324     push_delay = 0;
3325     return(MF_NO_ACTION);
3326   }
3327
3328   if (IS_MOVING(x,y))
3329     return(MF_NO_ACTION);
3330
3331   element = Feld[x][y];
3332
3333   switch(element)
3334   {
3335     case EL_LEERRAUM:
3336       break;
3337
3338     case EL_ERDREICH:
3339       Feld[x][y] = EL_LEERRAUM;
3340       break;
3341
3342     case EL_EDELSTEIN:
3343     case EL_EDELSTEIN_BD:
3344     case EL_EDELSTEIN_GELB:
3345     case EL_EDELSTEIN_ROT:
3346     case EL_EDELSTEIN_LILA:
3347       Feld[x][y] = EL_LEERRAUM;
3348       MovDelay[x][y] = 0;       /* wegen EDELSTEIN_BD-Funkeln! */
3349       if (Gems>0)
3350         Gems--;
3351       RaiseScoreElement(EL_EDELSTEIN);
3352       DrawText(DX_EMERALDS,DY_EMERALDS,int2str(Gems,3),FS_SMALL,FC_YELLOW);
3353       PlaySoundLevel(x,y,SND_PONG);
3354       break;
3355
3356     case EL_DIAMANT:
3357       Feld[x][y] = EL_LEERRAUM;
3358       Gems -= 3;
3359       if (Gems<0)
3360         Gems=0;
3361       RaiseScoreElement(EL_DIAMANT);
3362       DrawText(DX_EMERALDS,DY_EMERALDS,int2str(Gems,3),FS_SMALL,FC_YELLOW);
3363       PlaySoundLevel(x,y,SND_PONG);
3364       break;
3365
3366     case EL_DYNAMIT_AUS:
3367       Feld[x][y] = EL_LEERRAUM;
3368       Dynamite++;
3369       RaiseScoreElement(EL_DYNAMIT);
3370       DrawText(DX_DYNAMITE,DY_DYNAMITE,int2str(Dynamite,3),FS_SMALL,FC_YELLOW);
3371       PlaySoundLevel(x,y,SND_PONG);
3372       break;
3373
3374     case EL_DYNABOMB_NR:
3375       Feld[x][y] = EL_LEERRAUM;
3376       DynaBombCount++;
3377       DynaBombsLeft++;
3378       RaiseScoreElement(EL_DYNAMIT);
3379       PlaySoundLevel(x,y,SND_PONG);
3380       break;
3381     case EL_DYNABOMB_SZ:
3382
3383       Feld[x][y] = EL_LEERRAUM;
3384       DynaBombSize++;
3385       RaiseScoreElement(EL_DYNAMIT);
3386       PlaySoundLevel(x,y,SND_PONG);
3387       break;
3388
3389     case EL_DYNABOMB_XL:
3390       Feld[x][y] = EL_LEERRAUM;
3391       DynaBombXL = TRUE;
3392       RaiseScoreElement(EL_DYNAMIT);
3393       PlaySoundLevel(x,y,SND_PONG);
3394       break;
3395
3396     case EL_SCHLUESSEL1:
3397     case EL_SCHLUESSEL2:
3398     case EL_SCHLUESSEL3:
3399     case EL_SCHLUESSEL4:
3400     {
3401       int key_nr = element-EL_SCHLUESSEL1;
3402
3403       Feld[x][y] = EL_LEERRAUM;
3404       Key[key_nr] = TRUE;
3405       RaiseScoreElement(EL_SCHLUESSEL);
3406       DrawMiniGraphicExtHiRes(drawto,gc,
3407                               DX_KEYS+key_nr*MINI_TILEX,DY_KEYS,
3408                               GFX_SCHLUESSEL1+key_nr);
3409       DrawMiniGraphicExtHiRes(window,gc,
3410                               DX_KEYS+key_nr*MINI_TILEX,DY_KEYS,
3411                               GFX_SCHLUESSEL1+key_nr);
3412       PlaySoundLevel(x,y,SND_PONG);
3413       break;
3414     }
3415
3416     case EL_ABLENK_AUS:
3417       Feld[x][y] = EL_ABLENK_EIN;
3418       ZX = x;
3419       ZY = y;
3420       DrawLevelField(x,y);
3421       return(MF_ACTION);
3422       break;
3423
3424     case EL_FELSBROCKEN:
3425     case EL_BOMBE:
3426     case EL_KOKOSNUSS:
3427     case EL_ZEIT_LEER:
3428       if (dy || mode==DF_SNAP)
3429         return(MF_NO_ACTION);
3430
3431       PlayerPushing = TRUE;
3432
3433       if (!IN_LEV_FIELD(x+dx,y+dy) || Feld[x+dx][y+dy] != EL_LEERRAUM)
3434         return(MF_NO_ACTION);
3435
3436       if (real_dy)
3437       {
3438         if (IN_LEV_FIELD(JX,JY+real_dy) && !IS_SOLID(Feld[JX][JY+real_dy]))
3439           return(MF_NO_ACTION);
3440       }
3441
3442       if (push_delay == 0)
3443         push_delay = FrameCounter;
3444       if (!FrameReached(&push_delay,push_delay_value) && !tape.playing)
3445         return(MF_NO_ACTION);
3446
3447       Feld[x][y] = EL_LEERRAUM;
3448       Feld[x+dx][y+dy] = element;
3449
3450       push_delay_value = 2+RND(8);
3451
3452       DrawLevelField(x+dx,y+dy);
3453       if (element==EL_FELSBROCKEN)
3454         PlaySoundLevel(x+dx,y+dy,SND_PUSCH);
3455       else if (element==EL_KOKOSNUSS)
3456         PlaySoundLevel(x+dx,y+dy,SND_KNURK);
3457       else
3458         PlaySoundLevel(x+dx,y+dy,SND_KLOPF);
3459       break;
3460
3461     case EL_PFORTE1:
3462     case EL_PFORTE2:
3463     case EL_PFORTE3:
3464     case EL_PFORTE4:
3465       if (!Key[element-EL_PFORTE1])
3466         return(MF_NO_ACTION);
3467       break;
3468
3469     case EL_PFORTE1X:
3470     case EL_PFORTE2X:
3471     case EL_PFORTE3X:
3472     case EL_PFORTE4X:
3473       if (!Key[element-EL_PFORTE1X])
3474         return(MF_NO_ACTION);
3475       break;
3476
3477     case EL_AUSGANG_ZU:
3478     case EL_AUSGANG_ACT:
3479       /* Tür ist (noch) nicht offen! */
3480       return(MF_NO_ACTION);
3481       break;
3482
3483     case EL_AUSGANG_AUF:
3484       if (mode==DF_SNAP)
3485         return(MF_NO_ACTION);
3486
3487       PlayerGone = TRUE;
3488       PlaySoundLevel(x,y,SND_BUING);
3489
3490       if (!Friends)
3491         LevelSolved = GameOver = TRUE;
3492
3493       break;
3494
3495     case EL_BIRNE_AUS:
3496       Feld[x][y] = EL_BIRNE_EIN;
3497       Lights--;
3498       DrawLevelField(x,y);
3499       PlaySoundLevel(x,y,SND_DENG);
3500       return(MF_ACTION);
3501       break;
3502
3503     case EL_ZEIT_VOLL:
3504       Feld[x][y] = EL_ZEIT_LEER;
3505       TimeLeft += 10;
3506       DrawText(DX_TIME,DY_TIME,int2str(TimeLeft,3),FS_SMALL,FC_YELLOW);
3507       DrawLevelField(x,y);
3508       PlaySoundStereo(SND_GONG,PSND_MAX_RIGHT);
3509       return(MF_ACTION);
3510       break;
3511
3512     case EL_SOKOBAN_FELD_LEER:
3513       break;
3514
3515     case EL_SOKOBAN_FELD_VOLL:
3516     case EL_SOKOBAN_OBJEKT:
3517     case EL_SONDE:
3518       if (mode==DF_SNAP)
3519         return(MF_NO_ACTION);
3520
3521       PlayerPushing = TRUE;
3522
3523       if (!IN_LEV_FIELD(x+dx,y+dy)
3524           || (Feld[x+dx][y+dy] != EL_LEERRAUM
3525               && (Feld[x+dx][y+dy] != EL_SOKOBAN_FELD_LEER
3526                   || !IS_SB_ELEMENT(element))))
3527         return(MF_NO_ACTION);
3528
3529       if (dx && real_dy)
3530       {
3531         if (IN_LEV_FIELD(JX,JY+real_dy) && !IS_SOLID(Feld[JX][JY+real_dy]))
3532           return(MF_NO_ACTION);
3533       }
3534       else if (dy && real_dx)
3535       {
3536         if (IN_LEV_FIELD(JX+real_dx,JY) && !IS_SOLID(Feld[JX+real_dx][JY]))
3537           return(MF_NO_ACTION);
3538       }
3539
3540       if (push_delay == 0)
3541         push_delay = FrameCounter;
3542       if (!FrameReached(&push_delay,push_delay_value) && !tape.playing)
3543         return(MF_NO_ACTION);
3544
3545       if (IS_SB_ELEMENT(element))
3546       {
3547         if (element == EL_SOKOBAN_FELD_VOLL)
3548         {
3549           Feld[x][y] = EL_SOKOBAN_FELD_LEER;
3550           SokobanFields++;
3551         }
3552         else
3553           Feld[x][y] = EL_LEERRAUM;
3554
3555         if (Feld[x+dx][y+dy] == EL_SOKOBAN_FELD_LEER)
3556         {
3557           Feld[x+dx][y+dy] = EL_SOKOBAN_FELD_VOLL;
3558           SokobanFields--;
3559           if (element == EL_SOKOBAN_OBJEKT)
3560             PlaySoundLevel(x,y,SND_DENG);
3561         }
3562         else
3563           Feld[x+dx][y+dy] = EL_SOKOBAN_OBJEKT;
3564       }
3565       else
3566       {
3567         Feld[x][y] = EL_LEERRAUM;
3568         Feld[x+dx][y+dy] = element;
3569       }
3570
3571       push_delay_value = 2;
3572
3573       DrawLevelField(x,y);
3574       DrawLevelField(x+dx,y+dy);
3575       PlaySoundLevel(x+dx,y+dy,SND_PUSCH);
3576
3577       if (IS_SB_ELEMENT(element) &&
3578           SokobanFields == 0 && game_emulation == EMU_SOKOBAN)
3579       {
3580         LevelSolved = GameOver = TRUE;
3581         PlaySoundLevel(x,y,SND_BUING);
3582       }
3583
3584       break;
3585
3586     case EL_MAULWURF:
3587     case EL_PINGUIN:
3588     case EL_SCHWEIN:
3589     case EL_DRACHE:
3590       break;
3591
3592     default:
3593       return(MF_NO_ACTION);
3594       break;
3595   }
3596
3597   push_delay = 0;
3598
3599   return(MF_MOVING);
3600 }
3601
3602 BOOL SnapField(int dx, int dy)
3603 {
3604   int x = JX+dx, y = JY+dy;
3605   static int snapped = FALSE;
3606
3607   if (PlayerGone || !IN_LEV_FIELD(x,y))
3608     return(FALSE);
3609   if (dx && dy)
3610     return(FALSE);
3611   if (!dx && !dy)
3612   {
3613     snapped = FALSE;
3614     return(FALSE);
3615   }
3616   if (snapped)
3617     return(FALSE);
3618
3619   PlayerMovDir = (dx < 0 ? MV_LEFT :
3620                   dx > 0 ? MV_RIGHT :
3621                   dy < 0 ? MV_UP :
3622                   dy > 0 ? MV_DOWN :    MV_NO_MOVING);
3623
3624   if (!DigField(x,y, 0,0, DF_SNAP))
3625     return(FALSE);
3626
3627   snapped = TRUE;
3628   DrawLevelField(x,y);
3629   BackToFront();
3630
3631   return(TRUE);
3632 }
3633
3634 BOOL PlaceBomb(void)
3635 {
3636   int element;
3637
3638   if (PlayerGone || PlayerMovPos)
3639     return(FALSE);
3640
3641   element = Feld[JX][JY];
3642
3643   if ((Dynamite==0 && DynaBombsLeft==0) ||
3644       element==EL_DYNAMIT || element==EL_DYNABOMB || element==EL_EXPLODING)
3645     return(FALSE);
3646
3647   if (element != EL_LEERRAUM)
3648     Store[JX][JY] = element;
3649
3650   if (Dynamite)
3651   {
3652     Feld[JX][JY] = EL_DYNAMIT;
3653     MovDelay[JX][JY] = 96;
3654     Dynamite--;
3655     DrawText(DX_DYNAMITE,DY_DYNAMITE,int2str(Dynamite,3),FS_SMALL,FC_YELLOW);
3656     DrawGraphicThruMask(SCROLLX(JX),SCROLLY(JY),GFX_DYNAMIT);
3657   }
3658   else
3659   {
3660     Feld[JX][JY] = EL_DYNABOMB;
3661     MovDelay[JX][JY] = 96;
3662     DynaBombsLeft--;
3663     DrawGraphicThruMask(SCROLLX(JX),SCROLLY(JY),GFX_DYNABOMB);
3664   }
3665
3666   return(TRUE);
3667 }
3668
3669 void PlaySoundLevel(int x, int y, int sound_nr)
3670 {
3671   int sx = SCROLLX(x), sy = SCROLLY(y);
3672   int volume, stereo;
3673   int silence_distance = 8;
3674
3675   if ((!sound_simple_on && !IS_LOOP_SOUND(sound_nr)) ||
3676       (!sound_loops_on && IS_LOOP_SOUND(sound_nr)))
3677     return;
3678
3679   if (!IN_LEV_FIELD(x,y) ||
3680       sx < -silence_distance || sx >= SCR_FIELDX+silence_distance ||
3681       sy < -silence_distance || sy >= SCR_FIELDY+silence_distance)
3682     return;
3683
3684   volume = PSND_MAX_VOLUME;
3685 #ifndef MSDOS
3686   stereo = (sx-SCR_FIELDX/2)*12;
3687 #else
3688   stereo = PSND_MIDDLE+(2*sx-(SCR_FIELDX-1))*5;
3689   if(stereo > PSND_MAX_RIGHT) stereo = PSND_MAX_RIGHT;
3690   if(stereo < PSND_MAX_LEFT) stereo = PSND_MAX_LEFT;
3691 #endif
3692
3693   if (!IN_SCR_FIELD(sx,sy))
3694   {
3695     int dx = ABS(sx-SCR_FIELDX/2)-SCR_FIELDX/2;
3696     int dy = ABS(sy-SCR_FIELDY/2)-SCR_FIELDY/2;
3697
3698     volume -= volume*(dx > dy ? dx : dy)/silence_distance;
3699   }
3700
3701   PlaySoundExt(sound_nr, volume, stereo, PSND_NO_LOOP);
3702 }
3703
3704 void RaiseScore(int value)
3705 {
3706   Score += value;
3707   DrawText(DX_SCORE,DY_SCORE,int2str(Score,5),FS_SMALL,FC_YELLOW);
3708 }
3709
3710 void RaiseScoreElement(int element)
3711 {
3712   switch(element)
3713   {
3714     case EL_EDELSTEIN:
3715       RaiseScore(level.score[SC_EDELSTEIN]);
3716       break;
3717     case EL_DIAMANT:
3718       RaiseScore(level.score[SC_DIAMANT]);
3719       break;
3720     case EL_KAEFER:
3721     case EL_BUTTERFLY:
3722       RaiseScore(level.score[SC_KAEFER]);
3723       break;
3724     case EL_FLIEGER:
3725     case EL_FIREFLY:
3726       RaiseScore(level.score[SC_FLIEGER]);
3727       break;
3728     case EL_MAMPFER:
3729     case EL_MAMPFER2:
3730       RaiseScore(level.score[SC_MAMPFER]);
3731       break;
3732     case EL_ROBOT:
3733       RaiseScore(level.score[SC_ROBOT]);
3734       break;
3735     case EL_PACMAN:
3736       RaiseScore(level.score[SC_PACMAN]);
3737       break;
3738     case EL_KOKOSNUSS:
3739       RaiseScore(level.score[SC_KOKOSNUSS]);
3740       break;
3741     case EL_DYNAMIT:
3742       RaiseScore(level.score[SC_DYNAMIT]);
3743       break;
3744     case EL_SCHLUESSEL:
3745       RaiseScore(level.score[SC_SCHLUESSEL]);
3746       break;
3747     default:
3748       break;
3749   }
3750 }