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