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