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