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