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