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