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