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