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