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