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