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