Merge branch 'master' into releases
[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
24 void GetPlayerConfig()
25 {
26   int old_joystick_nr = joystick_nr;
27
28   if (sound_status==SOUND_OFF)
29     player.setup &= ~SETUP_SOUND;
30   if (!sound_loops_allowed)
31   {
32     player.setup &= ~SETUP_SOUND_LOOPS;
33     player.setup &= ~SETUP_SOUND_MUSIC;
34   }
35
36   sound_on = SETUP_SOUND_ON(player.setup);
37   sound_loops_on = SETUP_SOUND_LOOPS_ON(player.setup);
38   sound_music_on = SETUP_SOUND_MUSIC_ON(player.setup);
39   toons_on = SETUP_TOONS_ON(player.setup);
40   direct_draw_on = SETUP_DIRECT_DRAW_ON(player.setup);
41   fading_on = SETUP_FADING_ON(player.setup);
42   autorecord_on = SETUP_RECORD_EACH_GAME_ON(player.setup);
43   joystick_nr = SETUP_2ND_JOYSTICK_ON(player.setup);
44   quick_doors = SETUP_QUICK_DOORS_ON(player.setup);
45
46   if (joystick_nr != old_joystick_nr)
47   {
48     if (joystick_device)
49       close(joystick_device);
50     InitJoystick();
51   }
52 }
53
54 void InitGame()
55 {
56   int i,x,y;
57
58   Dynamite = Score = 0;
59   Gems = level.edelsteine;
60   Key[0] = Key[1] = Key[2] = Key[3] = FALSE;
61   MampferNr = 0;
62   TimeLeft = level.time;
63   CheckMoving = TRUE;
64   CheckExploding = FALSE;
65   LevelSolved = GameOver = SiebAktiv = FALSE;
66   JX = JY = 0;
67   ZX = ZY = -1;
68
69   if (tape.recording)
70     TapeStartRecording();
71   else if (tape.playing)
72     TapeStartPlaying();
73
74   DigField(0,0,DF_NO_PUSH);
75   SnapField(0,0);
76
77   for(i=0;i<MAX_NUM_AMOEBA;i++)
78     AmoebaCnt[i] = 0;
79
80   for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
81   {
82     Feld[x][y] = Ur[x][y];
83     MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
84     Store[x][y] = Store2[x][y] = Frame[x][y] = AmoebaNr[x][y] = 0;
85
86     switch(Feld[x][y])
87     {
88       case EL_SPIELFIGUR:
89       case EL_SPIELER1:
90         Feld[x][y] = EL_LEERRAUM;
91         JX = x;
92         JY = y;
93         break;
94       case EL_SPIELER2:
95         Feld[x][y] = EL_LEERRAUM;
96         break;
97       case EL_BADEWANNE:
98         if (x<lev_fieldx-1 && Feld[x+1][y]==EL_SALZSAEURE)
99           Feld[x][y] = EL_BADEWANNE1;
100         else if (x>0 && Feld[x-1][y]==EL_SALZSAEURE)
101           Feld[x][y] = EL_BADEWANNE2;
102         else if (y>0 && Feld[x][y-1]==EL_BADEWANNE1)
103           Feld[x][y] = EL_BADEWANNE3;
104         else if (y>0 && Feld[x][y-1]==EL_SALZSAEURE)
105           Feld[x][y] = EL_BADEWANNE4;
106         else if (y>0 && Feld[x][y-1]==EL_BADEWANNE2)
107           Feld[x][y] = EL_BADEWANNE5;
108         break;
109       case EL_KAEFER_R:
110       case EL_KAEFER_O:
111       case EL_KAEFER_L:
112       case EL_KAEFER_U:
113       case EL_KAEFER:
114       case EL_FLIEGER_R:
115       case EL_FLIEGER_O:
116       case EL_FLIEGER_L:
117       case EL_FLIEGER_U:
118       case EL_FLIEGER:
119       case EL_PACMAN_R:
120       case EL_PACMAN_O:
121       case EL_PACMAN_L:
122       case EL_PACMAN_U:
123       case EL_MAMPFER:
124       case EL_ZOMBIE:
125       case EL_PACMAN:
126         InitMovDir(x,y);
127         break;
128       case EL_AMOEBE_VOLL:
129         InitAmoebaNr(x,y);
130         break;
131       case EL_TROPFEN:
132         if (y==lev_fieldy-1)
133         {
134           Feld[x][y] = EL_AMOEBING;
135           Store[x][y] = EL_AMOEBE_NASS;
136         }
137         break;
138       default:
139         break;
140     }
141   }
142
143   scroll_x = scroll_y = -1;
144   if (JX>=MIDPOSX-1)
145     scroll_x =
146       (JX<=lev_fieldx-MIDPOSX ? JX-MIDPOSX : lev_fieldx-SCR_FIELDX+1);
147   if (JY>=MIDPOSY-1)
148     scroll_y =
149       (JY<=lev_fieldy-MIDPOSY ? JY-MIDPOSY : lev_fieldy-SCR_FIELDY+1);
150
151   DrawLevel();
152   DrawLevelElement(JX,JY,EL_SPIELFIGUR);
153   FadeToFront();
154
155   XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
156             DOOR_GFX_PAGEX5,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
157             DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
158   DrawTextExt(pix[PIX_DB_DOOR],gc,
159               DOOR_GFX_PAGEX1+XX_LEVEL,DOOR_GFX_PAGEY1+YY_LEVEL,
160               int2str(level_nr,2),FS_SMALL,FC_YELLOW);
161   DrawTextExt(pix[PIX_DB_DOOR],gc,
162               DOOR_GFX_PAGEX1+XX_EMERALDS,DOOR_GFX_PAGEY1+YY_EMERALDS,
163               int2str(Gems,3),FS_SMALL,FC_YELLOW);
164   DrawTextExt(pix[PIX_DB_DOOR],gc,
165               DOOR_GFX_PAGEX1+XX_DYNAMITE,DOOR_GFX_PAGEY1+YY_DYNAMITE,
166               int2str(Dynamite,3),FS_SMALL,FC_YELLOW);
167   DrawTextExt(pix[PIX_DB_DOOR],gc,
168               DOOR_GFX_PAGEX1+XX_SCORE,DOOR_GFX_PAGEY1+YY_SCORE,
169               int2str(Score,5),FS_SMALL,FC_YELLOW);
170   DrawTextExt(pix[PIX_DB_DOOR],gc,
171               DOOR_GFX_PAGEX1+XX_TIME,DOOR_GFX_PAGEY1+YY_TIME,
172               int2str(TimeLeft,3),FS_SMALL,FC_YELLOW);
173
174   DrawGameButton(BUTTON_GAME_STOP);
175   DrawGameButton(BUTTON_GAME_PAUSE);
176   DrawGameButton(BUTTON_GAME_PLAY);
177   DrawSoundDisplay(BUTTON_SOUND_MUSIC | (BUTTON_ON * sound_music_on));
178   DrawSoundDisplay(BUTTON_SOUND_LOOPS | (BUTTON_ON * sound_loops_on));
179   DrawSoundDisplay(BUTTON_SOUND_SOUND | (BUTTON_ON * sound_on));
180   XCopyArea(display,drawto,pix[PIX_DB_DOOR],gc,
181             DX+GAME_CONTROL_XPOS,DY+GAME_CONTROL_YPOS,
182             GAME_CONTROL_XSIZE,2*GAME_CONTROL_YSIZE,
183             DOOR_GFX_PAGEX1+GAME_CONTROL_XPOS,
184             DOOR_GFX_PAGEY1+GAME_CONTROL_YPOS);
185
186   OpenDoor(DOOR_OPEN_1);
187
188   if (sound_music_on)
189     PlaySoundLoop(background_loop[level_nr % num_bg_loops]);
190
191   XAutoRepeatOff(display);
192 }
193
194 void InitMovDir(int x, int y)
195 {
196   int i, element = Feld[x][y];
197   static int xy[4][2] =
198   {
199     0,+1,
200     +1,0,
201     0,-1,
202     -1,0
203   };
204   static int direction[2][4] =
205   {
206     MV_RIGHT, MV_UP,   MV_LEFT,  MV_DOWN,
207     MV_LEFT,  MV_DOWN, MV_RIGHT, MV_UP
208   };
209
210   switch(element)
211   {
212     case EL_KAEFER_R:
213     case EL_KAEFER_O:
214     case EL_KAEFER_L:
215     case EL_KAEFER_U:
216       Feld[x][y] = EL_KAEFER;
217       MovDir[x][y] = direction[0][element-EL_KAEFER_R];
218       break;
219     case EL_FLIEGER_R:
220     case EL_FLIEGER_O:
221     case EL_FLIEGER_L:
222     case EL_FLIEGER_U:
223       Feld[x][y] = EL_FLIEGER;
224       MovDir[x][y] = direction[0][element-EL_FLIEGER_R];
225       break;
226     case EL_PACMAN_R:
227     case EL_PACMAN_O:
228     case EL_PACMAN_L:
229     case EL_PACMAN_U:
230       Feld[x][y] = EL_PACMAN;
231       MovDir[x][y] = direction[0][element-EL_PACMAN_R];
232       break;
233     default:
234       MovDir[x][y] = 1<<RND(4);
235       if (element!=EL_KAEFER && element!=EL_FLIEGER)
236         break;
237
238       for(i=0;i<4;i++)
239       {
240         int x1,y1;
241
242         x1 = x+xy[i][0];
243         y1 = y+xy[i][1];
244
245         if (!IN_LEV_FIELD(x1,y1) || !IS_FREE(x1,y1))
246         {
247           if (element==EL_KAEFER)
248           {
249             MovDir[x][y] = direction[0][i];
250             break;
251           }
252           else if (element==EL_FLIEGER)
253           {
254             MovDir[x][y] = direction[1][i];
255             break;
256           }
257         }
258       }
259       break;
260   }
261 }
262
263 void InitAmoebaNr(int x, int y)
264 {
265   int i;
266   int group_nr = AmoebeNachbarNr(x,y);
267
268   if (group_nr==0)
269   {
270     for(i=1;i<MAX_NUM_AMOEBA;i++)
271     {
272       if (AmoebaCnt[i]==0)
273       {
274         group_nr = i;
275         break;
276       }
277     }
278   }
279
280   AmoebaNr[x][y] = group_nr;
281   AmoebaCnt[group_nr]++;
282 }
283
284 void GameWon()
285 {
286   int hi_pos;
287   int bumplevel = FALSE;
288
289   if (sound_loops_on)
290     PlaySoundExt(SND_SIRR,PSND_MAX_VOLUME,PSND_MAX_RIGHT,PSND_LOOP);
291
292   if (TimeLeft>0) 
293   {
294     for(;TimeLeft>=0;TimeLeft--)
295     {
296       if (!sound_loops_on)
297         PlaySoundStereo(SND_SIRR,PSND_MAX_RIGHT);
298       if (TimeLeft && !(TimeLeft % 10))
299         RaiseScore(level.score[SC_ZEITBONUS]);
300       DrawText(DX_TIME,DY_TIME,int2str(TimeLeft,3),FS_SMALL,FC_YELLOW);
301       BackToFront();
302       Delay(10000);
303     }
304   }
305
306   if (sound_loops_on)
307     StopSound(SND_SIRR);
308   FadeSounds();
309
310   if (tape.playing)
311     return;
312
313   CloseDoor(DOOR_CLOSE_1);
314
315   if (level_nr==player.handicap &&
316       level_nr<leveldir[leveldir_nr].num_ready) 
317   { 
318     player.handicap++; 
319     bumplevel = TRUE;
320     SavePlayerInfo(PLAYER_LEVEL);
321   }
322
323   if ((hi_pos=NewHiScore())>=0) 
324   {
325     game_status = HALLOFFAME;
326     DrawHallOfFame(hi_pos);
327     if (bumplevel && TAPE_IS_EMPTY(tape))
328       level_nr++;
329   }
330   else
331   {
332     game_status = MAINMENU;
333     if (bumplevel && TAPE_IS_EMPTY(tape))
334       level_nr++;
335     DrawMainMenu();
336   }
337   BackToFront();
338 }
339
340 BOOL NewHiScore()
341 {
342   int k,l;
343   int position = -1;
344
345   LoadScore(level_nr);
346
347   if (!strcmp(player.alias_name,EMPTY_ALIAS) ||
348       Score<highscore[MAX_SCORE_ENTRIES-1].Score) 
349     return(-1);
350
351   for(k=0;k<MAX_SCORE_ENTRIES;k++) 
352   {
353     if (Score>highscore[k].Score)       /* Spieler kommt in Highscore-Liste */
354     {
355       if (k<MAX_SCORE_ENTRIES-1)
356       {
357         int m = MAX_SCORE_ENTRIES-1;
358
359 #ifdef ONE_PER_NAME
360         for(l=k;l<MAX_SCORE_ENTRIES;l++)
361           if (!strcmp(player.alias_name,highscore[l].Name))
362             m = l;
363         if (m==k)       /* Spieler überschreibt seine alte Position */
364           goto put_into_list;
365 #endif
366
367         for(l=m;l>k;l--)
368         {
369           strcpy(highscore[l].Name,highscore[l-1].Name);
370           highscore[l].Score = highscore[l-1].Score;
371         }
372       }
373
374 #ifdef ONE_PER_NAME
375       put_into_list:
376 #endif
377       sprintf(highscore[k].Name,player.alias_name);
378       highscore[k].Score = Score; 
379       position = k;
380       break;
381     }
382
383 #ifdef ONE_PER_NAME
384     else if (!strcmp(player.alias_name,highscore[k].Name))
385       break;    /* Spieler schon mit besserer Punktzahl in der Liste */
386 #endif
387
388   }
389
390   if (position>=0) 
391     SaveScore(level_nr);
392
393   return(position);
394 }
395
396 void InitMovingField(int x, int y, int direction)
397 {
398   int newx = x + (direction==MV_LEFT ? -1 : direction==MV_RIGHT ? +1 : 0);
399   int newy = y + (direction==MV_UP   ? -1 : direction==MV_DOWN  ? +1 : 0);
400
401   CheckMoving = TRUE;
402   MovDir[x][y] = direction;
403   MovDir[newx][newy] = direction;
404   if (Feld[newx][newy]==EL_LEERRAUM)
405     Feld[newx][newy] = EL_BLOCKED;
406 }
407
408 void Moving2Blocked(int x, int y, int *goes_to_x, int *goes_to_y)
409 {
410   int direction = MovDir[x][y];
411   int newx = x + (direction==MV_LEFT ? -1 : direction==MV_RIGHT ? +1 : 0);
412   int newy = y + (direction==MV_UP   ? -1 : direction==MV_DOWN  ? +1 : 0);
413
414   *goes_to_x = newx;
415   *goes_to_y = newy;
416 }
417
418 void Blocked2Moving(int x, int y, int *comes_from_x, int *comes_from_y)
419 {
420   int oldx = x, oldy = y;
421   int direction = MovDir[x][y];
422
423   if (direction==MV_LEFT)
424     oldx++;
425   else if (direction==MV_RIGHT)
426     oldx--;
427   else if (direction==MV_UP)
428     oldy++;
429   else if (direction==MV_DOWN)
430     oldy--;
431
432   *comes_from_x = oldx;
433   *comes_from_y = oldy;
434 }
435
436 int MovingOrBlocked2Element(int x, int y)
437 {
438   int element = Feld[x][y];
439
440   if (element==EL_BLOCKED)
441   {
442     int oldx,oldy;
443
444     Blocked2Moving(x,y,&oldx,&oldy);
445     return(Feld[oldx][oldy]);
446   }
447   else
448     return(element);
449 }
450
451 void RemoveMovingField(int x, int y)
452 {
453   int oldx=x,oldy=y, newx=x,newy=y;
454
455   if (Feld[x][y]!=EL_BLOCKED && !IS_MOVING(x,y))
456     return;
457
458   if (IS_MOVING(x,y))
459   {
460     Moving2Blocked(x,y,&newx,&newy);
461     if (Feld[newx][newy]!=EL_BLOCKED)
462       return;
463   }
464   else if (Feld[x][y]==EL_BLOCKED)
465   {
466     Blocked2Moving(x,y,&oldx,&oldy);
467     if (!IS_MOVING(oldx,oldy))
468       return;
469   }
470
471   Feld[oldx][oldy] = EL_LEERRAUM;
472   Feld[newx][newy] = EL_LEERRAUM;
473   MovPos[oldx][oldy] = MovDir[oldx][oldy] = MovDelay[oldx][oldy] = 0;
474   MovPos[newx][newy] = MovDir[newx][newy] = MovDelay[newx][newy] = 0;
475   DrawLevelField(oldx,oldy);
476   DrawLevelField(newx,newy);
477 }
478
479 void DrawDynamite(int x, int y)
480 {
481   int phase = (48-MovDelay[x][y])/6;
482
483   if (!IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
484     return;
485
486   if (phase>6)
487     phase = 6;
488
489   if (Store[x][y])
490   {
491     DrawGraphic(SCROLLX(x),SCROLLY(y),el2gfx(Store[x][y]));
492     if (PLAYER(x,y))
493       DrawGraphicThruMask(SCROLLX(JX),SCROLLY(JY),GFX_SPIELFIGUR);
494   }
495   else if (PLAYER(x,y))
496     DrawGraphic(SCROLLX(JX),SCROLLY(JY),GFX_SPIELFIGUR);
497
498   if (Store[x][y] || PLAYER(x,y))
499     DrawGraphicThruMask(SCROLLX(x),SCROLLY(y),GFX_DYNAMIT+phase);
500   else
501     DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_DYNAMIT+phase);
502 }
503
504 void CheckDynamite(int x, int y)
505 {
506   CheckExploding=TRUE;
507
508   if (MovDelay[x][y])           /* neues Dynamit / in Wartezustand */
509   {
510     MovDelay[x][y]--;
511     if (MovDelay[x][y])
512     {
513       if (!(MovDelay[x][y] % 6))
514       {
515         DrawDynamite(x,y);
516         PlaySoundLevel(x,y,SND_ZISCH);
517       }
518
519       return;
520     }
521   }
522
523   StopSound(SND_ZISCH);
524   Bang(x,y);
525 }
526
527 void Explode(int ex, int ey, int phase)
528 {
529   int x,y;
530   int num_phase = 9, delay = 1;
531   int last_phase = num_phase*delay;
532   int half_phase = (num_phase/2)*delay;
533
534   if (phase==0)                 /* Feld 'Store' initialisieren */
535   {
536     int center_element = Feld[ex][ey];
537
538     if (center_element==EL_BLOCKED)
539       center_element = MovingOrBlocked2Element(ex,ey);
540
541     for(y=ey-1;y<ey+2;y++) for(x=ex-1;x<ex+2;x++)
542     {
543       int element = Feld[x][y];
544
545       if (!IN_LEV_FIELD(x,y) || IS_MASSIV(element))
546         continue;
547
548       if (center_element==EL_AMOEBA2DIAM && (x!=ex || y!=ey))
549         continue;
550
551       if (element==EL_EXPLODING)
552         element = Store2[x][y];
553
554       if (PLAYER(ex,ey) || center_element==EL_KAEFER)
555         Store[x][y] = ((x==ex && y==ey) ? EL_DIAMANT : EL_EDELSTEIN);
556       else if (center_element==EL_MAMPFER)
557         Store[x][y] = level.mampfer_inhalt[MampferNr][x-ex+1][y-ey+1];
558       else if (center_element==EL_AMOEBA2DIAM)
559         Store[x][y] = level.amoebe_inhalt;
560       else if (element==EL_ERZ_EDEL)
561         Store[x][y] = EL_EDELSTEIN;
562       else if (element==EL_ERZ_DIAM)
563         Store[x][y] = EL_DIAMANT;
564       else if (!IS_PFORTE(Store[x][y]))
565         Store[x][y] = EL_LEERRAUM;
566
567       if (x!=ex || y!=ey || center_element==EL_AMOEBA2DIAM)
568         Store2[x][y] = element;
569
570       if (AmoebaNr[x][y] && (element==EL_AMOEBE_VOLL || element==EL_AMOEBING))
571         AmoebaCnt[AmoebaNr[x][y]]--;
572
573       RemoveMovingField(x,y);
574       Feld[x][y] = EL_EXPLODING;
575       MovDir[x][y] = MovPos[x][y] = 0;
576       AmoebaNr[x][y] = 0;
577       Frame[x][y] = 1;
578       Stop[x][y] = TRUE;
579     }
580
581     if (center_element==EL_MAMPFER)
582       MampferNr = (MampferNr+1) % 4;
583
584     return;
585   }
586
587   if (Stop[ex][ey])
588     return;
589
590   x = ex;
591   y = ey;
592
593   Frame[x][y] = (phase<last_phase ? phase+1 : 0);
594
595   if (phase==half_phase)
596   {
597     int element = Store2[x][y];
598
599     if (PLAYER(x,y))
600       KillHero();
601     else if (element==EL_BOMBE ||
602              element==EL_DYNAMIT ||
603              element==EL_DYNAMIT_AUS ||
604              element==EL_KAEFER)
605     {
606       Feld[x][y] = Store2[x][y];
607       Store2[x][y] = 0;
608       Bang(x,y);
609     }
610     else if (element==EL_AMOEBA2DIAM)
611       AmoebeUmwandeln(x,y);
612   }
613
614   if (phase==last_phase)
615   {
616     int element;
617
618     element = Feld[x][y] = Store[x][y];
619     Store[x][y] = Store2[x][y] = 0;
620     MovDir[x][y] = MovPos[x][y] = MovDelay[x][y] = 0;
621     if (CAN_MOVE(element) || COULD_MOVE(element))
622       InitMovDir(x,y);
623     DrawLevelField(x,y);
624   }
625   else if (!(phase%delay) && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
626   {
627     if (phase==delay)
628       ErdreichAnbroeckeln(SCROLLX(x),SCROLLY(y));
629
630     DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_EXPLOSION+(phase/delay-1));
631   }
632
633   CheckExploding=TRUE;
634 }
635
636 void Bang(int x, int y)
637 {
638   int element = Feld[x][y];
639
640   CheckExploding=TRUE;
641   PlaySoundLevel(x,y,SND_ROAAAR);
642
643   switch(element)
644   {
645     case EL_KAEFER:
646       RaiseScore(level.score[SC_KAEFER]);
647       break;
648     case EL_FLIEGER:
649       RaiseScore(level.score[SC_FLIEGER]);
650       break;
651     case EL_MAMPFER:
652       RaiseScore(level.score[SC_MAMPFER]);
653       break;
654     case EL_ZOMBIE:
655       RaiseScore(level.score[SC_ZOMBIE]);
656       break;
657     case EL_PACMAN:
658       RaiseScore(level.score[SC_PACMAN]);
659       break;
660     default:
661       break;
662   }
663
664   Explode(x,y,0);
665 }
666
667 void Blurb(int x, int y)
668 {
669   int element = Feld[x][y];
670
671   if (element!=EL_BLURB_LEFT && element!=EL_BLURB_RIGHT) /* Anfang */
672   {
673     PlaySoundLevel(x,y,SND_BLURB);
674     if (IN_LEV_FIELD(x-1,y) && IS_FREE(x-1,y) &&
675         (!IN_LEV_FIELD(x-1,y-1) ||
676          !CAN_FALL(MovingOrBlocked2Element(x-1,y-1))))
677     {
678       Feld[x-1][y] = EL_BLURB_LEFT;
679     }
680     if (IN_LEV_FIELD(x+1,y) && IS_FREE(x+1,y) &&
681         (!IN_LEV_FIELD(x+1,y-1) ||
682          !CAN_FALL(MovingOrBlocked2Element(x+1,y-1))))
683     {
684       Feld[x+1][y] = EL_BLURB_RIGHT;
685     }
686   }
687   else                                                   /* Blubbern */
688   {
689     int graphic = (element==EL_BLURB_LEFT ? GFX_BLURB_LEFT : GFX_BLURB_RIGHT);
690
691     CheckExploding=TRUE;
692
693     if (!MovDelay[x][y])        /* neue Phase / noch nicht gewartet */
694       MovDelay[x][y] = 5;
695
696     if (MovDelay[x][y])         /* neue Phase / in Wartezustand */
697     {
698       MovDelay[x][y]--;
699       if (MovDelay[x][y] && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
700         DrawGraphic(SCROLLX(x),SCROLLY(y),graphic+4-MovDelay[x][y]);
701
702       if (!MovDelay[x][y])
703       {
704         Feld[x][y] = EL_LEERRAUM;
705         DrawLevelField(x,y);
706       }
707     }
708   }
709 }
710
711 void Impact(int x, int y)
712 {
713   BOOL lastline = (y==lev_fieldy-1);
714   BOOL object_hit = FALSE;
715   int element = Feld[x][y];
716
717   /* Element darunter berührt? */
718   if (!lastline)
719     object_hit = (!IS_FREE(x,y+1) && (!IS_MOVING(x,y+1) ||
720                                       MovDir[x][y+1]!=MV_DOWN ||
721                                       MovPos[x][y+1]<=TILEY/2));
722
723   /* Auftreffendes Element fällt in Salzsäure */
724   if (!lastline && Feld[x][y+1]==EL_SALZSAEURE)
725   {
726     Blurb(x,y);
727     return;
728   }
729
730   /* Auftreffendes Element ist Bombe */
731   if (element==EL_BOMBE && (lastline || object_hit))
732   {
733     Bang(x,y);
734     return;
735   }
736
737   /* Auftreffendes Element ist Säuretropfen */
738   if (element==EL_TROPFEN && (lastline || object_hit))
739   {
740     if (object_hit && PLAYER(x,y+1))
741       KillHero();
742     else
743     {
744       Feld[x][y] = EL_AMOEBING;
745       Store[x][y] = EL_AMOEBE_NASS;
746     }
747     return;
748   }
749
750   /* Welches Element kriegt was auf die Rübe? */
751   if (!lastline && object_hit)
752   {
753     int smashed = Feld[x][y+1];
754
755     if (PLAYER(x,y+1))
756     {
757       KillHero();
758       return;
759     }
760     else if (element==EL_FELSBROCKEN)
761     {
762       if (IS_ENEMY(MovingOrBlocked2Element(x,y+1)))
763       {
764         Bang(x,y+1);
765         return;
766       }
767       else if (!IS_MOVING(x,y+1))
768       {
769         if (smashed==EL_BOMBE)
770         {
771           Bang(x,y+1);
772           return;
773         }
774         else if (smashed==EL_KOKOSNUSS)
775         {
776           Feld[x][y+1] = EL_CRACKINGNUT;
777           PlaySoundLevel(x,y,SND_KNACK);
778           RaiseScore(level.score[SC_KOKOSNUSS]);
779           return;
780         }
781         else if (smashed==EL_DIAMANT)
782         {
783           Feld[x][y+1] = EL_LEERRAUM;
784           PlaySoundLevel(x,y,SND_QUIRK);
785           return;
786         }
787       }
788     }
789   }
790
791   /* Kein Geräusch beim Durchqueren des Siebes */
792   if (!lastline && Feld[x][y+1]==EL_SIEB_LEER)
793     return;
794
795   /* Geräusch beim Auftreffen */
796   if (lastline || object_hit)
797   {
798     int sound;
799
800     switch(element)
801     {
802       case EL_EDELSTEIN:
803       case EL_DIAMANT:
804         sound = SND_PLING;
805         break;
806       case EL_KOKOSNUSS:
807         sound = SND_KLUMPF;
808         break;
809       case EL_FELSBROCKEN:
810         sound = SND_KLOPF;
811         break;
812       case EL_SCHLUESSEL:
813       case EL_SCHLUESSEL1:
814       case EL_SCHLUESSEL2:
815       case EL_SCHLUESSEL3:
816       case EL_SCHLUESSEL4:
817         sound = SND_KINK;
818         break;
819       case EL_ZEIT_VOLL:
820       case EL_ZEIT_LEER:
821         sound = SND_DENG;
822         break;
823       default:
824         sound = -1;
825         break;
826     }
827
828     if (sound>=0)
829       PlaySoundLevel(x,y,sound);
830   }
831 }
832
833 void TurnRound(int x, int y)
834 {
835   int element = Feld[x][y];
836   int direction = MovDir[x][y];
837
838   if (element==EL_KAEFER)
839   {
840     TestIfBadThingHitsOtherBadThing(x,y);
841
842     if (MovDir[x][y]==MV_LEFT)
843     {
844       if (IN_LEV_FIELD(x,y-1) && IS_FREE(x,y-1))
845         MovDir[x][y]=MV_UP;
846       else if (!IN_LEV_FIELD(x-1,y) || !IS_FREE(x-1,y))
847         MovDir[x][y]=MV_DOWN;
848     }
849     else if (MovDir[x][y]==MV_RIGHT)
850     {
851       if (IN_LEV_FIELD(x,y+1) && IS_FREE(x,y+1))
852         MovDir[x][y]=MV_DOWN;
853       else if (!IN_LEV_FIELD(x+1,y) || !IS_FREE(x+1,y))
854         MovDir[x][y]=MV_UP;
855     }
856     else if (MovDir[x][y]==MV_UP)
857     {
858       if (IN_LEV_FIELD(x+1,y) && IS_FREE(x+1,y))
859         MovDir[x][y]=MV_RIGHT;
860       else if (!IN_LEV_FIELD(x,y-1) || !IS_FREE(x,y-1))
861         MovDir[x][y]=MV_LEFT;
862     }
863     else if (MovDir[x][y]==MV_DOWN)
864     {
865       if (IN_LEV_FIELD(x-1,y) && IS_FREE(x-1,y))
866         MovDir[x][y]=MV_LEFT;
867       else if (!IN_LEV_FIELD(x,y+1) || !IS_FREE(x,y+1))
868         MovDir[x][y]=MV_RIGHT;
869     }
870
871     if (direction!=MovDir[x][y])
872       MovDelay[x][y]=5;
873   }
874   else if (element==EL_FLIEGER)
875   {
876     TestIfBadThingHitsOtherBadThing(x,y);
877
878     if (MovDir[x][y]==MV_LEFT)
879     {
880       if (IN_LEV_FIELD(x,y+1) && IS_FREE(x,y+1))
881         MovDir[x][y]=MV_DOWN;
882       else if (!IN_LEV_FIELD(x-1,y) || !IS_FREE(x-1,y))
883         MovDir[x][y]=MV_UP;
884     }
885     else if (MovDir[x][y]==MV_RIGHT)
886     {
887       if (IN_LEV_FIELD(x,y-1) && IS_FREE(x,y-1))
888         MovDir[x][y]=MV_UP;
889       else if (!IN_LEV_FIELD(x+1,y) || !IS_FREE(x+1,y))
890         MovDir[x][y]=MV_DOWN;
891     }
892     else if (MovDir[x][y]==MV_UP)
893     {
894       if (IN_LEV_FIELD(x-1,y) && IS_FREE(x-1,y))
895         MovDir[x][y]=MV_LEFT;
896       else if (!IN_LEV_FIELD(x,y-1) || !IS_FREE(x,y-1))
897         MovDir[x][y]=MV_RIGHT;
898     }
899     else if (MovDir[x][y]==MV_DOWN)
900     {
901       if (IN_LEV_FIELD(x+1,y) && IS_FREE(x+1,y))
902         MovDir[x][y]=MV_RIGHT;
903       else if (!IN_LEV_FIELD(x,y+1) || !IS_FREE(x,y+1))
904         MovDir[x][y]=MV_LEFT;
905     }
906
907     if (direction!=MovDir[x][y])
908       MovDelay[x][y]=5;
909   }
910   else if (element==EL_MAMPFER)
911   {
912     if (MovDir[x][y]==MV_LEFT || MovDir[x][y]==MV_RIGHT)
913     {
914       MovDir[x][y]=(MovDir[x][y]==MV_LEFT ? MV_RIGHT : MV_LEFT);
915       if (IN_LEV_FIELD(x,y-1) &&
916           (IS_FREE(x,y-1) || Feld[x][y-1]==EL_DIAMANT) &&
917           RND(2))
918         MovDir[x][y]=MV_UP;
919       if (IN_LEV_FIELD(x,y+1) &&
920           (IS_FREE(x,y+1) || Feld[x][y+1]==EL_DIAMANT) &&
921           RND(2))
922         MovDir[x][y]=MV_DOWN;
923     }
924     else if (MovDir[x][y]==MV_UP || MovDir[x][y]==MV_DOWN)
925     {
926       MovDir[x][y]=(MovDir[x][y]==MV_UP ? MV_DOWN : MV_UP);
927       if (IN_LEV_FIELD(x-1,y) &&
928           (IS_FREE(x-1,y) || Feld[x-1][y]==EL_DIAMANT) &&
929           RND(2))
930         MovDir[x][y]=MV_LEFT;
931       if (IN_LEV_FIELD(x+1,y) &&
932           (IS_FREE(x+1,y) || Feld[x+1][y]==EL_DIAMANT) &&
933           RND(2))
934         MovDir[x][y]=MV_RIGHT;
935     }
936
937     MovDelay[x][y]=8+8*RND(3);
938   }
939   else if (element==EL_PACMAN)
940   {
941     if (MovDir[x][y]==MV_LEFT || MovDir[x][y]==MV_RIGHT)
942     {
943       MovDir[x][y]=(MovDir[x][y]==MV_LEFT ? MV_RIGHT : MV_LEFT);
944       if (IN_LEV_FIELD(x,y-1) &&
945           (IS_FREE(x,y-1) || IS_AMOEBOID(Feld[x][y-1])) &&
946           RND(2))
947         MovDir[x][y]=MV_UP;
948       if (IN_LEV_FIELD(x,y+1) &&
949           (IS_FREE(x,y+1) || IS_AMOEBOID(Feld[x][y+1])) &&
950           RND(2))
951         MovDir[x][y]=MV_DOWN;
952     }
953     else if (MovDir[x][y]==MV_UP || MovDir[x][y]==MV_DOWN)
954     {
955       MovDir[x][y]=(MovDir[x][y]==MV_UP ? MV_DOWN : MV_UP);
956       if (IN_LEV_FIELD(x-1,y) &&
957           (IS_FREE(x-1,y) || IS_AMOEBOID(Feld[x-1][y])) &&
958           RND(2))
959         MovDir[x][y]=MV_LEFT;
960       if (IN_LEV_FIELD(x+1,y) &&
961           (IS_FREE(x+1,y) || IS_AMOEBOID(Feld[x+1][y])) &&
962           RND(2))
963         MovDir[x][y]=MV_RIGHT;
964     }
965
966     MovDelay[x][y]=3+RND(20);
967   }
968   else if (element==EL_ZOMBIE)
969   {
970     int attr_x = JX, attr_y = JY;
971
972     if (ZX>=0 && ZY>=0)
973     {
974       attr_x = ZX;
975       attr_y = ZY;
976     }
977
978     MovDir[x][y]=MV_NO_MOVING;
979     if (attr_x<x)
980       MovDir[x][y]|=MV_LEFT;
981     else if (attr_x>x)
982       MovDir[x][y]|=MV_RIGHT;
983     if (attr_y<y)
984       MovDir[x][y]|=MV_UP;
985     else if (attr_y>y)
986       MovDir[x][y]|=MV_DOWN;
987     if ((MovDir[x][y]&(MV_LEFT|MV_RIGHT)) && (MovDir[x][y]&(MV_UP|MV_DOWN)))
988       MovDir[x][y] &= (RND(2) ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
989
990     MovDelay[x][y] = 8+8*RND(2);
991   }
992 }
993
994 void StartMoving(int x, int y)
995 {
996   int element = Feld[x][y];
997
998   if (Stop[x][y])
999     return;
1000
1001   if (CAN_FALL(element) && y<lev_fieldy-1)
1002   {
1003     if (element==EL_MORAST_VOLL)
1004     {
1005       if (IS_FREE(x,y+1))
1006       {
1007         InitMovingField(x,y,MV_DOWN);
1008         Feld[x][y] = EL_FELSBROCKEN;
1009         Store[x][y] = EL_MORAST_LEER;
1010       }
1011       else if (Feld[x][y+1]==EL_MORAST_LEER)
1012       {
1013         CheckMoving=TRUE;
1014
1015         if (!MovDelay[x][y])
1016           MovDelay[x][y] = 16;
1017
1018         if (MovDelay[x][y])
1019         {
1020           MovDelay[x][y]--;
1021           if (MovDelay[x][y])
1022             return;
1023         }
1024
1025         Feld[x][y] = EL_MORAST_LEER;
1026         Feld[x][y+1] = EL_MORAST_VOLL;
1027       }
1028     }
1029     else if (element==EL_FELSBROCKEN && Feld[x][y+1]==EL_MORAST_LEER)
1030     {
1031       InitMovingField(x,y,MV_DOWN);
1032       Store[x][y] = EL_MORAST_VOLL;
1033     }
1034     else if (element==EL_SIEB_VOLL)
1035     {
1036       if (IS_FREE(x,y+1))
1037       {
1038         InitMovingField(x,y,MV_DOWN);
1039         Feld[x][y] = EL_CHANGED(Store2[x][y]);
1040         Store[x][y] = EL_SIEB_LEER;
1041       }
1042     }
1043     else if (CAN_CHANGE(element) && Feld[x][y+1]==EL_SIEB_LEER)
1044     {
1045       InitMovingField(x,y,MV_DOWN);
1046       Store[x][y] = EL_SIEB_VOLL;
1047       Store2[x][y+1] = element;
1048       SiebAktiv = 330;
1049     }
1050     else if (CAN_SMASH(element) && Feld[x][y+1]==EL_SALZSAEURE)
1051     {
1052       Blurb(x,y);
1053       InitMovingField(x,y,MV_DOWN);
1054       Store[x][y] = EL_SALZSAEURE;
1055     }
1056     else if (CAN_SMASH(element) && Feld[x][y+1]==EL_BLOCKED)
1057     {
1058       Impact(x,y);
1059     }
1060     else if (IS_FREE(x,y+1))
1061     {
1062       InitMovingField(x,y,MV_DOWN);
1063     }
1064     else if (element==EL_TROPFEN)
1065     {
1066       Feld[x][y] = EL_AMOEBING;
1067       Store[x][y] = EL_AMOEBE_NASS;
1068     }
1069     else if (IS_SLIPPERY(Feld[x][y+1]) && !Store[x][y+1])
1070     {
1071       int left  = (x>0 && IS_FREE(x-1,y) &&
1072                    (IS_FREE(x-1,y+1) || Feld[x-1][y+1]==EL_SALZSAEURE));
1073       int right = (x<lev_fieldx-1 && IS_FREE(x+1,y) &&
1074                    (IS_FREE(x+1,y+1) || Feld[x+1][y+1]==EL_SALZSAEURE));
1075
1076       if (left || right)
1077       {
1078         if (left && right)
1079           left = !(right=RND(2));
1080         InitMovingField(x,y,left ? MV_LEFT : MV_RIGHT);
1081       }
1082     }
1083   }
1084   else if (CAN_MOVE(element))
1085   {
1086     int newx,newy;
1087
1088     CheckMoving = TRUE;
1089
1090     if (!MovDelay[x][y])        /* neuer Schritt / noch nicht gewartet */
1091     {
1092       if (element==EL_ZOMBIE || element==EL_KAEFER || element==EL_FLIEGER)
1093       {
1094         TurnRound(x,y);
1095         if (MovDelay[x][y] && (element==EL_KAEFER || element==EL_FLIEGER))
1096           DrawLevelField(x,y);
1097       }
1098     }
1099
1100     if (MovDelay[x][y])         /* neuer Schritt / in Wartezustand */
1101     {
1102       MovDelay[x][y]--;
1103
1104       if (element==EL_ZOMBIE || element==EL_MAMPFER)
1105       {
1106         int phase = MovDelay[x][y] % 8;
1107
1108         if (phase>3)
1109           phase = 7-phase;
1110
1111         if (IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
1112           DrawGraphic(SCROLLX(x),SCROLLY(y),
1113                       el2gfx(element)+phase);
1114
1115         if (element==EL_MAMPFER && MovDelay[x][y]%4==3)
1116           PlaySoundLevel(x,y,SND_NJAM);
1117       }
1118
1119       if (MovDelay[x][y])
1120         return;
1121     }
1122
1123     if (element==EL_KAEFER)
1124     {
1125       PlaySoundLevel(x,y,SND_KLAPPER);
1126     }
1127     else if (element==EL_FLIEGER)
1128     {
1129       PlaySoundLevel(x,y,SND_ROEHR);
1130     }
1131
1132     /* neuer Schritt / Wartezustand beendet */
1133
1134     Moving2Blocked(x,y,&newx,&newy);    /* wohin soll's gehen? */
1135
1136     if (PLAYER(newx,newy))              /* Spieler erwischt */
1137     {
1138       MovDir[x][y] = 0;
1139       KillHero();
1140       return;
1141     }
1142     else if (element==EL_MAMPFER && IN_LEV_FIELD(newx,newy) &&
1143              Feld[newx][newy]==EL_DIAMANT)
1144     {
1145       if (IS_MOVING(newx,newy))
1146         RemoveMovingField(newx,newy);
1147       else
1148       {
1149         Feld[newx][newy] = EL_LEERRAUM;
1150         DrawLevelField(newx,newy);
1151       }
1152     }
1153     else if (element==EL_PACMAN && IN_LEV_FIELD(newx,newy) &&
1154              IS_AMOEBOID(Feld[newx][newy]))
1155     {
1156       if (AmoebaNr[newx][newy] && Feld[newx][newy]==EL_AMOEBE_VOLL)
1157         AmoebaCnt[AmoebaNr[newx][newy]]--;
1158
1159       Feld[newx][newy] = EL_LEERRAUM;
1160       DrawLevelField(newx,newy);
1161     }
1162     else if (element==EL_ZOMBIE && IN_LEV_FIELD(newx,newy) &&
1163              MovDir[x][y]==MV_DOWN && Feld[newx][newy]==EL_SALZSAEURE)
1164     {
1165       Blurb(x,y);
1166       Store[x][y] = EL_SALZSAEURE;
1167     }
1168     else if (!IN_LEV_FIELD(newx,newy) || !IS_FREE(newx,newy))
1169     {                                   /* gegen Wand gelaufen */
1170       TurnRound(x,y);
1171       DrawLevelField(x,y);
1172       return;
1173     }
1174
1175     InitMovingField(x,y,MovDir[x][y]);
1176   }
1177
1178   if (MovDir[x][y])
1179     ContinueMoving(x,y);
1180 }
1181
1182 void ContinueMoving(int x, int y)
1183 {
1184   int element = Feld[x][y];
1185   int direction = MovDir[x][y];
1186   int dx = (direction==MV_LEFT ? -1 : direction==MV_RIGHT ? +1 : 0);
1187   int dy = (direction==MV_UP   ? -1 : direction==MV_DOWN  ? +1 : 0);
1188   int horiz_move = (dx!=0);
1189   int newx = x + dx, newy = y + dy;
1190   int step = (horiz_move ? dx : dy)*TILEX/4;
1191
1192   if (CAN_FALL(element) && horiz_move)
1193     step*=2;
1194   else if (element==EL_TROPFEN)
1195     step/=2;
1196   else if (Store[x][y]==EL_MORAST_VOLL || Store[x][y]==EL_MORAST_LEER)
1197     step/=4;
1198
1199   MovPos[x][y] += step;
1200
1201   if (ABS(MovPos[x][y])>=TILEX)         /* Zielfeld erreicht */
1202   {
1203     Feld[x][y]=EL_LEERRAUM;
1204     Feld[newx][newy]=element;
1205
1206     if (Store[x][y]==EL_MORAST_VOLL)
1207     {
1208       Store[x][y] = 0;
1209       Feld[newx][newy] = EL_MORAST_VOLL;
1210       element = EL_MORAST_VOLL;
1211     }
1212     else if (Store[x][y]==EL_MORAST_LEER)
1213     {
1214       Store[x][y] = 0;
1215       Feld[x][y] = EL_MORAST_LEER;
1216     }
1217     else if (Store[x][y]==EL_SIEB_VOLL)
1218     {
1219       Store[x][y] = 0;
1220       Feld[newx][newy] = EL_SIEB_VOLL;
1221       element = EL_SIEB_VOLL;
1222     }
1223     else if (Store[x][y]==EL_SIEB_LEER)
1224     {
1225       Store[x][y] = Store2[x][y] = 0;
1226       Feld[x][y] = EL_SIEB_LEER;
1227     }
1228     else if (Store[x][y]==EL_SALZSAEURE)
1229     {
1230       Store[x][y] = 0;
1231       Feld[newx][newy] = EL_SALZSAEURE;
1232       element = EL_SALZSAEURE;
1233     }
1234     else if (Store[x][y]==EL_AMOEBE_NASS)
1235     {
1236       Store[x][y] = 0;
1237       Feld[x][y] = EL_AMOEBE_NASS;
1238     }
1239
1240     MovPos[x][y] = MovDir[x][y] = 0;
1241
1242     if (!CAN_MOVE(element))
1243       MovDir[newx][newy] = 0;
1244
1245     DrawLevelField(x,y);
1246     DrawLevelField(newx,newy);
1247
1248     Stop[newx][newy]=TRUE;
1249     CheckMoving=TRUE;
1250
1251     if (DONT_TOUCH(element))    /* Käfer oder Flieger */
1252     {
1253       TestIfBadThingHitsHero();
1254       TestIfBadThingHitsOtherBadThing(newx,newy);
1255     }
1256
1257     if (CAN_SMASH(element) && direction==MV_DOWN &&
1258         (newy==lev_fieldy-1 || !IS_FREE(x,newy+1)))
1259       Impact(x,newy);
1260   }
1261   else                          /* noch in Bewegung */
1262   {
1263     DrawLevelField(x,y);
1264     CheckMoving=TRUE;
1265   }
1266 }
1267
1268 int AmoebeNachbarNr(int ax, int ay)
1269 {
1270   int i;
1271   int element = Feld[ax][ay];
1272   int group_nr = 0;
1273   static int xy[4][2] =
1274   {
1275     0,-1,
1276     -1,0,
1277     +1,0,
1278     0,+1
1279   };
1280
1281   for(i=0;i<4;i++)
1282   {
1283     int x = ax+xy[i%4][0];
1284     int y = ay+xy[i%4][1];
1285
1286     if (!IN_LEV_FIELD(x,y))
1287       continue;
1288
1289     if (Feld[x][y]==element && AmoebaNr[x][y]>0)
1290       group_nr = AmoebaNr[x][y];
1291   }
1292
1293   return(group_nr);
1294 }
1295
1296 void AmoebenVereinigen(int ax, int ay)
1297 {
1298   int i,x,y,xx,yy;
1299   int new_group_nr = AmoebaNr[ax][ay];
1300   static int xy[4][2] =
1301   {
1302     0,-1,
1303     -1,0,
1304     +1,0,
1305     0,+1
1306   };
1307
1308   if (!new_group_nr)
1309     return;
1310
1311   for(i=0;i<4;i++)
1312   {
1313     x = ax+xy[i%4][0];
1314     y = ay+xy[i%4][1];
1315
1316     if (!IN_LEV_FIELD(x,y))
1317       continue;
1318
1319     if ((Feld[x][y]==EL_AMOEBE_VOLL || Feld[x][y]==EL_AMOEBE_TOT) &&
1320         AmoebaNr[x][y] != new_group_nr)
1321     {
1322       int old_group_nr = AmoebaNr[x][y];
1323
1324       AmoebaCnt[new_group_nr] += AmoebaCnt[old_group_nr];
1325       AmoebaCnt[old_group_nr] = 0;
1326
1327       for(yy=0;yy<lev_fieldy;yy++) for(xx=0;xx<lev_fieldx;xx++)
1328         if (AmoebaNr[xx][yy]==old_group_nr)
1329           AmoebaNr[xx][yy] = new_group_nr;
1330     }
1331   }
1332 }
1333
1334 void AmoebeUmwandeln(int ax, int ay)
1335 {
1336   int i,x,y;
1337   int group_nr = AmoebaNr[ax][ay];
1338   static int xy[4][2] =
1339   {
1340     0,-1,
1341     -1,0,
1342     +1,0,
1343     0,+1
1344   };
1345
1346   if (Feld[ax][ay]==EL_AMOEBE_TOT)
1347   {
1348     for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
1349     {
1350       if (Feld[x][y]==EL_AMOEBE_TOT && AmoebaNr[x][y]==group_nr)
1351       {
1352         AmoebaNr[x][y] = 0;
1353         Feld[x][y] = EL_AMOEBA2DIAM;
1354       }
1355     }
1356     Bang(ax,ay);
1357   }
1358   else
1359   {
1360     for(i=0;i<4;i++)
1361     {
1362       x = ax+xy[i%4][0];
1363       y = ay+xy[i%4][1];
1364
1365       if (!IN_LEV_FIELD(x,y))
1366         continue;
1367
1368       if (Feld[x][y]==EL_AMOEBA2DIAM)
1369         Bang(x,y);
1370     }
1371   }
1372 }
1373
1374 void AmoebeWaechst(int x, int y)
1375 {
1376   static long sound_delay = 0;
1377   static int sound_delay_value = 0;
1378
1379   CheckExploding=TRUE;
1380
1381   if (!MovDelay[x][y])          /* neue Phase / noch nicht gewartet */
1382   {
1383     MovDelay[x][y] = 4;
1384
1385     if (DelayReached(&sound_delay,sound_delay_value))
1386     {
1387       PlaySoundLevel(x,y,SND_AMOEBE);
1388       sound_delay_value = 30;
1389     }
1390   }
1391
1392   if (MovDelay[x][y])           /* neue Phase / in Wartezustand */
1393   {
1394     MovDelay[x][y]--;
1395     if (MovDelay[x][y] && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
1396       DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_AMOEBING+3-MovDelay[x][y]);
1397
1398     if (!MovDelay[x][y])
1399     {
1400       Feld[x][y] = Store[x][y];
1401       Store[x][y] = 0;
1402       DrawLevelField(x,y);
1403     }
1404   }
1405 }
1406
1407 void AmoebeAbleger(int ax, int ay)
1408 {
1409   int i;
1410   int element = Feld[ax][ay];
1411   int newax = ax, neway = ay;
1412   static int xy[4][2] =
1413   {
1414     0,-1,
1415     -1,0,
1416     +1,0,
1417     0,+1
1418   };
1419
1420   CheckExploding=TRUE;
1421
1422   if (!level.tempo_amoebe)
1423   {
1424     Feld[ax][ay] = EL_AMOEBE_TOT;
1425     DrawLevelField(ax,ay);
1426     return;
1427   }
1428
1429   if (!MovDelay[ax][ay])        /* neue Amoebe / noch nicht gewartet */
1430     MovDelay[ax][ay] = RND(33*20/(1+level.tempo_amoebe));
1431
1432   if (MovDelay[ax][ay])         /* neue Amoebe / in Wartezustand */
1433   {
1434     MovDelay[ax][ay]--;
1435     if (MovDelay[ax][ay])
1436       return;
1437   }
1438
1439   if (element==EL_AMOEBE_NASS)  /* tropfende Amöbe */
1440   {
1441     int start = RND(4);
1442     int x = ax+xy[start][0];
1443     int y = ay+xy[start][1];
1444
1445     if (!IN_LEV_FIELD(x,y))
1446       return;
1447
1448     if (IS_FREE(x,y) ||
1449         Feld[x][y]==EL_ERDREICH || Feld[x][y]==EL_MORAST_LEER)
1450     {
1451       newax = x;
1452       neway = y;
1453     }
1454
1455     if (newax==ax && neway==ay)
1456       return;
1457   }
1458   else                          /* normale oder "gefüllte" Amöbe */
1459   {
1460     int start = RND(4);
1461     BOOL waiting_for_player = FALSE;
1462
1463     for(i=0;i<4;i++)
1464     {
1465       int j = (start+i)%4;
1466       int x = ax+xy[j][0];
1467       int y = ay+xy[j][1];
1468
1469       if (!IN_LEV_FIELD(x,y))
1470         continue;
1471
1472       if (IS_FREE(x,y) ||
1473           Feld[x][y]==EL_ERDREICH || Feld[x][y]==EL_MORAST_LEER)
1474       {
1475         newax = x;
1476         neway = y;
1477         break;
1478       }
1479       else if (PLAYER(x,y))
1480         waiting_for_player = TRUE;
1481     }
1482
1483     if (newax==ax && neway==ay)
1484     {
1485       if (i==4 && !waiting_for_player)
1486       {
1487         Feld[ax][ay] = EL_AMOEBE_TOT;
1488         DrawLevelField(ax,ay);
1489
1490         if (element==EL_AMOEBE_VOLL && --AmoebaCnt[AmoebaNr[ax][ay]]<=0)
1491           AmoebeUmwandeln(ax,ay);
1492       }
1493       return;
1494     }
1495     else if (element==EL_AMOEBE_VOLL)
1496     {
1497       int new_group_nr = AmoebaNr[ax][ay];
1498
1499       AmoebaNr[newax][neway] = new_group_nr;
1500       AmoebaCnt[new_group_nr]++;
1501       AmoebenVereinigen(newax,neway);
1502     }
1503   }
1504
1505   if (element!=EL_AMOEBE_NASS || neway<ay || !IS_FREE(newax,neway) ||
1506       (neway==lev_fieldy-1 && newax!=ax))
1507   {
1508     Feld[newax][neway] = EL_AMOEBING;
1509     Store[newax][neway] = element;
1510   }
1511   else if (neway==ay)
1512     Feld[newax][neway] = EL_TROPFEN;
1513   else
1514   {
1515     InitMovingField(ax,ay,MV_DOWN);
1516     Feld[ax][ay] = EL_TROPFEN;
1517     Store[ax][ay] = EL_AMOEBE_NASS;
1518     ContinueMoving(ax,ay);
1519     return;
1520   }
1521
1522   DrawLevelField(newax,neway);
1523 }
1524
1525 void Life(int ax, int ay)
1526 {
1527   int x1,y1,x2,y2;
1528   static int life[4] = { 2,3,3,3 };     /* "Life"-Parameter */
1529   int life_time = 20;
1530   int element = Feld[ax][ay];
1531
1532   CheckExploding=TRUE;
1533
1534   if (Stop[ax][ay])
1535     return;
1536
1537   if (!MovDelay[ax][ay])        /* neue Phase / noch nicht gewartet */
1538     MovDelay[ax][ay] = life_time;
1539
1540   if (MovDelay[ax][ay])         /* neue Phase / in Wartezustand */
1541   {
1542     MovDelay[ax][ay]--;
1543     if (MovDelay[ax][ay])
1544       return;
1545   }
1546
1547   for(y1=-1;y1<2;y1++) for(x1=-1;x1<2;x1++)
1548   {
1549     int xx = ax+x1, yy = ay+y1;
1550     int nachbarn = 0;
1551
1552     if (!IN_LEV_FIELD(xx,yy))
1553       continue;
1554
1555     for(y2=-1;y2<2;y2++) for(x2=-1;x2<2;x2++)
1556     {
1557       int x = xx+x2, y = yy+y2;
1558
1559       if (!IN_LEV_FIELD(x,y) || (x==xx && y==yy))
1560         continue;
1561
1562       if (((Feld[x][y]==element || (element==EL_LIFE && PLAYER(x,y))) &&
1563            !Stop[x][y]) ||
1564           (IS_FREE(x,y) && Stop[x][y]))
1565         nachbarn++;
1566     }
1567
1568     if (xx==ax && yy==ay)               /* mittleres Feld mit Amoebe */
1569     {
1570       if (nachbarn<life[0] || nachbarn>life[1])
1571       {
1572         Feld[xx][yy] = EL_LEERRAUM;
1573         if (!Stop[xx][yy])
1574           DrawLevelField(xx,yy);
1575         Stop[xx][yy] = TRUE;
1576       }
1577     }
1578     else if (IS_FREE(xx,yy) || Feld[xx][yy]==EL_ERDREICH)
1579     {                                   /* Randfeld ohne Amoebe */
1580       if (nachbarn>=life[2] && nachbarn<=life[3])
1581       {
1582         Feld[xx][yy] = element;
1583         MovDelay[xx][yy] = (element==EL_LIFE ? 0 : life_time-1);
1584         if (!Stop[xx][yy])
1585           DrawLevelField(xx,yy);
1586         Stop[xx][yy] = TRUE;
1587       }
1588     }
1589   }
1590 }
1591
1592 void Ablenk(int x, int y)
1593 {
1594   CheckExploding=TRUE;
1595
1596   if (!MovDelay[x][y])          /* neue Phase / noch nicht gewartet */
1597     MovDelay[x][y] = 33*(level.dauer_ablenk/10);
1598   if (MovDelay[x][y])           /* neue Phase / in Wartezustand */
1599   {
1600     MovDelay[x][y]--;
1601     if (MovDelay[x][y])
1602     {
1603       if (IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
1604         DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_ABLENK+MovDelay[x][y]%4);
1605       if (!(MovDelay[x][y]%4))
1606         PlaySoundLevel(x,y,SND_MIEP);
1607       return;
1608     }
1609   }
1610
1611   Feld[x][y]=EL_ABLENK_AUS;
1612   DrawLevelField(x,y);
1613   if (ZX==x && ZY==y)
1614     ZX=ZY=-1;
1615 }
1616
1617 void Birne(int x, int y)
1618 {
1619   CheckExploding=TRUE;
1620
1621   if (!MovDelay[x][y])          /* neue Phase / noch nicht gewartet */
1622     MovDelay[x][y] = 400;
1623
1624   if (MovDelay[x][y])           /* neue Phase / in Wartezustand */
1625   {
1626     MovDelay[x][y]--;
1627     if (MovDelay[x][y])
1628     {
1629       if (!(MovDelay[x][y]%5))
1630       {
1631         if (!(MovDelay[x][y]%10))
1632           Feld[x][y]=EL_ABLENK_EIN;
1633         else
1634           Feld[x][y]=EL_ABLENK_AUS;
1635         DrawLevelField(x,y);
1636         Feld[x][y]=EL_ABLENK_EIN;
1637       }
1638       return;
1639     }
1640   }
1641
1642   Feld[x][y]=EL_ABLENK_AUS;
1643   DrawLevelField(x,y);
1644   if (ZX==x && ZY==y)
1645     ZX=ZY=-1;
1646 }
1647
1648 void Blubber(int x, int y)
1649 {
1650   CheckExploding=TRUE;
1651
1652   if (!MovDelay[x][y])          /* neue Phase / noch nicht gewartet */
1653     MovDelay[x][y] = 20;
1654
1655   if (MovDelay[x][y])           /* neue Phase / in Wartezustand */
1656   {
1657     int blubber;
1658
1659     MovDelay[x][y]--;
1660     blubber = MovDelay[x][y]/5;
1661     if (!(MovDelay[x][y]%5) && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
1662       DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_GEBLUBBER+3-blubber);
1663   }
1664 }
1665
1666 void NussKnacken(int x, int y)
1667 {
1668   CheckExploding=TRUE;
1669
1670   if (!MovDelay[x][y])          /* neue Phase / noch nicht gewartet */
1671     MovDelay[x][y] = 4;
1672
1673   if (MovDelay[x][y])           /* neue Phase / in Wartezustand */
1674   {
1675     MovDelay[x][y]--;
1676     if (MovDelay[x][y] && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
1677       DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_CRACKINGNUT+3-MovDelay[x][y]);
1678
1679     if (!MovDelay[x][y])
1680     {
1681       Feld[x][y] = EL_EDELSTEIN;
1682       DrawLevelField(x,y);
1683     }
1684   }
1685 }
1686
1687 void SiebAktivieren(int x, int y)
1688 {
1689   CheckExploding=TRUE;
1690
1691   if (SiebAktiv>1)
1692   {
1693     if (SiebAktiv%2 && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
1694       DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_SIEB_VOLL+3-(SiebAktiv%8)/2);
1695
1696 /*
1697     if (!(SiebAktiv%4))
1698       PlaySoundLevel(x,y,SND_MIEP);
1699 */
1700
1701   }
1702   else
1703   {
1704     Feld[x][y] = EL_SIEB_TOT;
1705     DrawLevelField(x,y);
1706   }
1707 }
1708
1709 void AusgangstuerPruefen(int x, int y)
1710 {
1711   CheckExploding=TRUE;
1712
1713   if (!Gems)
1714     Feld[x][y] = EL_AUSGANG_ACT;
1715 }
1716
1717 void AusgangstuerOeffnen(int x, int y)
1718 {
1719   CheckExploding=TRUE;
1720
1721   if (!MovDelay[x][y])          /* neue Phase / noch nicht gewartet */
1722     MovDelay[x][y] = 20;
1723
1724   if (MovDelay[x][y])           /* neue Phase / in Wartezustand */
1725   {
1726     int tuer;
1727
1728     MovDelay[x][y]--;
1729     tuer = MovDelay[x][y]/5;
1730     if (!(MovDelay[x][y]%5) && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
1731       DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_AUSGANG_ZU+3-tuer);
1732
1733     if (!MovDelay[x][y])
1734     {
1735       Feld[x][y] = EL_AUSGANG_AUF;
1736       DrawLevelField(x,y);
1737     }
1738   }
1739 }
1740
1741 int GameActions(int mx, int my, int button)
1742 {
1743   static long time_delay=0, action_delay=0;
1744   int Action;
1745
1746   if (TimeLeft>0 && DelayReached(&time_delay,100) && !tape.pausing)
1747   {
1748     TimeLeft--;
1749
1750     if (tape.recording || tape.playing)
1751       DrawVideoDisplay(VIDEO_STATE_TIME_ON,level.time-TimeLeft);
1752
1753     if (TimeLeft<=10)
1754       PlaySoundStereo(SND_GONG,PSND_MAX_RIGHT);
1755
1756     DrawText(DX_TIME,DY_TIME,int2str(TimeLeft,3),FS_SMALL,FC_YELLOW);
1757     BackToFront();
1758   }
1759
1760   if (!TimeLeft)
1761     KillHero();
1762
1763   Action = (CheckMoving || CheckExploding || SiebAktiv);
1764
1765 /*
1766   if (Action && DelayReached(&action_delay,3))
1767 */
1768
1769   if (DelayReached(&action_delay,3))
1770   {
1771     int x,y,element;
1772
1773     if (tape.pausing || (tape.playing && !TapePlayDelay()))
1774       return(ACT_GO_ON);
1775     else if (tape.recording)
1776       TapeRecordDelay();
1777
1778     CheckMoving = CheckExploding = FALSE;
1779     for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
1780       Stop[x][y] = FALSE;
1781
1782     for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
1783     {
1784       element = Feld[x][y];
1785
1786       if (element==EL_LEERRAUM || element==EL_ERDREICH)
1787         continue;
1788
1789       if (!IS_MOVING(x,y) && (CAN_FALL(element) || CAN_MOVE(element)))
1790         StartMoving(x,y);
1791       else if (IS_MOVING(x,y))
1792         ContinueMoving(x,y);
1793       else if (element==EL_DYNAMIT)
1794         CheckDynamite(x,y);
1795       else if (element==EL_EXPLODING)
1796         Explode(x,y,Frame[x][y]);
1797       else if (element==EL_AMOEBING)
1798         AmoebeWaechst(x,y);
1799       else if (IS_AMOEBALIVE(element))
1800         AmoebeAbleger(x,y);
1801       else if (element==EL_LIFE || element==EL_LIFE_ASYNC)
1802         Life(x,y);
1803       else if (element==EL_ABLENK_EIN)
1804         Ablenk(x,y);
1805       else if (element==EL_SALZSAEURE)
1806         Blubber(x,y);
1807       else if (element==EL_BLURB_LEFT || element==EL_BLURB_RIGHT)
1808         Blurb(x,y);
1809       else if (element==EL_CRACKINGNUT)
1810         NussKnacken(x,y);
1811       else if (element==EL_AUSGANG_ZU)
1812         AusgangstuerPruefen(x,y);
1813       else if (element==EL_AUSGANG_ACT)
1814         AusgangstuerOeffnen(x,y);
1815
1816       if (SiebAktiv && (element==EL_SIEB_LEER ||
1817                         element==EL_SIEB_VOLL ||
1818                         Store[x][y]==EL_SIEB_LEER))
1819         SiebAktivieren(x,y);
1820     }
1821
1822     if (SiebAktiv)
1823       SiebAktiv--;
1824
1825     if (CheckMoving || CheckExploding)
1826       BackToFront();
1827   }
1828
1829   return(ACT_GO_ON);
1830 }
1831
1832 void ScrollLevel(int dx, int dy)
1833 {
1834   int x,y;
1835
1836   XCopyArea(display,drawto_field,drawto_field,gc,
1837             SX+TILEX*(dx==-1),SY+TILEY*(dy==-1),
1838             SXSIZE-TILEX*(dx!=0),SYSIZE-TILEY*(dy!=0),
1839             SX+TILEX*(dx==1),SY+TILEY*(dy==1));
1840
1841   if (dx)
1842   {
1843     x = dx==1 ? 0 : SCR_FIELDX-1;
1844     for(y=0;y<SCR_FIELDY;y++)
1845       DrawScreenField(x,y);
1846   }
1847   if (dy)
1848   {
1849     y = dy==1 ? 0 : SCR_FIELDY-1;
1850     for(x=0;x<SCR_FIELDY;x++)
1851       DrawScreenField(x,y);
1852   }
1853
1854   redraw_mask|=REDRAW_FIELD;
1855 }
1856
1857 BOOL MoveFigureOneStep(int dx, int dy)
1858 {
1859   int oldJX,oldJY, newJX = JX+dx,newJY = JY+dy;
1860   int element;
1861   int can_move;
1862
1863   if (!dx && !dy)
1864     return(MF_NO_ACTION);
1865   if (!IN_LEV_FIELD(newJX,newJY))
1866     return(MF_NO_ACTION);
1867
1868   element = MovingOrBlocked2Element(newJX,newJY);
1869
1870   if (DONT_GO_TO(element))
1871   {
1872     if (element==EL_SALZSAEURE && dx==0 && dy==1)
1873     {
1874       Blurb(JX,JY);
1875       Feld[JX][JY] = EL_SPIELFIGUR;
1876       InitMovingField(JX,JY,MV_DOWN);
1877       Store[JX][JY] = EL_SALZSAEURE;
1878       ContinueMoving(JX,JY);
1879
1880       PlaySoundLevel(JX,JY,SND_AUTSCH);
1881       PlaySoundLevel(JX,JY,SND_LACHEN);
1882       GameOver = TRUE;
1883       JX = JY = -1;
1884     }
1885     else
1886       KillHero();
1887
1888     return(MF_MOVING);
1889   }
1890
1891   can_move = DigField(newJX,newJY,DF_DIG);
1892   if (can_move != MF_MOVING)
1893     return(can_move);
1894
1895   oldJX = JX;
1896   oldJY = JY;
1897   JX = newJX;
1898   JY = newJY;
1899
1900   if (Store[oldJX][oldJY])
1901   {
1902     DrawGraphic(SCROLLX(oldJX),SCROLLY(oldJY),el2gfx(Store[oldJX][oldJY]));
1903     DrawGraphicThruMask(SCROLLX(oldJX),SCROLLY(oldJY),
1904                         el2gfx(Feld[oldJX][oldJY]));
1905   }
1906   else if (Feld[oldJX][oldJY]==EL_DYNAMIT)
1907     DrawDynamite(oldJX,oldJY);
1908   else
1909     DrawLevelField(oldJX,oldJY);
1910
1911   return(MF_MOVING);
1912 }
1913
1914 BOOL MoveFigure(int dx, int dy)
1915 {
1916   static long move_delay = 0;
1917   int moved = MF_NO_ACTION;
1918
1919   if (GameOver || (!dx && !dy))
1920     return(FALSE);
1921
1922   if (!DelayReached(&move_delay,10) && !tape.playing)
1923     return(FALSE);
1924
1925   if (moved |= MoveFigureOneStep(dx,0))
1926     moved |= MoveFigureOneStep(0,dy);
1927   else
1928   {
1929     moved |= MoveFigureOneStep(0,dy);
1930     moved |= MoveFigureOneStep(dx,0);
1931   }
1932
1933   if (moved & MF_MOVING)
1934   {
1935     int old_scroll_x=scroll_x, old_scroll_y=scroll_y;
1936
1937     if (scroll_x!=JX-MIDPOSX && JX>=MIDPOSX-1 && JX<=lev_fieldx-MIDPOSX)
1938       scroll_x = JX-MIDPOSX;
1939     if (scroll_y!=JY-MIDPOSY && JY>=MIDPOSY-1 && JY<=lev_fieldy-MIDPOSY)
1940       scroll_y = JY-MIDPOSY;
1941
1942     if (scroll_x!=old_scroll_x || scroll_y!=old_scroll_y)
1943       ScrollLevel(old_scroll_x-scroll_x,old_scroll_y-scroll_y);
1944
1945     if (Feld[JX][JY]==EL_LEERRAUM)
1946       DrawLevelElement(JX,JY,EL_SPIELFIGUR);
1947     else
1948       DrawGraphicThruMask(SCROLLX(JX),SCROLLY(JY),GFX_SPIELFIGUR);
1949   }
1950
1951   TestIfHeroHitsBadThing();
1952
1953   BackToFront();
1954
1955   if (LevelSolved)
1956     GameWon();
1957
1958   return(moved);
1959 }
1960
1961 void TestIfHeroHitsBadThing()
1962 {
1963   int i, killx = JX,killy = JY;
1964   static int xy[4][2] =
1965   {
1966     0,-1,
1967     -1,0,
1968     +1,0,
1969     0,+1
1970   };
1971   static int harmless[4] =
1972   {
1973     MV_UP,
1974     MV_LEFT,
1975     MV_RIGHT,
1976     MV_DOWN
1977   };
1978
1979   for(i=0;i<4;i++)
1980   {
1981     int x,y,element;
1982
1983     x = JX+xy[i][0];
1984     y = JY+xy[i][1];
1985     if (!IN_LEV_FIELD(x,y))
1986       continue;
1987
1988     element = Feld[x][y];
1989
1990     if (DONT_TOUCH(element))
1991     {
1992       if (MovDir[x][y]==harmless[i])
1993         continue;
1994
1995       killx = x;
1996       killy = y;
1997       break;
1998     }
1999   }
2000
2001   if (killx!=JX || killy!=JY)
2002     KillHero();
2003 }
2004
2005 void TestIfBadThingHitsHero()
2006 {
2007   TestIfHeroHitsBadThing();
2008 }
2009
2010 void TestIfBadThingHitsOtherBadThing(int badx, int bady)
2011 {
2012   int i, killx=badx, killy=bady;
2013   static int xy[4][2] =
2014   {
2015     0,-1,
2016     -1,0,
2017     +1,0,
2018     0,+1
2019   };
2020
2021   for(i=0;i<4;i++)
2022   {
2023     int x,y,element;
2024
2025     x=badx+xy[i][0];
2026     y=bady+xy[i][1];
2027     if (!IN_LEV_FIELD(x,y))
2028       continue;
2029
2030     element=Feld[x][y];
2031     if (IS_AMOEBOID(element) || element==EL_LIFE ||
2032         element==EL_AMOEBING || element==EL_TROPFEN)
2033     {
2034       killx=x;
2035       killy=y;
2036       break;
2037     }
2038   }
2039
2040   if (killx!=badx || killy!=bady)
2041     Bang(badx,bady);
2042 }
2043
2044 void KillHero()
2045 {
2046   if (PLAYER(-1,-1))
2047     return;
2048
2049   if (IS_PFORTE(Feld[JX][JY]))
2050     Feld[JX][JY] = EL_LEERRAUM;
2051
2052   PlaySoundLevel(JX,JY,SND_AUTSCH);
2053   PlaySoundLevel(JX,JY,SND_LACHEN);
2054   Bang(JX,JY);
2055   GameOver = TRUE;
2056   JX = JY = -1;
2057 }
2058
2059 int DigField(int x, int y, int mode)
2060 {
2061   int dx=x-JX, dy=y-JY;
2062   int element;
2063   static long push_delay = 0;
2064   static int push_delay_value = 20;
2065
2066   if (mode==DF_NO_PUSH)
2067   {
2068     push_delay = 0;
2069     return(MF_NO_ACTION);
2070   }
2071
2072   if (IS_MOVING(x,y))
2073     return(MF_NO_ACTION);
2074
2075   element = Feld[x][y];
2076
2077   switch(element)
2078   {
2079     case EL_LEERRAUM:
2080       CheckMoving=TRUE;
2081       break;
2082     case EL_ERDREICH:
2083       Feld[x][y]=EL_LEERRAUM;
2084       CheckMoving=TRUE;
2085       break;
2086     case EL_EDELSTEIN:
2087       Feld[x][y]=EL_LEERRAUM;
2088       CheckMoving=TRUE;
2089       if (Gems>0)
2090         Gems--;
2091       RaiseScore(level.score[SC_EDELSTEIN]);
2092       DrawText(DX_EMERALDS,DY_EMERALDS,int2str(Gems,3),FS_SMALL,FC_YELLOW);
2093       PlaySoundLevel(x,y,SND_PONG);
2094       break;
2095     case EL_DIAMANT:
2096       Feld[x][y]=EL_LEERRAUM;
2097       CheckMoving=TRUE;
2098       Gems -= 3;
2099       if (Gems<0)
2100         Gems=0;
2101       RaiseScore(level.score[SC_DIAMANT]);
2102       DrawText(DX_EMERALDS,DY_EMERALDS,int2str(Gems,3),FS_SMALL,FC_YELLOW);
2103       PlaySoundLevel(x,y,SND_PONG);
2104       break;
2105     case EL_DYNAMIT_AUS:
2106       Feld[x][y]=EL_LEERRAUM;
2107       CheckMoving=TRUE;
2108       Dynamite++;
2109       RaiseScore(level.score[SC_DYNAMIT]);
2110       DrawText(DX_DYNAMITE,DY_DYNAMITE,int2str(Dynamite,3),FS_SMALL,FC_YELLOW);
2111       PlaySoundLevel(x,y,SND_PONG);
2112       break;
2113     case EL_SCHLUESSEL1:
2114     case EL_SCHLUESSEL2:
2115     case EL_SCHLUESSEL3:
2116     case EL_SCHLUESSEL4:
2117     {
2118       int key_nr = element-EL_SCHLUESSEL1;
2119
2120       Feld[x][y] = EL_LEERRAUM;
2121       CheckMoving = TRUE;
2122       Key[key_nr] = TRUE;
2123       RaiseScore(level.score[SC_SCHLUESSEL]);
2124       DrawMiniGraphicExtHiRes(drawto,gc,
2125                               DX_KEYS+key_nr*MINI_TILEX,DY_KEYS,
2126                               GFX_SCHLUESSEL1+key_nr);
2127       DrawMiniGraphicExtHiRes(window,gc,
2128                               DX_KEYS+key_nr*MINI_TILEX,DY_KEYS,
2129                               GFX_SCHLUESSEL1+key_nr);
2130       PlaySoundLevel(x,y,SND_PONG);
2131       break;
2132     }
2133     case EL_ABLENK_AUS:
2134       Feld[x][y] = EL_ABLENK_EIN;
2135       CheckExploding=TRUE;
2136       ZX=x;
2137       ZY=y;
2138       DrawLevelField(x,y);
2139       return(MF_ACTION);
2140       break;
2141     case EL_FELSBROCKEN:
2142     case EL_BOMBE:
2143     case EL_KOKOSNUSS:
2144     case EL_ZEIT_LEER:
2145       if (mode==DF_SNAP)
2146         return(MF_NO_ACTION);
2147       if (dy || !IN_LEV_FIELD(x+dx,y+dy) || Feld[x+dx][y+dy]!=EL_LEERRAUM)
2148         return(MF_NO_ACTION);
2149
2150       if (Counter() > push_delay+4*push_delay_value)
2151         push_delay = Counter();
2152       if (!DelayReached(&push_delay,push_delay_value) && !tape.playing)
2153         return(MF_NO_ACTION);
2154
2155       Feld[x][y] = EL_LEERRAUM;
2156       Feld[x+dx][y+dy] = element;
2157       push_delay_value = 10+RND(30);
2158       CheckMoving = TRUE;
2159       DrawLevelField(x+dx,y+dy);
2160       if (element==EL_FELSBROCKEN)
2161         PlaySoundLevel(x+dx,y+dy,SND_PUSCH);
2162       else if (element==EL_KOKOSNUSS)
2163         PlaySoundLevel(x+dx,y+dy,SND_KNURK);
2164       else
2165         PlaySoundLevel(x+dx,y+dy,SND_KLOPF);
2166       break;
2167     case EL_PFORTE1:
2168     case EL_PFORTE2:
2169     case EL_PFORTE3:
2170     case EL_PFORTE4:
2171       if (!Key[element-EL_PFORTE1])
2172         return(MF_NO_ACTION);
2173       break;
2174     case EL_PFORTE1X:
2175     case EL_PFORTE2X:
2176     case EL_PFORTE3X:
2177     case EL_PFORTE4X:
2178       if (!Key[element-EL_PFORTE1X])
2179         return(MF_NO_ACTION);
2180       break;
2181     case EL_AUSGANG_ZU:
2182     case EL_AUSGANG_ACT:
2183       /* Tür ist (noch) nicht offen! */
2184       return(MF_NO_ACTION);
2185       break;
2186     case EL_AUSGANG_AUF:
2187       if (mode==DF_SNAP || Gems>0)
2188         return(MF_NO_ACTION);
2189       LevelSolved = GameOver = TRUE;
2190       PlaySoundLevel(x,y,SND_BUING);
2191       break;
2192     case EL_BIRNE_AUS:
2193       Feld[x][y] = EL_BIRNE_EIN;
2194       DrawLevelField(x,y);
2195       PlaySoundLevel(x,y,SND_DENG);
2196       return(MF_ACTION);
2197       break;
2198     case EL_ZEIT_VOLL:
2199       Feld[x][y] = EL_ZEIT_LEER;
2200       DrawLevelField(x,y);
2201       PlaySoundStereo(SND_GONG,PSND_MAX_RIGHT);
2202       return(MF_ACTION);
2203       break;
2204     default:
2205       return(MF_NO_ACTION);
2206       break;
2207   }
2208   push_delay=0;
2209   return(MF_MOVING);
2210 }
2211
2212 BOOL SnapField(int dx, int dy)
2213 {
2214   int x = JX+dx, y = JY+dy;
2215   static int snapped = FALSE;
2216
2217   if (GameOver || !IN_LEV_FIELD(x,y))
2218     return(FALSE);
2219   if (dx && dy)
2220     return(FALSE);
2221   if (!dx && !dy)
2222   {
2223     snapped = FALSE;
2224     return(FALSE);
2225   }
2226   if (snapped)
2227     return(FALSE);
2228
2229   if (!DigField(x,y,DF_SNAP))
2230     return(FALSE);
2231
2232   snapped = TRUE;
2233   DrawLevelField(x,y);
2234   BackToFront();
2235
2236   return(TRUE);
2237 }
2238
2239 BOOL PlaceBomb(void)
2240 {
2241   if (Dynamite==0 || Feld[JX][JY]==EL_DYNAMIT)
2242     return(FALSE);
2243
2244   if (Feld[JX][JY]!=EL_LEERRAUM)
2245     Store[JX][JY] = Feld[JX][JY];
2246   Feld[JX][JY] = EL_DYNAMIT;
2247   MovDelay[JX][JY] = 48;
2248   Dynamite--;
2249   DrawText(DX_DYNAMITE,DY_DYNAMITE,int2str(Dynamite,3),FS_SMALL,FC_YELLOW);
2250   DrawGraphicThruMask(SCROLLX(JX),SCROLLY(JY),GFX_DYNAMIT);
2251   CheckExploding = TRUE;
2252   return(TRUE);
2253 }
2254
2255 void PlaySoundLevel(int x, int y, int sound_nr)
2256 {
2257   int sx = SCROLLX(x), sy = SCROLLY(y);
2258   int volume, stereo;
2259
2260   if (!sound_loops_on && IS_LOOP_SOUND(sound_nr))
2261     return;
2262
2263   if (!IN_LEV_FIELD(x,y))
2264     return;
2265
2266   volume = PSND_MAX_VOLUME;
2267   stereo = (sx-SCR_FIELDX/2)*12;
2268
2269   if (!IN_SCR_FIELD(sx,sy))
2270   {
2271     if (sx<0 || sx>=SCR_FIELDX)
2272       volume = PSND_MAX_VOLUME - 2*ABS(sx-SCR_FIELDX/2);
2273     else
2274       volume = PSND_MAX_VOLUME - 2*ABS(sy-SCR_FIELDY/2);
2275   }
2276
2277   PlaySoundExt(sound_nr, volume, stereo, PSND_NO_LOOP);
2278 }
2279
2280 void RaiseScore(int value)
2281 {
2282   Score += value;
2283   DrawText(DX_SCORE,DY_SCORE,int2str(Score,5),FS_SMALL,FC_YELLOW);
2284   BackToFront();
2285 }
2286
2287 void TapeInitRecording()
2288 {
2289   time_t zeit1 = time(NULL);
2290   struct tm *zeit2 = localtime(&zeit1);
2291
2292   if (tape.recording || tape.playing)
2293     return;
2294
2295   tape.level_nr = level_nr;
2296   tape.recording = TRUE;
2297   tape.pausing = TRUE;
2298   tape.date =
2299     10000*(zeit2->tm_year%100) + 100*zeit2->tm_mon + zeit2->tm_mday;
2300
2301   DrawVideoDisplay(VIDEO_STATE_REC_ON | VIDEO_STATE_PAUSE_ON,0);
2302   DrawVideoDisplay(VIDEO_STATE_DATE_ON,tape.date);
2303   DrawVideoDisplay(VIDEO_STATE_TIME_ON,0);
2304 }
2305
2306 void TapeStartRecording()
2307 {
2308   tape.length = 0;
2309   tape.counter = 0;
2310   tape.pos[tape.counter].delay = 0;
2311   tape.recording = TRUE;
2312   tape.playing = FALSE;
2313   tape.pausing = FALSE;
2314   tape.random_seed = InitRND(NEW_RANDOMIZE);
2315   DrawVideoDisplay(VIDEO_STATE_REC_ON | VIDEO_STATE_PAUSE_OFF,0);
2316 }
2317
2318 void TapeStopRecording()
2319 {
2320   if (!tape.recording)
2321     return;
2322
2323   tape.length = tape.counter;
2324   tape.recording = FALSE;
2325   tape.pausing = FALSE;
2326   DrawVideoDisplay(VIDEO_STATE_REC_OFF,0);
2327
2328   master_tape = tape;
2329 }
2330
2331 void TapeRecordAction(int joy)
2332 {
2333   if (!tape.recording || tape.pausing)
2334     return;
2335
2336   if (tape.counter>=MAX_TAPELEN-1)
2337   {
2338     TapeStopRecording();
2339     return;
2340   }
2341
2342   if (joy)
2343   {
2344     tape.pos[tape.counter].joystickdata = joy;
2345     tape.counter++;
2346     tape.pos[tape.counter].delay = 0;
2347   }
2348 }
2349
2350 void TapeRecordDelay()
2351 {
2352   if (!tape.recording || tape.pausing)
2353     return;
2354
2355   if (tape.counter>=MAX_TAPELEN)
2356   {
2357     TapeStopRecording();
2358     return;
2359   }
2360
2361   tape.pos[tape.counter].delay++;
2362
2363   if (tape.pos[tape.counter].delay>=255)
2364   {
2365     tape.pos[tape.counter].joystickdata = 0;
2366     tape.counter++;
2367     tape.pos[tape.counter].delay = 0;
2368   }
2369 }
2370
2371 void TapeTogglePause()
2372 {
2373   if (!tape.recording && !tape.playing)
2374     return;
2375
2376   if (tape.pausing)
2377   {
2378     tape.pausing = FALSE;
2379     DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0);
2380     if (game_status==MAINMENU)
2381       HandleMainMenu(SX+16,SY+7*32+16,0,0,MB_MENU_CHOICE);
2382   }
2383   else
2384   {
2385     tape.pausing = TRUE;
2386     DrawVideoDisplay(VIDEO_STATE_PAUSE_ON,0);
2387   }
2388 }
2389
2390 void TapeInitPlaying()
2391 {
2392   if (tape.recording || tape.playing || TAPE_IS_EMPTY(tape))
2393     return;
2394
2395   tape.playing = TRUE;
2396   tape.pausing = TRUE;
2397   DrawVideoDisplay(VIDEO_STATE_PLAY_ON | VIDEO_STATE_PAUSE_ON,0);
2398   DrawVideoDisplay(VIDEO_STATE_DATE_ON,tape.date);
2399   DrawVideoDisplay(VIDEO_STATE_TIME_ON,0);
2400 }
2401
2402 void TapeStartPlaying()
2403 {
2404   tape = master_tape;
2405
2406   tape.counter = 0;
2407   tape.recording = FALSE;
2408   tape.playing = TRUE;
2409   tape.pausing = FALSE;
2410   InitRND(tape.random_seed);
2411   DrawVideoDisplay(VIDEO_STATE_PLAY_ON | VIDEO_STATE_PAUSE_OFF,0);
2412 }
2413
2414 void TapeStopPlaying()
2415 {
2416   if (!tape.playing)
2417     return;
2418
2419   tape.playing = FALSE;
2420   tape.pausing = FALSE;
2421   DrawVideoDisplay(VIDEO_STATE_PLAY_OFF,0);
2422 }
2423
2424 int TapePlayAction()
2425 {
2426   if (!tape.playing || tape.pausing)
2427     return(0);
2428
2429   if (tape.counter>=tape.length)
2430   {
2431     TapeStopPlaying();
2432     return(0);
2433   }
2434
2435   if (!tape.pos[tape.counter].delay)
2436   {
2437     tape.counter++;
2438     return(tape.pos[tape.counter-1].joystickdata);
2439   }
2440   else
2441     return(0);
2442 }
2443
2444 BOOL TapePlayDelay()
2445 {
2446   if (!tape.playing || tape.pausing)
2447     return(0);
2448
2449   if (tape.counter>=tape.length)
2450   {
2451     TapeStopPlaying();
2452     return(TRUE);
2453   }
2454
2455   if (tape.pos[tape.counter].delay)
2456   {
2457     tape.pos[tape.counter].delay--;
2458     return(TRUE);
2459   }
2460   else
2461     return(FALSE);
2462 }
2463
2464 void TapeStop()
2465 {
2466   TapeStopRecording();
2467   TapeStopPlaying();
2468   DrawVideoDisplay(VIDEO_ALL_OFF,0);
2469   if (tape.date && tape.length)
2470   {
2471     DrawVideoDisplay(VIDEO_STATE_DATE_ON,tape.date);
2472     DrawVideoDisplay(VIDEO_STATE_TIME_ON,0);
2473   }
2474 }
2475
2476 void TapeErase()
2477 {
2478   tape.length = 0;
2479 }