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