1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * ©1995 Artsoft Development *
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 *----------------------------------------------------------*
13 ***********************************************************/
27 extern int Movemethod;
28 extern int Movespeed[2];
30 void GetPlayerConfig()
32 int old_joystick_nr = joystick_nr;
34 if (sound_status==SOUND_OFF)
35 player.setup &= ~SETUP_SOUND;
36 if (!sound_loops_allowed)
38 player.setup &= ~SETUP_SOUND_LOOPS;
39 player.setup &= ~SETUP_SOUND_MUSIC;
42 sound_on = sound_simple_on = SETUP_SOUND_ON(player.setup);
43 sound_loops_on = SETUP_SOUND_LOOPS_ON(player.setup);
44 sound_music_on = SETUP_SOUND_MUSIC_ON(player.setup);
45 toons_on = SETUP_TOONS_ON(player.setup);
46 direct_draw_on = SETUP_DIRECT_DRAW_ON(player.setup);
47 fading_on = SETUP_FADING_ON(player.setup);
48 autorecord_on = SETUP_AUTO_RECORD_ON(player.setup);
49 joystick_nr = SETUP_2ND_JOYSTICK_ON(player.setup);
50 quick_doors = SETUP_QUICK_DOORS_ON(player.setup);
51 scroll_delay_on = SETUP_SCROLL_DELAY_ON(player.setup);
53 if (joystick_nr != old_joystick_nr)
56 close(joystick_device);
64 BOOL emulate_bd = TRUE; /* unless non-BOULDERDASH elements found */
65 BOOL emulate_sb = TRUE; /* unless non-SOKOBAN elements found */
68 Gems = level.edelsteine;
69 SokobanFields = Lights = Friends = 0;
70 DynaBombCount = DynaBombSize = DynaBombsLeft = 0;
72 Key[0] = Key[1] = Key[2] = Key[3] = FALSE;
76 TimeLeft = level.time;
77 PlayerMovDir = MV_NO_MOVING;
79 PlayerPushing = FALSE;
80 PlayerGone = LevelSolved = GameOver = SiebAktiv = FALSE;
84 DigField(0,0,0,0,DF_NO_PUSH);
87 for(i=0;i<MAX_NUM_AMOEBA;i++)
88 AmoebaCnt[i] = AmoebaCnt2[i] = 0;
90 for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
92 Feld[x][y] = Ur[x][y];
93 MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
94 Store[x][y] = Store2[x][y] = Frame[x][y] = AmoebaNr[x][y] = 0;
97 if (emulate_bd && !IS_BD_ELEMENT(Feld[x][y]))
99 if (emulate_sb && !IS_SB_ELEMENT(Feld[x][y]))
106 Feld[x][y] = EL_LEERRAUM;
111 Feld[x][y] = EL_LEERRAUM;
114 if (x<lev_fieldx-1 && Feld[x+1][y]==EL_SALZSAEURE)
115 Feld[x][y] = EL_BADEWANNE1;
116 else if (x>0 && Feld[x-1][y]==EL_SALZSAEURE)
117 Feld[x][y] = EL_BADEWANNE2;
118 else if (y>0 && Feld[x][y-1]==EL_BADEWANNE1)
119 Feld[x][y] = EL_BADEWANNE3;
120 else if (y>0 && Feld[x][y-1]==EL_SALZSAEURE)
121 Feld[x][y] = EL_BADEWANNE4;
122 else if (y>0 && Feld[x][y-1]==EL_BADEWANNE2)
123 Feld[x][y] = EL_BADEWANNE5;
162 Feld[x][y] = EL_AMOEBING;
163 Store[x][y] = EL_AMOEBE_NASS;
172 case EL_SOKOBAN_FELD_LEER:
181 MovDir[x][y] = 1<<RND(4);
188 game_emulation = (emulate_bd ? EMU_BOULDERDASH :
189 emulate_sb ? EMU_SOKOBAN : EMU_NONE);
191 scroll_x = scroll_y = -1;
194 (JX<=lev_fieldx-MIDPOSX ? JX-MIDPOSX : lev_fieldx-SCR_FIELDX+1);
197 (JY<=lev_fieldy-MIDPOSY ? JY-MIDPOSY : lev_fieldy-SCR_FIELDY+1);
199 CloseDoor(DOOR_CLOSE_1);
202 DrawLevelElement(JX,JY,EL_SPIELFIGUR);
205 XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
206 DOOR_GFX_PAGEX5,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
207 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
208 DrawTextExt(pix[PIX_DB_DOOR],gc,
209 DOOR_GFX_PAGEX1+XX_LEVEL,DOOR_GFX_PAGEY1+YY_LEVEL,
210 int2str(level_nr,2),FS_SMALL,FC_YELLOW);
211 DrawTextExt(pix[PIX_DB_DOOR],gc,
212 DOOR_GFX_PAGEX1+XX_EMERALDS,DOOR_GFX_PAGEY1+YY_EMERALDS,
213 int2str(Gems,3),FS_SMALL,FC_YELLOW);
214 DrawTextExt(pix[PIX_DB_DOOR],gc,
215 DOOR_GFX_PAGEX1+XX_DYNAMITE,DOOR_GFX_PAGEY1+YY_DYNAMITE,
216 int2str(Dynamite,3),FS_SMALL,FC_YELLOW);
217 DrawTextExt(pix[PIX_DB_DOOR],gc,
218 DOOR_GFX_PAGEX1+XX_SCORE,DOOR_GFX_PAGEY1+YY_SCORE,
219 int2str(Score,5),FS_SMALL,FC_YELLOW);
220 DrawTextExt(pix[PIX_DB_DOOR],gc,
221 DOOR_GFX_PAGEX1+XX_TIME,DOOR_GFX_PAGEY1+YY_TIME,
222 int2str(TimeLeft,3),FS_SMALL,FC_YELLOW);
224 DrawGameButton(BUTTON_GAME_STOP);
225 DrawGameButton(BUTTON_GAME_PAUSE);
226 DrawGameButton(BUTTON_GAME_PLAY);
227 DrawSoundDisplay(BUTTON_SOUND_MUSIC | (BUTTON_ON * sound_music_on));
228 DrawSoundDisplay(BUTTON_SOUND_LOOPS | (BUTTON_ON * sound_loops_on));
229 DrawSoundDisplay(BUTTON_SOUND_SIMPLE | (BUTTON_ON * sound_simple_on));
230 XCopyArea(display,drawto,pix[PIX_DB_DOOR],gc,
231 DX+GAME_CONTROL_XPOS,DY+GAME_CONTROL_YPOS,
232 GAME_CONTROL_XSIZE,2*GAME_CONTROL_YSIZE,
233 DOOR_GFX_PAGEX1+GAME_CONTROL_XPOS,
234 DOOR_GFX_PAGEY1+GAME_CONTROL_YPOS);
236 OpenDoor(DOOR_OPEN_1);
239 PlaySoundLoop(background_loop[level_nr % num_bg_loops]);
241 XAutoRepeatOff(display);
244 void InitMovDir(int x, int y)
246 int i, element = Feld[x][y];
247 static int xy[4][2] =
254 static int direction[2][4] =
256 { MV_RIGHT, MV_UP, MV_LEFT, MV_DOWN },
257 { MV_LEFT, MV_DOWN, MV_RIGHT, MV_UP }
266 Feld[x][y] = EL_KAEFER;
267 MovDir[x][y] = direction[0][element-EL_KAEFER_R];
273 Feld[x][y] = EL_FLIEGER;
274 MovDir[x][y] = direction[0][element-EL_FLIEGER_R];
280 Feld[x][y] = EL_BUTTERFLY;
281 MovDir[x][y] = direction[0][element-EL_BUTTERFLY_R];
287 Feld[x][y] = EL_FIREFLY;
288 MovDir[x][y] = direction[0][element-EL_FIREFLY_R];
294 Feld[x][y] = EL_PACMAN;
295 MovDir[x][y] = direction[0][element-EL_PACMAN_R];
298 MovDir[x][y] = 1<<RND(4);
299 if (element != EL_KAEFER &&
300 element != EL_FLIEGER &&
301 element != EL_BUTTERFLY &&
302 element != EL_FIREFLY)
312 if (!IN_LEV_FIELD(x1,y1) || !IS_FREE(x1,y1))
314 if (element==EL_KAEFER || element==EL_BUTTERFLY)
316 MovDir[x][y] = direction[0][i];
319 else if (element==EL_FLIEGER || element==EL_FIREFLY)
321 MovDir[x][y] = direction[1][i];
330 void InitAmoebaNr(int x, int y)
333 int group_nr = AmoebeNachbarNr(x,y);
337 for(i=1;i<MAX_NUM_AMOEBA;i++)
347 AmoebaNr[x][y] = group_nr;
348 AmoebaCnt[group_nr]++;
349 AmoebaCnt2[group_nr]++;
355 int bumplevel = FALSE;
362 PlaySoundExt(SND_SIRR,PSND_MAX_VOLUME,PSND_MAX_RIGHT,PSND_LOOP);
367 PlaySoundStereo(SND_SIRR,PSND_MAX_RIGHT);
368 if (TimeLeft && !(TimeLeft % 10))
369 RaiseScore(level.score[SC_ZEITBONUS]);
370 if (TimeLeft > 100 && !(TimeLeft % 10))
374 DrawText(DX_TIME,DY_TIME,int2str(TimeLeft,3),FS_SMALL,FC_YELLOW);
385 /* Hero disappears */
386 DrawLevelElement(ExitX,ExitY,Feld[ExitX][ExitY]);
392 CloseDoor(DOOR_CLOSE_1);
397 SaveLevelTape(tape.level_nr); /* Ask to save tape */
400 if (level_nr==player.handicap &&
401 level_nr<leveldir[leveldir_nr].levels-1)
405 SavePlayerInfo(PLAYER_LEVEL);
408 if ((hi_pos=NewHiScore())>=0)
410 game_status = HALLOFFAME;
411 DrawHallOfFame(hi_pos);
412 if (bumplevel && TAPE_IS_EMPTY(tape))
417 game_status = MAINMENU;
418 if (bumplevel && TAPE_IS_EMPTY(tape))
433 if (!strcmp(player.alias_name,EMPTY_ALIAS) ||
434 Score<highscore[MAX_SCORE_ENTRIES-1].Score)
437 for(k=0;k<MAX_SCORE_ENTRIES;k++)
439 if (Score>highscore[k].Score) /* Spieler kommt in Highscore-Liste */
441 if (k<MAX_SCORE_ENTRIES-1)
443 int m = MAX_SCORE_ENTRIES-1;
446 for(l=k;l<MAX_SCORE_ENTRIES;l++)
447 if (!strcmp(player.alias_name,highscore[l].Name))
449 if (m==k) /* Spieler überschreibt seine alte Position */
455 strcpy(highscore[l].Name,highscore[l-1].Name);
456 highscore[l].Score = highscore[l-1].Score;
463 sprintf(highscore[k].Name,player.alias_name);
464 highscore[k].Score = Score;
470 else if (!strcmp(player.alias_name,highscore[k].Name))
471 break; /* Spieler schon mit besserer Punktzahl in der Liste */
482 void InitMovingField(int x, int y, int direction)
484 int newx = x + (direction==MV_LEFT ? -1 : direction==MV_RIGHT ? +1 : 0);
485 int newy = y + (direction==MV_UP ? -1 : direction==MV_DOWN ? +1 : 0);
487 MovDir[x][y] = direction;
488 MovDir[newx][newy] = direction;
489 if (Feld[newx][newy]==EL_LEERRAUM)
490 Feld[newx][newy] = EL_BLOCKED;
493 void Moving2Blocked(int x, int y, int *goes_to_x, int *goes_to_y)
495 int direction = MovDir[x][y];
496 int newx = x + (direction==MV_LEFT ? -1 : direction==MV_RIGHT ? +1 : 0);
497 int newy = y + (direction==MV_UP ? -1 : direction==MV_DOWN ? +1 : 0);
503 void Blocked2Moving(int x, int y, int *comes_from_x, int *comes_from_y)
505 int oldx = x, oldy = y;
506 int direction = MovDir[x][y];
508 if (direction==MV_LEFT)
510 else if (direction==MV_RIGHT)
512 else if (direction==MV_UP)
514 else if (direction==MV_DOWN)
517 *comes_from_x = oldx;
518 *comes_from_y = oldy;
521 int MovingOrBlocked2Element(int x, int y)
523 int element = Feld[x][y];
525 if (element==EL_BLOCKED)
529 Blocked2Moving(x,y,&oldx,&oldy);
530 return(Feld[oldx][oldy]);
536 void RemoveMovingField(int x, int y)
538 int oldx = x,oldy = y, newx = x,newy = y;
540 if (Feld[x][y] != EL_BLOCKED && !IS_MOVING(x,y))
545 Moving2Blocked(x,y,&newx,&newy);
546 if (Feld[newx][newy] != EL_BLOCKED)
549 else if (Feld[x][y]==EL_BLOCKED)
551 Blocked2Moving(x,y,&oldx,&oldy);
552 if (!IS_MOVING(oldx,oldy))
556 if (Feld[x][y]==EL_BLOCKED &&
557 (Store[oldx][oldy]==EL_MORAST_LEER ||
558 Store[oldx][oldy]==EL_SIEB_LEER ||
559 Store[oldx][oldy]==EL_SIEB2_LEER ||
560 Store[oldx][oldy]==EL_AMOEBE_NASS))
562 Feld[oldx][oldy] = Store[oldx][oldy];
563 Store[oldx][oldy] = Store2[oldx][oldy] = 0;
566 Feld[oldx][oldy] = EL_LEERRAUM;
568 Feld[newx][newy] = EL_LEERRAUM;
569 MovPos[oldx][oldy] = MovDir[oldx][oldy] = MovDelay[oldx][oldy] = 0;
570 MovPos[newx][newy] = MovDir[newx][newy] = MovDelay[newx][newy] = 0;
572 DrawLevelField(oldx,oldy);
573 DrawLevelField(newx,newy);
576 void DrawDynamite(int x, int y)
578 int sx = SCROLLX(x), sy = SCROLLY(y);
579 int graphic = el2gfx(Feld[x][y]);
582 if (!IN_SCR_FIELD(sx,sy) || IS_PLAYER(x,y))
586 DrawGraphic(sx,sy, el2gfx(Store[x][y]));
588 if (Feld[x][y]==EL_DYNAMIT)
590 if ((phase = (48-MovDelay[x][y])/6) > 6)
595 if ((phase = ((48-MovDelay[x][y])/3) % 8) > 3)
600 DrawGraphicThruMask(sx,sy, graphic + phase);
602 DrawGraphic(sx,sy, graphic + phase);
605 void CheckDynamite(int x, int y)
607 if (MovDelay[x][y]) /* neues Dynamit / in Wartezustand */
612 if (!(MovDelay[x][y] % 6))
613 PlaySoundLevel(x,y,SND_ZISCH);
615 if (Feld[x][y]==EL_DYNAMIT && !(MovDelay[x][y] % 6))
617 else if (Feld[x][y]==EL_DYNABOMB && !(MovDelay[x][y] % 3))
624 StopSound(SND_ZISCH);
628 void Explode(int ex, int ey, int phase, int mode)
631 int num_phase = 9, delay = 1;
632 int last_phase = num_phase*delay;
633 int half_phase = (num_phase/2)*delay;
635 if (phase==0) /* Feld 'Store' initialisieren */
637 int center_element = Feld[ex][ey];
639 if (IS_MOVING(ex,ey) || IS_BLOCKED(ex,ey))
641 center_element = MovingOrBlocked2Element(ex,ey);
642 RemoveMovingField(ex,ey);
645 for(y=ey-1;y<ey+2;y++) for(x=ex-1;x<ex+2;x++)
647 int element = Feld[x][y];
649 if (IS_MOVING(x,y) || IS_BLOCKED(x,y))
651 element = MovingOrBlocked2Element(x,y);
652 RemoveMovingField(x,y);
655 if (!IN_LEV_FIELD(x,y) || IS_MASSIV(element) || element==EL_BURNING)
658 if ((mode!=EX_NORMAL || center_element==EL_AMOEBA2DIAM) &&
662 if (element==EL_EXPLODING)
663 element = Store2[x][y];
665 if (IS_PLAYER(ex,ey))
666 Store[x][y] = EL_EDELSTEIN_GELB;
667 else if (center_element==EL_MAULWURF)
668 Store[x][y] = EL_EDELSTEIN_ROT;
669 else if (center_element==EL_PINGUIN)
670 Store[x][y] = EL_EDELSTEIN_LILA;
671 else if (center_element==EL_KAEFER)
672 Store[x][y] = ((x==ex && y==ey) ? EL_DIAMANT : EL_EDELSTEIN);
673 else if (center_element==EL_BUTTERFLY)
674 Store[x][y] = EL_EDELSTEIN_BD;
675 else if (center_element==EL_MAMPFER)
676 Store[x][y] = level.mampfer_inhalt[MampferNr][x-ex+1][y-ey+1];
677 else if (center_element==EL_AMOEBA2DIAM)
678 Store[x][y] = level.amoebe_inhalt;
679 else if (element==EL_ERZ_EDEL)
680 Store[x][y] = EL_EDELSTEIN;
681 else if (element==EL_ERZ_DIAM)
682 Store[x][y] = EL_DIAMANT;
683 else if (element==EL_ERZ_EDEL_BD)
684 Store[x][y] = EL_EDELSTEIN_BD;
685 else if (element==EL_ERZ_EDEL_GELB)
686 Store[x][y] = EL_EDELSTEIN_GELB;
687 else if (element==EL_ERZ_EDEL_ROT)
688 Store[x][y] = EL_EDELSTEIN_ROT;
689 else if (element==EL_ERZ_EDEL_LILA)
690 Store[x][y] = EL_EDELSTEIN_LILA;
691 else if (!IS_PFORTE(Store[x][y]))
692 Store[x][y] = EL_LEERRAUM;
694 if (x!=ex || y!=ey || center_element==EL_AMOEBA2DIAM || mode==EX_BORDER)
695 Store2[x][y] = element;
697 if (AmoebaNr[x][y] &&
698 (element==EL_AMOEBE_VOLL ||
699 element==EL_AMOEBE_BD ||
700 element==EL_AMOEBING))
702 AmoebaCnt[AmoebaNr[x][y]]--;
703 AmoebaCnt2[AmoebaNr[x][y]]--;
706 Feld[x][y] = EL_EXPLODING;
707 MovDir[x][y] = MovPos[x][y] = 0;
713 if (center_element==EL_MAMPFER)
714 MampferNr = (MampferNr+1) % 4;
725 Frame[x][y] = (phase<last_phase ? phase+1 : 0);
727 if (phase==half_phase)
729 int element = Store2[x][y];
733 else if (IS_EXPLOSIVE(element))
735 Feld[x][y] = Store2[x][y];
739 else if (element==EL_AMOEBA2DIAM)
740 AmoebeUmwandeln(x,y);
743 if (phase==last_phase)
747 element = Feld[x][y] = Store[x][y];
748 Store[x][y] = Store2[x][y] = 0;
749 MovDir[x][y] = MovPos[x][y] = MovDelay[x][y] = 0;
750 if (CAN_MOVE(element) || COULD_MOVE(element))
754 else if (!(phase%delay) && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
757 ErdreichAnbroeckeln(SCROLLX(x),SCROLLY(y));
759 DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_EXPLOSION+(phase/delay-1));
763 void DynaExplode(int ex, int ey, int size)
766 static int xy[4][2] =
774 Explode(ex,ey,0,EX_CENTER);
780 int x = ex+j*xy[i%4][0];
781 int y = ey+j*xy[i%4][1];
784 if (!IN_LEV_FIELD(x,y) || IS_MASSIV(Feld[x][y]))
787 element = Feld[x][y];
788 Explode(x,y,0,EX_BORDER);
790 if (element != EL_LEERRAUM &&
791 element != EL_ERDREICH &&
792 element != EL_EXPLODING &&
801 void Bang(int x, int y)
803 int element = Feld[x][y];
805 PlaySoundLevel(x,y,SND_ROAAAR);
817 RaiseScoreElement(element);
818 Explode(x,y,0,EX_NORMAL);
824 DynaExplode(x,y,DynaBombSize);
828 Explode(x,y,0,EX_CENTER);
831 Explode(x,y,0,EX_NORMAL);
836 void Blurb(int x, int y)
838 int element = Feld[x][y];
840 if (element!=EL_BLURB_LEFT && element!=EL_BLURB_RIGHT) /* Anfang */
842 PlaySoundLevel(x,y,SND_BLURB);
843 if (IN_LEV_FIELD(x-1,y) && IS_FREE(x-1,y) &&
844 (!IN_LEV_FIELD(x-1,y-1) ||
845 !CAN_FALL(MovingOrBlocked2Element(x-1,y-1))))
847 Feld[x-1][y] = EL_BLURB_LEFT;
849 if (IN_LEV_FIELD(x+1,y) && IS_FREE(x+1,y) &&
850 (!IN_LEV_FIELD(x+1,y-1) ||
851 !CAN_FALL(MovingOrBlocked2Element(x+1,y-1))))
853 Feld[x+1][y] = EL_BLURB_RIGHT;
858 int graphic = (element==EL_BLURB_LEFT ? GFX_BLURB_LEFT : GFX_BLURB_RIGHT);
860 if (!MovDelay[x][y]) /* neue Phase / noch nicht gewartet */
863 if (MovDelay[x][y]) /* neue Phase / in Wartezustand */
866 if (MovDelay[x][y] && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
867 DrawGraphic(SCROLLX(x),SCROLLY(y),graphic+4-MovDelay[x][y]);
871 Feld[x][y] = EL_LEERRAUM;
878 void Impact(int x, int y)
880 BOOL lastline = (y==lev_fieldy-1);
881 BOOL object_hit = FALSE;
882 int element = Feld[x][y];
885 /* Element darunter berührt? */
888 object_hit = (!IS_FREE(x,y+1) && (!IS_MOVING(x,y+1) ||
889 MovDir[x][y+1]!=MV_DOWN ||
890 MovPos[x][y+1]<=TILEY/2));
892 smashed = MovingOrBlocked2Element(x,y+1);
895 /* Auftreffendes Element fällt in Salzsäure */
896 if (!lastline && smashed==EL_SALZSAEURE)
902 /* Auftreffendes Element ist Bombe */
903 if (element==EL_BOMBE && (lastline || object_hit))
909 /* Auftreffendes Element ist Säuretropfen */
910 if (element==EL_TROPFEN && (lastline || object_hit))
912 if (object_hit && IS_PLAYER(x,y+1))
914 else if (object_hit && (smashed==EL_MAULWURF || smashed==EL_PINGUIN))
918 Feld[x][y] = EL_AMOEBING;
919 Store[x][y] = EL_AMOEBE_NASS;
924 /* Welches Element kriegt was auf die Rübe? */
925 if (!lastline && object_hit)
927 if (CAN_CHANGE(element) &&
928 (smashed==EL_SIEB_LEER || smashed==EL_SIEB2_LEER) && !SiebAktiv)
929 SiebAktiv = level.dauer_sieb * FRAMES_PER_SECOND;
931 if (IS_PLAYER(x,y+1))
936 else if (smashed==EL_MAULWURF || smashed==EL_PINGUIN)
941 else if (element==EL_EDELSTEIN_BD)
943 if (IS_ENEMY(smashed) && IS_BD_ELEMENT(smashed))
949 else if (element==EL_FELSBROCKEN)
951 if (IS_ENEMY(smashed) || smashed==EL_BOMBE || smashed==EL_SONDE ||
952 smashed==EL_SCHWEIN || smashed==EL_DRACHE)
957 else if (!IS_MOVING(x,y+1))
959 if (smashed==EL_BIRNE_AUS || smashed==EL_BIRNE_EIN)
964 else if (smashed==EL_KOKOSNUSS)
966 Feld[x][y+1] = EL_CRACKINGNUT;
967 PlaySoundLevel(x,y,SND_KNACK);
968 RaiseScoreElement(EL_KOKOSNUSS);
971 else if (smashed==EL_DIAMANT)
973 Feld[x][y+1] = EL_LEERRAUM;
974 PlaySoundLevel(x,y,SND_QUIRK);
981 /* Geräusch beim Durchqueren des Siebes */
982 if (!lastline && (Feld[x][y+1]==EL_SIEB_LEER || Feld[x][y+1]==EL_SIEB2_LEER))
984 PlaySoundLevel(x,y,SND_QUIRK);
988 /* Geräusch beim Auftreffen */
989 if (lastline || object_hit)
996 case EL_EDELSTEIN_BD:
997 case EL_EDELSTEIN_GELB:
998 case EL_EDELSTEIN_ROT:
999 case EL_EDELSTEIN_LILA:
1006 case EL_FELSBROCKEN:
1010 case EL_SCHLUESSEL1:
1011 case EL_SCHLUESSEL2:
1012 case EL_SCHLUESSEL3:
1013 case EL_SCHLUESSEL4:
1026 PlaySoundLevel(x,y,sound);
1030 void TurnRound(int x, int y)
1042 { 0,0 }, { 0,0 }, { 0,0 },
1047 int left,right,back;
1051 { MV_DOWN, MV_UP, MV_RIGHT },
1052 { MV_UP, MV_DOWN, MV_LEFT },
1054 { MV_LEFT, MV_RIGHT, MV_DOWN },
1055 { 0,0,0 }, { 0,0,0 }, { 0,0,0 },
1056 { MV_RIGHT, MV_LEFT, MV_UP }
1059 int element = Feld[x][y];
1060 int old_move_dir = MovDir[x][y];
1061 int left_dir = turn[old_move_dir].left;
1062 int right_dir = turn[old_move_dir].right;
1063 int back_dir = turn[old_move_dir].back;
1065 int left_dx = move_xy[left_dir].x, left_dy = move_xy[left_dir].y;
1066 int right_dx = move_xy[right_dir].x, right_dy = move_xy[right_dir].y;
1067 int move_dx = move_xy[old_move_dir].x, move_dy = move_xy[old_move_dir].y;
1068 int back_dx = move_xy[back_dir].x, back_dy = move_xy[back_dir].y;
1070 int left_x = x+left_dx, left_y = y+left_dy;
1071 int right_x = x+right_dx, right_y = y+right_dy;
1072 int move_x = x+move_dx, move_y = y+move_dy;
1074 if (element==EL_KAEFER || element==EL_BUTTERFLY)
1076 TestIfBadThingHitsOtherBadThing(x,y);
1078 if (IN_LEV_FIELD(right_x,right_y) &&
1079 IS_FREE_OR_PLAYER(right_x,right_y))
1080 MovDir[x][y] = right_dir;
1081 else if (!IN_LEV_FIELD(move_x,move_y) ||
1082 !IS_FREE_OR_PLAYER(move_x,move_y))
1083 MovDir[x][y] = left_dir;
1085 if (element==EL_KAEFER && MovDir[x][y] != old_move_dir)
1087 else if (element==EL_BUTTERFLY) /* && MovDir[x][y]==left_dir) */
1090 else if (element==EL_FLIEGER || element==EL_FIREFLY)
1092 TestIfBadThingHitsOtherBadThing(x,y);
1094 if (IN_LEV_FIELD(left_x,left_y) &&
1095 IS_FREE_OR_PLAYER(left_x,left_y))
1096 MovDir[x][y] = left_dir;
1097 else if (!IN_LEV_FIELD(move_x,move_y) ||
1098 !IS_FREE_OR_PLAYER(move_x,move_y))
1099 MovDir[x][y] = right_dir;
1101 if (element==EL_FLIEGER && MovDir[x][y] != old_move_dir)
1103 else if (element==EL_FIREFLY) /* && MovDir[x][y]==right_dir) */
1106 else if (element==EL_MAMPFER)
1108 BOOL can_turn_left = FALSE, can_turn_right = FALSE;
1110 if (IN_LEV_FIELD(left_x,left_y) &&
1111 (IS_FREE_OR_PLAYER(left_x,left_y) ||
1112 Feld[left_x][left_y] == EL_DIAMANT))
1113 can_turn_left = TRUE;
1114 if (IN_LEV_FIELD(right_x,right_y) &&
1115 (IS_FREE_OR_PLAYER(right_x,right_y) ||
1116 Feld[right_x][right_y] == EL_DIAMANT))
1117 can_turn_right = TRUE;
1119 if (can_turn_left && can_turn_right)
1120 MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
1121 else if (can_turn_left)
1122 MovDir[x][y] = (RND(2) ? left_dir : back_dir);
1123 else if (can_turn_right)
1124 MovDir[x][y] = (RND(2) ? right_dir : back_dir);
1126 MovDir[x][y] = back_dir;
1128 MovDelay[x][y] = 8+8*RND(3);
1130 else if (element==EL_MAMPFER2)
1132 BOOL can_turn_left = FALSE, can_turn_right = FALSE;
1134 if (IN_LEV_FIELD(left_x,left_y) &&
1135 (IS_FREE_OR_PLAYER(left_x,left_y) ||
1136 IS_MAMPF2(Feld[left_x][left_y])))
1137 can_turn_left = TRUE;
1138 if (IN_LEV_FIELD(right_x,right_y) &&
1139 (IS_FREE_OR_PLAYER(right_x,right_y) ||
1140 IS_MAMPF2(Feld[right_x][right_y])))
1141 can_turn_right = TRUE;
1143 if (can_turn_left && can_turn_right)
1144 MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
1145 else if (can_turn_left)
1146 MovDir[x][y] = (RND(2) ? left_dir : back_dir);
1147 else if (can_turn_right)
1148 MovDir[x][y] = (RND(2) ? right_dir : back_dir);
1150 MovDir[x][y] = back_dir;
1152 MovDelay[x][y] = 8+8*RND(3);
1154 else if (element==EL_PACMAN)
1156 BOOL can_turn_left = FALSE, can_turn_right = FALSE;
1158 if (IN_LEV_FIELD(left_x,left_y) &&
1159 (IS_FREE_OR_PLAYER(left_x,left_y) ||
1160 IS_AMOEBOID(Feld[left_x][left_y])))
1161 can_turn_left = TRUE;
1162 if (IN_LEV_FIELD(right_x,right_y) &&
1163 (IS_FREE_OR_PLAYER(right_x,right_y) ||
1164 IS_AMOEBOID(Feld[right_x][right_y])))
1165 can_turn_right = TRUE;
1167 if (can_turn_left && can_turn_right)
1168 MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
1169 else if (can_turn_left)
1170 MovDir[x][y] = (RND(2) ? left_dir : back_dir);
1171 else if (can_turn_right)
1172 MovDir[x][y] = (RND(2) ? right_dir : back_dir);
1174 MovDir[x][y] = back_dir;
1176 MovDelay[x][y] = 3+RND(20);
1178 else if (element==EL_SCHWEIN)
1180 BOOL can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE;
1181 BOOL should_turn_left = FALSE, should_turn_right = FALSE;
1182 BOOL should_move_on = FALSE;
1184 int rnd = RND(rnd_value);
1186 if (IN_LEV_FIELD(left_x,left_y) &&
1187 (IS_FREE(left_x,left_y) || IS_GEM(Feld[left_x][left_y])))
1188 can_turn_left = TRUE;
1189 if (IN_LEV_FIELD(right_x,right_y) &&
1190 (IS_FREE(right_x,right_y) || IS_GEM(Feld[right_x][right_y])))
1191 can_turn_right = TRUE;
1192 if (IN_LEV_FIELD(move_x,move_y) &&
1193 (IS_FREE(move_x,move_y) || IS_GEM(Feld[move_x][move_y])))
1196 if (can_turn_left &&
1198 (IN_LEV_FIELD(x+back_dx+left_dx,y+back_dy+left_dy) &&
1199 !IS_FREE(x+back_dx+left_dx,y+back_dy+left_dy))))
1200 should_turn_left = TRUE;
1201 if (can_turn_right &&
1203 (IN_LEV_FIELD(x+back_dx+right_dx,y+back_dy+right_dy) &&
1204 !IS_FREE(x+back_dx+right_dx,y+back_dy+right_dy))))
1205 should_turn_right = TRUE;
1207 (!can_turn_left || !can_turn_right ||
1208 (IN_LEV_FIELD(x+move_dx+left_dx,y+move_dy+left_dy) &&
1209 !IS_FREE(x+move_dx+left_dx,y+move_dy+left_dy)) ||
1210 (IN_LEV_FIELD(x+move_dx+right_dx,y+move_dy+right_dy) &&
1211 !IS_FREE(x+move_dx+right_dx,y+move_dy+right_dy))))
1212 should_move_on = TRUE;
1214 if (should_turn_left || should_turn_right || should_move_on)
1216 if (should_turn_left && should_turn_right && should_move_on)
1217 MovDir[x][y] = (rnd < rnd_value/3 ? left_dir :
1218 rnd < 2*rnd_value/3 ? right_dir :
1220 else if (should_turn_left && should_turn_right)
1221 MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
1222 else if (should_turn_left && should_move_on)
1223 MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : old_move_dir);
1224 else if (should_turn_right && should_move_on)
1225 MovDir[x][y] = (rnd < rnd_value/2 ? right_dir : old_move_dir);
1226 else if (should_turn_left)
1227 MovDir[x][y] = left_dir;
1228 else if (should_turn_right)
1229 MovDir[x][y] = right_dir;
1230 else if (should_move_on)
1231 MovDir[x][y] = old_move_dir;
1233 else if (can_move_on && rnd > rnd_value/8)
1234 MovDir[x][y] = old_move_dir;
1235 else if (can_turn_left && can_turn_right)
1236 MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
1237 else if (can_turn_left && rnd > rnd_value/8)
1238 MovDir[x][y] = left_dir;
1239 else if (can_turn_right && rnd > rnd_value/8)
1240 MovDir[x][y] = right_dir;
1242 MovDir[x][y] = back_dir;
1244 if (!IS_FREE(x+move_xy[MovDir[x][y]].x,y+move_xy[MovDir[x][y]].y) &&
1245 !IS_GEM(Feld[x+move_xy[MovDir[x][y]].x][y+move_xy[MovDir[x][y]].y]))
1246 MovDir[x][y] = old_move_dir;
1250 else if (element==EL_DRACHE)
1252 BOOL can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE;
1254 int rnd = RND(rnd_value);
1256 if (IN_LEV_FIELD(left_x,left_y) && IS_FREE(left_x,left_y))
1257 can_turn_left = TRUE;
1258 if (IN_LEV_FIELD(right_x,right_y) && IS_FREE(right_x,right_y))
1259 can_turn_right = TRUE;
1260 if (IN_LEV_FIELD(move_x,move_y) && IS_FREE(move_x,move_y))
1263 if (can_move_on && rnd > rnd_value/8)
1264 MovDir[x][y] = old_move_dir;
1265 else if (can_turn_left && can_turn_right)
1266 MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
1267 else if (can_turn_left && rnd > rnd_value/8)
1268 MovDir[x][y] = left_dir;
1269 else if (can_turn_right && rnd > rnd_value/8)
1270 MovDir[x][y] = right_dir;
1272 MovDir[x][y] = back_dir;
1274 if (!IS_FREE(x+move_xy[MovDir[x][y]].x,y+move_xy[MovDir[x][y]].y))
1275 MovDir[x][y] = old_move_dir;
1279 else if (element==EL_ROBOT || element==EL_SONDE ||
1280 element==EL_MAULWURF || element==EL_PINGUIN)
1282 int attr_x = JX, attr_y = JY;
1291 if (element==EL_ROBOT && ZX>=0 && ZY>=0)
1297 if (element==EL_MAULWURF || element==EL_PINGUIN)
1300 static int xy[4][2] =
1310 int ex = x+xy[i%4][0];
1311 int ey = y+xy[i%4][1];
1313 if (IN_LEV_FIELD(ex,ey) && Feld[ex][ey] == EL_AUSGANG_AUF)
1322 MovDir[x][y] = MV_NO_MOVING;
1324 MovDir[x][y] |= (GameOver ? MV_RIGHT : MV_LEFT);
1326 MovDir[x][y] |= (GameOver ? MV_LEFT : MV_RIGHT);
1328 MovDir[x][y] |= (GameOver ? MV_DOWN : MV_UP);
1330 MovDir[x][y] |= (GameOver ? MV_UP : MV_DOWN);
1332 if (element==EL_ROBOT)
1334 if ((MovDir[x][y]&(MV_LEFT|MV_RIGHT)) && (MovDir[x][y]&(MV_UP|MV_DOWN)))
1335 MovDir[x][y] &= (RND(2) ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
1336 Moving2Blocked(x,y,&newx,&newy);
1338 if (IN_LEV_FIELD(newx,newy) && IS_FREE_OR_PLAYER(newx,newy))
1339 MovDelay[x][y] = 4+4*!RND(3);
1347 if ((MovDir[x][y]&(MV_LEFT|MV_RIGHT)) && (MovDir[x][y]&(MV_UP|MV_DOWN)))
1349 BOOL first_horiz = RND(2);
1350 int new_move_dir = MovDir[x][y];
1353 new_move_dir & (first_horiz ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
1354 Moving2Blocked(x,y,&newx,&newy);
1356 if (IN_LEV_FIELD(newx,newy) &&
1357 (IS_FREE(newx,newy) ||
1358 Feld[newx][newy] == EL_SALZSAEURE ||
1359 ((element == EL_MAULWURF || element==EL_PINGUIN) &&
1360 (Feld[newx][newy] == EL_AUSGANG_AUF ||
1361 IS_MAMPF3(Feld[newx][newy])))))
1365 new_move_dir & (!first_horiz ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
1366 Moving2Blocked(x,y,&newx,&newy);
1368 if (IN_LEV_FIELD(newx,newy) &&
1369 (IS_FREE(newx,newy) ||
1370 Feld[newx][newy] == EL_SALZSAEURE ||
1371 ((element == EL_MAULWURF || element==EL_PINGUIN) &&
1372 (Feld[newx][newy] == EL_AUSGANG_AUF ||
1373 IS_MAMPF3(Feld[newx][newy])))))
1376 MovDir[x][y] = old_move_dir;
1383 void StartMoving(int x, int y)
1385 int element = Feld[x][y];
1390 if (CAN_FALL(element) && y<lev_fieldy-1)
1392 if (element==EL_MORAST_VOLL)
1396 InitMovingField(x,y,MV_DOWN);
1397 Feld[x][y] = EL_FELSBROCKEN;
1398 Store[x][y] = EL_MORAST_LEER;
1400 else if (Feld[x][y+1]==EL_MORAST_LEER)
1402 if (!MovDelay[x][y])
1403 MovDelay[x][y] = 16;
1412 Feld[x][y] = EL_MORAST_LEER;
1413 Feld[x][y+1] = EL_MORAST_VOLL;
1416 else if (element==EL_FELSBROCKEN && Feld[x][y+1]==EL_MORAST_LEER)
1418 InitMovingField(x,y,MV_DOWN);
1419 Store[x][y] = EL_MORAST_VOLL;
1421 else if (element==EL_SIEB_VOLL)
1425 InitMovingField(x,y,MV_DOWN);
1426 Feld[x][y] = EL_CHANGED(Store2[x][y]);
1427 Store[x][y] = EL_SIEB_LEER;
1429 else if (Feld[x][y+1]==EL_SIEB_LEER)
1431 if (!MovDelay[x][y])
1441 Feld[x][y] = EL_SIEB_LEER;
1442 Feld[x][y+1] = EL_SIEB_VOLL;
1443 Store2[x][y+1] = EL_CHANGED(Store2[x][y]);
1447 else if (element==EL_SIEB2_VOLL)
1451 InitMovingField(x,y,MV_DOWN);
1452 Feld[x][y] = EL_CHANGED2(Store2[x][y]);
1453 Store[x][y] = EL_SIEB2_LEER;
1455 else if (Feld[x][y+1]==EL_SIEB2_LEER)
1457 if (!MovDelay[x][y])
1467 Feld[x][y] = EL_SIEB2_LEER;
1468 Feld[x][y+1] = EL_SIEB2_VOLL;
1469 Store2[x][y+1] = EL_CHANGED2(Store2[x][y]);
1473 else if (SiebAktiv && CAN_CHANGE(element) &&
1474 (Feld[x][y+1]==EL_SIEB_LEER || Feld[x][y+1]==EL_SIEB2_LEER))
1476 InitMovingField(x,y,MV_DOWN);
1478 (Feld[x][y+1]==EL_SIEB_LEER ? EL_SIEB_VOLL : EL_SIEB2_VOLL);
1479 Store2[x][y+1] = element;
1481 else if (CAN_SMASH(element) && Feld[x][y+1]==EL_SALZSAEURE)
1484 InitMovingField(x,y,MV_DOWN);
1485 Store[x][y] = EL_SALZSAEURE;
1487 else if (CAN_SMASH(element) && Feld[x][y+1]==EL_BLOCKED && JustHit[x][y])
1491 else if (IS_FREE(x,y+1))
1493 InitMovingField(x,y,MV_DOWN);
1495 else if (element==EL_TROPFEN)
1497 Feld[x][y] = EL_AMOEBING;
1498 Store[x][y] = EL_AMOEBE_NASS;
1500 else if (IS_SLIPPERY(Feld[x][y+1]) && !Store[x][y+1])
1502 BOOL left = (x>0 && IS_FREE(x-1,y) &&
1503 (IS_FREE(x-1,y+1) || Feld[x-1][y+1]==EL_SALZSAEURE));
1504 BOOL right = (x<lev_fieldx-1 && IS_FREE(x+1,y) &&
1505 (IS_FREE(x+1,y+1) || Feld[x+1][y+1]==EL_SALZSAEURE));
1509 if (left && right && game_emulation != EMU_BOULDERDASH)
1510 left = !(right = RND(2));
1512 InitMovingField(x,y,left ? MV_LEFT : MV_RIGHT);
1516 else if (CAN_MOVE(element))
1520 if (!MovDelay[x][y]) /* neuer Schritt / noch nicht gewartet */
1522 /* Alle Figuren, die nach jeden Schritt die Richtung wechseln können.
1523 * (MAMPFER, MAMPFER2 und PACMAN laufen bis zur nächsten Wand.)
1526 if (element!=EL_MAMPFER && element!=EL_MAMPFER2 && element!=EL_PACMAN)
1529 if (MovDelay[x][y] && (element == EL_KAEFER || element == EL_FLIEGER))
1530 DrawLevelField(x,y);
1534 if (MovDelay[x][y]) /* neuer Schritt / in Wartezustand */
1538 if (element==EL_ROBOT || element==EL_MAMPFER || element==EL_MAMPFER2)
1540 int phase = MovDelay[x][y] % 8;
1545 if (IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
1546 DrawGraphic(SCROLLX(x),SCROLLY(y), el2gfx(element)+phase);
1548 if ((element==EL_MAMPFER || element==EL_MAMPFER2)
1549 && MovDelay[x][y]%4==3)
1550 PlaySoundLevel(x,y,SND_NJAM);
1552 else if (element==EL_DRACHE)
1555 int dir = MovDir[x][y];
1556 int dx = (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1557 int dy = (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1558 int graphic = (dir == MV_LEFT ? GFX_FLAMMEN_LEFT :
1559 dir == MV_RIGHT ? GFX_FLAMMEN_RIGHT :
1560 dir == MV_UP ? GFX_FLAMMEN_UP :
1561 dir == MV_DOWN ? GFX_FLAMMEN_DOWN : GFX_LEERRAUM);
1562 int phase = FrameCounter % 2;
1566 int xx = x + i*dx, yy = y + i*dy;
1567 int sx = SCROLLX(xx), sy = SCROLLY(yy);
1569 if (!IN_LEV_FIELD(xx,yy) ||
1570 IS_SOLID(Feld[xx][yy]) || Feld[xx][yy]==EL_EXPLODING)
1575 int flamed = MovingOrBlocked2Element(xx,yy);
1577 if (IS_ENEMY(flamed) || IS_EXPLOSIVE(flamed))
1580 RemoveMovingField(xx,yy);
1582 Feld[xx][yy] = EL_BURNING;
1583 if (IN_SCR_FIELD(sx,sy))
1584 DrawGraphic(sx,sy, graphic + phase*3 + i-1);
1588 if (Feld[xx][yy] == EL_BURNING)
1589 Feld[xx][yy] = EL_LEERRAUM;
1590 DrawLevelField(xx,yy);
1599 if (element==EL_KAEFER || element==EL_BUTTERFLY)
1601 PlaySoundLevel(x,y,SND_KLAPPER);
1603 else if (element==EL_FLIEGER || element==EL_FIREFLY)
1605 PlaySoundLevel(x,y,SND_ROEHR);
1608 /* neuer Schritt / Wartezustand beendet */
1610 Moving2Blocked(x,y,&newx,&newy); /* wohin soll's gehen? */
1612 if (IS_ENEMY(element) && IS_PLAYER(newx,newy))
1614 /* Spieler erwischt */
1619 else if ((element == EL_MAULWURF || element == EL_PINGUIN ||
1620 element==EL_ROBOT || element==EL_SONDE) &&
1621 IN_LEV_FIELD(newx,newy) &&
1622 MovDir[x][y]==MV_DOWN && Feld[newx][newy]==EL_SALZSAEURE)
1625 Store[x][y] = EL_SALZSAEURE;
1627 else if ((element == EL_MAULWURF || element == EL_PINGUIN) &&
1628 IN_LEV_FIELD(newx,newy))
1630 if (Feld[newx][newy] == EL_AUSGANG_AUF)
1632 Feld[x][y] = EL_LEERRAUM;
1633 DrawLevelField(x,y);
1635 PlaySoundLevel(newx,newy,SND_BUING);
1636 if (IN_SCR_FIELD(SCROLLX(newx),SCROLLY(newy)))
1637 DrawGraphicThruMask(SCROLLX(newx),SCROLLY(newy),el2gfx(element));
1640 if (!Friends && PlayerGone && !GameOver)
1641 LevelSolved = GameOver = TRUE;
1645 else if (IS_MAMPF3(Feld[newx][newy]))
1647 if (DigField(newx,newy, 0,0, DF_DIG) == MF_MOVING)
1648 DrawLevelField(newx,newy);
1650 MovDir[x][y] = MV_NO_MOVING;
1652 else if (!IS_FREE(newx,newy))
1657 DrawLevelField(x,y);
1661 else if (element == EL_SCHWEIN && IN_LEV_FIELD(newx,newy))
1663 if (IS_GEM(Feld[newx][newy]))
1665 if (IS_MOVING(newx,newy))
1666 RemoveMovingField(newx,newy);
1669 Feld[newx][newy] = EL_LEERRAUM;
1670 DrawLevelField(newx,newy);
1673 else if (!IS_FREE(newx,newy))
1678 DrawLevelField(x,y);
1682 else if (element==EL_DRACHE && IN_LEV_FIELD(newx,newy))
1684 if (!IS_FREE(newx,newy))
1689 DrawLevelField(x,y);
1694 BOOL wanna_flame = !RND(10);
1695 int dx = newx - x, dy = newy - y;
1696 int newx1 = newx+1*dx, newy1 = newy+1*dy;
1697 int newx2 = newx+2*dx, newy2 = newy+2*dy;
1698 int element1 = (IN_LEV_FIELD(newx1,newy1) ?
1699 MovingOrBlocked2Element(newx1,newy1) : EL_BETON);
1700 int element2 = (IN_LEV_FIELD(newx2,newy2) ?
1701 MovingOrBlocked2Element(newx2,newy2) : EL_BETON);
1703 if ((wanna_flame || IS_ENEMY(element1) || IS_ENEMY(element2)) &&
1704 element1 != EL_DRACHE && element2 != EL_DRACHE &&
1705 element1 != EL_BURNING && element2 != EL_BURNING)
1710 DrawLevelField(x,y);
1712 MovDelay[x][y] = 25;
1713 Feld[newx][newy] = EL_BURNING;
1714 if (IN_LEV_FIELD(newx1,newy1) && Feld[newx1][newy1] == EL_LEERRAUM)
1715 Feld[newx1][newy1] = EL_BURNING;
1716 if (IN_LEV_FIELD(newx2,newy2) && Feld[newx2][newy2] == EL_LEERRAUM)
1717 Feld[newx2][newy2] = EL_BURNING;
1722 else if (element==EL_MAMPFER && IN_LEV_FIELD(newx,newy) &&
1723 Feld[newx][newy]==EL_DIAMANT)
1725 if (IS_MOVING(newx,newy))
1726 RemoveMovingField(newx,newy);
1729 Feld[newx][newy] = EL_LEERRAUM;
1730 DrawLevelField(newx,newy);
1733 else if (element==EL_MAMPFER2 && IN_LEV_FIELD(newx,newy) &&
1734 IS_MAMPF2(Feld[newx][newy]))
1736 if (AmoebaNr[newx][newy])
1738 AmoebaCnt2[AmoebaNr[newx][newy]]--;
1739 if (Feld[newx][newy]==EL_AMOEBE_VOLL || Feld[newx][newy]==EL_AMOEBE_BD)
1740 AmoebaCnt[AmoebaNr[newx][newy]]--;
1743 if (IS_MOVING(newx,newy))
1744 RemoveMovingField(newx,newy);
1747 Feld[newx][newy] = EL_LEERRAUM;
1748 DrawLevelField(newx,newy);
1751 else if (element==EL_PACMAN && IN_LEV_FIELD(newx,newy) &&
1752 IS_AMOEBOID(Feld[newx][newy]))
1754 if (AmoebaNr[newx][newy])
1756 AmoebaCnt2[AmoebaNr[newx][newy]]--;
1757 if (Feld[newx][newy]==EL_AMOEBE_VOLL || Feld[newx][newy]==EL_AMOEBE_BD)
1758 AmoebaCnt[AmoebaNr[newx][newy]]--;
1761 Feld[newx][newy] = EL_LEERRAUM;
1762 DrawLevelField(newx,newy);
1764 else if (!IN_LEV_FIELD(newx,newy) || !IS_FREE(newx,newy))
1765 { /* gegen Wand gelaufen */
1768 if (element == EL_KAEFER || element == EL_FLIEGER)
1769 DrawLevelField(x,y);
1770 else if (element == EL_BUTTERFLY || element == EL_FIREFLY)
1771 DrawGraphicAnimation(x,y, el2gfx(element), 2, 2, ANIM_NORMAL);
1772 else if (element==EL_SONDE)
1773 DrawGraphicAnimation(x,y, GFX_SONDE_START, 8, 1, ANIM_NORMAL);
1778 if (element==EL_ROBOT && IN_SCR_FIELD(x,y))
1779 PlaySoundLevel(x,y,SND_SCHLURF);
1781 InitMovingField(x,y,MovDir[x][y]);
1785 ContinueMoving(x,y);
1788 void ContinueMoving(int x, int y)
1790 int element = Feld[x][y];
1791 int direction = MovDir[x][y];
1792 int dx = (direction==MV_LEFT ? -1 : direction==MV_RIGHT ? +1 : 0);
1793 int dy = (direction==MV_UP ? -1 : direction==MV_DOWN ? +1 : 0);
1794 int horiz_move = (dx!=0);
1795 int newx = x + dx, newy = y + dy;
1796 int step = (horiz_move ? dx : dy)*TILEX/4;
1798 if (CAN_FALL(element) && horiz_move)
1800 else if (element==EL_TROPFEN)
1802 else if (Store[x][y]==EL_MORAST_VOLL || Store[x][y]==EL_MORAST_LEER)
1805 MovPos[x][y] += step;
1807 if (ABS(MovPos[x][y])>=TILEX) /* Zielfeld erreicht */
1809 Feld[x][y] = EL_LEERRAUM;
1810 Feld[newx][newy] = element;
1812 if (Store[x][y]==EL_MORAST_VOLL)
1815 Feld[newx][newy] = EL_MORAST_VOLL;
1816 element = EL_MORAST_VOLL;
1818 else if (Store[x][y]==EL_MORAST_LEER)
1821 Feld[x][y] = EL_MORAST_LEER;
1823 else if (Store[x][y]==EL_SIEB_VOLL)
1826 element = Feld[newx][newy] = (SiebAktiv ? EL_SIEB_VOLL : EL_SIEB_TOT);
1828 else if (Store[x][y]==EL_SIEB_LEER)
1830 Store[x][y] = Store2[x][y] = 0;
1831 Feld[x][y] = (SiebAktiv ? EL_SIEB_LEER : EL_SIEB_TOT);
1833 else if (Store[x][y]==EL_SIEB2_VOLL)
1836 element = Feld[newx][newy] = (SiebAktiv ? EL_SIEB2_VOLL : EL_SIEB2_TOT);
1838 else if (Store[x][y]==EL_SIEB2_LEER)
1840 Store[x][y] = Store2[x][y] = 0;
1841 Feld[x][y] = (SiebAktiv ? EL_SIEB2_LEER : EL_SIEB2_TOT);
1843 else if (Store[x][y]==EL_SALZSAEURE)
1846 Feld[newx][newy] = EL_SALZSAEURE;
1847 element = EL_SALZSAEURE;
1849 else if (Store[x][y]==EL_AMOEBE_NASS)
1852 Feld[x][y] = EL_AMOEBE_NASS;
1855 MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
1856 MovDelay[newx][newy] = 0;
1858 if (!CAN_MOVE(element))
1859 MovDir[newx][newy] = 0;
1861 DrawLevelField(x,y);
1862 DrawLevelField(newx,newy);
1864 Stop[newx][newy] = TRUE;
1865 JustHit[x][newy] = 3;
1867 if (DONT_TOUCH(element)) /* Käfer oder Flieger */
1869 TestIfBadThingHitsHero();
1870 TestIfBadThingHitsFriend(newx,newy);
1871 TestIfBadThingHitsOtherBadThing(newx,newy);
1873 else if (element == EL_PINGUIN)
1874 TestIfFriendHitsBadThing(newx,newy);
1876 if (CAN_SMASH(element) && direction==MV_DOWN &&
1877 (newy==lev_fieldy-1 || !IS_FREE(x,newy+1)))
1880 else /* noch in Bewegung */
1881 DrawLevelField(x,y);
1884 int AmoebeNachbarNr(int ax, int ay)
1887 int element = Feld[ax][ay];
1889 static int xy[4][2] =
1899 int x = ax+xy[i%4][0];
1900 int y = ay+xy[i%4][1];
1902 if (!IN_LEV_FIELD(x,y))
1905 if (Feld[x][y]==element && AmoebaNr[x][y]>0)
1906 group_nr = AmoebaNr[x][y];
1912 void AmoebenVereinigen(int ax, int ay)
1915 int new_group_nr = AmoebaNr[ax][ay];
1916 static int xy[4][2] =
1932 if (!IN_LEV_FIELD(x,y))
1935 if ((Feld[x][y]==EL_AMOEBE_VOLL ||
1936 Feld[x][y]==EL_AMOEBE_BD ||
1937 Feld[x][y]==EL_AMOEBE_TOT) &&
1938 AmoebaNr[x][y] != new_group_nr)
1940 int old_group_nr = AmoebaNr[x][y];
1942 AmoebaCnt[new_group_nr] += AmoebaCnt[old_group_nr];
1943 AmoebaCnt[old_group_nr] = 0;
1944 AmoebaCnt2[new_group_nr] += AmoebaCnt2[old_group_nr];
1945 AmoebaCnt2[old_group_nr] = 0;
1947 for(yy=0;yy<lev_fieldy;yy++) for(xx=0;xx<lev_fieldx;xx++)
1948 if (AmoebaNr[xx][yy]==old_group_nr)
1949 AmoebaNr[xx][yy] = new_group_nr;
1954 void AmoebeUmwandeln(int ax, int ay)
1957 int group_nr = AmoebaNr[ax][ay];
1958 static int xy[4][2] =
1966 if (Feld[ax][ay]==EL_AMOEBE_TOT)
1968 for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
1970 if (Feld[x][y]==EL_AMOEBE_TOT && AmoebaNr[x][y]==group_nr)
1973 Feld[x][y] = EL_AMOEBA2DIAM;
1985 if (!IN_LEV_FIELD(x,y))
1988 if (Feld[x][y]==EL_AMOEBA2DIAM)
1994 void AmoebeUmwandeln2(int ax, int ay, int new_element)
1997 int group_nr = AmoebaNr[ax][ay];
2000 for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
2002 if (AmoebaNr[x][y]==group_nr &&
2003 (Feld[x][y]==EL_AMOEBE_TOT ||
2004 Feld[x][y]==EL_AMOEBE_BD ||
2005 Feld[x][y]==EL_AMOEBING))
2008 Feld[x][y] = new_element;
2009 DrawLevelField(x,y);
2015 PlaySoundLevel(ax,ay,new_element==EL_FELSBROCKEN ? SND_KLOPF : SND_PLING);
2018 void AmoebeWaechst(int x, int y)
2020 static long sound_delay = 0;
2021 static int sound_delay_value = 0;
2023 if (!MovDelay[x][y]) /* neue Phase / noch nicht gewartet */
2027 if (DelayReached(&sound_delay,sound_delay_value))
2029 PlaySoundLevel(x,y,SND_AMOEBE);
2030 sound_delay_value = 30;
2034 if (MovDelay[x][y]) /* neue Phase / in Wartezustand */
2037 if (MovDelay[x][y] && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
2038 DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_AMOEBING+3-MovDelay[x][y]);
2040 if (!MovDelay[x][y])
2042 Feld[x][y] = Store[x][y];
2044 DrawLevelField(x,y);
2049 void AmoebeAbleger(int ax, int ay)
2052 int element = Feld[ax][ay];
2053 int newax = ax, neway = ay;
2054 static int xy[4][2] =
2062 if (!level.tempo_amoebe)
2064 Feld[ax][ay] = EL_AMOEBE_TOT;
2065 DrawLevelField(ax,ay);
2069 if (!MovDelay[ax][ay]) /* neue Amoebe / noch nicht gewartet */
2070 MovDelay[ax][ay] = RND(FRAMES_PER_SECOND * 25/(1+level.tempo_amoebe));
2072 if (MovDelay[ax][ay]) /* neue Amoebe / in Wartezustand */
2075 if (MovDelay[ax][ay])
2079 if (element==EL_AMOEBE_NASS) /* tropfende Amöbe */
2082 int x = ax+xy[start][0];
2083 int y = ay+xy[start][1];
2085 if (!IN_LEV_FIELD(x,y))
2089 Feld[x][y]==EL_ERDREICH || Feld[x][y]==EL_MORAST_LEER)
2095 if (newax==ax && neway==ay)
2098 else /* normale oder "gefüllte" Amöbe */
2101 BOOL waiting_for_player = FALSE;
2105 int j = (start+i)%4;
2106 int x = ax+xy[j][0];
2107 int y = ay+xy[j][1];
2109 if (!IN_LEV_FIELD(x,y))
2113 Feld[x][y]==EL_ERDREICH || Feld[x][y]==EL_MORAST_LEER)
2119 else if (IS_PLAYER(x,y))
2120 waiting_for_player = TRUE;
2123 if (newax==ax && neway==ay)
2125 if (i==4 && !waiting_for_player)
2127 Feld[ax][ay] = EL_AMOEBE_TOT;
2128 DrawLevelField(ax,ay);
2129 AmoebaCnt[AmoebaNr[ax][ay]]--;
2131 if (AmoebaCnt[AmoebaNr[ax][ay]]<=0) /* Amöbe vollständig tot */
2133 if (element==EL_AMOEBE_VOLL)
2134 AmoebeUmwandeln(ax,ay);
2135 else if (element==EL_AMOEBE_BD)
2136 AmoebeUmwandeln2(ax,ay,level.amoebe_inhalt);
2141 else if (element==EL_AMOEBE_VOLL || element==EL_AMOEBE_BD)
2143 int new_group_nr = AmoebaNr[ax][ay];
2145 AmoebaNr[newax][neway] = new_group_nr;
2146 AmoebaCnt[new_group_nr]++;
2147 AmoebaCnt2[new_group_nr]++;
2148 AmoebenVereinigen(newax,neway);
2150 if (AmoebaCnt2[new_group_nr] >= 200 && element==EL_AMOEBE_BD)
2152 AmoebeUmwandeln2(newax,neway,EL_FELSBROCKEN);
2158 if (element!=EL_AMOEBE_NASS || neway<ay || !IS_FREE(newax,neway) ||
2159 (neway==lev_fieldy-1 && newax!=ax))
2161 Feld[newax][neway] = EL_AMOEBING;
2162 Store[newax][neway] = element;
2165 Feld[newax][neway] = EL_TROPFEN;
2168 InitMovingField(ax,ay,MV_DOWN);
2169 Feld[ax][ay] = EL_TROPFEN;
2170 Store[ax][ay] = EL_AMOEBE_NASS;
2171 ContinueMoving(ax,ay);
2175 DrawLevelField(newax,neway);
2178 void Life(int ax, int ay)
2181 static int life[4] = { 2,3,3,3 }; /* "Life"-Parameter */
2183 int element = Feld[ax][ay];
2188 if (!MovDelay[ax][ay]) /* neue Phase / noch nicht gewartet */
2189 MovDelay[ax][ay] = life_time;
2191 if (MovDelay[ax][ay]) /* neue Phase / in Wartezustand */
2194 if (MovDelay[ax][ay])
2198 for(y1=-1;y1<2;y1++) for(x1=-1;x1<2;x1++)
2200 int xx = ax+x1, yy = ay+y1;
2203 if (!IN_LEV_FIELD(xx,yy))
2206 for(y2=-1;y2<2;y2++) for(x2=-1;x2<2;x2++)
2208 int x = xx+x2, y = yy+y2;
2210 if (!IN_LEV_FIELD(x,y) || (x==xx && y==yy))
2213 if (((Feld[x][y]==element || (element==EL_LIFE && IS_PLAYER(x,y))) &&
2215 (IS_FREE(x,y) && Stop[x][y]))
2219 if (xx==ax && yy==ay) /* mittleres Feld mit Amoebe */
2221 if (nachbarn<life[0] || nachbarn>life[1])
2223 Feld[xx][yy] = EL_LEERRAUM;
2225 DrawLevelField(xx,yy);
2226 Stop[xx][yy] = TRUE;
2229 else if (IS_FREE(xx,yy) || Feld[xx][yy]==EL_ERDREICH)
2230 { /* Randfeld ohne Amoebe */
2231 if (nachbarn>=life[2] && nachbarn<=life[3])
2233 Feld[xx][yy] = element;
2234 MovDelay[xx][yy] = (element==EL_LIFE ? 0 : life_time-1);
2236 DrawLevelField(xx,yy);
2237 Stop[xx][yy] = TRUE;
2243 void Ablenk(int x, int y)
2245 if (!MovDelay[x][y]) /* neue Phase / noch nicht gewartet */
2246 MovDelay[x][y] = level.dauer_ablenk * FRAMES_PER_SECOND;
2248 if (MovDelay[x][y]) /* neue Phase / in Wartezustand */
2253 if (IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
2254 DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_ABLENK+MovDelay[x][y]%4);
2255 if (!(MovDelay[x][y]%4))
2256 PlaySoundLevel(x,y,SND_MIEP);
2261 Feld[x][y] = EL_ABLENK_AUS;
2262 DrawLevelField(x,y);
2267 void Birne(int x, int y)
2269 if (!MovDelay[x][y]) /* neue Phase / noch nicht gewartet */
2270 MovDelay[x][y] = 400;
2272 if (MovDelay[x][y]) /* neue Phase / in Wartezustand */
2277 if (!(MovDelay[x][y]%5))
2279 if (!(MovDelay[x][y]%10))
2280 Feld[x][y]=EL_ABLENK_EIN;
2282 Feld[x][y]=EL_ABLENK_AUS;
2283 DrawLevelField(x,y);
2284 Feld[x][y]=EL_ABLENK_EIN;
2290 Feld[x][y]=EL_ABLENK_AUS;
2291 DrawLevelField(x,y);
2296 void Blubber(int x, int y)
2298 DrawGraphicAnimation(x,y, GFX_GEBLUBBER, 4, 5, ANIM_NORMAL);
2301 void NussKnacken(int x, int y)
2303 if (!MovDelay[x][y]) /* neue Phase / noch nicht gewartet */
2306 if (MovDelay[x][y]) /* neue Phase / in Wartezustand */
2309 if (MovDelay[x][y] && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
2310 DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_CRACKINGNUT+3-MovDelay[x][y]);
2312 if (!MovDelay[x][y])
2314 Feld[x][y] = EL_EDELSTEIN;
2315 DrawLevelField(x,y);
2320 void SiebAktivieren(int x, int y, int typ)
2322 if (SiebAktiv%2 && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
2323 DrawGraphic(SCROLLX(x),SCROLLY(y),
2324 (typ==1 ? GFX_SIEB_VOLL : GFX_SIEB2_VOLL)+3-(SiebAktiv%8)/2);
2327 void AusgangstuerPruefen(int x, int y)
2329 if (!Gems && !SokobanFields && !Lights)
2331 Feld[x][y] = EL_AUSGANG_ACT;
2332 PlaySoundLevel(x,y,SND_OEFFNEN);
2336 void AusgangstuerOeffnen(int x, int y)
2340 if (!MovDelay[x][y]) /* neue Phase / noch nicht gewartet */
2341 MovDelay[x][y] = 5*speed;
2343 if (MovDelay[x][y]) /* neue Phase / in Wartezustand */
2348 tuer = MovDelay[x][y]/speed;
2349 if (!(MovDelay[x][y]%speed) && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
2350 DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_AUSGANG_AUF-tuer);
2352 if (!MovDelay[x][y])
2354 Feld[x][y] = EL_AUSGANG_AUF;
2355 DrawLevelField(x,y);
2360 void AusgangstuerBlinken(int x, int y)
2362 DrawGraphicAnimation(x,y, GFX_AUSGANG_AUF, 4, 2, ANIM_OSCILLATE);
2365 void EdelsteinFunkeln(int x, int y)
2367 if (!IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)) || IS_MOVING(x,y))
2370 if (Feld[x][y] == EL_EDELSTEIN_BD)
2372 const int delay = 2;
2373 const int frames = 4;
2374 int phase = (FrameCounter % (delay*frames)) / delay;
2376 if (!(FrameCounter % delay))
2377 DrawGraphic(SCROLLX(x),SCROLLY(y), GFX_EDELSTEIN_BD - phase);
2381 if (!MovDelay[x][y]) /* neue Phase / noch nicht gewartet */
2382 MovDelay[x][y] = 6*!SimpleRND(500);
2384 if (MovDelay[x][y]) /* neue Phase / in Wartezustand */
2388 if (direct_draw_on && MovDelay[x][y])
2389 drawto_field = backbuffer;
2391 DrawGraphic(SCROLLX(x),SCROLLY(y), el2gfx(Feld[x][y]));
2395 int src_x,src_y, dest_x,dest_y;
2396 int phase = MovDelay[x][y]-1;
2398 src_x = SX+GFX_PER_LINE*TILEX;
2399 src_y = SY+(phase > 2 ? 4-phase : phase)*TILEY;
2400 dest_x = SX+SCROLLX(x)*TILEX;
2401 dest_y = SY+SCROLLY(y)*TILEY;
2403 XSetClipOrigin(display,clip_gc[PIX_BACK],dest_x-src_x,dest_y-src_y);
2404 XCopyArea(display,pix[PIX_BACK],drawto_field,clip_gc[PIX_BACK],
2405 src_x,src_y, TILEX,TILEY, dest_x,dest_y);
2409 XCopyArea(display,backbuffer,window,gc,
2410 dest_x,dest_y, TILEX,TILEY, dest_x,dest_y);
2411 drawto_field = window;
2418 void MauerWaechst(int x, int y)
2422 if (!MovDelay[x][y]) /* neue Phase / noch nicht gewartet */
2423 MovDelay[x][y] = 3*speed;
2425 if (MovDelay[x][y]) /* neue Phase / in Wartezustand */
2430 phase = 2-MovDelay[x][y]/speed;
2431 if (!(MovDelay[x][y]%speed) && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
2432 DrawGraphic(SCROLLX(x),SCROLLY(y),
2433 (Store[x][y]==MV_LEFT ? GFX_MAUER_L1 : GFX_MAUER_R1)+phase);
2435 if (!MovDelay[x][y])
2437 if (Store[x][y]==MV_LEFT)
2439 if (IN_LEV_FIELD(x-1,y) && IS_MAUER(Feld[x-1][y]))
2440 DrawLevelField(x-1,y);
2444 if (IN_LEV_FIELD(x+1,y) && IS_MAUER(Feld[x+1][y]))
2445 DrawLevelField(x+1,y);
2448 Feld[x][y] = EL_MAUER_LEBT;
2450 DrawLevelField(x,y);
2455 void MauerAbleger(int ax, int ay)
2457 BOOL links_frei = FALSE, rechts_frei = FALSE;
2458 BOOL links_massiv = FALSE, rechts_massiv = FALSE;
2460 if (!MovDelay[ax][ay]) /* neue Mauer / noch nicht gewartet */
2461 MovDelay[ax][ay] = 3;
2463 if (MovDelay[ax][ay]) /* neue Mauer / in Wartezustand */
2466 if (MovDelay[ax][ay])
2470 if (IN_LEV_FIELD(ax-1,ay) && IS_FREE(ax-1,ay))
2472 if (IN_LEV_FIELD(ax+1,ay) && IS_FREE(ax+1,ay))
2477 Feld[ax-1][ay] = EL_MAUERND;
2478 Store[ax-1][ay] = MV_LEFT;
2479 if (IN_SCR_FIELD(SCROLLX(ax-1),SCROLLY(ay)))
2480 DrawGraphic(SCROLLX(ax-1),SCROLLY(ay),GFX_MAUER_L1);
2484 Feld[ax+1][ay] = EL_MAUERND;
2485 Store[ax+1][ay] = MV_RIGHT;
2486 if (IN_SCR_FIELD(SCROLLX(ax+1),SCROLLY(ay)))
2487 DrawGraphic(SCROLLX(ax+1),SCROLLY(ay),GFX_MAUER_R1);
2490 if (links_frei || rechts_frei)
2491 DrawLevelField(ax,ay);
2493 if (!IN_LEV_FIELD(ax-1,ay) || IS_MAUER(Feld[ax-1][ay]))
2494 links_massiv = TRUE;
2495 if (!IN_LEV_FIELD(ax+1,ay) || IS_MAUER(Feld[ax+1][ay]))
2496 rechts_massiv = TRUE;
2498 if (links_massiv && rechts_massiv)
2499 Feld[ax][ay] = EL_MAUERWERK;
2502 void CheckForDragon(int x, int y)
2505 BOOL dragon_found = FALSE;
2506 static int xy[4][2] =
2518 int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
2520 if (IN_LEV_FIELD(xx,yy) &&
2521 (Feld[xx][yy] == EL_BURNING || Feld[xx][yy] == EL_DRACHE))
2523 if (Feld[xx][yy] == EL_DRACHE)
2524 dragon_found = TRUE;
2537 int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
2539 if (IN_LEV_FIELD(xx,yy) && Feld[xx][yy] == EL_BURNING)
2541 Feld[xx][yy] = EL_LEERRAUM;
2542 DrawLevelField(xx,yy);
2553 static long action_delay=0;
2554 long action_delay_value;
2556 if (game_status != PLAYING)
2560 action_delay_value =
2561 (tape.playing && tape.fast_forward ? FFWD_FRAME_DELAY : GAME_FRAME_DELAY);
2564 action_delay_value =
2565 (tape.playing && tape.fast_forward ? FFWD_FRAME_DELAY : Gamespeed);
2567 if (DelayReached(&action_delay, action_delay_value))
2570 int sieb_x = 0, sieb_y = 0;
2572 if (tape.pausing || (tape.playing && !TapePlayDelay()))
2574 else if (tape.recording)
2580 for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
2583 if (JustHit[x][y]>0)
2587 if (IS_BLOCKED(x,y))
2591 Blocked2Moving(x,y,&oldx,&oldy);
2592 if (!IS_MOVING(oldx,oldy))
2594 printf("GameActions(): (BLOCKED=>MOVING) context corrupted!\n");
2595 printf("GameActions(): BLOCKED: x = %d, y = %d\n",x,y);
2596 printf("GameActions(): !MOVING: oldx = %d, oldy = %d\n",oldx,oldy);
2597 printf("GameActions(): This should never happen!\n");
2604 for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
2606 element = Feld[x][y];
2608 if (IS_INACTIVE(element))
2611 if (!IS_MOVING(x,y) && (CAN_FALL(element) || CAN_MOVE(element)))
2615 if (IS_GEM(element))
2616 EdelsteinFunkeln(x,y);
2618 else if (IS_MOVING(x,y))
2619 ContinueMoving(x,y);
2620 else if (element==EL_DYNAMIT || element==EL_DYNABOMB)
2622 else if (element==EL_EXPLODING)
2623 Explode(x,y,Frame[x][y],EX_NORMAL);
2624 else if (element==EL_AMOEBING)
2626 else if (IS_AMOEBALIVE(element))
2628 else if (element==EL_LIFE || element==EL_LIFE_ASYNC)
2630 else if (element==EL_ABLENK_EIN)
2632 else if (element==EL_SALZSAEURE)
2634 else if (element==EL_BLURB_LEFT || element==EL_BLURB_RIGHT)
2636 else if (element==EL_CRACKINGNUT)
2638 else if (element==EL_AUSGANG_ZU)
2639 AusgangstuerPruefen(x,y);
2640 else if (element==EL_AUSGANG_ACT)
2641 AusgangstuerOeffnen(x,y);
2642 else if (element==EL_AUSGANG_AUF)
2643 AusgangstuerBlinken(x,y);
2644 else if (element==EL_MAUERND)
2646 else if (element==EL_MAUER_LEBT)
2648 else if (element==EL_BURNING)
2649 CheckForDragon(x,y);
2655 if (element==EL_SIEB_LEER || element==EL_SIEB_VOLL ||
2656 Store[x][y]==EL_SIEB_LEER)
2658 SiebAktivieren(x, y, 1);
2661 else if (element==EL_SIEB2_LEER || element==EL_SIEB2_VOLL ||
2662 Store[x][y]==EL_SIEB2_LEER)
2664 SiebAktivieren(x, y, 2);
2668 if (sieb && ABS(x-JX)+ABS(y-JY) < ABS(sieb_x-JX)+ABS(sieb_y-JY))
2679 PlaySoundLevel(sieb_x,sieb_y,SND_MIEP);
2683 for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
2685 element = Feld[x][y];
2686 if (element==EL_SIEB_LEER || element==EL_SIEB_VOLL)
2688 Feld[x][y] = EL_SIEB_TOT;
2689 DrawLevelField(x,y);
2691 else if (element==EL_SIEB2_LEER || element==EL_SIEB2_VOLL)
2693 Feld[x][y] = EL_SIEB2_TOT;
2694 DrawLevelField(x,y);
2701 if (TimeLeft>0 && TimeFrames>=25 && !tape.pausing)
2706 if (tape.recording || tape.playing)
2707 DrawVideoDisplay(VIDEO_STATE_TIME_ON,level.time-TimeLeft);
2710 PlaySoundStereo(SND_GONG,PSND_MAX_RIGHT);
2712 DrawText(DX_TIME,DY_TIME,int2str(TimeLeft,3),FS_SMALL,FC_YELLOW);
2721 void ScrollLevel(int dx, int dy)
2725 XCopyArea(display,drawto_field,drawto_field,gc,
2726 SX+TILEX*(dx==-1),SY+TILEY*(dy==-1),
2727 SXSIZE-TILEX*(dx!=0),SYSIZE-TILEY*(dy!=0),
2728 SX+TILEX*(dx==1),SY+TILEY*(dy==1));
2732 x = (dx==1 ? 0 : SCR_FIELDX-1);
2733 for(y=0;y<SCR_FIELDY;y++)
2734 DrawScreenField(x,y);
2738 y = (dy==1 ? 0 : SCR_FIELDY-1);
2739 for(x=0;x<SCR_FIELDX;x++)
2740 DrawScreenField(x,y);
2743 redraw_mask|=REDRAW_FIELD;
2746 BOOL MoveFigureOneStep(int dx, int dy, int real_dx, int real_dy)
2748 int oldJX,oldJY, newJX = JX+dx,newJY = JY+dy;
2753 int old_move_dir = PlayerMovDir;
2756 if (PlayerGone || (!dx && !dy))
2757 return(MF_NO_ACTION);
2759 PlayerMovDir = (dx < 0 ? MV_LEFT :
2762 dy > 0 ? MV_DOWN : MV_NO_MOVING);
2764 if (old_move_dir != PlayerMovDir)
2767 PlayerFrame = (PlayerFrame + 1) % 4;
2770 if (!IN_LEV_FIELD(newJX,newJY))
2771 return(MF_NO_ACTION);
2773 element = MovingOrBlocked2Element(newJX,newJY);
2775 if (DONT_GO_TO(element))
2777 if (element==EL_SALZSAEURE && dx==0 && dy==1)
2780 Feld[JX][JY] = EL_SPIELFIGUR;
2781 InitMovingField(JX,JY,MV_DOWN);
2782 Store[JX][JY] = EL_SALZSAEURE;
2783 ContinueMoving(JX,JY);
2792 can_move = DigField(newJX,newJY, real_dx,real_dy, DF_DIG);
2793 if (can_move != MF_MOVING)
2805 PlayerMovPos = TILEX/4;
2806 PlayerMovPos = (dx > 0 || dy > 0 ? -1 : 1) * 3*TILEX/4;
2810 if (Store[oldJX][oldJY])
2812 DrawGraphic(SCROLLX(oldJX),SCROLLY(oldJY),el2gfx(Store[oldJX][oldJY]));
2813 DrawGraphicThruMask(SCROLLX(oldJX),SCROLLY(oldJY),
2814 el2gfx(Feld[oldJX][oldJY]));
2816 else if (Feld[oldJX][oldJY]==EL_DYNAMIT)
2817 DrawDynamite(oldJX,oldJY);
2819 DrawLevelField(oldJX,oldJY);
2824 BOOL MoveFigure(int dx, int dy)
2826 static long move_delay = 0;
2827 int moved = MF_NO_ACTION;
2828 int oldJX = JX, oldJY = JY;
2830 if (PlayerGone || (!dx && !dy))
2834 if (!DelayReached(&move_delay,8) && !tape.playing)
2839 if (!DelayReached(&move_delay,10) && !tape.playing)
2844 if (!FrameReached(&move_delay,2) && !tape.playing)
2848 if (Movemethod == 0)
2850 if (!DelayReached(&move_delay,Movespeed[0]) && !tape.playing)
2855 if (!FrameReached(&move_delay,Movespeed[1]) && !tape.playing)
2859 if (moved |= MoveFigureOneStep(dx,0, dx,dy))
2860 moved |= MoveFigureOneStep(0,dy, dx,dy);
2863 moved |= MoveFigureOneStep(0,dy, dx,dy);
2864 moved |= MoveFigureOneStep(dx,0, dx,dy);
2867 if (moved & MF_MOVING)
2869 int old_scroll_x=scroll_x, old_scroll_y=scroll_y;
2870 int offset = (scroll_delay_on ? 3 : 0);
2872 if ((scroll_x < JX-MIDPOSX-offset || scroll_x > JX-MIDPOSX+offset) &&
2873 JX>=MIDPOSX-1-offset && JX<=lev_fieldx-(MIDPOSX-offset))
2874 scroll_x = JX-MIDPOSX + (scroll_x < JX-MIDPOSX ? -offset : offset);
2875 if ((scroll_y < JY-MIDPOSY-offset || scroll_y > JY-MIDPOSY+offset) &&
2876 JY>=MIDPOSY-1-offset && JY<=lev_fieldy-(MIDPOSY-offset))
2877 scroll_y = JY-MIDPOSY + (scroll_y < JY-MIDPOSY ? -offset : offset);
2879 if (scroll_x!=old_scroll_x || scroll_y!=old_scroll_y)
2880 ScrollLevel(old_scroll_x-scroll_x,old_scroll_y-scroll_y);
2883 if (!(moved & MF_MOVING) && !PlayerPushing)
2886 PlayerFrame = (PlayerFrame + 1) % 4;
2888 if (moved & MF_MOVING)
2890 if (oldJX != JX && oldJY == JY)
2891 PlayerMovDir = (oldJX < JX ? MV_RIGHT : MV_LEFT);
2892 else if (oldJX == JX && oldJY != JY)
2893 PlayerMovDir = (oldJY < JY ? MV_DOWN : MV_UP);
2895 DrawLevelField(JX,JY); /* für "ErdreichAnbroeckeln()" */
2898 TestIfHeroHitsBadThing();
2908 void ScrollFigure(int init)
2910 static long actual_frame_counter;
2914 actual_frame_counter = FrameCounter;
2917 else if (!FrameReached(&actual_frame_counter,1))
2920 PlayerMovPos += (PlayerMovPos > 0 ? -1 : 1) * TILEX/4;
2922 DrawLevelElement(JX2,JY2, Feld[JX2][JY2]);
2926 void TestIfGoodThingHitsBadThing(int goodx, int goody)
2928 int i, killx = goodx, killy = goody;
2929 static int xy[4][2] =
2936 static int harmless[4] =
2950 if (!IN_LEV_FIELD(x,y))
2953 element = Feld[x][y];
2955 if (DONT_TOUCH(element))
2957 if (MovDir[x][y]==harmless[i])
2966 if (killx!=goodx || killy!=goody)
2968 if (IS_PLAYER(goodx,goody))
2975 void TestIfBadThingHitsGoodThing(int badx, int bady)
2977 int i, killx = badx, killy = bady;
2978 static int xy[4][2] =
2985 static int harmless[4] =
2999 if (!IN_LEV_FIELD(x,y))
3002 element = Feld[x][y];
3004 if (element==EL_PINGUIN)
3006 if (MovDir[x][y]==harmless[i] && IS_MOVING(x,y))
3015 if (killx!=badx || killy!=bady)
3019 void TestIfHeroHitsBadThing()
3021 TestIfGoodThingHitsBadThing(JX,JY);
3024 void TestIfBadThingHitsHero()
3026 TestIfGoodThingHitsBadThing(JX,JY);
3030 void TestIfFriendHitsBadThing(int x, int y)
3032 TestIfGoodThingHitsBadThing(x,y);
3035 void TestIfBadThingHitsFriend(int x, int y)
3037 TestIfBadThingHitsGoodThing(x,y);
3040 void TestIfBadThingHitsOtherBadThing(int badx, int bady)
3042 int i, killx=badx, killy=bady;
3043 static int xy[4][2] =
3057 if (!IN_LEV_FIELD(x,y))
3061 if (IS_AMOEBOID(element) || element==EL_LIFE ||
3062 element==EL_AMOEBING || element==EL_TROPFEN)
3070 if (killx!=badx || killy!=bady)
3079 if (IS_PFORTE(Feld[JX][JY]))
3080 Feld[JX][JY] = EL_LEERRAUM;
3091 PlaySoundLevel(JX,JY,SND_AUTSCH);
3092 PlaySoundLevel(JX,JY,SND_LACHEN);
3107 int DigField(int x, int y, int real_dx, int real_dy, int mode)
3109 int dx = x-JX, dy = y-JY;
3111 static long push_delay = 0;
3112 static int push_delay_value = 5;
3114 PlayerPushing = FALSE;
3116 if (mode == DF_NO_PUSH)
3119 return(MF_NO_ACTION);
3123 return(MF_NO_ACTION);
3125 element = Feld[x][y];
3133 Feld[x][y] = EL_LEERRAUM;
3137 case EL_EDELSTEIN_BD:
3138 case EL_EDELSTEIN_GELB:
3139 case EL_EDELSTEIN_ROT:
3140 case EL_EDELSTEIN_LILA:
3141 Feld[x][y] = EL_LEERRAUM;
3142 MovDelay[x][y] = 0; /* wegen EDELSTEIN_BD-Funkeln! */
3145 RaiseScoreElement(EL_EDELSTEIN);
3146 DrawText(DX_EMERALDS,DY_EMERALDS,int2str(Gems,3),FS_SMALL,FC_YELLOW);
3147 PlaySoundLevel(x,y,SND_PONG);
3151 Feld[x][y] = EL_LEERRAUM;
3155 RaiseScoreElement(EL_DIAMANT);
3156 DrawText(DX_EMERALDS,DY_EMERALDS,int2str(Gems,3),FS_SMALL,FC_YELLOW);
3157 PlaySoundLevel(x,y,SND_PONG);
3160 case EL_DYNAMIT_AUS:
3161 Feld[x][y] = EL_LEERRAUM;
3163 RaiseScoreElement(EL_DYNAMIT);
3164 DrawText(DX_DYNAMITE,DY_DYNAMITE,int2str(Dynamite,3),FS_SMALL,FC_YELLOW);
3165 PlaySoundLevel(x,y,SND_PONG);
3168 case EL_DYNABOMB_NR:
3169 Feld[x][y] = EL_LEERRAUM;
3172 RaiseScoreElement(EL_DYNAMIT);
3173 PlaySoundLevel(x,y,SND_PONG);
3175 case EL_DYNABOMB_SZ:
3177 Feld[x][y] = EL_LEERRAUM;
3179 RaiseScoreElement(EL_DYNAMIT);
3180 PlaySoundLevel(x,y,SND_PONG);
3183 case EL_DYNABOMB_XL:
3184 Feld[x][y] = EL_LEERRAUM;
3186 RaiseScoreElement(EL_DYNAMIT);
3187 PlaySoundLevel(x,y,SND_PONG);
3190 case EL_SCHLUESSEL1:
3191 case EL_SCHLUESSEL2:
3192 case EL_SCHLUESSEL3:
3193 case EL_SCHLUESSEL4:
3195 int key_nr = element-EL_SCHLUESSEL1;
3197 Feld[x][y] = EL_LEERRAUM;
3199 RaiseScoreElement(EL_SCHLUESSEL);
3200 DrawMiniGraphicExtHiRes(drawto,gc,
3201 DX_KEYS+key_nr*MINI_TILEX,DY_KEYS,
3202 GFX_SCHLUESSEL1+key_nr);
3203 DrawMiniGraphicExtHiRes(window,gc,
3204 DX_KEYS+key_nr*MINI_TILEX,DY_KEYS,
3205 GFX_SCHLUESSEL1+key_nr);
3206 PlaySoundLevel(x,y,SND_PONG);
3211 Feld[x][y] = EL_ABLENK_EIN;
3214 DrawLevelField(x,y);
3218 case EL_FELSBROCKEN:
3222 if (dy || mode==DF_SNAP)
3223 return(MF_NO_ACTION);
3225 PlayerPushing = TRUE;
3227 if (!IN_LEV_FIELD(x+dx,y+dy) || Feld[x+dx][y+dy] != EL_LEERRAUM)
3228 return(MF_NO_ACTION);
3232 if (IN_LEV_FIELD(JX,JY+real_dy) && !IS_SOLID(Feld[JX][JY+real_dy]))
3233 return(MF_NO_ACTION);
3236 if (push_delay == 0)
3237 push_delay = FrameCounter;
3238 if (!FrameReached(&push_delay,push_delay_value) && !tape.playing)
3239 return(MF_NO_ACTION);
3241 Feld[x][y] = EL_LEERRAUM;
3242 Feld[x+dx][y+dy] = element;
3244 push_delay_value = 2+RND(8);
3246 DrawLevelField(x+dx,y+dy);
3247 if (element==EL_FELSBROCKEN)
3248 PlaySoundLevel(x+dx,y+dy,SND_PUSCH);
3249 else if (element==EL_KOKOSNUSS)
3250 PlaySoundLevel(x+dx,y+dy,SND_KNURK);
3252 PlaySoundLevel(x+dx,y+dy,SND_KLOPF);
3259 if (!Key[element-EL_PFORTE1])
3260 return(MF_NO_ACTION);
3267 if (!Key[element-EL_PFORTE1X])
3268 return(MF_NO_ACTION);
3272 case EL_AUSGANG_ACT:
3273 /* Tür ist (noch) nicht offen! */
3274 return(MF_NO_ACTION);
3277 case EL_AUSGANG_AUF:
3279 return(MF_NO_ACTION);
3282 PlaySoundLevel(x,y,SND_BUING);
3285 LevelSolved = GameOver = TRUE;
3290 Feld[x][y] = EL_BIRNE_EIN;
3292 DrawLevelField(x,y);
3293 PlaySoundLevel(x,y,SND_DENG);
3298 Feld[x][y] = EL_ZEIT_LEER;
3300 DrawText(DX_TIME,DY_TIME,int2str(TimeLeft,3),FS_SMALL,FC_YELLOW);
3301 DrawLevelField(x,y);
3302 PlaySoundStereo(SND_GONG,PSND_MAX_RIGHT);
3306 case EL_SOKOBAN_FELD_LEER:
3309 case EL_SOKOBAN_FELD_VOLL:
3310 case EL_SOKOBAN_OBJEKT:
3313 return(MF_NO_ACTION);
3315 PlayerPushing = TRUE;
3317 if (!IN_LEV_FIELD(x+dx,y+dy)
3318 || (Feld[x+dx][y+dy] != EL_LEERRAUM
3319 && (Feld[x+dx][y+dy] != EL_SOKOBAN_FELD_LEER
3320 || !IS_SB_ELEMENT(element))))
3321 return(MF_NO_ACTION);
3325 if (IN_LEV_FIELD(JX,JY+real_dy) && !IS_SOLID(Feld[JX][JY+real_dy]))
3326 return(MF_NO_ACTION);
3328 else if (dy && real_dx)
3330 if (IN_LEV_FIELD(JX+real_dx,JY) && !IS_SOLID(Feld[JX+real_dx][JY]))
3331 return(MF_NO_ACTION);
3334 if (push_delay == 0)
3335 push_delay = FrameCounter;
3336 if (!FrameReached(&push_delay,push_delay_value) && !tape.playing)
3337 return(MF_NO_ACTION);
3339 if (IS_SB_ELEMENT(element))
3341 if (element == EL_SOKOBAN_FELD_VOLL)
3343 Feld[x][y] = EL_SOKOBAN_FELD_LEER;
3347 Feld[x][y] = EL_LEERRAUM;
3349 if (Feld[x+dx][y+dy] == EL_SOKOBAN_FELD_LEER)
3351 Feld[x+dx][y+dy] = EL_SOKOBAN_FELD_VOLL;
3353 if (element == EL_SOKOBAN_OBJEKT)
3354 PlaySoundLevel(x,y,SND_DENG);
3357 Feld[x+dx][y+dy] = EL_SOKOBAN_OBJEKT;
3361 Feld[x][y] = EL_LEERRAUM;
3362 Feld[x+dx][y+dy] = element;
3365 push_delay_value = 2;
3367 DrawLevelField(x,y);
3368 DrawLevelField(x+dx,y+dy);
3369 PlaySoundLevel(x+dx,y+dy,SND_PUSCH);
3371 if (IS_SB_ELEMENT(element) &&
3372 SokobanFields == 0 && game_emulation == EMU_SOKOBAN)
3374 LevelSolved = GameOver = TRUE;
3375 PlaySoundLevel(x,y,SND_BUING);
3387 return(MF_NO_ACTION);
3396 BOOL SnapField(int dx, int dy)
3398 int x = JX+dx, y = JY+dy;
3399 static int snapped = FALSE;
3401 if (PlayerGone || !IN_LEV_FIELD(x,y))
3413 PlayerMovDir = (dx < 0 ? MV_LEFT :
3416 dy > 0 ? MV_DOWN : MV_NO_MOVING);
3418 if (!DigField(x,y, 0,0, DF_SNAP))
3422 DrawLevelField(x,y);
3428 BOOL PlaceBomb(void)
3435 element = Feld[JX][JY];
3437 if ((Dynamite==0 && DynaBombsLeft==0) ||
3438 element==EL_DYNAMIT || element==EL_DYNABOMB || element==EL_EXPLODING)
3441 if (element != EL_LEERRAUM)
3442 Store[JX][JY] = element;
3446 Feld[JX][JY] = EL_DYNAMIT;
3447 MovDelay[JX][JY] = 48;
3449 DrawText(DX_DYNAMITE,DY_DYNAMITE,int2str(Dynamite,3),FS_SMALL,FC_YELLOW);
3450 DrawGraphicThruMask(SCROLLX(JX),SCROLLY(JY),GFX_DYNAMIT);
3454 Feld[JX][JY] = EL_DYNABOMB;
3455 MovDelay[JX][JY] = 48;
3457 DrawGraphicThruMask(SCROLLX(JX),SCROLLY(JY),GFX_DYNABOMB);
3463 void PlaySoundLevel(int x, int y, int sound_nr)
3465 int sx = SCROLLX(x), sy = SCROLLY(y);
3467 int silence_distance = 8;
3469 if ((!sound_simple_on && !IS_LOOP_SOUND(sound_nr)) ||
3470 (!sound_loops_on && IS_LOOP_SOUND(sound_nr)))
3473 if (!IN_LEV_FIELD(x,y) ||
3474 sx < -silence_distance || sx >= SCR_FIELDX+silence_distance ||
3475 sy < -silence_distance || sy >= SCR_FIELDY+silence_distance)
3478 volume = PSND_MAX_VOLUME;
3479 stereo = (sx-SCR_FIELDX/2)*12;
3481 if (!IN_SCR_FIELD(sx,sy))
3483 int dx = ABS(sx-SCR_FIELDX/2)-SCR_FIELDX/2;
3484 int dy = ABS(sy-SCR_FIELDY/2)-SCR_FIELDY/2;
3486 volume -= volume*(dx > dy ? dx : dy)/silence_distance;
3489 PlaySoundExt(sound_nr, volume, stereo, PSND_NO_LOOP);
3492 void RaiseScore(int value)
3495 DrawText(DX_SCORE,DY_SCORE,int2str(Score,5),FS_SMALL,FC_YELLOW);
3499 void RaiseScoreElement(int element)
3504 RaiseScore(level.score[SC_EDELSTEIN]);
3507 RaiseScore(level.score[SC_DIAMANT]);
3511 RaiseScore(level.score[SC_KAEFER]);
3515 RaiseScore(level.score[SC_FLIEGER]);
3519 RaiseScore(level.score[SC_MAMPFER]);
3522 RaiseScore(level.score[SC_ROBOT]);
3525 RaiseScore(level.score[SC_PACMAN]);
3528 RaiseScore(level.score[SC_KOKOSNUSS]);
3531 RaiseScore(level.score[SC_DYNAMIT]);
3534 RaiseScore(level.score[SC_SCHLUESSEL]);