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