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