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