rnd-19980928-4
[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   static int stored_player_action[MAX_PLAYERS];
2714   static int num_stored_actions = 0;
2715   BOOL moved = FALSE, snapped = FALSE, bombed = FALSE;
2716   int jx = player->jx, jy = player->jy;
2717   int left      = player_action & JOY_LEFT;
2718   int right     = player_action & JOY_RIGHT;
2719   int up        = player_action & JOY_UP;
2720   int down      = player_action & JOY_DOWN;
2721   int button1   = player_action & JOY_BUTTON_1;
2722   int button2   = player_action & JOY_BUTTON_2;
2723   int dx        = (left ? -1    : right ? 1     : 0);
2724   int dy        = (up   ? -1    : down  ? 1     : 0);
2725
2726   stored_player_action[player->nr] = 0;
2727   num_stored_actions++;
2728
2729   if (!player->active || player->gone)
2730     return;
2731
2732   if (player_action)
2733   {
2734     player->frame_reset_delay = 0;
2735
2736     if (button1)
2737       snapped = SnapField(player, dx,dy);
2738     else
2739     {
2740       if (button2)
2741         bombed = PlaceBomb(player);
2742       moved = MoveFigure(player, dx,dy);
2743     }
2744
2745     if (tape.recording && (moved || snapped || bombed))
2746     {
2747       if (bombed && !moved)
2748         player_action &= JOY_BUTTON;
2749
2750       stored_player_action[player->nr] = player_action;
2751
2752       /* this allows cycled sequences of PlayerActions() */
2753       if (num_stored_actions >= MAX_PLAYERS)
2754       {
2755         TapeRecordAction(stored_player_action);
2756         num_stored_actions = 0;
2757       }
2758     }
2759     else if (tape.playing && snapped)
2760       SnapField(player, 0,0);                   /* stop snapping */
2761   }
2762   else
2763   {
2764     DigField(player, 0,0, 0,0, DF_NO_PUSH);
2765     SnapField(player, 0,0);
2766     if (++player->frame_reset_delay > MoveSpeed)
2767       player->Frame = 0;
2768   }
2769
2770   if (tape.playing && !tape.pausing && !player_action &&
2771       tape.counter < tape.length)
2772   {
2773     int next_joy =
2774       tape.pos[tape.counter].joystickdata[player->nr] & (JOY_LEFT|JOY_RIGHT);
2775
2776     if (next_joy == JOY_LEFT || next_joy == JOY_RIGHT)
2777     {
2778       int dx = (next_joy == JOY_LEFT ? -1 : +1);
2779
2780       if (IN_LEV_FIELD(jx+dx,jy) && IS_PUSHABLE(Feld[jx+dx][jy]))
2781       {
2782         int el = Feld[jx+dx][jy];
2783         int push_delay = (IS_SB_ELEMENT(el) || el==EL_SONDE ? 2 : 10);
2784
2785         if (tape.delay_played + push_delay >= tape.pos[tape.counter].delay)
2786         {
2787           player->MovDir = next_joy;
2788           player->Frame = FrameCounter % 4;
2789           player->Pushing = TRUE;
2790         }
2791       }
2792     }
2793   }
2794 }
2795
2796 void GameActions(int player_action)
2797 {
2798   static long action_delay = 0;
2799   long action_delay_value;
2800   int sieb_x = 0, sieb_y = 0;
2801   int i, x,y, element;
2802   int *recorded_player_action;
2803
2804   if (game_status != PLAYING)
2805     return;
2806
2807 #ifdef DEBUG
2808   action_delay_value =
2809     (tape.playing && tape.fast_forward ? FFWD_FRAME_DELAY : GameFrameDelay);
2810 #else
2811   action_delay_value =
2812     (tape.playing && tape.fast_forward ? FFWD_FRAME_DELAY : GAME_FRAME_DELAY);
2813 #endif
2814
2815   /* main game synchronization point */
2816   WaitUntilDelayReached(&action_delay, action_delay_value);
2817
2818   if (tape.playing)
2819     recorded_player_action = TapePlayAction();
2820   else
2821     recorded_player_action = NULL;
2822
2823   for(i=0; i<MAX_PLAYERS; i++)
2824   {
2825     int actual_player_action = player_action;
2826     /* TEST TEST TEST */
2827
2828     if (i != TestPlayer && !stored_player[i].MovPos)
2829       actual_player_action = 0;
2830
2831     /* TEST TEST TEST */
2832
2833     if (recorded_player_action)
2834       actual_player_action = recorded_player_action[i];
2835
2836     PlayerActions(&stored_player[i], actual_player_action);
2837     ScrollFigure(&stored_player[i], SCROLL_GO_ON);
2838   }
2839
2840   ScrollScreen(NULL, SCROLL_GO_ON);
2841
2842   if (tape.pausing || (tape.playing && !TapePlayDelay()))
2843     return;
2844   else if (tape.recording)
2845     TapeRecordDelay();
2846
2847   FrameCounter++;
2848   TimeFrames++;
2849
2850   for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
2851   {
2852     Stop[x][y] = FALSE;
2853     if (JustHit[x][y]>0)
2854       JustHit[x][y]--;
2855
2856 #if DEBUG
2857     if (IS_BLOCKED(x,y))
2858     {
2859       int oldx,oldy;
2860
2861       Blocked2Moving(x,y,&oldx,&oldy);
2862       if (!IS_MOVING(oldx,oldy))
2863       {
2864         printf("GameActions(): (BLOCKED=>MOVING) context corrupted!\n");
2865         printf("GameActions(): BLOCKED: x = %d, y = %d\n",x,y);
2866         printf("GameActions(): !MOVING: oldx = %d, oldy = %d\n",oldx,oldy);
2867         printf("GameActions(): This should never happen!\n");
2868       }
2869     }
2870 #endif
2871   }
2872
2873   for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
2874   {
2875     element = Feld[x][y];
2876
2877     if (IS_INACTIVE(element))
2878       continue;
2879
2880     if (!IS_MOVING(x,y) && (CAN_FALL(element) || CAN_MOVE(element)))
2881     {
2882       StartMoving(x,y);
2883
2884       if (IS_GEM(element))
2885         EdelsteinFunkeln(x,y);
2886     }
2887     else if (IS_MOVING(x,y))
2888       ContinueMoving(x,y);
2889     else if (element==EL_DYNAMIT || element==EL_DYNABOMB)
2890       CheckDynamite(x,y);
2891     else if (element==EL_EXPLODING)
2892       Explode(x,y,Frame[x][y],EX_NORMAL);
2893     else if (element==EL_AMOEBING)
2894       AmoebeWaechst(x,y);
2895     else if (IS_AMOEBALIVE(element))
2896       AmoebeAbleger(x,y);
2897     else if (element==EL_LIFE || element==EL_LIFE_ASYNC)
2898       Life(x,y);
2899     else if (element==EL_ABLENK_EIN)
2900       Ablenk(x,y);
2901     else if (element==EL_SALZSAEURE)
2902       Blubber(x,y);
2903     else if (element==EL_BLURB_LEFT || element==EL_BLURB_RIGHT)
2904       Blurb(x,y);
2905     else if (element==EL_CRACKINGNUT)
2906       NussKnacken(x,y);
2907     else if (element==EL_AUSGANG_ZU)
2908       AusgangstuerPruefen(x,y);
2909     else if (element==EL_AUSGANG_ACT)
2910       AusgangstuerOeffnen(x,y);
2911     else if (element==EL_AUSGANG_AUF)
2912       AusgangstuerBlinken(x,y);
2913     else if (element==EL_MAUERND)
2914       MauerWaechst(x,y);
2915     else if (element==EL_MAUER_LEBT)
2916       MauerAbleger(x,y);
2917     else if (element==EL_BURNING)
2918       CheckForDragon(x,y);
2919
2920     if (SiebAktiv)
2921     {
2922       BOOL sieb = FALSE;
2923       int jx = local_player->jx, jy = local_player->jy;
2924
2925       if (element==EL_SIEB_LEER || element==EL_SIEB_VOLL ||
2926           Store[x][y]==EL_SIEB_LEER)
2927       {
2928         SiebAktivieren(x, y, 1);
2929         sieb = TRUE;
2930       }
2931       else if (element==EL_SIEB2_LEER || element==EL_SIEB2_VOLL ||
2932                Store[x][y]==EL_SIEB2_LEER)
2933       {
2934         SiebAktivieren(x, y, 2);
2935         sieb = TRUE;
2936       }
2937
2938       /* play the element sound at the position nearest to the player */
2939       if (sieb && ABS(x-jx)+ABS(y-jy) < ABS(sieb_x-jx)+ABS(sieb_y-jy))
2940       {
2941         sieb_x = x;
2942         sieb_y = y;
2943       }
2944     }
2945   }
2946
2947   if (SiebAktiv)
2948   {
2949     if (!(SiebAktiv%4))
2950       PlaySoundLevel(sieb_x,sieb_y,SND_MIEP);
2951     SiebAktiv--;
2952     if (!SiebAktiv)
2953     {
2954       for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
2955       {
2956         element = Feld[x][y];
2957         if (element==EL_SIEB_LEER || element==EL_SIEB_VOLL)
2958         {
2959           Feld[x][y] = EL_SIEB_TOT;
2960           DrawLevelField(x,y);
2961         }
2962         else if (element==EL_SIEB2_LEER || element==EL_SIEB2_VOLL)
2963         {
2964           Feld[x][y] = EL_SIEB2_TOT;
2965           DrawLevelField(x,y);
2966         }
2967       }
2968     }
2969   }
2970
2971   if (TimeLeft>0 && TimeFrames>=(1000/GameFrameDelay) && !tape.pausing)
2972   {
2973     TimeFrames = 0;
2974     TimeLeft--;
2975
2976     if (tape.recording || tape.playing)
2977       DrawVideoDisplay(VIDEO_STATE_TIME_ON,level.time-TimeLeft);
2978
2979     if (TimeLeft<=10)
2980       PlaySoundStereo(SND_GONG,PSND_MAX_RIGHT);
2981
2982     DrawText(DX_TIME,DY_TIME,int2str(TimeLeft,3),FS_SMALL,FC_YELLOW);
2983
2984     if (!TimeLeft)
2985       for(i=0; i<MAX_PLAYERS; i++)
2986         KillHero(&stored_player[i]);
2987   }
2988
2989   DrawAllPlayers();
2990 }
2991
2992 static BOOL AllPlayersInSight(struct PlayerInfo *player, int x, int y)
2993 {
2994   int min_x = x, min_y = y, max_x = x, max_y = y;
2995   int i;
2996
2997   for(i=0; i<MAX_PLAYERS; i++)
2998   {
2999     int jx = stored_player[i].jx, jy = stored_player[i].jy;
3000
3001     if (!stored_player[i].active || stored_player[i].gone ||
3002         &stored_player[i] == player)
3003       continue;
3004
3005     min_x = MIN(min_x, jx);
3006     min_y = MIN(min_y, jy);
3007     max_x = MAX(max_x, jx);
3008     max_y = MAX(max_y, jy);
3009   }
3010
3011   return(max_x - min_x < SCR_FIELDX && max_y - min_y < SCR_FIELDY);
3012 }
3013
3014 static BOOL AllPlayersInVisibleScreen()
3015 {
3016   int i;
3017
3018   for(i=0; i<MAX_PLAYERS; i++)
3019   {
3020     int jx = stored_player[i].jx, jy = stored_player[i].jy;
3021
3022     if (!stored_player[i].active || stored_player[i].gone)
3023       continue;
3024
3025     if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
3026       return(FALSE);
3027   }
3028
3029   return(TRUE);
3030 }
3031
3032 void ScrollLevel(int dx, int dy)
3033 {
3034   int softscroll_offset = (soft_scrolling_on ? TILEX : 0);
3035   int x,y;
3036
3037   /*
3038   ScreenGfxPos = local_player->GfxPos;
3039   */
3040
3041   XCopyArea(display,drawto_field,drawto_field,gc,
3042             FX + TILEX*(dx==-1) - softscroll_offset,
3043             FY + TILEY*(dy==-1) - softscroll_offset,
3044             SXSIZE - TILEX*(dx!=0) + 2*softscroll_offset,
3045             SYSIZE - TILEY*(dy!=0) + 2*softscroll_offset,
3046             FX + TILEX*(dx==1) - softscroll_offset,
3047             FY + TILEY*(dy==1) - softscroll_offset);
3048
3049   if (dx)
3050   {
3051     x = (dx==1 ? BX1 : BX2);
3052     for(y=BY1; y<=BY2; y++)
3053       DrawScreenField(x,y);
3054   }
3055   if (dy)
3056   {
3057     y = (dy==1 ? BY1 : BY2);
3058     for(x=BX1; x<=BX2; x++)
3059       DrawScreenField(x,y);
3060   }
3061
3062   redraw_mask |= REDRAW_FIELD;
3063 }
3064
3065 BOOL MoveFigureOneStep(struct PlayerInfo *player,
3066                        int dx, int dy, int real_dx, int real_dy)
3067 {
3068   int jx = player->jx, jy = player->jy;
3069   int new_jx = jx+dx, new_jy = jy+dy;
3070   int element;
3071   int can_move;
3072
3073   if (player->gone || (!dx && !dy))
3074     return(MF_NO_ACTION);
3075
3076   player->MovDir = (dx < 0 ? MV_LEFT :
3077                     dx > 0 ? MV_RIGHT :
3078                     dy < 0 ? MV_UP :
3079                     dy > 0 ? MV_DOWN :  MV_NO_MOVING);
3080
3081   if (!IN_LEV_FIELD(new_jx,new_jy))
3082     return(MF_NO_ACTION);
3083
3084   if (!networking && !AllPlayersInSight(player, new_jx,new_jy))
3085     return(MF_NO_ACTION);
3086
3087   element = MovingOrBlocked2Element(new_jx,new_jy);
3088
3089   if (DONT_GO_TO(element))
3090   {
3091     if (element==EL_SALZSAEURE && dx==0 && dy==1)
3092     {
3093       Blurb(jx,jy);
3094       Feld[jx][jy] = EL_SPIELFIGUR;
3095       InitMovingField(jx,jy,MV_DOWN);
3096       Store[jx][jy] = EL_SALZSAEURE;
3097       ContinueMoving(jx,jy);
3098       BuryHero(player);
3099     }
3100     else
3101       KillHero(player);
3102
3103     return(MF_MOVING);
3104   }
3105
3106   can_move = DigField(player, new_jx,new_jy, real_dx,real_dy, DF_DIG);
3107   if (can_move != MF_MOVING)
3108     return(can_move);
3109
3110   StorePlayer[jx][jy] = 0;
3111   player->last_jx = jx;
3112   player->last_jy = jy;
3113   jx = player->jx = new_jx;
3114   jy = player->jy = new_jy;
3115   StorePlayer[jx][jy] = EL_SPIELER1 + player->nr;
3116
3117   player->MovPos = (dx > 0 || dy > 0 ? -1 : 1) * 7*TILEX/8;
3118
3119   ScrollFigure(player, SCROLL_INIT);
3120
3121   return(MF_MOVING);
3122 }
3123
3124 BOOL MoveFigure(struct PlayerInfo *player, int dx, int dy)
3125 {
3126   int jx = player->jx, jy = player->jy;
3127   int old_jx = jx, old_jy = jy;
3128   int moved = MF_NO_ACTION;
3129
3130   if (player->gone || (!dx && !dy))
3131     return(FALSE);
3132
3133   if (!FrameReached(&player->move_delay,MoveSpeed) && !tape.playing)
3134     return(FALSE);
3135
3136   if (player->last_move_dir & (MV_LEFT | MV_RIGHT))
3137   {
3138     if (!(moved |= MoveFigureOneStep(player, 0,dy, dx,dy)))
3139       moved |= MoveFigureOneStep(player, dx,0, dx,dy);
3140   }
3141   else
3142   {
3143     if (!(moved |= MoveFigureOneStep(player, dx,0, dx,dy)))
3144       moved |= MoveFigureOneStep(player, 0,dy, dx,dy);
3145   }
3146
3147   jx = player->jx;
3148   jy = player->jy;
3149
3150
3151
3152   /*
3153   if (moved & MF_MOVING && player == local_player)
3154   */
3155
3156   if (moved & MF_MOVING && !ScreenMovPos)
3157   {
3158     int old_scroll_x = scroll_x, old_scroll_y = scroll_y;
3159     int offset = (scroll_delay_on ? 3 : 0);
3160
3161     if (!IN_VIS_FIELD(SCREENX(jx),SCREENY(jy)))
3162     {
3163       /* actual player has left the screen -- scroll in that direction */
3164       if (jx != old_jx)         /* player has moved horizontally */
3165         scroll_x += (jx - old_jx);
3166       else                      /* player has moved vertically */
3167         scroll_y += (jy - old_jy);
3168     }
3169     else
3170     {
3171       if (jx != old_jx)         /* player has moved horizontally */
3172       {
3173         if ((scroll_x < jx-MIDPOSX-offset || scroll_x > jx-MIDPOSX+offset) &&
3174             jx >= MIDPOSX-1-offset && jx <= lev_fieldx-(MIDPOSX-offset))
3175           scroll_x = jx-MIDPOSX + (scroll_x < jx-MIDPOSX ? -offset : offset);
3176
3177         /* don't scroll more than one field at a time */
3178         scroll_x = old_scroll_x + SIGN(scroll_x - old_scroll_x);
3179
3180         /* don't scroll against the player's moving direction */
3181         if ((player->MovDir == MV_LEFT && scroll_x > old_scroll_x) ||
3182             (player->MovDir == MV_RIGHT && scroll_x < old_scroll_x))
3183           scroll_x = old_scroll_x;
3184       }
3185       else                      /* player has moved vertically */
3186       {
3187         if ((scroll_y < jy-MIDPOSY-offset || scroll_y > jy-MIDPOSY+offset) &&
3188             jy >= MIDPOSY-1-offset && jy <= lev_fieldy-(MIDPOSY-offset))
3189           scroll_y = jy-MIDPOSY + (scroll_y < jy-MIDPOSY ? -offset : offset);
3190
3191         /* don't scroll more than one field at a time */
3192         scroll_y = old_scroll_y + SIGN(scroll_y - old_scroll_y);
3193
3194         /* don't scroll against the player's moving direction */
3195         if ((player->MovDir == MV_UP && scroll_y > old_scroll_y) ||
3196             (player->MovDir == MV_DOWN && scroll_y < old_scroll_y))
3197           scroll_y = old_scroll_y;
3198       }
3199     }
3200
3201 #if 0
3202     if (player == local_player)
3203     {
3204       if ((scroll_x < jx-MIDPOSX-offset || scroll_x > jx-MIDPOSX+offset) &&
3205           jx >= MIDPOSX-1-offset && jx <= lev_fieldx-(MIDPOSX-offset))
3206         scroll_x = jx-MIDPOSX + (scroll_x < jx-MIDPOSX ? -offset : offset);
3207       if ((scroll_y < jy-MIDPOSY-offset || scroll_y > jy-MIDPOSY+offset) &&
3208           jy >= MIDPOSY-1-offset && jy <= lev_fieldy-(MIDPOSY-offset))
3209         scroll_y = jy-MIDPOSY + (scroll_y < jy-MIDPOSY ? -offset : offset);
3210
3211       /* don't scroll more than one field at a time */
3212       scroll_x = old_scroll_x + SIGN(scroll_x - old_scroll_x);
3213       scroll_y = old_scroll_y + SIGN(scroll_y - old_scroll_y);
3214     }
3215 #endif
3216
3217     if (scroll_x != old_scroll_x || scroll_y != old_scroll_y)
3218     {
3219       if (networking || AllPlayersInVisibleScreen())
3220       {
3221         ScrollScreen(player, SCROLL_INIT);
3222
3223         /*
3224         ScreenMovDir = player->MovDir;
3225         ScreenMovPos = player->MovPos;
3226         ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
3227         */
3228
3229         ScrollLevel(old_scroll_x - scroll_x, old_scroll_y - scroll_y);
3230       }
3231       else
3232       {
3233         scroll_x = old_scroll_x;
3234         scroll_y = old_scroll_y;
3235       }
3236     }
3237   }
3238
3239   if (!(moved & MF_MOVING) && !player->Pushing)
3240     player->Frame = 0;
3241   else
3242     player->Frame = (player->Frame + 1) % 4;
3243
3244   if (moved & MF_MOVING)
3245   {
3246     if (old_jx != jx && old_jy == jy)
3247       player->MovDir = (old_jx < jx ? MV_RIGHT : MV_LEFT);
3248     else if (old_jx == jx && old_jy != jy)
3249       player->MovDir = (old_jy < jy ? MV_DOWN : MV_UP);
3250
3251     DrawLevelField(jx,jy);      /* für "ErdreichAnbroeckeln()" */
3252
3253     player->last_move_dir = player->MovDir;
3254   }
3255   else
3256     player->last_move_dir = MV_NO_MOVING;
3257
3258   TestIfHeroHitsBadThing(jx,jy);
3259
3260   if (player->gone)
3261     RemoveHero(player);
3262
3263   return(moved);
3264 }
3265
3266 void ScrollFigure(struct PlayerInfo *player, int mode)
3267 {
3268   int jx = player->jx, jy = player->jy;
3269   int last_jx = player->last_jx, last_jy = player->last_jy;
3270
3271   if (!player->active || player->gone || !player->MovPos)
3272     return;
3273
3274   if (mode == SCROLL_INIT)
3275   {
3276     player->actual_frame_counter = FrameCounter;
3277     player->GfxPos = ScrollStepSize * (player->MovPos / ScrollStepSize);
3278
3279     /*
3280     ScreenGfxPos = local_player->GfxPos;
3281     */
3282
3283     if (Feld[last_jx][last_jy] == EL_LEERRAUM)
3284       Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING;
3285
3286     DrawPlayer(player);
3287     return;
3288   }
3289   else if (!FrameReached(&player->actual_frame_counter,1))
3290     return;
3291
3292   player->MovPos += (player->MovPos > 0 ? -1 : 1) * TILEX/8;
3293   player->GfxPos = ScrollStepSize * (player->MovPos / ScrollStepSize);
3294
3295   /*
3296   if (ScreenMovPos)
3297   {
3298     ScreenMovPos += (ScreenMovPos > 0 ? -1 : 1) * TILEX/8;
3299     ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
3300   }
3301   */
3302
3303   /*
3304   if (ScreenGfxPos && ScreenGfxPos != local_player->GfxPos)
3305   {
3306     ScreenGfxPos = local_player->GfxPos;
3307     redraw_mask |= REDRAW_FIELD;
3308   }
3309   */
3310
3311   if (Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING)
3312     Feld[last_jx][last_jy] = EL_LEERRAUM;
3313
3314   DrawPlayer(player);
3315
3316   if (!player->MovPos)
3317   {
3318     player->last_jx = jx;
3319     player->last_jy = jy;
3320
3321     if (Feld[jx][jy] == EL_AUSGANG_AUF)
3322     {
3323       RemoveHero(player);
3324
3325       if (!local_player->friends_still_needed)
3326         player->LevelSolved = player->GameOver = TRUE;
3327     }
3328   }
3329 }
3330
3331 void ScrollScreen(struct PlayerInfo *player, int mode)
3332 {
3333   static long screen_frame_counter = 0;
3334
3335   if (mode == SCROLL_INIT)
3336   {
3337     screen_frame_counter = FrameCounter;
3338     ScreenMovDir = player->MovDir;
3339     ScreenMovPos = player->MovPos;
3340     ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
3341     return;
3342   }
3343   else if (!FrameReached(&screen_frame_counter,1))
3344     return;
3345
3346   if (ScreenMovPos)
3347   {
3348     /*
3349     printf("ScreenMovDir = %d, ", ScreenMovDir);
3350     printf("ScreenMovPos = %d, ", ScreenMovPos);
3351     printf("ScreenGfxPos = %d\n", ScreenGfxPos);
3352     */
3353
3354     ScreenMovPos += (ScreenMovPos > 0 ? -1 : 1) * TILEX/8;
3355     ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
3356     redraw_mask |= REDRAW_FIELD;
3357   }
3358   else
3359     ScreenMovDir = MV_NO_MOVING;
3360 }
3361
3362 void TestIfGoodThingHitsBadThing(int goodx, int goody)
3363 {
3364   int i, killx = goodx, killy = goody;
3365   static int xy[4][2] =
3366   {
3367     { 0,-1 },
3368     { -1,0 },
3369     { +1,0 },
3370     { 0,+1 }
3371   };
3372   static int harmless[4] =
3373   {
3374     MV_UP,
3375     MV_LEFT,
3376     MV_RIGHT,
3377     MV_DOWN
3378   };
3379
3380   for(i=0; i<4; i++)
3381   {
3382     int x,y, element;
3383
3384     x = goodx + xy[i][0];
3385     y = goody + xy[i][1];
3386     if (!IN_LEV_FIELD(x,y))
3387       continue;
3388
3389     element = Feld[x][y];
3390
3391     if (DONT_TOUCH(element))
3392     {
3393       if (MovDir[x][y] == harmless[i])
3394         continue;
3395
3396       killx = x;
3397       killy = y;
3398       break;
3399     }
3400   }
3401
3402   if (killx != goodx || killy != goody)
3403   {
3404     if (IS_PLAYER(goodx,goody))
3405       KillHero(PLAYERINFO(goodx,goody));
3406     else
3407       Bang(goodx,goody);
3408   }
3409 }
3410
3411 void TestIfBadThingHitsGoodThing(int badx, int bady)
3412 {
3413   int i, killx = badx, killy = bady;
3414   static int xy[4][2] =
3415   {
3416     { 0,-1 },
3417     { -1,0 },
3418     { +1,0 },
3419     { 0,+1 }
3420   };
3421   static int harmless[4] =
3422   {
3423     MV_UP,
3424     MV_LEFT,
3425     MV_RIGHT,
3426     MV_DOWN
3427   };
3428
3429   for(i=0; i<4; i++)
3430   {
3431     int x,y, element;
3432
3433     x = badx + xy[i][0];
3434     y = bady + xy[i][1];
3435     if (!IN_LEV_FIELD(x,y))
3436       continue;
3437
3438     element = Feld[x][y];
3439
3440     if (IS_PLAYER(x,y))
3441     {
3442       killx = x;
3443       killy = y;
3444       break;
3445     }
3446     else if (element == EL_PINGUIN)
3447     {
3448       if (MovDir[x][y] == harmless[i] && IS_MOVING(x,y))
3449         continue;
3450
3451       killx = x;
3452       killy = y;
3453       break;
3454     }
3455   }
3456
3457   if (killx != badx || killy != bady)
3458   {
3459     if (IS_PLAYER(killx,killy))
3460       KillHero(PLAYERINFO(killx,killy));
3461     else
3462       Bang(killx,killy);
3463   }
3464 }
3465
3466 void TestIfHeroHitsBadThing(int x, int y)
3467 {
3468   TestIfGoodThingHitsBadThing(x,y);
3469 }
3470
3471 void TestIfBadThingHitsHero(int x, int y)
3472 {
3473   /*
3474   TestIfGoodThingHitsBadThing(JX,JY);
3475   */
3476
3477   TestIfBadThingHitsGoodThing(x,y);
3478 }
3479
3480 void TestIfFriendHitsBadThing(int x, int y)
3481 {
3482   TestIfGoodThingHitsBadThing(x,y);
3483 }
3484
3485 void TestIfBadThingHitsFriend(int x, int y)
3486 {
3487   TestIfBadThingHitsGoodThing(x,y);
3488 }
3489
3490 void TestIfBadThingHitsOtherBadThing(int badx, int bady)
3491 {
3492   int i, killx = badx, killy = bady;
3493   static int xy[4][2] =
3494   {
3495     { 0,-1 },
3496     { -1,0 },
3497     { +1,0 },
3498     { 0,+1 }
3499   };
3500
3501   for(i=0; i<4; i++)
3502   {
3503     int x,y, element;
3504
3505     x=badx + xy[i][0];
3506     y=bady + xy[i][1];
3507     if (!IN_LEV_FIELD(x,y))
3508       continue;
3509
3510     element = Feld[x][y];
3511     if (IS_AMOEBOID(element) || element == EL_LIFE ||
3512         element == EL_AMOEBING || element == EL_TROPFEN)
3513     {
3514       killx = x;
3515       killy = y;
3516       break;
3517     }
3518   }
3519
3520   if (killx != badx || killy != bady)
3521     Bang(badx,bady);
3522 }
3523
3524 void KillHero(struct PlayerInfo *player)
3525 {
3526   int jx = player->jx, jy = player->jy;
3527
3528   if (player->gone)
3529     return;
3530
3531   if (IS_PFORTE(Feld[jx][jy]))
3532     Feld[jx][jy] = EL_LEERRAUM;
3533
3534   Bang(jx,jy);
3535   BuryHero(player);
3536 }
3537
3538 void BuryHero(struct PlayerInfo *player)
3539 {
3540   int jx = player->jx, jy = player->jy;
3541
3542   if (player->gone)
3543     return;
3544
3545   PlaySoundLevel(jx,jy, SND_AUTSCH);
3546   PlaySoundLevel(jx,jy, SND_LACHEN);
3547
3548   player->GameOver = TRUE;
3549   RemoveHero(player);
3550 }
3551
3552 void RemoveHero(struct PlayerInfo *player)
3553 {
3554   int jx = player->jx, jy = player->jy;
3555   int i, found = FALSE;
3556
3557   player->gone = TRUE;
3558   StorePlayer[jx][jy] = 0;
3559
3560   for(i=0; i<MAX_PLAYERS; i++)
3561     if (stored_player[i].active && !stored_player[i].gone)
3562       found = TRUE;
3563
3564   if (!found)
3565     AllPlayersGone = TRUE;
3566
3567   ExitX = ZX = jx;
3568   ExitY = ZY = jy;
3569 }
3570
3571 int DigField(struct PlayerInfo *player,
3572              int x, int y, int real_dx, int real_dy, int mode)
3573 {
3574   int jx = player->jx, jy = player->jy;
3575   int dx = x - jx, dy = y - jy;
3576   int element;
3577
3578   if (!player->MovPos)
3579     player->Pushing = FALSE;
3580
3581   if (mode == DF_NO_PUSH)
3582   {
3583     player->push_delay = 0;
3584     return(MF_NO_ACTION);
3585   }
3586
3587   if (IS_MOVING(x,y) || IS_PLAYER(x,y))
3588     return(MF_NO_ACTION);
3589
3590   element = Feld[x][y];
3591
3592   switch(element)
3593   {
3594     case EL_LEERRAUM:
3595       break;
3596
3597     case EL_ERDREICH:
3598       Feld[x][y] = EL_LEERRAUM;
3599       break;
3600
3601     case EL_EDELSTEIN:
3602     case EL_EDELSTEIN_BD:
3603     case EL_EDELSTEIN_GELB:
3604     case EL_EDELSTEIN_ROT:
3605     case EL_EDELSTEIN_LILA:
3606     case EL_DIAMANT:
3607       RemoveField(x,y);
3608       local_player->gems_still_needed -= (element == EL_DIAMANT ? 3 : 1);
3609       if (local_player->gems_still_needed < 0)
3610         local_player->gems_still_needed = 0;
3611       RaiseScoreElement(element);
3612       DrawText(DX_EMERALDS, DY_EMERALDS,
3613                int2str(local_player->gems_still_needed, 3),
3614                FS_SMALL, FC_YELLOW);
3615       PlaySoundLevel(x, y, SND_PONG);
3616       break;
3617
3618     case EL_DYNAMIT_AUS:
3619       RemoveField(x,y);
3620       player->dynamite++;
3621       RaiseScoreElement(EL_DYNAMIT);
3622       DrawText(DX_DYNAMITE, DY_DYNAMITE,
3623                int2str(local_player->dynamite, 3),
3624                FS_SMALL, FC_YELLOW);
3625       PlaySoundLevel(x,y,SND_PONG);
3626       break;
3627
3628     case EL_DYNABOMB_NR:
3629       RemoveField(x,y);
3630       player->dynabomb_count++;
3631       player->dynabombs_left++;
3632       RaiseScoreElement(EL_DYNAMIT);
3633       PlaySoundLevel(x,y,SND_PONG);
3634       break;
3635
3636     case EL_DYNABOMB_SZ:
3637       RemoveField(x,y);
3638       player->dynabomb_size++;
3639       RaiseScoreElement(EL_DYNAMIT);
3640       PlaySoundLevel(x,y,SND_PONG);
3641       break;
3642
3643     case EL_DYNABOMB_XL:
3644       RemoveField(x,y);
3645       player->dynabomb_xl = TRUE;
3646       RaiseScoreElement(EL_DYNAMIT);
3647       PlaySoundLevel(x,y,SND_PONG);
3648       break;
3649
3650     case EL_SCHLUESSEL1:
3651     case EL_SCHLUESSEL2:
3652     case EL_SCHLUESSEL3:
3653     case EL_SCHLUESSEL4:
3654     {
3655       int key_nr = element-EL_SCHLUESSEL1;
3656
3657       RemoveField(x,y);
3658       player->key[key_nr] = TRUE;
3659       RaiseScoreElement(EL_SCHLUESSEL);
3660       DrawMiniGraphicExt(drawto,gc,
3661                          DX_KEYS+key_nr*MINI_TILEX,DY_KEYS,
3662                          GFX_SCHLUESSEL1+key_nr);
3663       DrawMiniGraphicExt(window,gc,
3664                          DX_KEYS+key_nr*MINI_TILEX,DY_KEYS,
3665                          GFX_SCHLUESSEL1+key_nr);
3666       PlaySoundLevel(x,y,SND_PONG);
3667       break;
3668     }
3669
3670     case EL_ABLENK_AUS:
3671       Feld[x][y] = EL_ABLENK_EIN;
3672       ZX = x;
3673       ZY = y;
3674       DrawLevelField(x,y);
3675       return(MF_ACTION);
3676       break;
3677
3678     case EL_FELSBROCKEN:
3679     case EL_BOMBE:
3680     case EL_KOKOSNUSS:
3681     case EL_ZEIT_LEER:
3682       if (dy || mode==DF_SNAP)
3683         return(MF_NO_ACTION);
3684
3685       player->Pushing = TRUE;
3686
3687       if (!IN_LEV_FIELD(x+dx,y+dy) || !IS_FREE(x+dx,y+dy))
3688         return(MF_NO_ACTION);
3689
3690       if (real_dy)
3691       {
3692         if (IN_LEV_FIELD(jx,jy+real_dy) && !IS_SOLID(Feld[jx][jy+real_dy]))
3693           return(MF_NO_ACTION);
3694       }
3695
3696       if (player->push_delay == 0)
3697         player->push_delay = FrameCounter;
3698       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
3699           !tape.playing)
3700         return(MF_NO_ACTION);
3701
3702       RemoveField(x,y);
3703       Feld[x+dx][y+dy] = element;
3704
3705       player->push_delay_value = 2+RND(8);
3706
3707       DrawLevelField(x+dx,y+dy);
3708       if (element==EL_FELSBROCKEN)
3709         PlaySoundLevel(x+dx,y+dy,SND_PUSCH);
3710       else if (element==EL_KOKOSNUSS)
3711         PlaySoundLevel(x+dx,y+dy,SND_KNURK);
3712       else
3713         PlaySoundLevel(x+dx,y+dy,SND_KLOPF);
3714       break;
3715
3716     case EL_PFORTE1:
3717     case EL_PFORTE2:
3718     case EL_PFORTE3:
3719     case EL_PFORTE4:
3720       if (!player->key[element-EL_PFORTE1])
3721         return(MF_NO_ACTION);
3722       break;
3723
3724     case EL_PFORTE1X:
3725     case EL_PFORTE2X:
3726     case EL_PFORTE3X:
3727     case EL_PFORTE4X:
3728       if (!player->key[element-EL_PFORTE1X])
3729         return(MF_NO_ACTION);
3730       break;
3731
3732     case EL_AUSGANG_ZU:
3733     case EL_AUSGANG_ACT:
3734       /* Tür ist (noch) nicht offen! */
3735       return(MF_NO_ACTION);
3736       break;
3737
3738     case EL_AUSGANG_AUF:
3739       if (mode==DF_SNAP)
3740         return(MF_NO_ACTION);
3741
3742       PlaySoundLevel(x,y,SND_BUING);
3743
3744       /*
3745       player->gone = TRUE;
3746       PlaySoundLevel(x,y,SND_BUING);
3747
3748       if (!local_player->friends_still_needed)
3749         player->LevelSolved = player->GameOver = TRUE;
3750       */
3751
3752       break;
3753
3754     case EL_BIRNE_AUS:
3755       Feld[x][y] = EL_BIRNE_EIN;
3756       local_player->lights_still_needed--;
3757       DrawLevelField(x,y);
3758       PlaySoundLevel(x,y,SND_DENG);
3759       return(MF_ACTION);
3760       break;
3761
3762     case EL_ZEIT_VOLL:
3763       Feld[x][y] = EL_ZEIT_LEER;
3764       TimeLeft += 10;
3765       DrawText(DX_TIME,DY_TIME,int2str(TimeLeft,3),FS_SMALL,FC_YELLOW);
3766       DrawLevelField(x,y);
3767       PlaySoundStereo(SND_GONG,PSND_MAX_RIGHT);
3768       return(MF_ACTION);
3769       break;
3770
3771     case EL_SOKOBAN_FELD_LEER:
3772       break;
3773
3774     case EL_SOKOBAN_FELD_VOLL:
3775     case EL_SOKOBAN_OBJEKT:
3776     case EL_SONDE:
3777       if (mode==DF_SNAP)
3778         return(MF_NO_ACTION);
3779
3780       player->Pushing = TRUE;
3781
3782       if (!IN_LEV_FIELD(x+dx,y+dy)
3783           || (!IS_FREE(x+dx,y+dy)
3784               && (Feld[x+dx][y+dy] != EL_SOKOBAN_FELD_LEER
3785                   || !IS_SB_ELEMENT(element))))
3786         return(MF_NO_ACTION);
3787
3788       if (dx && real_dy)
3789       {
3790         if (IN_LEV_FIELD(jx,jy+real_dy) && !IS_SOLID(Feld[jx][jy+real_dy]))
3791           return(MF_NO_ACTION);
3792       }
3793       else if (dy && real_dx)
3794       {
3795         if (IN_LEV_FIELD(jx+real_dx,jy) && !IS_SOLID(Feld[jx+real_dx][jy]))
3796           return(MF_NO_ACTION);
3797       }
3798
3799       if (player->push_delay == 0)
3800         player->push_delay = FrameCounter;
3801       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
3802           !tape.playing)
3803         return(MF_NO_ACTION);
3804
3805       if (IS_SB_ELEMENT(element))
3806       {
3807         if (element == EL_SOKOBAN_FELD_VOLL)
3808         {
3809           Feld[x][y] = EL_SOKOBAN_FELD_LEER;
3810           local_player->sokobanfields_still_needed++;
3811         }
3812         else
3813           RemoveField(x,y);
3814
3815         if (Feld[x+dx][y+dy] == EL_SOKOBAN_FELD_LEER)
3816         {
3817           Feld[x+dx][y+dy] = EL_SOKOBAN_FELD_VOLL;
3818           local_player->sokobanfields_still_needed--;
3819           if (element == EL_SOKOBAN_OBJEKT)
3820             PlaySoundLevel(x,y,SND_DENG);
3821         }
3822         else
3823           Feld[x+dx][y+dy] = EL_SOKOBAN_OBJEKT;
3824       }
3825       else
3826       {
3827         RemoveField(x,y);
3828         Feld[x+dx][y+dy] = element;
3829       }
3830
3831       player->push_delay_value = 2;
3832
3833       DrawLevelField(x,y);
3834       DrawLevelField(x+dx,y+dy);
3835       PlaySoundLevel(x+dx,y+dy,SND_PUSCH);
3836
3837       if (IS_SB_ELEMENT(element) &&
3838           local_player->sokobanfields_still_needed == 0 &&
3839           game_emulation == EMU_SOKOBAN)
3840       {
3841         player->LevelSolved = player->GameOver = TRUE;
3842         PlaySoundLevel(x,y,SND_BUING);
3843       }
3844
3845       break;
3846
3847     case EL_MAULWURF:
3848     case EL_PINGUIN:
3849     case EL_SCHWEIN:
3850     case EL_DRACHE:
3851       break;
3852
3853     default:
3854       return(MF_NO_ACTION);
3855       break;
3856   }
3857
3858   player->push_delay = 0;
3859
3860   return(MF_MOVING);
3861 }
3862
3863 BOOL SnapField(struct PlayerInfo *player, int dx, int dy)
3864 {
3865   int jx = player->jx, jy = player->jy;
3866   int x = jx + dx, y = jy + dy;
3867
3868   if (player->gone || !IN_LEV_FIELD(x,y))
3869     return(FALSE);
3870
3871   if (dx && dy)
3872     return(FALSE);
3873
3874   if (!dx && !dy)
3875   {
3876     player->snapped = FALSE;
3877     return(FALSE);
3878   }
3879
3880   if (player->snapped)
3881     return(FALSE);
3882
3883   player->MovDir = (dx < 0 ? MV_LEFT :
3884                     dx > 0 ? MV_RIGHT :
3885                     dy < 0 ? MV_UP :
3886                     dy > 0 ? MV_DOWN :  MV_NO_MOVING);
3887
3888   if (!DigField(player, x,y, 0,0, DF_SNAP))
3889     return(FALSE);
3890
3891   player->snapped = TRUE;
3892   DrawLevelField(x,y);
3893   BackToFront();
3894
3895   return(TRUE);
3896 }
3897
3898 BOOL PlaceBomb(struct PlayerInfo *player)
3899 {
3900   int jx = player->jx, jy = player->jy;
3901   int element;
3902
3903   if (player->gone || player->MovPos)
3904     return(FALSE);
3905
3906   element = Feld[jx][jy];
3907
3908   if ((player->dynamite==0 && player->dynabombs_left==0) ||
3909       element==EL_DYNAMIT || element==EL_DYNABOMB || element==EL_EXPLODING)
3910     return(FALSE);
3911
3912   if (element != EL_LEERRAUM)
3913     Store[jx][jy] = element;
3914
3915   if (player->dynamite)
3916   {
3917     Feld[jx][jy] = EL_DYNAMIT;
3918     MovDelay[jx][jy] = 96;
3919     player->dynamite--;
3920     DrawText(DX_DYNAMITE, DY_DYNAMITE, int2str(local_player->dynamite, 3),
3921              FS_SMALL, FC_YELLOW);
3922     DrawGraphicThruMask(SCREENX(jx),SCREENY(jy),GFX_DYNAMIT);
3923   }
3924   else
3925   {
3926     Feld[jx][jy] = EL_DYNABOMB;
3927     Store2[jx][jy] = EL_SPIELER1 + player->nr;  /* for DynaExplode() */
3928     MovDelay[jx][jy] = 96;
3929     player->dynabombs_left--;
3930     DrawGraphicThruMask(SCREENX(jx),SCREENY(jy),GFX_DYNABOMB);
3931   }
3932
3933   return(TRUE);
3934 }
3935
3936 void PlaySoundLevel(int x, int y, int sound_nr)
3937 {
3938   int sx = SCREENX(x), sy = SCREENY(y);
3939   int volume, stereo;
3940   int silence_distance = 8;
3941
3942   if ((!sound_simple_on && !IS_LOOP_SOUND(sound_nr)) ||
3943       (!sound_loops_on && IS_LOOP_SOUND(sound_nr)))
3944     return;
3945
3946   if (!IN_LEV_FIELD(x,y) ||
3947       sx < -silence_distance || sx >= SCR_FIELDX+silence_distance ||
3948       sy < -silence_distance || sy >= SCR_FIELDY+silence_distance)
3949     return;
3950
3951   volume = PSND_MAX_VOLUME;
3952 #ifndef MSDOS
3953   stereo = (sx-SCR_FIELDX/2)*12;
3954 #else
3955   stereo = PSND_MIDDLE+(2*sx-(SCR_FIELDX-1))*5;
3956   if(stereo > PSND_MAX_RIGHT) stereo = PSND_MAX_RIGHT;
3957   if(stereo < PSND_MAX_LEFT) stereo = PSND_MAX_LEFT;
3958 #endif
3959
3960   if (!IN_SCR_FIELD(sx,sy))
3961   {
3962     int dx = ABS(sx-SCR_FIELDX/2)-SCR_FIELDX/2;
3963     int dy = ABS(sy-SCR_FIELDY/2)-SCR_FIELDY/2;
3964
3965     volume -= volume*(dx > dy ? dx : dy)/silence_distance;
3966   }
3967
3968   PlaySoundExt(sound_nr, volume, stereo, PSND_NO_LOOP);
3969 }
3970
3971 void RaiseScore(int value)
3972 {
3973   local_player->score += value;
3974   DrawText(DX_SCORE, DY_SCORE, int2str(local_player->score, 5),
3975            FS_SMALL, FC_YELLOW);
3976 }
3977
3978 void RaiseScoreElement(int element)
3979 {
3980   switch(element)
3981   {
3982     case EL_EDELSTEIN:
3983     case EL_EDELSTEIN_BD:
3984     case EL_EDELSTEIN_GELB:
3985     case EL_EDELSTEIN_ROT:
3986     case EL_EDELSTEIN_LILA:
3987       RaiseScore(level.score[SC_EDELSTEIN]);
3988       break;
3989     case EL_DIAMANT:
3990       RaiseScore(level.score[SC_DIAMANT]);
3991       break;
3992     case EL_KAEFER:
3993     case EL_BUTTERFLY:
3994       RaiseScore(level.score[SC_KAEFER]);
3995       break;
3996     case EL_FLIEGER:
3997     case EL_FIREFLY:
3998       RaiseScore(level.score[SC_FLIEGER]);
3999       break;
4000     case EL_MAMPFER:
4001     case EL_MAMPFER2:
4002       RaiseScore(level.score[SC_MAMPFER]);
4003       break;
4004     case EL_ROBOT:
4005       RaiseScore(level.score[SC_ROBOT]);
4006       break;
4007     case EL_PACMAN:
4008       RaiseScore(level.score[SC_PACMAN]);
4009       break;
4010     case EL_KOKOSNUSS:
4011       RaiseScore(level.score[SC_KOKOSNUSS]);
4012       break;
4013     case EL_DYNAMIT:
4014       RaiseScore(level.score[SC_DYNAMIT]);
4015       break;
4016     case EL_SCHLUESSEL:
4017       RaiseScore(level.score[SC_SCHLUESSEL]);
4018       break;
4019     default:
4020       break;
4021   }
4022 }