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