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