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