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