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