rnd-19981024-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
3375
3376       printf("prevent player %d from leaving visible screen\n",
3377              player->index_nr);
3378
3379
3380
3381       /* actual player has left the screen -- scroll in that direction */
3382       if (jx != old_jx)         /* player has moved horizontally */
3383         scroll_x += (jx - old_jx);
3384       else                      /* player has moved vertically */
3385         scroll_y += (jy - old_jy);
3386     }
3387     else
3388     {
3389       if (jx != old_jx)         /* player has moved horizontally */
3390       {
3391         /*
3392         if ((scroll_x < jx-MIDPOSX-offset || scroll_x > jx-MIDPOSX+offset) &&
3393             jx >= MIDPOSX-1-offset && jx <= lev_fieldx-(MIDPOSX-offset))
3394           scroll_x = jx-MIDPOSX + (scroll_x < jx-MIDPOSX ? -offset : +offset);
3395         */
3396
3397         if ((player->MovDir == MV_LEFT && scroll_x > jx-MIDPOSX+offset) ||
3398             (player->MovDir == MV_RIGHT && scroll_x < jx-MIDPOSX-offset))
3399           scroll_x = jx-MIDPOSX + (scroll_x < jx-MIDPOSX ? -offset : +offset);
3400
3401         /* don't scroll over playfield boundaries */
3402         if (scroll_x < -1 || scroll_x > lev_fieldx - SCR_FIELDX + 2)
3403           scroll_x = (scroll_x < -1 ? -1 : lev_fieldx - SCR_FIELDX + 2);
3404
3405         /* don't scroll more than one field at a time */
3406         scroll_x = old_scroll_x + SIGN(scroll_x - old_scroll_x);
3407
3408         /* don't scroll against the player's moving direction */
3409         if ((player->MovDir == MV_LEFT && scroll_x > old_scroll_x) ||
3410             (player->MovDir == MV_RIGHT && scroll_x < old_scroll_x))
3411           scroll_x = old_scroll_x;
3412       }
3413       else                      /* player has moved vertically */
3414       {
3415         /*
3416         if ((scroll_y < jy-MIDPOSY-offset || scroll_y > jy-MIDPOSY+offset) &&
3417             jy >= MIDPOSY-1-offset && jy <= lev_fieldy-(MIDPOSY-offset))
3418           scroll_y = jy-MIDPOSY + (scroll_y < jy-MIDPOSY ? -offset : +offset);
3419         */
3420
3421         if ((player->MovDir == MV_UP && scroll_y > jy-MIDPOSY+offset) ||
3422             (player->MovDir == MV_DOWN && scroll_y < jy-MIDPOSY-offset))
3423           scroll_y = jy-MIDPOSY + (scroll_y < jy-MIDPOSY ? -offset : +offset);
3424
3425         /* don't scroll over playfield boundaries */
3426         if (scroll_y < -1 || scroll_y > lev_fieldy - SCR_FIELDY + 2)
3427           scroll_y = (scroll_y < -1 ? -1 : lev_fieldy - SCR_FIELDY + 2);
3428
3429         /* don't scroll more than one field at a time */
3430         scroll_y = old_scroll_y + SIGN(scroll_y - old_scroll_y);
3431
3432         /* don't scroll against the player's moving direction */
3433         if ((player->MovDir == MV_UP && scroll_y > old_scroll_y) ||
3434             (player->MovDir == MV_DOWN && scroll_y < old_scroll_y))
3435           scroll_y = old_scroll_y;
3436       }
3437     }
3438
3439 #if 0
3440     if (player == local_player)
3441     {
3442       if ((scroll_x < jx-MIDPOSX-offset || scroll_x > jx-MIDPOSX+offset) &&
3443           jx >= MIDPOSX-1-offset && jx <= lev_fieldx-(MIDPOSX-offset))
3444         scroll_x = jx-MIDPOSX + (scroll_x < jx-MIDPOSX ? -offset : offset);
3445       if ((scroll_y < jy-MIDPOSY-offset || scroll_y > jy-MIDPOSY+offset) &&
3446           jy >= MIDPOSY-1-offset && jy <= lev_fieldy-(MIDPOSY-offset))
3447         scroll_y = jy-MIDPOSY + (scroll_y < jy-MIDPOSY ? -offset : offset);
3448
3449       /* don't scroll more than one field at a time */
3450       scroll_x = old_scroll_x + SIGN(scroll_x - old_scroll_x);
3451       scroll_y = old_scroll_y + SIGN(scroll_y - old_scroll_y);
3452     }
3453 #endif
3454
3455     if (scroll_x != old_scroll_x || scroll_y != old_scroll_y)
3456     {
3457       if (!options.network && !AllPlayersInVisibleScreen())
3458       {
3459
3460
3461         printf("oops! not all players visible if we scroll now\n");
3462
3463
3464
3465         scroll_x = old_scroll_x;
3466         scroll_y = old_scroll_y;
3467       }
3468       else
3469       {
3470
3471
3472         printf("ok, scrolling screen...\n");
3473
3474
3475
3476         ScrollScreen(player, SCROLL_INIT);
3477         ScrollLevel(old_scroll_x - scroll_x, old_scroll_y - scroll_y);
3478       }
3479     }
3480   }
3481
3482   if (!(moved & MF_MOVING) && !player->Pushing)
3483     player->Frame = 0;
3484   else
3485     player->Frame = (player->Frame + 1) % 4;
3486
3487   if (moved & MF_MOVING)
3488   {
3489     if (old_jx != jx && old_jy == jy)
3490       player->MovDir = (old_jx < jx ? MV_RIGHT : MV_LEFT);
3491     else if (old_jx == jx && old_jy != jy)
3492       player->MovDir = (old_jy < jy ? MV_DOWN : MV_UP);
3493
3494     DrawLevelField(jx,jy);      /* für "ErdreichAnbroeckeln()" */
3495
3496     player->last_move_dir = player->MovDir;
3497   }
3498   else
3499     player->last_move_dir = MV_NO_MOVING;
3500
3501   TestIfHeroHitsBadThing(jx,jy);
3502
3503   if (player->gone)
3504     RemoveHero(player);
3505
3506   return(moved);
3507 }
3508
3509 void ScrollFigure(struct PlayerInfo *player, int mode)
3510 {
3511   int jx = player->jx, jy = player->jy;
3512   int last_jx = player->last_jx, last_jy = player->last_jy;
3513
3514   if (!player->active || player->gone || !player->MovPos)
3515     return;
3516
3517   if (mode == SCROLL_INIT)
3518   {
3519     player->actual_frame_counter = FrameCounter;
3520     player->GfxPos = ScrollStepSize * (player->MovPos / ScrollStepSize);
3521
3522     if (Feld[last_jx][last_jy] == EL_LEERRAUM)
3523       Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING;
3524
3525     DrawPlayer(player);
3526     return;
3527   }
3528   else if (!FrameReached(&player->actual_frame_counter,1))
3529     return;
3530
3531   player->MovPos += (player->MovPos > 0 ? -1 : 1) * TILEX/8;
3532   player->GfxPos = ScrollStepSize * (player->MovPos / ScrollStepSize);
3533
3534   if (Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING)
3535     Feld[last_jx][last_jy] = EL_LEERRAUM;
3536
3537   DrawPlayer(player);
3538
3539   if (!player->MovPos)
3540   {
3541     player->last_jx = jx;
3542     player->last_jy = jy;
3543
3544     if (Feld[jx][jy] == EL_AUSGANG_AUF)
3545     {
3546       RemoveHero(player);
3547
3548       if (!local_player->friends_still_needed)
3549         player->LevelSolved = player->GameOver = TRUE;
3550     }
3551   }
3552 }
3553
3554 void ScrollScreen(struct PlayerInfo *player, int mode)
3555 {
3556   static long screen_frame_counter = 0;
3557
3558   if (mode == SCROLL_INIT)
3559   {
3560     screen_frame_counter = FrameCounter;
3561     ScreenMovDir = player->MovDir;
3562     ScreenMovPos = player->MovPos;
3563     ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
3564     return;
3565   }
3566   else if (!FrameReached(&screen_frame_counter,1))
3567     return;
3568
3569   if (ScreenMovPos)
3570   {
3571     ScreenMovPos += (ScreenMovPos > 0 ? -1 : 1) * TILEX/8;
3572     ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
3573     redraw_mask |= REDRAW_FIELD;
3574   }
3575   else
3576     ScreenMovDir = MV_NO_MOVING;
3577 }
3578
3579 void TestIfGoodThingHitsBadThing(int goodx, int goody)
3580 {
3581   int i, killx = goodx, killy = goody;
3582   static int xy[4][2] =
3583   {
3584     { 0,-1 },
3585     { -1,0 },
3586     { +1,0 },
3587     { 0,+1 }
3588   };
3589   static int harmless[4] =
3590   {
3591     MV_UP,
3592     MV_LEFT,
3593     MV_RIGHT,
3594     MV_DOWN
3595   };
3596
3597   for(i=0; i<4; i++)
3598   {
3599     int x,y, element;
3600
3601     x = goodx + xy[i][0];
3602     y = goody + xy[i][1];
3603     if (!IN_LEV_FIELD(x,y))
3604       continue;
3605
3606     element = Feld[x][y];
3607
3608     if (DONT_TOUCH(element))
3609     {
3610       if (MovDir[x][y] == harmless[i])
3611         continue;
3612
3613       killx = x;
3614       killy = y;
3615       break;
3616     }
3617   }
3618
3619   if (killx != goodx || killy != goody)
3620   {
3621     if (IS_PLAYER(goodx,goody))
3622       KillHero(PLAYERINFO(goodx,goody));
3623     else
3624       Bang(goodx,goody);
3625   }
3626 }
3627
3628 void TestIfBadThingHitsGoodThing(int badx, int bady)
3629 {
3630   int i, killx = badx, killy = bady;
3631   static int xy[4][2] =
3632   {
3633     { 0,-1 },
3634     { -1,0 },
3635     { +1,0 },
3636     { 0,+1 }
3637   };
3638   static int harmless[4] =
3639   {
3640     MV_UP,
3641     MV_LEFT,
3642     MV_RIGHT,
3643     MV_DOWN
3644   };
3645
3646   for(i=0; i<4; i++)
3647   {
3648     int x,y, element;
3649
3650     x = badx + xy[i][0];
3651     y = bady + xy[i][1];
3652     if (!IN_LEV_FIELD(x,y))
3653       continue;
3654
3655     element = Feld[x][y];
3656
3657     if (IS_PLAYER(x,y))
3658     {
3659       killx = x;
3660       killy = y;
3661       break;
3662     }
3663     else if (element == EL_PINGUIN)
3664     {
3665       if (MovDir[x][y] == harmless[i] && IS_MOVING(x,y))
3666         continue;
3667
3668       killx = x;
3669       killy = y;
3670       break;
3671     }
3672   }
3673
3674   if (killx != badx || killy != bady)
3675   {
3676     if (IS_PLAYER(killx,killy))
3677       KillHero(PLAYERINFO(killx,killy));
3678     else
3679       Bang(killx,killy);
3680   }
3681 }
3682
3683 void TestIfHeroHitsBadThing(int x, int y)
3684 {
3685   TestIfGoodThingHitsBadThing(x,y);
3686 }
3687
3688 void TestIfBadThingHitsHero(int x, int y)
3689 {
3690   /*
3691   TestIfGoodThingHitsBadThing(JX,JY);
3692   */
3693
3694   TestIfBadThingHitsGoodThing(x,y);
3695 }
3696
3697 void TestIfFriendHitsBadThing(int x, int y)
3698 {
3699   TestIfGoodThingHitsBadThing(x,y);
3700 }
3701
3702 void TestIfBadThingHitsFriend(int x, int y)
3703 {
3704   TestIfBadThingHitsGoodThing(x,y);
3705 }
3706
3707 void TestIfBadThingHitsOtherBadThing(int badx, int bady)
3708 {
3709   int i, killx = badx, killy = bady;
3710   static int xy[4][2] =
3711   {
3712     { 0,-1 },
3713     { -1,0 },
3714     { +1,0 },
3715     { 0,+1 }
3716   };
3717
3718   for(i=0; i<4; i++)
3719   {
3720     int x,y, element;
3721
3722     x=badx + xy[i][0];
3723     y=bady + xy[i][1];
3724     if (!IN_LEV_FIELD(x,y))
3725       continue;
3726
3727     element = Feld[x][y];
3728     if (IS_AMOEBOID(element) || element == EL_LIFE ||
3729         element == EL_AMOEBING || element == EL_TROPFEN)
3730     {
3731       killx = x;
3732       killy = y;
3733       break;
3734     }
3735   }
3736
3737   if (killx != badx || killy != bady)
3738     Bang(badx,bady);
3739 }
3740
3741 void KillHero(struct PlayerInfo *player)
3742 {
3743   int jx = player->jx, jy = player->jy;
3744
3745   if (player->gone)
3746     return;
3747
3748   if (IS_PFORTE(Feld[jx][jy]))
3749     Feld[jx][jy] = EL_LEERRAUM;
3750
3751   Bang(jx,jy);
3752   BuryHero(player);
3753 }
3754
3755 void BuryHero(struct PlayerInfo *player)
3756 {
3757   int jx = player->jx, jy = player->jy;
3758
3759   if (player->gone)
3760     return;
3761
3762   PlaySoundLevel(jx,jy, SND_AUTSCH);
3763   PlaySoundLevel(jx,jy, SND_LACHEN);
3764
3765   player->GameOver = TRUE;
3766   RemoveHero(player);
3767 }
3768
3769 void RemoveHero(struct PlayerInfo *player)
3770 {
3771   int jx = player->jx, jy = player->jy;
3772   int i, found = FALSE;
3773
3774   player->gone = TRUE;
3775   StorePlayer[jx][jy] = 0;
3776
3777   for(i=0; i<MAX_PLAYERS; i++)
3778     if (stored_player[i].active && !stored_player[i].gone)
3779       found = TRUE;
3780
3781   if (!found)
3782     AllPlayersGone = TRUE;
3783
3784   ExitX = ZX = jx;
3785   ExitY = ZY = jy;
3786 }
3787
3788 int DigField(struct PlayerInfo *player,
3789              int x, int y, int real_dx, int real_dy, int mode)
3790 {
3791   int jx = player->jx, jy = player->jy;
3792   int dx = x - jx, dy = y - jy;
3793   int element;
3794
3795   if (!player->MovPos)
3796     player->Pushing = FALSE;
3797
3798   if (mode == DF_NO_PUSH)
3799   {
3800     player->push_delay = 0;
3801     return(MF_NO_ACTION);
3802   }
3803
3804   if (IS_MOVING(x,y) || IS_PLAYER(x,y))
3805     return(MF_NO_ACTION);
3806
3807   element = Feld[x][y];
3808
3809   switch(element)
3810   {
3811     case EL_LEERRAUM:
3812       break;
3813
3814     case EL_ERDREICH:
3815       Feld[x][y] = EL_LEERRAUM;
3816       break;
3817
3818     case EL_EDELSTEIN:
3819     case EL_EDELSTEIN_BD:
3820     case EL_EDELSTEIN_GELB:
3821     case EL_EDELSTEIN_ROT:
3822     case EL_EDELSTEIN_LILA:
3823     case EL_DIAMANT:
3824       RemoveField(x,y);
3825       local_player->gems_still_needed -= (element == EL_DIAMANT ? 3 : 1);
3826       if (local_player->gems_still_needed < 0)
3827         local_player->gems_still_needed = 0;
3828       RaiseScoreElement(element);
3829       DrawText(DX_EMERALDS, DY_EMERALDS,
3830                int2str(local_player->gems_still_needed, 3),
3831                FS_SMALL, FC_YELLOW);
3832       PlaySoundLevel(x, y, SND_PONG);
3833       break;
3834
3835     case EL_DYNAMIT_AUS:
3836       RemoveField(x,y);
3837       player->dynamite++;
3838       RaiseScoreElement(EL_DYNAMIT);
3839       DrawText(DX_DYNAMITE, DY_DYNAMITE,
3840                int2str(local_player->dynamite, 3),
3841                FS_SMALL, FC_YELLOW);
3842       PlaySoundLevel(x,y,SND_PONG);
3843       break;
3844
3845     case EL_DYNABOMB_NR:
3846       RemoveField(x,y);
3847       player->dynabomb_count++;
3848       player->dynabombs_left++;
3849       RaiseScoreElement(EL_DYNAMIT);
3850       PlaySoundLevel(x,y,SND_PONG);
3851       break;
3852
3853     case EL_DYNABOMB_SZ:
3854       RemoveField(x,y);
3855       player->dynabomb_size++;
3856       RaiseScoreElement(EL_DYNAMIT);
3857       PlaySoundLevel(x,y,SND_PONG);
3858       break;
3859
3860     case EL_DYNABOMB_XL:
3861       RemoveField(x,y);
3862       player->dynabomb_xl = TRUE;
3863       RaiseScoreElement(EL_DYNAMIT);
3864       PlaySoundLevel(x,y,SND_PONG);
3865       break;
3866
3867     case EL_SCHLUESSEL1:
3868     case EL_SCHLUESSEL2:
3869     case EL_SCHLUESSEL3:
3870     case EL_SCHLUESSEL4:
3871     {
3872       int key_nr = element-EL_SCHLUESSEL1;
3873
3874       RemoveField(x,y);
3875       player->key[key_nr] = TRUE;
3876       RaiseScoreElement(EL_SCHLUESSEL);
3877       DrawMiniGraphicExt(drawto,gc,
3878                          DX_KEYS+key_nr*MINI_TILEX,DY_KEYS,
3879                          GFX_SCHLUESSEL1+key_nr);
3880       DrawMiniGraphicExt(window,gc,
3881                          DX_KEYS+key_nr*MINI_TILEX,DY_KEYS,
3882                          GFX_SCHLUESSEL1+key_nr);
3883       PlaySoundLevel(x,y,SND_PONG);
3884       break;
3885     }
3886
3887     case EL_ABLENK_AUS:
3888       Feld[x][y] = EL_ABLENK_EIN;
3889       ZX = x;
3890       ZY = y;
3891       DrawLevelField(x,y);
3892       return(MF_ACTION);
3893       break;
3894
3895     case EL_FELSBROCKEN:
3896     case EL_BOMBE:
3897     case EL_KOKOSNUSS:
3898     case EL_ZEIT_LEER:
3899       if (dy || mode==DF_SNAP)
3900         return(MF_NO_ACTION);
3901
3902       player->Pushing = TRUE;
3903
3904       if (!IN_LEV_FIELD(x+dx,y+dy) || !IS_FREE(x+dx,y+dy))
3905         return(MF_NO_ACTION);
3906
3907       if (real_dy)
3908       {
3909         if (IN_LEV_FIELD(jx,jy+real_dy) && !IS_SOLID(Feld[jx][jy+real_dy]))
3910           return(MF_NO_ACTION);
3911       }
3912
3913       if (player->push_delay == 0)
3914         player->push_delay = FrameCounter;
3915       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
3916           !tape.playing)
3917         return(MF_NO_ACTION);
3918
3919       RemoveField(x,y);
3920       Feld[x+dx][y+dy] = element;
3921
3922       player->push_delay_value = 2+RND(8);
3923
3924       DrawLevelField(x+dx,y+dy);
3925       if (element==EL_FELSBROCKEN)
3926         PlaySoundLevel(x+dx,y+dy,SND_PUSCH);
3927       else if (element==EL_KOKOSNUSS)
3928         PlaySoundLevel(x+dx,y+dy,SND_KNURK);
3929       else
3930         PlaySoundLevel(x+dx,y+dy,SND_KLOPF);
3931       break;
3932
3933     case EL_PFORTE1:
3934     case EL_PFORTE2:
3935     case EL_PFORTE3:
3936     case EL_PFORTE4:
3937       if (!player->key[element-EL_PFORTE1])
3938         return(MF_NO_ACTION);
3939       break;
3940
3941     case EL_PFORTE1X:
3942     case EL_PFORTE2X:
3943     case EL_PFORTE3X:
3944     case EL_PFORTE4X:
3945       if (!player->key[element-EL_PFORTE1X])
3946         return(MF_NO_ACTION);
3947       break;
3948
3949     case EL_AUSGANG_ZU:
3950     case EL_AUSGANG_ACT:
3951       /* Tür ist (noch) nicht offen! */
3952       return(MF_NO_ACTION);
3953       break;
3954
3955     case EL_AUSGANG_AUF:
3956       if (mode==DF_SNAP)
3957         return(MF_NO_ACTION);
3958
3959       PlaySoundLevel(x,y,SND_BUING);
3960
3961       /*
3962       player->gone = TRUE;
3963       PlaySoundLevel(x,y,SND_BUING);
3964
3965       if (!local_player->friends_still_needed)
3966         player->LevelSolved = player->GameOver = TRUE;
3967       */
3968
3969       break;
3970
3971     case EL_BIRNE_AUS:
3972       Feld[x][y] = EL_BIRNE_EIN;
3973       local_player->lights_still_needed--;
3974       DrawLevelField(x,y);
3975       PlaySoundLevel(x,y,SND_DENG);
3976       return(MF_ACTION);
3977       break;
3978
3979     case EL_ZEIT_VOLL:
3980       Feld[x][y] = EL_ZEIT_LEER;
3981       TimeLeft += 10;
3982       DrawText(DX_TIME,DY_TIME,int2str(TimeLeft,3),FS_SMALL,FC_YELLOW);
3983       DrawLevelField(x,y);
3984       PlaySoundStereo(SND_GONG,PSND_MAX_RIGHT);
3985       return(MF_ACTION);
3986       break;
3987
3988     case EL_SOKOBAN_FELD_LEER:
3989       break;
3990
3991     case EL_SOKOBAN_FELD_VOLL:
3992     case EL_SOKOBAN_OBJEKT:
3993     case EL_SONDE:
3994       if (mode==DF_SNAP)
3995         return(MF_NO_ACTION);
3996
3997       player->Pushing = TRUE;
3998
3999       if (!IN_LEV_FIELD(x+dx,y+dy)
4000           || (!IS_FREE(x+dx,y+dy)
4001               && (Feld[x+dx][y+dy] != EL_SOKOBAN_FELD_LEER
4002                   || !IS_SB_ELEMENT(element))))
4003         return(MF_NO_ACTION);
4004
4005       if (dx && real_dy)
4006       {
4007         if (IN_LEV_FIELD(jx,jy+real_dy) && !IS_SOLID(Feld[jx][jy+real_dy]))
4008           return(MF_NO_ACTION);
4009       }
4010       else if (dy && real_dx)
4011       {
4012         if (IN_LEV_FIELD(jx+real_dx,jy) && !IS_SOLID(Feld[jx+real_dx][jy]))
4013           return(MF_NO_ACTION);
4014       }
4015
4016       if (player->push_delay == 0)
4017         player->push_delay = FrameCounter;
4018       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
4019           !tape.playing)
4020         return(MF_NO_ACTION);
4021
4022       if (IS_SB_ELEMENT(element))
4023       {
4024         if (element == EL_SOKOBAN_FELD_VOLL)
4025         {
4026           Feld[x][y] = EL_SOKOBAN_FELD_LEER;
4027           local_player->sokobanfields_still_needed++;
4028         }
4029         else
4030           RemoveField(x,y);
4031
4032         if (Feld[x+dx][y+dy] == EL_SOKOBAN_FELD_LEER)
4033         {
4034           Feld[x+dx][y+dy] = EL_SOKOBAN_FELD_VOLL;
4035           local_player->sokobanfields_still_needed--;
4036           if (element == EL_SOKOBAN_OBJEKT)
4037             PlaySoundLevel(x,y,SND_DENG);
4038         }
4039         else
4040           Feld[x+dx][y+dy] = EL_SOKOBAN_OBJEKT;
4041       }
4042       else
4043       {
4044         RemoveField(x,y);
4045         Feld[x+dx][y+dy] = element;
4046       }
4047
4048       player->push_delay_value = 2;
4049
4050       DrawLevelField(x,y);
4051       DrawLevelField(x+dx,y+dy);
4052       PlaySoundLevel(x+dx,y+dy,SND_PUSCH);
4053
4054       if (IS_SB_ELEMENT(element) &&
4055           local_player->sokobanfields_still_needed == 0 &&
4056           game_emulation == EMU_SOKOBAN)
4057       {
4058         player->LevelSolved = player->GameOver = TRUE;
4059         PlaySoundLevel(x,y,SND_BUING);
4060       }
4061
4062       break;
4063
4064     case EL_MAULWURF:
4065     case EL_PINGUIN:
4066     case EL_SCHWEIN:
4067     case EL_DRACHE:
4068       break;
4069
4070     default:
4071       return(MF_NO_ACTION);
4072       break;
4073   }
4074
4075   player->push_delay = 0;
4076
4077   return(MF_MOVING);
4078 }
4079
4080 boolean SnapField(struct PlayerInfo *player, int dx, int dy)
4081 {
4082   int jx = player->jx, jy = player->jy;
4083   int x = jx + dx, y = jy + dy;
4084
4085   if (player->gone || !IN_LEV_FIELD(x,y))
4086     return(FALSE);
4087
4088   if (dx && dy)
4089     return(FALSE);
4090
4091   if (!dx && !dy)
4092   {
4093     player->snapped = FALSE;
4094     return(FALSE);
4095   }
4096
4097   if (player->snapped)
4098     return(FALSE);
4099
4100   player->MovDir = (dx < 0 ? MV_LEFT :
4101                     dx > 0 ? MV_RIGHT :
4102                     dy < 0 ? MV_UP :
4103                     dy > 0 ? MV_DOWN :  MV_NO_MOVING);
4104
4105   if (!DigField(player, x,y, 0,0, DF_SNAP))
4106     return(FALSE);
4107
4108   player->snapped = TRUE;
4109   DrawLevelField(x,y);
4110   BackToFront();
4111
4112   return(TRUE);
4113 }
4114
4115 boolean PlaceBomb(struct PlayerInfo *player)
4116 {
4117   int jx = player->jx, jy = player->jy;
4118   int element;
4119
4120   if (player->gone || player->MovPos)
4121     return(FALSE);
4122
4123   element = Feld[jx][jy];
4124
4125   if ((player->dynamite==0 && player->dynabombs_left==0) ||
4126       element==EL_DYNAMIT || element==EL_DYNABOMB || element==EL_EXPLODING)
4127     return(FALSE);
4128
4129   if (element != EL_LEERRAUM)
4130     Store[jx][jy] = element;
4131
4132   if (player->dynamite)
4133   {
4134     Feld[jx][jy] = EL_DYNAMIT;
4135     MovDelay[jx][jy] = 96;
4136     player->dynamite--;
4137     DrawText(DX_DYNAMITE, DY_DYNAMITE, int2str(local_player->dynamite, 3),
4138              FS_SMALL, FC_YELLOW);
4139     if (IN_SCR_FIELD(SCREENX(jx),SCREENY(jy)))
4140       DrawGraphicThruMask(SCREENX(jx),SCREENY(jy),GFX_DYNAMIT);
4141   }
4142   else
4143   {
4144     Feld[jx][jy] = EL_DYNABOMB;
4145     Store2[jx][jy] = player->element_nr;        /* for DynaExplode() */
4146     MovDelay[jx][jy] = 96;
4147     player->dynabombs_left--;
4148     if (IN_SCR_FIELD(SCREENX(jx),SCREENY(jy)))
4149       DrawGraphicThruMask(SCREENX(jx),SCREENY(jy),GFX_DYNABOMB);
4150   }
4151
4152   return(TRUE);
4153 }
4154
4155 void PlaySoundLevel(int x, int y, int sound_nr)
4156 {
4157   int sx = SCREENX(x), sy = SCREENY(y);
4158   int volume, stereo;
4159   int silence_distance = 8;
4160
4161   if ((!setup.sound_simple_on && !IS_LOOP_SOUND(sound_nr)) ||
4162       (!setup.sound_loops_on && IS_LOOP_SOUND(sound_nr)))
4163     return;
4164
4165   if (!IN_LEV_FIELD(x,y) ||
4166       sx < -silence_distance || sx >= SCR_FIELDX+silence_distance ||
4167       sy < -silence_distance || sy >= SCR_FIELDY+silence_distance)
4168     return;
4169
4170   volume = PSND_MAX_VOLUME;
4171 #ifndef MSDOS
4172   stereo = (sx-SCR_FIELDX/2)*12;
4173 #else
4174   stereo = PSND_MIDDLE+(2*sx-(SCR_FIELDX-1))*5;
4175   if(stereo > PSND_MAX_RIGHT) stereo = PSND_MAX_RIGHT;
4176   if(stereo < PSND_MAX_LEFT) stereo = PSND_MAX_LEFT;
4177 #endif
4178
4179   if (!IN_SCR_FIELD(sx,sy))
4180   {
4181     int dx = ABS(sx-SCR_FIELDX/2)-SCR_FIELDX/2;
4182     int dy = ABS(sy-SCR_FIELDY/2)-SCR_FIELDY/2;
4183
4184     volume -= volume*(dx > dy ? dx : dy)/silence_distance;
4185   }
4186
4187   PlaySoundExt(sound_nr, volume, stereo, PSND_NO_LOOP);
4188 }
4189
4190 void RaiseScore(int value)
4191 {
4192   local_player->score += value;
4193   DrawText(DX_SCORE, DY_SCORE, int2str(local_player->score, 5),
4194            FS_SMALL, FC_YELLOW);
4195 }
4196
4197 void RaiseScoreElement(int element)
4198 {
4199   switch(element)
4200   {
4201     case EL_EDELSTEIN:
4202     case EL_EDELSTEIN_BD:
4203     case EL_EDELSTEIN_GELB:
4204     case EL_EDELSTEIN_ROT:
4205     case EL_EDELSTEIN_LILA:
4206       RaiseScore(level.score[SC_EDELSTEIN]);
4207       break;
4208     case EL_DIAMANT:
4209       RaiseScore(level.score[SC_DIAMANT]);
4210       break;
4211     case EL_KAEFER:
4212     case EL_BUTTERFLY:
4213       RaiseScore(level.score[SC_KAEFER]);
4214       break;
4215     case EL_FLIEGER:
4216     case EL_FIREFLY:
4217       RaiseScore(level.score[SC_FLIEGER]);
4218       break;
4219     case EL_MAMPFER:
4220     case EL_MAMPFER2:
4221       RaiseScore(level.score[SC_MAMPFER]);
4222       break;
4223     case EL_ROBOT:
4224       RaiseScore(level.score[SC_ROBOT]);
4225       break;
4226     case EL_PACMAN:
4227       RaiseScore(level.score[SC_PACMAN]);
4228       break;
4229     case EL_KOKOSNUSS:
4230       RaiseScore(level.score[SC_KOKOSNUSS]);
4231       break;
4232     case EL_DYNAMIT:
4233       RaiseScore(level.score[SC_DYNAMIT]);
4234       break;
4235     case EL_SCHLUESSEL:
4236       RaiseScore(level.score[SC_SCHLUESSEL]);
4237       break;
4238     default:
4239       break;
4240   }
4241 }