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