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