1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-98 Artsoft Entertainment *
8 * phone: ++49 +521 290471 *
9 * email: aeglos@valinor.owl.de *
10 *----------------------------------------------------------*
12 ***********************************************************/
26 void GetPlayerConfig()
28 int old_joystick_nr = joystick_nr;
30 if (sound_status==SOUND_OFF)
31 local_player->setup &= ~SETUP_SOUND;
32 if (!sound_loops_allowed)
34 local_player->setup &= ~SETUP_SOUND_LOOPS;
35 local_player->setup &= ~SETUP_SOUND_MUSIC;
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);
51 if (joystick_nr != old_joystick_nr)
54 close(joystick_device);
63 BOOL emulate_bd = TRUE; /* unless non-BOULDERDASH elements found */
64 BOOL emulate_sb = TRUE; /* unless non-SOKOBAN elements found */
66 /* don't play tapes over network */
67 network_playing = (network && !tape.playing);
69 for(i=0; i<MAX_PLAYERS; i++)
71 struct PlayerInfo *player = &stored_player[i];
74 player->element_nr = EL_SPIELER1 + i;
75 player->active = FALSE;
76 player->local = FALSE;
79 player->gems_still_needed = level.edelsteine;
80 player->sokobanfields_still_needed = 0;
81 player->lights_still_needed = 0;
82 player->friends_still_needed = 0;
85 player->key[j] = FALSE;
88 player->dynabomb_count = 0;
89 player->dynabomb_size = 0;
90 player->dynabombs_left = 0;
91 player->dynabomb_xl = FALSE;
93 player->MovDir = MV_NO_MOVING;
95 player->Pushing = FALSE;
99 player->actual_frame_counter = 0;
101 player->frame_reset_delay = 0;
103 player->push_delay = 0;
104 player->push_delay_value = 5;
106 player->move_delay = 0;
107 player->last_move_dir = MV_NO_MOVING;
109 player->snapped = FALSE;
111 player->gone = FALSE;
113 player->last_jx = player->last_jy = 0;
114 player->jx = player->jy = 0;
116 DigField(player, 0,0,0,0,DF_NO_PUSH);
117 SnapField(player, 0,0);
123 stored_player[i].active = TRUE;
128 player->LevelSolved = FALSE;
129 player->GameOver = FALSE;
132 local_player->active = TRUE;
133 local_player->local = TRUE;
135 network_player_action_received = FALSE;
137 /* initial null action */
139 SendToServer_MovePlayer(MV_NO_MOVING);
146 TimeLeft = level.time;
148 ScreenMovDir = MV_NO_MOVING;
152 AllPlayersGone = SiebAktiv = FALSE;
154 for(i=0;i<MAX_NUM_AMOEBA;i++)
155 AmoebaCnt[i] = AmoebaCnt2[i] = 0;
157 for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
159 Feld[x][y] = Ur[x][y];
160 MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
161 Store[x][y] = Store2[x][y] = StorePlayer[x][y] = 0;
166 if (emulate_bd && !IS_BD_ELEMENT(Feld[x][y]))
168 if (emulate_sb && !IS_SB_ELEMENT(Feld[x][y]))
174 Feld[x][y] = EL_SPIELER1;
181 struct PlayerInfo *player = &stored_player[Feld[x][y] - EL_SPIELER1];
182 int jx = player->jx, jy = player->jy;
184 /* remove duplicate players */
185 if (StorePlayer[jx][jy] == Feld[x][y])
186 StorePlayer[jx][jy] = 0;
188 player->active = TRUE;
190 StorePlayer[x][y] = Feld[x][y];
191 Feld[x][y] = EL_LEERRAUM;
192 player->jx = player->last_jx = x;
193 player->jy = player->last_jy = y;
197 if (x<lev_fieldx-1 && Feld[x+1][y]==EL_SALZSAEURE)
198 Feld[x][y] = EL_BADEWANNE1;
199 else if (x>0 && Feld[x-1][y]==EL_SALZSAEURE)
200 Feld[x][y] = EL_BADEWANNE2;
201 else if (y>0 && Feld[x][y-1]==EL_BADEWANNE1)
202 Feld[x][y] = EL_BADEWANNE3;
203 else if (y>0 && Feld[x][y-1]==EL_SALZSAEURE)
204 Feld[x][y] = EL_BADEWANNE4;
205 else if (y>0 && Feld[x][y-1]==EL_BADEWANNE2)
206 Feld[x][y] = EL_BADEWANNE5;
245 Feld[x][y] = EL_AMOEBING;
246 Store[x][y] = EL_AMOEBE_NASS;
253 local_player->lights_still_needed++;
255 case EL_SOKOBAN_FELD_LEER:
256 local_player->sokobanfields_still_needed++;
260 local_player->friends_still_needed++;
264 MovDir[x][y] = 1<<RND(4);
271 game_emulation = (emulate_bd ? EMU_BOULDERDASH :
272 emulate_sb ? EMU_SOKOBAN : EMU_NONE);
274 scroll_x = scroll_y = -1;
275 if (local_player->jx >= MIDPOSX-1)
276 scroll_x = (local_player->jx <= lev_fieldx-MIDPOSX ?
277 local_player->jx - MIDPOSX :
278 lev_fieldx - SCR_FIELDX + 1);
279 if (local_player->jy >= MIDPOSY-1)
280 scroll_y = (local_player->jy <= lev_fieldy-MIDPOSY ?
281 local_player->jy - MIDPOSY :
282 lev_fieldy - SCR_FIELDY + 1);
284 CloseDoor(DOOR_CLOSE_1);
290 XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
291 DOOR_GFX_PAGEX5,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
292 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
293 DrawTextExt(pix[PIX_DB_DOOR],gc,
294 DOOR_GFX_PAGEX1+XX_LEVEL,DOOR_GFX_PAGEY1+YY_LEVEL,
295 int2str(level_nr,2),FS_SMALL,FC_YELLOW);
296 DrawTextExt(pix[PIX_DB_DOOR],gc,
297 DOOR_GFX_PAGEX1+XX_EMERALDS,DOOR_GFX_PAGEY1+YY_EMERALDS,
298 int2str(local_player->gems_still_needed,3),FS_SMALL,FC_YELLOW);
299 DrawTextExt(pix[PIX_DB_DOOR],gc,
300 DOOR_GFX_PAGEX1+XX_DYNAMITE,DOOR_GFX_PAGEY1+YY_DYNAMITE,
301 int2str(local_player->dynamite,3),FS_SMALL,FC_YELLOW);
302 DrawTextExt(pix[PIX_DB_DOOR],gc,
303 DOOR_GFX_PAGEX1+XX_SCORE,DOOR_GFX_PAGEY1+YY_SCORE,
304 int2str(local_player->score,5),FS_SMALL,FC_YELLOW);
305 DrawTextExt(pix[PIX_DB_DOOR],gc,
306 DOOR_GFX_PAGEX1+XX_TIME,DOOR_GFX_PAGEY1+YY_TIME,
307 int2str(TimeLeft,3),FS_SMALL,FC_YELLOW);
309 DrawGameButton(BUTTON_GAME_STOP);
310 DrawGameButton(BUTTON_GAME_PAUSE);
311 DrawGameButton(BUTTON_GAME_PLAY);
312 DrawSoundDisplay(BUTTON_SOUND_MUSIC | (BUTTON_ON * sound_music_on));
313 DrawSoundDisplay(BUTTON_SOUND_LOOPS | (BUTTON_ON * sound_loops_on));
314 DrawSoundDisplay(BUTTON_SOUND_SIMPLE | (BUTTON_ON * sound_simple_on));
315 XCopyArea(display,drawto,pix[PIX_DB_DOOR],gc,
316 DX+GAME_CONTROL_XPOS,DY+GAME_CONTROL_YPOS,
317 GAME_CONTROL_XSIZE,2*GAME_CONTROL_YSIZE,
318 DOOR_GFX_PAGEX1+GAME_CONTROL_XPOS,
319 DOOR_GFX_PAGEY1+GAME_CONTROL_YPOS);
321 OpenDoor(DOOR_OPEN_1);
324 PlaySoundLoop(background_loop[level_nr % num_bg_loops]);
326 XAutoRepeatOff(display);
329 void InitMovDir(int x, int y)
331 int i, element = Feld[x][y];
332 static int xy[4][2] =
339 static int direction[2][4] =
341 { MV_RIGHT, MV_UP, MV_LEFT, MV_DOWN },
342 { MV_LEFT, MV_DOWN, MV_RIGHT, MV_UP }
351 Feld[x][y] = EL_KAEFER;
352 MovDir[x][y] = direction[0][element-EL_KAEFER_R];
358 Feld[x][y] = EL_FLIEGER;
359 MovDir[x][y] = direction[0][element-EL_FLIEGER_R];
365 Feld[x][y] = EL_BUTTERFLY;
366 MovDir[x][y] = direction[0][element-EL_BUTTERFLY_R];
372 Feld[x][y] = EL_FIREFLY;
373 MovDir[x][y] = direction[0][element-EL_FIREFLY_R];
379 Feld[x][y] = EL_PACMAN;
380 MovDir[x][y] = direction[0][element-EL_PACMAN_R];
383 MovDir[x][y] = 1<<RND(4);
384 if (element != EL_KAEFER &&
385 element != EL_FLIEGER &&
386 element != EL_BUTTERFLY &&
387 element != EL_FIREFLY)
397 if (!IN_LEV_FIELD(x1,y1) || !IS_FREE(x1,y1))
399 if (element==EL_KAEFER || element==EL_BUTTERFLY)
401 MovDir[x][y] = direction[0][i];
404 else if (element==EL_FLIEGER || element==EL_FIREFLY)
406 MovDir[x][y] = direction[1][i];
415 void InitAmoebaNr(int x, int y)
418 int group_nr = AmoebeNachbarNr(x,y);
422 for(i=1;i<MAX_NUM_AMOEBA;i++)
432 AmoebaNr[x][y] = group_nr;
433 AmoebaCnt[group_nr]++;
434 AmoebaCnt2[group_nr]++;
440 int bumplevel = FALSE;
442 local_player->LevelSolved = FALSE;
447 PlaySoundExt(SND_SIRR, PSND_MAX_VOLUME, PSND_MAX_RIGHT, PSND_LOOP);
452 PlaySoundStereo(SND_SIRR, PSND_MAX_RIGHT);
453 if (TimeLeft && !(TimeLeft % 10))
454 RaiseScore(level.score[SC_ZEITBONUS]);
455 if (TimeLeft > 100 && !(TimeLeft % 10))
459 DrawText(DX_TIME, DY_TIME, int2str(TimeLeft,3), FS_SMALL, FC_YELLOW);
470 /* Hero disappears */
471 DrawLevelField(ExitX, ExitY);
477 CloseDoor(DOOR_CLOSE_1);
482 SaveLevelTape(tape.level_nr); /* Ask to save tape */
485 if (level_nr == local_player->handicap &&
486 level_nr < leveldir[leveldir_nr].levels-1)
488 local_player->handicap++;
490 SavePlayerInfo(PLAYER_LEVEL);
493 if ((hi_pos=NewHiScore()) >= 0)
495 game_status = HALLOFFAME;
496 DrawHallOfFame(hi_pos);
497 if (bumplevel && TAPE_IS_EMPTY(tape))
502 game_status = MAINMENU;
503 if (bumplevel && TAPE_IS_EMPTY(tape))
518 if (!strcmp(local_player->alias_name,EMPTY_ALIAS) ||
519 local_player->score < highscore[MAX_SCORE_ENTRIES-1].Score)
522 for(k=0;k<MAX_SCORE_ENTRIES;k++)
524 if (local_player->score > highscore[k].Score)
526 /* Spieler kommt in Highscore-Liste */
528 if (k<MAX_SCORE_ENTRIES-1)
530 int m = MAX_SCORE_ENTRIES-1;
533 for(l=k;l<MAX_SCORE_ENTRIES;l++)
534 if (!strcmp(local_player->alias_name,highscore[l].Name))
536 if (m==k) /* Spieler überschreibt seine alte Position */
542 strcpy(highscore[l].Name,highscore[l-1].Name);
543 highscore[l].Score = highscore[l-1].Score;
550 sprintf(highscore[k].Name,local_player->alias_name);
551 highscore[k].Score = local_player->score;
557 else if (!strcmp(local_player->alias_name,highscore[k].Name))
558 break; /* Spieler schon mit besserer Punktzahl in der Liste */
569 void InitMovingField(int x, int y, int direction)
571 int newx = x + (direction==MV_LEFT ? -1 : direction==MV_RIGHT ? +1 : 0);
572 int newy = y + (direction==MV_UP ? -1 : direction==MV_DOWN ? +1 : 0);
574 MovDir[x][y] = direction;
575 MovDir[newx][newy] = direction;
576 if (Feld[newx][newy] == EL_LEERRAUM)
577 Feld[newx][newy] = EL_BLOCKED;
580 void Moving2Blocked(int x, int y, int *goes_to_x, int *goes_to_y)
582 int direction = MovDir[x][y];
583 int newx = x + (direction==MV_LEFT ? -1 : direction==MV_RIGHT ? +1 : 0);
584 int newy = y + (direction==MV_UP ? -1 : direction==MV_DOWN ? +1 : 0);
590 void Blocked2Moving(int x, int y, int *comes_from_x, int *comes_from_y)
592 int oldx = x, oldy = y;
593 int direction = MovDir[x][y];
595 if (direction==MV_LEFT)
597 else if (direction==MV_RIGHT)
599 else if (direction==MV_UP)
601 else if (direction==MV_DOWN)
604 *comes_from_x = oldx;
605 *comes_from_y = oldy;
608 int MovingOrBlocked2Element(int x, int y)
610 int element = Feld[x][y];
612 if (element==EL_BLOCKED)
616 Blocked2Moving(x,y,&oldx,&oldy);
617 return(Feld[oldx][oldy]);
623 static void RemoveField(int x, int y)
625 Feld[x][y] = EL_LEERRAUM;
631 void RemoveMovingField(int x, int y)
633 int oldx = x,oldy = y, newx = x,newy = y;
635 if (Feld[x][y] != EL_BLOCKED && !IS_MOVING(x,y))
640 Moving2Blocked(x,y,&newx,&newy);
641 if (Feld[newx][newy] != EL_BLOCKED)
644 else if (Feld[x][y]==EL_BLOCKED)
646 Blocked2Moving(x,y,&oldx,&oldy);
647 if (!IS_MOVING(oldx,oldy))
651 if (Feld[x][y]==EL_BLOCKED &&
652 (Store[oldx][oldy]==EL_MORAST_LEER ||
653 Store[oldx][oldy]==EL_SIEB_LEER ||
654 Store[oldx][oldy]==EL_SIEB2_LEER ||
655 Store[oldx][oldy]==EL_AMOEBE_NASS))
657 Feld[oldx][oldy] = Store[oldx][oldy];
658 Store[oldx][oldy] = Store2[oldx][oldy] = 0;
661 Feld[oldx][oldy] = EL_LEERRAUM;
663 Feld[newx][newy] = EL_LEERRAUM;
664 MovPos[oldx][oldy] = MovDir[oldx][oldy] = MovDelay[oldx][oldy] = 0;
665 MovPos[newx][newy] = MovDir[newx][newy] = MovDelay[newx][newy] = 0;
667 DrawLevelField(oldx,oldy);
668 DrawLevelField(newx,newy);
671 void DrawDynamite(int x, int y)
673 int sx = SCREENX(x), sy = SCREENY(y);
674 int graphic = el2gfx(Feld[x][y]);
677 if (!IN_SCR_FIELD(sx,sy) || IS_PLAYER(x,y))
681 DrawGraphic(sx,sy, el2gfx(Store[x][y]));
683 if (Feld[x][y]==EL_DYNAMIT)
685 if ((phase = (96-MovDelay[x][y])/12) > 6)
690 if ((phase = ((96-MovDelay[x][y])/6) % 8) > 3)
695 DrawGraphicThruMask(sx,sy, graphic + phase);
697 DrawGraphic(sx,sy, graphic + phase);
700 void CheckDynamite(int x, int y)
702 if (MovDelay[x][y]) /* neues Dynamit / in Wartezustand */
707 if (!(MovDelay[x][y] % 12))
708 PlaySoundLevel(x,y,SND_ZISCH);
710 if (Feld[x][y]==EL_DYNAMIT && !(MovDelay[x][y] % 12))
712 else if (Feld[x][y]==EL_DYNABOMB && !(MovDelay[x][y] % 6))
719 StopSound(SND_ZISCH);
723 void Explode(int ex, int ey, int phase, int mode)
726 int num_phase = 9, delay = 2;
727 int last_phase = num_phase*delay;
728 int half_phase = (num_phase/2)*delay;
730 if (phase==0) /* Feld 'Store' initialisieren */
732 int center_element = Feld[ex][ey];
734 if (IS_MOVING(ex,ey) || IS_BLOCKED(ex,ey))
736 center_element = MovingOrBlocked2Element(ex,ey);
737 RemoveMovingField(ex,ey);
740 for(y=ey-1;y<ey+2;y++) for(x=ex-1;x<ex+2;x++)
742 int element = Feld[x][y];
744 if (IS_MOVING(x,y) || IS_BLOCKED(x,y))
746 element = MovingOrBlocked2Element(x,y);
747 RemoveMovingField(x,y);
750 if (!IN_LEV_FIELD(x,y) || IS_MASSIV(element) || element==EL_BURNING)
753 if ((mode!=EX_NORMAL || center_element==EL_AMOEBA2DIAM) &&
757 if (element==EL_EXPLODING)
758 element = Store2[x][y];
760 if (IS_PLAYER(ex,ey))
762 switch(StorePlayer[ex][ey])
765 Store[x][y] = EL_EDELSTEIN_ROT;
768 Store[x][y] = EL_EDELSTEIN;
771 Store[x][y] = EL_EDELSTEIN_LILA;
775 Store[x][y] = EL_EDELSTEIN_GELB;
779 else if (center_element==EL_MAULWURF)
780 Store[x][y] = EL_EDELSTEIN_ROT;
781 else if (center_element==EL_PINGUIN)
782 Store[x][y] = EL_EDELSTEIN_LILA;
783 else if (center_element==EL_KAEFER)
784 Store[x][y] = ((x==ex && y==ey) ? EL_DIAMANT : EL_EDELSTEIN);
785 else if (center_element==EL_BUTTERFLY)
786 Store[x][y] = EL_EDELSTEIN_BD;
787 else if (center_element==EL_MAMPFER)
788 Store[x][y] = level.mampfer_inhalt[MampferNr][x-ex+1][y-ey+1];
789 else if (center_element==EL_AMOEBA2DIAM)
790 Store[x][y] = level.amoebe_inhalt;
791 else if (element==EL_ERZ_EDEL)
792 Store[x][y] = EL_EDELSTEIN;
793 else if (element==EL_ERZ_DIAM)
794 Store[x][y] = EL_DIAMANT;
795 else if (element==EL_ERZ_EDEL_BD)
796 Store[x][y] = EL_EDELSTEIN_BD;
797 else if (element==EL_ERZ_EDEL_GELB)
798 Store[x][y] = EL_EDELSTEIN_GELB;
799 else if (element==EL_ERZ_EDEL_ROT)
800 Store[x][y] = EL_EDELSTEIN_ROT;
801 else if (element==EL_ERZ_EDEL_LILA)
802 Store[x][y] = EL_EDELSTEIN_LILA;
803 else if (!IS_PFORTE(Store[x][y]))
804 Store[x][y] = EL_LEERRAUM;
806 if (x!=ex || y!=ey || center_element==EL_AMOEBA2DIAM || mode==EX_BORDER)
807 Store2[x][y] = element;
809 if (AmoebaNr[x][y] &&
810 (element==EL_AMOEBE_VOLL ||
811 element==EL_AMOEBE_BD ||
812 element==EL_AMOEBING))
814 AmoebaCnt[AmoebaNr[x][y]]--;
815 AmoebaCnt2[AmoebaNr[x][y]]--;
818 Feld[x][y] = EL_EXPLODING;
819 MovDir[x][y] = MovPos[x][y] = 0;
825 if (center_element==EL_MAMPFER)
826 MampferNr = (MampferNr+1) % 4;
837 Frame[x][y] = (phase<last_phase ? phase+1 : 0);
839 if (phase==half_phase)
841 int element = Store2[x][y];
844 KillHero(PLAYERINFO(x,y));
845 else if (IS_EXPLOSIVE(element))
847 Feld[x][y] = Store2[x][y];
851 else if (element==EL_AMOEBA2DIAM)
852 AmoebeUmwandeln(x,y);
855 if (phase==last_phase)
859 element = Feld[x][y] = Store[x][y];
860 Store[x][y] = Store2[x][y] = 0;
861 MovDir[x][y] = MovPos[x][y] = MovDelay[x][y] = 0;
862 if (CAN_MOVE(element) || COULD_MOVE(element))
866 else if (!(phase%delay) && IN_SCR_FIELD(SCREENX(x),SCREENY(y)))
869 ErdreichAnbroeckeln(SCREENX(x),SCREENY(y));
871 DrawGraphic(SCREENX(x),SCREENY(y),GFX_EXPLOSION+(phase/delay-1));
875 void DynaExplode(int ex, int ey)
878 struct PlayerInfo *player = &stored_player[Store2[ex][ey] - EL_SPIELER1];
879 static int xy[4][2] =
887 Store2[ex][ey] = 0; /* delete player information */
889 Explode(ex,ey,0,EX_CENTER);
893 for(j=1; j<=player->dynabomb_size; j++)
895 int x = ex+j*xy[i%4][0];
896 int y = ey+j*xy[i%4][1];
899 if (!IN_LEV_FIELD(x,y) || IS_MASSIV(Feld[x][y]))
902 element = Feld[x][y];
903 Explode(x,y,0,EX_BORDER);
905 if (element != EL_LEERRAUM &&
906 element != EL_ERDREICH &&
907 element != EL_EXPLODING &&
908 !player->dynabomb_xl)
913 player->dynabombs_left++;
916 void Bang(int x, int y)
918 int element = Feld[x][y];
920 PlaySoundLevel(x,y,SND_ROAAAR);
932 RaiseScoreElement(element);
933 Explode(x,y,0,EX_NORMAL);
943 Explode(x,y,0,EX_CENTER);
946 Explode(x,y,0,EX_NORMAL);
951 void Blurb(int x, int y)
953 int element = Feld[x][y];
955 if (element!=EL_BLURB_LEFT && element!=EL_BLURB_RIGHT) /* Anfang */
957 PlaySoundLevel(x,y,SND_BLURB);
958 if (IN_LEV_FIELD(x-1,y) && IS_FREE(x-1,y) &&
959 (!IN_LEV_FIELD(x-1,y-1) ||
960 !CAN_FALL(MovingOrBlocked2Element(x-1,y-1))))
962 Feld[x-1][y] = EL_BLURB_LEFT;
964 if (IN_LEV_FIELD(x+1,y) && IS_FREE(x+1,y) &&
965 (!IN_LEV_FIELD(x+1,y-1) ||
966 !CAN_FALL(MovingOrBlocked2Element(x+1,y-1))))
968 Feld[x+1][y] = EL_BLURB_RIGHT;
973 int graphic = (element==EL_BLURB_LEFT ? GFX_BLURB_LEFT : GFX_BLURB_RIGHT);
975 if (!MovDelay[x][y]) /* neue Phase / noch nicht gewartet */
978 if (MovDelay[x][y]) /* neue Phase / in Wartezustand */
981 if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x),SCREENY(y)))
982 DrawGraphic(SCREENX(x),SCREENY(y),graphic+4-MovDelay[x][y]/2);
986 Feld[x][y] = EL_LEERRAUM;
993 void Impact(int x, int y)
995 BOOL lastline = (y==lev_fieldy-1);
996 BOOL object_hit = FALSE;
997 int element = Feld[x][y];
1000 /* Element darunter berührt? */
1003 if (Feld[x][y+1] == EL_PLAYER_IS_LEAVING)
1006 object_hit = (!IS_FREE(x,y+1) && (!IS_MOVING(x,y+1) ||
1007 MovDir[x][y+1]!=MV_DOWN ||
1008 MovPos[x][y+1]<=TILEY/2));
1010 smashed = MovingOrBlocked2Element(x,y+1);
1013 /* Auftreffendes Element fällt in Salzsäure */
1014 if (!lastline && smashed==EL_SALZSAEURE)
1020 /* Auftreffendes Element ist Bombe */
1021 if (element==EL_BOMBE && (lastline || object_hit))
1027 /* Auftreffendes Element ist Säuretropfen */
1028 if (element==EL_TROPFEN && (lastline || object_hit))
1030 if (object_hit && IS_PLAYER(x,y+1))
1031 KillHero(PLAYERINFO(x,y+1));
1032 else if (object_hit && (smashed==EL_MAULWURF || smashed==EL_PINGUIN))
1036 Feld[x][y] = EL_AMOEBING;
1037 Store[x][y] = EL_AMOEBE_NASS;
1042 /* Welches Element kriegt was auf die Rübe? */
1043 if (!lastline && object_hit)
1045 if (CAN_CHANGE(element) &&
1046 (smashed==EL_SIEB_LEER || smashed==EL_SIEB2_LEER) && !SiebAktiv)
1047 SiebAktiv = level.dauer_sieb * FRAMES_PER_SECOND;
1049 if (IS_PLAYER(x,y+1))
1051 KillHero(PLAYERINFO(x,y+1));
1054 else if (smashed==EL_MAULWURF || smashed==EL_PINGUIN)
1059 else if (element==EL_EDELSTEIN_BD)
1061 if (IS_ENEMY(smashed) && IS_BD_ELEMENT(smashed))
1067 else if (element==EL_FELSBROCKEN)
1069 if (IS_ENEMY(smashed) || smashed==EL_BOMBE || smashed==EL_SONDE ||
1070 smashed==EL_SCHWEIN || smashed==EL_DRACHE)
1075 else if (!IS_MOVING(x,y+1))
1077 if (smashed==EL_BIRNE_AUS || smashed==EL_BIRNE_EIN)
1082 else if (smashed==EL_KOKOSNUSS)
1084 Feld[x][y+1] = EL_CRACKINGNUT;
1085 PlaySoundLevel(x,y,SND_KNACK);
1086 RaiseScoreElement(EL_KOKOSNUSS);
1089 else if (smashed==EL_DIAMANT)
1091 Feld[x][y+1] = EL_LEERRAUM;
1092 PlaySoundLevel(x,y,SND_QUIRK);
1099 /* Geräusch beim Durchqueren des Siebes */
1100 if (!lastline && (Feld[x][y+1]==EL_SIEB_LEER || Feld[x][y+1]==EL_SIEB2_LEER))
1102 PlaySoundLevel(x,y,SND_QUIRK);
1106 /* Geräusch beim Auftreffen */
1107 if (lastline || object_hit)
1114 case EL_EDELSTEIN_BD:
1115 case EL_EDELSTEIN_GELB:
1116 case EL_EDELSTEIN_ROT:
1117 case EL_EDELSTEIN_LILA:
1124 case EL_FELSBROCKEN:
1128 case EL_SCHLUESSEL1:
1129 case EL_SCHLUESSEL2:
1130 case EL_SCHLUESSEL3:
1131 case EL_SCHLUESSEL4:
1144 PlaySoundLevel(x,y,sound);
1148 void TurnRound(int x, int y)
1160 { 0,0 }, { 0,0 }, { 0,0 },
1165 int left,right,back;
1169 { MV_DOWN, MV_UP, MV_RIGHT },
1170 { MV_UP, MV_DOWN, MV_LEFT },
1172 { MV_LEFT, MV_RIGHT, MV_DOWN },
1173 { 0,0,0 }, { 0,0,0 }, { 0,0,0 },
1174 { MV_RIGHT, MV_LEFT, MV_UP }
1177 int element = Feld[x][y];
1178 int old_move_dir = MovDir[x][y];
1179 int left_dir = turn[old_move_dir].left;
1180 int right_dir = turn[old_move_dir].right;
1181 int back_dir = turn[old_move_dir].back;
1183 int left_dx = move_xy[left_dir].x, left_dy = move_xy[left_dir].y;
1184 int right_dx = move_xy[right_dir].x, right_dy = move_xy[right_dir].y;
1185 int move_dx = move_xy[old_move_dir].x, move_dy = move_xy[old_move_dir].y;
1186 int back_dx = move_xy[back_dir].x, back_dy = move_xy[back_dir].y;
1188 int left_x = x+left_dx, left_y = y+left_dy;
1189 int right_x = x+right_dx, right_y = y+right_dy;
1190 int move_x = x+move_dx, move_y = y+move_dy;
1192 if (element==EL_KAEFER || element==EL_BUTTERFLY)
1194 TestIfBadThingHitsOtherBadThing(x,y);
1196 if (IN_LEV_FIELD(right_x,right_y) &&
1197 IS_FREE_OR_PLAYER(right_x,right_y))
1198 MovDir[x][y] = right_dir;
1199 else if (!IN_LEV_FIELD(move_x,move_y) ||
1200 !IS_FREE_OR_PLAYER(move_x,move_y))
1201 MovDir[x][y] = left_dir;
1203 if (element==EL_KAEFER && MovDir[x][y] != old_move_dir)
1205 else if (element==EL_BUTTERFLY) /* && MovDir[x][y]==left_dir) */
1208 else if (element==EL_FLIEGER || element==EL_FIREFLY)
1210 TestIfBadThingHitsOtherBadThing(x,y);
1212 if (IN_LEV_FIELD(left_x,left_y) &&
1213 IS_FREE_OR_PLAYER(left_x,left_y))
1214 MovDir[x][y] = left_dir;
1215 else if (!IN_LEV_FIELD(move_x,move_y) ||
1216 !IS_FREE_OR_PLAYER(move_x,move_y))
1217 MovDir[x][y] = right_dir;
1219 if (element==EL_FLIEGER && MovDir[x][y] != old_move_dir)
1221 else if (element==EL_FIREFLY) /* && MovDir[x][y]==right_dir) */
1224 else if (element==EL_MAMPFER)
1226 BOOL can_turn_left = FALSE, can_turn_right = FALSE;
1228 if (IN_LEV_FIELD(left_x,left_y) &&
1229 (IS_FREE_OR_PLAYER(left_x,left_y) ||
1230 Feld[left_x][left_y] == EL_DIAMANT))
1231 can_turn_left = TRUE;
1232 if (IN_LEV_FIELD(right_x,right_y) &&
1233 (IS_FREE_OR_PLAYER(right_x,right_y) ||
1234 Feld[right_x][right_y] == EL_DIAMANT))
1235 can_turn_right = TRUE;
1237 if (can_turn_left && can_turn_right)
1238 MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
1239 else if (can_turn_left)
1240 MovDir[x][y] = (RND(2) ? left_dir : back_dir);
1241 else if (can_turn_right)
1242 MovDir[x][y] = (RND(2) ? right_dir : back_dir);
1244 MovDir[x][y] = back_dir;
1246 MovDelay[x][y] = 16+16*RND(3);
1248 else if (element==EL_MAMPFER2)
1250 BOOL can_turn_left = FALSE, can_turn_right = FALSE;
1252 if (IN_LEV_FIELD(left_x,left_y) &&
1253 (IS_FREE_OR_PLAYER(left_x,left_y) ||
1254 IS_MAMPF2(Feld[left_x][left_y])))
1255 can_turn_left = TRUE;
1256 if (IN_LEV_FIELD(right_x,right_y) &&
1257 (IS_FREE_OR_PLAYER(right_x,right_y) ||
1258 IS_MAMPF2(Feld[right_x][right_y])))
1259 can_turn_right = TRUE;
1261 if (can_turn_left && can_turn_right)
1262 MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
1263 else if (can_turn_left)
1264 MovDir[x][y] = (RND(2) ? left_dir : back_dir);
1265 else if (can_turn_right)
1266 MovDir[x][y] = (RND(2) ? right_dir : back_dir);
1268 MovDir[x][y] = back_dir;
1270 MovDelay[x][y] = 16+16*RND(3);
1272 else if (element==EL_PACMAN)
1274 BOOL can_turn_left = FALSE, can_turn_right = FALSE;
1276 if (IN_LEV_FIELD(left_x,left_y) &&
1277 (IS_FREE_OR_PLAYER(left_x,left_y) ||
1278 IS_AMOEBOID(Feld[left_x][left_y])))
1279 can_turn_left = TRUE;
1280 if (IN_LEV_FIELD(right_x,right_y) &&
1281 (IS_FREE_OR_PLAYER(right_x,right_y) ||
1282 IS_AMOEBOID(Feld[right_x][right_y])))
1283 can_turn_right = TRUE;
1285 if (can_turn_left && can_turn_right)
1286 MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
1287 else if (can_turn_left)
1288 MovDir[x][y] = (RND(2) ? left_dir : back_dir);
1289 else if (can_turn_right)
1290 MovDir[x][y] = (RND(2) ? right_dir : back_dir);
1292 MovDir[x][y] = back_dir;
1294 MovDelay[x][y] = 6+RND(40);
1296 else if (element==EL_SCHWEIN)
1298 BOOL can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE;
1299 BOOL should_turn_left = FALSE, should_turn_right = FALSE;
1300 BOOL should_move_on = FALSE;
1302 int rnd = RND(rnd_value);
1304 if (IN_LEV_FIELD(left_x,left_y) &&
1305 (IS_FREE(left_x,left_y) || IS_GEM(Feld[left_x][left_y])))
1306 can_turn_left = TRUE;
1307 if (IN_LEV_FIELD(right_x,right_y) &&
1308 (IS_FREE(right_x,right_y) || IS_GEM(Feld[right_x][right_y])))
1309 can_turn_right = TRUE;
1310 if (IN_LEV_FIELD(move_x,move_y) &&
1311 (IS_FREE(move_x,move_y) || IS_GEM(Feld[move_x][move_y])))
1314 if (can_turn_left &&
1316 (IN_LEV_FIELD(x+back_dx+left_dx,y+back_dy+left_dy) &&
1317 !IS_FREE(x+back_dx+left_dx,y+back_dy+left_dy))))
1318 should_turn_left = TRUE;
1319 if (can_turn_right &&
1321 (IN_LEV_FIELD(x+back_dx+right_dx,y+back_dy+right_dy) &&
1322 !IS_FREE(x+back_dx+right_dx,y+back_dy+right_dy))))
1323 should_turn_right = TRUE;
1325 (!can_turn_left || !can_turn_right ||
1326 (IN_LEV_FIELD(x+move_dx+left_dx,y+move_dy+left_dy) &&
1327 !IS_FREE(x+move_dx+left_dx,y+move_dy+left_dy)) ||
1328 (IN_LEV_FIELD(x+move_dx+right_dx,y+move_dy+right_dy) &&
1329 !IS_FREE(x+move_dx+right_dx,y+move_dy+right_dy))))
1330 should_move_on = TRUE;
1332 if (should_turn_left || should_turn_right || should_move_on)
1334 if (should_turn_left && should_turn_right && should_move_on)
1335 MovDir[x][y] = (rnd < rnd_value/3 ? left_dir :
1336 rnd < 2*rnd_value/3 ? right_dir :
1338 else if (should_turn_left && should_turn_right)
1339 MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
1340 else if (should_turn_left && should_move_on)
1341 MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : old_move_dir);
1342 else if (should_turn_right && should_move_on)
1343 MovDir[x][y] = (rnd < rnd_value/2 ? right_dir : old_move_dir);
1344 else if (should_turn_left)
1345 MovDir[x][y] = left_dir;
1346 else if (should_turn_right)
1347 MovDir[x][y] = right_dir;
1348 else if (should_move_on)
1349 MovDir[x][y] = old_move_dir;
1351 else if (can_move_on && rnd > rnd_value/8)
1352 MovDir[x][y] = old_move_dir;
1353 else if (can_turn_left && can_turn_right)
1354 MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
1355 else if (can_turn_left && rnd > rnd_value/8)
1356 MovDir[x][y] = left_dir;
1357 else if (can_turn_right && rnd > rnd_value/8)
1358 MovDir[x][y] = right_dir;
1360 MovDir[x][y] = back_dir;
1362 if (!IS_FREE(x+move_xy[MovDir[x][y]].x,y+move_xy[MovDir[x][y]].y) &&
1363 !IS_GEM(Feld[x+move_xy[MovDir[x][y]].x][y+move_xy[MovDir[x][y]].y]))
1364 MovDir[x][y] = old_move_dir;
1368 else if (element==EL_DRACHE)
1370 BOOL can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE;
1372 int rnd = RND(rnd_value);
1374 if (IN_LEV_FIELD(left_x,left_y) && IS_FREE(left_x,left_y))
1375 can_turn_left = TRUE;
1376 if (IN_LEV_FIELD(right_x,right_y) && IS_FREE(right_x,right_y))
1377 can_turn_right = TRUE;
1378 if (IN_LEV_FIELD(move_x,move_y) && IS_FREE(move_x,move_y))
1381 if (can_move_on && rnd > rnd_value/8)
1382 MovDir[x][y] = old_move_dir;
1383 else if (can_turn_left && can_turn_right)
1384 MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
1385 else if (can_turn_left && rnd > rnd_value/8)
1386 MovDir[x][y] = left_dir;
1387 else if (can_turn_right && rnd > rnd_value/8)
1388 MovDir[x][y] = right_dir;
1390 MovDir[x][y] = back_dir;
1392 if (!IS_FREE(x+move_xy[MovDir[x][y]].x,y+move_xy[MovDir[x][y]].y))
1393 MovDir[x][y] = old_move_dir;
1397 else if (element==EL_ROBOT || element==EL_SONDE ||
1398 element==EL_MAULWURF || element==EL_PINGUIN)
1400 int attr_x = -1, attr_y = -1;
1411 for(i=0; i<MAX_PLAYERS; i++)
1413 struct PlayerInfo *player = &stored_player[i];
1414 int jx = player->jx, jy = player->jy;
1416 if (!player->active || player->gone)
1419 if (attr_x == -1 || ABS(jx-x)+ABS(jy-y) < ABS(attr_x-x)+ABS(attr_y-y))
1427 if (element==EL_ROBOT && ZX>=0 && ZY>=0)
1433 if (element==EL_MAULWURF || element==EL_PINGUIN)
1436 static int xy[4][2] =
1446 int ex = x + xy[i%4][0];
1447 int ey = y + xy[i%4][1];
1449 if (IN_LEV_FIELD(ex,ey) && Feld[ex][ey] == EL_AUSGANG_AUF)
1458 MovDir[x][y] = MV_NO_MOVING;
1460 MovDir[x][y] |= (AllPlayersGone ? MV_RIGHT : MV_LEFT);
1462 MovDir[x][y] |= (AllPlayersGone ? MV_LEFT : MV_RIGHT);
1464 MovDir[x][y] |= (AllPlayersGone ? MV_DOWN : MV_UP);
1466 MovDir[x][y] |= (AllPlayersGone ? MV_UP : MV_DOWN);
1468 if (element==EL_ROBOT)
1472 if ((MovDir[x][y]&(MV_LEFT|MV_RIGHT)) && (MovDir[x][y]&(MV_UP|MV_DOWN)))
1473 MovDir[x][y] &= (RND(2) ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
1474 Moving2Blocked(x,y,&newx,&newy);
1476 if (IN_LEV_FIELD(newx,newy) && IS_FREE_OR_PLAYER(newx,newy))
1477 MovDelay[x][y] = 8+8*!RND(3);
1479 MovDelay[x][y] = 16;
1487 if ((MovDir[x][y]&(MV_LEFT|MV_RIGHT)) && (MovDir[x][y]&(MV_UP|MV_DOWN)))
1489 BOOL first_horiz = RND(2);
1490 int new_move_dir = MovDir[x][y];
1493 new_move_dir & (first_horiz ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
1494 Moving2Blocked(x,y,&newx,&newy);
1496 if (IN_LEV_FIELD(newx,newy) &&
1497 (IS_FREE(newx,newy) ||
1498 Feld[newx][newy] == EL_SALZSAEURE ||
1499 ((element == EL_MAULWURF || element==EL_PINGUIN) &&
1500 (Feld[newx][newy] == EL_AUSGANG_AUF ||
1501 IS_MAMPF3(Feld[newx][newy])))))
1505 new_move_dir & (!first_horiz ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
1506 Moving2Blocked(x,y,&newx,&newy);
1508 if (IN_LEV_FIELD(newx,newy) &&
1509 (IS_FREE(newx,newy) ||
1510 Feld[newx][newy] == EL_SALZSAEURE ||
1511 ((element == EL_MAULWURF || element==EL_PINGUIN) &&
1512 (Feld[newx][newy] == EL_AUSGANG_AUF ||
1513 IS_MAMPF3(Feld[newx][newy])))))
1516 MovDir[x][y] = old_move_dir;
1523 static BOOL JustBeingPushed(int x, int y)
1527 for(i=0; i<MAX_PLAYERS; i++)
1529 struct PlayerInfo *player = &stored_player[i];
1531 if (player->active && !player->gone &&
1532 player->Pushing && player->MovPos)
1534 int next_jx = player->jx + (player->jx - player->last_jx);
1535 int next_jy = player->jy + (player->jy - player->last_jy);
1537 if (x == next_jx && y == next_jy)
1545 void StartMoving(int x, int y)
1547 int element = Feld[x][y];
1552 if (CAN_FALL(element) && y<lev_fieldy-1)
1554 if ((x>0 && IS_PLAYER(x-1,y)) || (x<lev_fieldx-1 && IS_PLAYER(x+1,y)))
1555 if (JustBeingPushed(x,y))
1558 if (element==EL_MORAST_VOLL)
1562 InitMovingField(x,y,MV_DOWN);
1563 Feld[x][y] = EL_FELSBROCKEN;
1564 Store[x][y] = EL_MORAST_LEER;
1566 else if (Feld[x][y+1]==EL_MORAST_LEER)
1568 if (!MovDelay[x][y])
1569 MovDelay[x][y] = TILEY + 1;
1578 Feld[x][y] = EL_MORAST_LEER;
1579 Feld[x][y+1] = EL_MORAST_VOLL;
1582 else if (element==EL_FELSBROCKEN && Feld[x][y+1]==EL_MORAST_LEER)
1584 InitMovingField(x,y,MV_DOWN);
1585 Store[x][y] = EL_MORAST_VOLL;
1587 else if (element==EL_SIEB_VOLL)
1591 InitMovingField(x,y,MV_DOWN);
1592 Feld[x][y] = EL_CHANGED(Store2[x][y]);
1593 Store[x][y] = EL_SIEB_LEER;
1595 else if (Feld[x][y+1]==EL_SIEB_LEER)
1597 if (!MovDelay[x][y])
1598 MovDelay[x][y] = TILEY/4 + 1;
1607 Feld[x][y] = EL_SIEB_LEER;
1608 Feld[x][y+1] = EL_SIEB_VOLL;
1609 Store2[x][y+1] = EL_CHANGED(Store2[x][y]);
1613 else if (element==EL_SIEB2_VOLL)
1617 InitMovingField(x,y,MV_DOWN);
1618 Feld[x][y] = EL_CHANGED2(Store2[x][y]);
1619 Store[x][y] = EL_SIEB2_LEER;
1621 else if (Feld[x][y+1]==EL_SIEB2_LEER)
1623 if (!MovDelay[x][y])
1624 MovDelay[x][y] = TILEY/4 + 1;
1633 Feld[x][y] = EL_SIEB2_LEER;
1634 Feld[x][y+1] = EL_SIEB2_VOLL;
1635 Store2[x][y+1] = EL_CHANGED2(Store2[x][y]);
1639 else if (SiebAktiv && CAN_CHANGE(element) &&
1640 (Feld[x][y+1]==EL_SIEB_LEER || Feld[x][y+1]==EL_SIEB2_LEER))
1642 InitMovingField(x,y,MV_DOWN);
1644 (Feld[x][y+1]==EL_SIEB_LEER ? EL_SIEB_VOLL : EL_SIEB2_VOLL);
1645 Store2[x][y+1] = element;
1647 else if (CAN_SMASH(element) && Feld[x][y+1]==EL_SALZSAEURE)
1650 InitMovingField(x,y,MV_DOWN);
1651 Store[x][y] = EL_SALZSAEURE;
1653 else if (CAN_SMASH(element) && Feld[x][y+1]==EL_BLOCKED && JustHit[x][y])
1657 else if (IS_FREE(x,y+1))
1659 InitMovingField(x,y,MV_DOWN);
1661 else if (element==EL_TROPFEN)
1663 Feld[x][y] = EL_AMOEBING;
1664 Store[x][y] = EL_AMOEBE_NASS;
1666 else if (IS_SLIPPERY(Feld[x][y+1]) && !Store[x][y+1])
1668 BOOL left = (x>0 && IS_FREE(x-1,y) &&
1669 (IS_FREE(x-1,y+1) || Feld[x-1][y+1]==EL_SALZSAEURE));
1670 BOOL right = (x<lev_fieldx-1 && IS_FREE(x+1,y) &&
1671 (IS_FREE(x+1,y+1) || Feld[x+1][y+1]==EL_SALZSAEURE));
1675 if (left && right && game_emulation != EMU_BOULDERDASH)
1676 left = !(right = RND(2));
1678 InitMovingField(x,y,left ? MV_LEFT : MV_RIGHT);
1682 else if (CAN_MOVE(element))
1686 if (element == EL_SONDE && JustBeingPushed(x,y))
1689 if (!MovDelay[x][y]) /* neuer Schritt / noch nicht gewartet */
1691 /* Alle Figuren, die nach jeden Schritt die Richtung wechseln können.
1692 * (MAMPFER, MAMPFER2 und PACMAN laufen bis zur nächsten Wand.)
1695 if (element!=EL_MAMPFER && element!=EL_MAMPFER2 && element!=EL_PACMAN)
1698 if (MovDelay[x][y] && (element == EL_KAEFER || element == EL_FLIEGER))
1699 DrawLevelField(x,y);
1703 if (MovDelay[x][y]) /* neuer Schritt / in Wartezustand */
1707 if (element==EL_ROBOT || element==EL_MAMPFER || element==EL_MAMPFER2)
1709 int phase = MovDelay[x][y] % 8;
1714 if (IN_SCR_FIELD(SCREENX(x),SCREENY(y)))
1715 DrawGraphic(SCREENX(x),SCREENY(y), el2gfx(element)+phase);
1717 if ((element==EL_MAMPFER || element==EL_MAMPFER2)
1718 && MovDelay[x][y]%4==3)
1719 PlaySoundLevel(x,y,SND_NJAM);
1721 else if (element==EL_DRACHE)
1724 int dir = MovDir[x][y];
1725 int dx = (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1726 int dy = (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1727 int graphic = (dir == MV_LEFT ? GFX_FLAMMEN_LEFT :
1728 dir == MV_RIGHT ? GFX_FLAMMEN_RIGHT :
1729 dir == MV_UP ? GFX_FLAMMEN_UP :
1730 dir == MV_DOWN ? GFX_FLAMMEN_DOWN : GFX_LEERRAUM);
1731 int phase = FrameCounter % 2;
1735 int xx = x + i*dx, yy = y + i*dy;
1736 int sx = SCREENX(xx), sy = SCREENY(yy);
1738 if (!IN_LEV_FIELD(xx,yy) ||
1739 IS_SOLID(Feld[xx][yy]) || Feld[xx][yy]==EL_EXPLODING)
1744 int flamed = MovingOrBlocked2Element(xx,yy);
1746 if (IS_ENEMY(flamed) || IS_EXPLOSIVE(flamed))
1749 RemoveMovingField(xx,yy);
1751 Feld[xx][yy] = EL_BURNING;
1752 if (IN_SCR_FIELD(sx,sy))
1753 DrawGraphic(sx,sy, graphic + phase*3 + i-1);
1757 if (Feld[xx][yy] == EL_BURNING)
1758 Feld[xx][yy] = EL_LEERRAUM;
1759 DrawLevelField(xx,yy);
1768 if (element==EL_KAEFER || element==EL_BUTTERFLY)
1770 PlaySoundLevel(x,y,SND_KLAPPER);
1772 else if (element==EL_FLIEGER || element==EL_FIREFLY)
1774 PlaySoundLevel(x,y,SND_ROEHR);
1777 /* neuer Schritt / Wartezustand beendet */
1779 Moving2Blocked(x,y,&newx,&newy); /* wohin soll's gehen? */
1781 if (IS_ENEMY(element) && IS_PLAYER(newx,newy))
1783 /* Spieler erwischt */
1785 KillHero(PLAYERINFO(newx,newy));
1788 else if ((element == EL_MAULWURF || element == EL_PINGUIN ||
1789 element==EL_ROBOT || element==EL_SONDE) &&
1790 IN_LEV_FIELD(newx,newy) &&
1791 MovDir[x][y]==MV_DOWN && Feld[newx][newy]==EL_SALZSAEURE)
1794 Store[x][y] = EL_SALZSAEURE;
1796 else if ((element == EL_MAULWURF || element == EL_PINGUIN) &&
1797 IN_LEV_FIELD(newx,newy))
1799 if (Feld[newx][newy] == EL_AUSGANG_AUF)
1801 Feld[x][y] = EL_LEERRAUM;
1802 DrawLevelField(x,y);
1804 PlaySoundLevel(newx,newy,SND_BUING);
1805 if (IN_SCR_FIELD(SCREENX(newx),SCREENY(newy)))
1806 DrawGraphicThruMask(SCREENX(newx),SCREENY(newy),el2gfx(element));
1808 local_player->friends_still_needed--;
1809 if (!local_player->friends_still_needed &&
1810 !local_player->GameOver && AllPlayersGone)
1811 local_player->LevelSolved = local_player->GameOver = TRUE;
1815 else if (IS_MAMPF3(Feld[newx][newy]))
1817 if (DigField(local_player, newx,newy, 0,0, DF_DIG) == MF_MOVING)
1818 DrawLevelField(newx,newy);
1820 MovDir[x][y] = MV_NO_MOVING;
1822 else if (!IS_FREE(newx,newy))
1825 DrawPlayerField(x,y);
1827 DrawLevelField(x,y);
1831 else if (element == EL_SCHWEIN && IN_LEV_FIELD(newx,newy))
1833 if (IS_GEM(Feld[newx][newy]))
1835 if (IS_MOVING(newx,newy))
1836 RemoveMovingField(newx,newy);
1839 Feld[newx][newy] = EL_LEERRAUM;
1840 DrawLevelField(newx,newy);
1843 else if (!IS_FREE(newx,newy))
1846 DrawPlayerField(x,y);
1848 DrawLevelField(x,y);
1852 else if (element==EL_DRACHE && IN_LEV_FIELD(newx,newy))
1854 if (!IS_FREE(newx,newy))
1857 DrawPlayerField(x,y);
1859 DrawLevelField(x,y);
1864 BOOL wanna_flame = !RND(10);
1865 int dx = newx - x, dy = newy - y;
1866 int newx1 = newx+1*dx, newy1 = newy+1*dy;
1867 int newx2 = newx+2*dx, newy2 = newy+2*dy;
1868 int element1 = (IN_LEV_FIELD(newx1,newy1) ?
1869 MovingOrBlocked2Element(newx1,newy1) : EL_BETON);
1870 int element2 = (IN_LEV_FIELD(newx2,newy2) ?
1871 MovingOrBlocked2Element(newx2,newy2) : EL_BETON);
1873 if ((wanna_flame || IS_ENEMY(element1) || IS_ENEMY(element2)) &&
1874 element1 != EL_DRACHE && element2 != EL_DRACHE &&
1875 element1 != EL_BURNING && element2 != EL_BURNING)
1878 DrawPlayerField(x,y);
1880 DrawLevelField(x,y);
1882 MovDelay[x][y] = 50;
1883 Feld[newx][newy] = EL_BURNING;
1884 if (IN_LEV_FIELD(newx1,newy1) && Feld[newx1][newy1] == EL_LEERRAUM)
1885 Feld[newx1][newy1] = EL_BURNING;
1886 if (IN_LEV_FIELD(newx2,newy2) && Feld[newx2][newy2] == EL_LEERRAUM)
1887 Feld[newx2][newy2] = EL_BURNING;
1892 else if (element==EL_MAMPFER && IN_LEV_FIELD(newx,newy) &&
1893 Feld[newx][newy]==EL_DIAMANT)
1895 if (IS_MOVING(newx,newy))
1896 RemoveMovingField(newx,newy);
1899 Feld[newx][newy] = EL_LEERRAUM;
1900 DrawLevelField(newx,newy);
1903 else if (element==EL_MAMPFER2 && IN_LEV_FIELD(newx,newy) &&
1904 IS_MAMPF2(Feld[newx][newy]))
1906 if (AmoebaNr[newx][newy])
1908 AmoebaCnt2[AmoebaNr[newx][newy]]--;
1909 if (Feld[newx][newy]==EL_AMOEBE_VOLL || Feld[newx][newy]==EL_AMOEBE_BD)
1910 AmoebaCnt[AmoebaNr[newx][newy]]--;
1913 if (IS_MOVING(newx,newy))
1914 RemoveMovingField(newx,newy);
1917 Feld[newx][newy] = EL_LEERRAUM;
1918 DrawLevelField(newx,newy);
1921 else if (element==EL_PACMAN && IN_LEV_FIELD(newx,newy) &&
1922 IS_AMOEBOID(Feld[newx][newy]))
1924 if (AmoebaNr[newx][newy])
1926 AmoebaCnt2[AmoebaNr[newx][newy]]--;
1927 if (Feld[newx][newy]==EL_AMOEBE_VOLL || Feld[newx][newy]==EL_AMOEBE_BD)
1928 AmoebaCnt[AmoebaNr[newx][newy]]--;
1931 Feld[newx][newy] = EL_LEERRAUM;
1932 DrawLevelField(newx,newy);
1934 else if (!IN_LEV_FIELD(newx,newy) || !IS_FREE(newx,newy))
1935 { /* gegen Wand gelaufen */
1938 if (element == EL_KAEFER || element == EL_FLIEGER)
1939 DrawLevelField(x,y);
1940 else if (element == EL_BUTTERFLY || element == EL_FIREFLY)
1941 DrawGraphicAnimation(x,y, el2gfx(element), 2, 4, ANIM_NORMAL);
1942 else if (element==EL_SONDE)
1943 DrawGraphicAnimation(x,y, GFX_SONDE_START, 8, 2, ANIM_NORMAL);
1948 if (element==EL_ROBOT && IN_SCR_FIELD(x,y))
1949 PlaySoundLevel(x,y,SND_SCHLURF);
1951 InitMovingField(x,y,MovDir[x][y]);
1955 ContinueMoving(x,y);
1958 void ContinueMoving(int x, int y)
1960 int element = Feld[x][y];
1961 int direction = MovDir[x][y];
1962 int dx = (direction==MV_LEFT ? -1 : direction==MV_RIGHT ? +1 : 0);
1963 int dy = (direction==MV_UP ? -1 : direction==MV_DOWN ? +1 : 0);
1964 int horiz_move = (dx!=0);
1965 int newx = x + dx, newy = y + dy;
1966 int step = (horiz_move ? dx : dy) * TILEX/8;
1968 if (CAN_FALL(element) && horiz_move)
1970 else if (element==EL_TROPFEN)
1972 else if (Store[x][y]==EL_MORAST_VOLL || Store[x][y]==EL_MORAST_LEER)
1975 MovPos[x][y] += step;
1977 if (ABS(MovPos[x][y])>=TILEX) /* Zielfeld erreicht */
1979 Feld[x][y] = EL_LEERRAUM;
1980 Feld[newx][newy] = element;
1982 if (Store[x][y]==EL_MORAST_VOLL)
1985 Feld[newx][newy] = EL_MORAST_VOLL;
1986 element = EL_MORAST_VOLL;
1988 else if (Store[x][y]==EL_MORAST_LEER)
1991 Feld[x][y] = EL_MORAST_LEER;
1993 else if (Store[x][y]==EL_SIEB_VOLL)
1996 element = Feld[newx][newy] = (SiebAktiv ? EL_SIEB_VOLL : EL_SIEB_TOT);
1998 else if (Store[x][y]==EL_SIEB_LEER)
2000 Store[x][y] = Store2[x][y] = 0;
2001 Feld[x][y] = (SiebAktiv ? EL_SIEB_LEER : EL_SIEB_TOT);
2003 else if (Store[x][y]==EL_SIEB2_VOLL)
2006 element = Feld[newx][newy] = (SiebAktiv ? EL_SIEB2_VOLL : EL_SIEB2_TOT);
2008 else if (Store[x][y]==EL_SIEB2_LEER)
2010 Store[x][y] = Store2[x][y] = 0;
2011 Feld[x][y] = (SiebAktiv ? EL_SIEB2_LEER : EL_SIEB2_TOT);
2013 else if (Store[x][y]==EL_SALZSAEURE)
2016 Feld[newx][newy] = EL_SALZSAEURE;
2017 element = EL_SALZSAEURE;
2019 else if (Store[x][y]==EL_AMOEBE_NASS)
2022 Feld[x][y] = EL_AMOEBE_NASS;
2025 MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
2026 MovDelay[newx][newy] = 0;
2028 if (!CAN_MOVE(element))
2029 MovDir[newx][newy] = 0;
2031 DrawLevelField(x,y);
2032 DrawLevelField(newx,newy);
2034 Stop[newx][newy] = TRUE;
2035 JustHit[x][newy] = 3;
2037 if (DONT_TOUCH(element)) /* Käfer oder Flieger */
2039 TestIfBadThingHitsHero(newx,newy);
2040 TestIfBadThingHitsFriend(newx,newy);
2041 TestIfBadThingHitsOtherBadThing(newx,newy);
2043 else if (element == EL_PINGUIN)
2044 TestIfFriendHitsBadThing(newx,newy);
2046 if (CAN_SMASH(element) && direction==MV_DOWN &&
2047 (newy==lev_fieldy-1 || !IS_FREE(x,newy+1)))
2050 else /* noch in Bewegung */
2051 DrawLevelField(x,y);
2054 int AmoebeNachbarNr(int ax, int ay)
2057 int element = Feld[ax][ay];
2059 static int xy[4][2] =
2069 int x = ax+xy[i%4][0];
2070 int y = ay+xy[i%4][1];
2072 if (!IN_LEV_FIELD(x,y))
2075 if (Feld[x][y]==element && AmoebaNr[x][y]>0)
2076 group_nr = AmoebaNr[x][y];
2082 void AmoebenVereinigen(int ax, int ay)
2085 int new_group_nr = AmoebaNr[ax][ay];
2086 static int xy[4][2] =
2102 if (!IN_LEV_FIELD(x,y))
2105 if ((Feld[x][y]==EL_AMOEBE_VOLL ||
2106 Feld[x][y]==EL_AMOEBE_BD ||
2107 Feld[x][y]==EL_AMOEBE_TOT) &&
2108 AmoebaNr[x][y] != new_group_nr)
2110 int old_group_nr = AmoebaNr[x][y];
2112 AmoebaCnt[new_group_nr] += AmoebaCnt[old_group_nr];
2113 AmoebaCnt[old_group_nr] = 0;
2114 AmoebaCnt2[new_group_nr] += AmoebaCnt2[old_group_nr];
2115 AmoebaCnt2[old_group_nr] = 0;
2117 for(yy=0;yy<lev_fieldy;yy++) for(xx=0;xx<lev_fieldx;xx++)
2118 if (AmoebaNr[xx][yy]==old_group_nr)
2119 AmoebaNr[xx][yy] = new_group_nr;
2124 void AmoebeUmwandeln(int ax, int ay)
2127 int group_nr = AmoebaNr[ax][ay];
2128 static int xy[4][2] =
2136 if (Feld[ax][ay]==EL_AMOEBE_TOT)
2138 for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
2140 if (Feld[x][y]==EL_AMOEBE_TOT && AmoebaNr[x][y]==group_nr)
2143 Feld[x][y] = EL_AMOEBA2DIAM;
2155 if (!IN_LEV_FIELD(x,y))
2158 if (Feld[x][y]==EL_AMOEBA2DIAM)
2164 void AmoebeUmwandeln2(int ax, int ay, int new_element)
2167 int group_nr = AmoebaNr[ax][ay];
2170 for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
2172 if (AmoebaNr[x][y]==group_nr &&
2173 (Feld[x][y]==EL_AMOEBE_TOT ||
2174 Feld[x][y]==EL_AMOEBE_BD ||
2175 Feld[x][y]==EL_AMOEBING))
2178 Feld[x][y] = new_element;
2179 DrawLevelField(x,y);
2185 PlaySoundLevel(ax,ay,new_element==EL_FELSBROCKEN ? SND_KLOPF : SND_PLING);
2188 void AmoebeWaechst(int x, int y)
2190 static long sound_delay = 0;
2191 static int sound_delay_value = 0;
2193 if (!MovDelay[x][y]) /* neue Phase / noch nicht gewartet */
2197 if (DelayReached(&sound_delay, sound_delay_value))
2199 PlaySoundLevel(x,y,SND_AMOEBE);
2200 sound_delay_value = 30;
2204 if (MovDelay[x][y]) /* neue Phase / in Wartezustand */
2207 if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x),SCREENY(y)))
2208 DrawGraphic(SCREENX(x),SCREENY(y),GFX_AMOEBING+3-MovDelay[x][y]/2);
2210 if (!MovDelay[x][y])
2212 Feld[x][y] = Store[x][y];
2214 DrawLevelField(x,y);
2219 void AmoebeAbleger(int ax, int ay)
2222 int element = Feld[ax][ay];
2223 int newax = ax, neway = ay;
2224 static int xy[4][2] =
2232 if (!level.tempo_amoebe)
2234 Feld[ax][ay] = EL_AMOEBE_TOT;
2235 DrawLevelField(ax,ay);
2239 if (!MovDelay[ax][ay]) /* neue Amoebe / noch nicht gewartet */
2240 MovDelay[ax][ay] = RND(FRAMES_PER_SECOND * 25/(1+level.tempo_amoebe));
2242 if (MovDelay[ax][ay]) /* neue Amoebe / in Wartezustand */
2245 if (MovDelay[ax][ay])
2249 if (element==EL_AMOEBE_NASS) /* tropfende Amöbe */
2252 int x = ax+xy[start][0];
2253 int y = ay+xy[start][1];
2255 if (!IN_LEV_FIELD(x,y))
2259 Feld[x][y]==EL_ERDREICH || Feld[x][y]==EL_MORAST_LEER)
2265 if (newax==ax && neway==ay)
2268 else /* normale oder "gefüllte" Amöbe */
2271 BOOL waiting_for_player = FALSE;
2275 int j = (start+i)%4;
2276 int x = ax+xy[j][0];
2277 int y = ay+xy[j][1];
2279 if (!IN_LEV_FIELD(x,y))
2283 Feld[x][y]==EL_ERDREICH || Feld[x][y]==EL_MORAST_LEER)
2289 else if (IS_PLAYER(x,y))
2290 waiting_for_player = TRUE;
2293 if (newax==ax && neway==ay)
2295 if (i==4 && !waiting_for_player)
2297 Feld[ax][ay] = EL_AMOEBE_TOT;
2298 DrawLevelField(ax,ay);
2299 AmoebaCnt[AmoebaNr[ax][ay]]--;
2301 if (AmoebaCnt[AmoebaNr[ax][ay]]<=0) /* Amöbe vollständig tot */
2303 if (element==EL_AMOEBE_VOLL)
2304 AmoebeUmwandeln(ax,ay);
2305 else if (element==EL_AMOEBE_BD)
2306 AmoebeUmwandeln2(ax,ay,level.amoebe_inhalt);
2311 else if (element==EL_AMOEBE_VOLL || element==EL_AMOEBE_BD)
2313 int new_group_nr = AmoebaNr[ax][ay];
2315 AmoebaNr[newax][neway] = new_group_nr;
2316 AmoebaCnt[new_group_nr]++;
2317 AmoebaCnt2[new_group_nr]++;
2318 AmoebenVereinigen(newax,neway);
2320 if (AmoebaCnt2[new_group_nr] >= 200 && element==EL_AMOEBE_BD)
2322 AmoebeUmwandeln2(newax,neway,EL_FELSBROCKEN);
2328 if (element!=EL_AMOEBE_NASS || neway<ay || !IS_FREE(newax,neway) ||
2329 (neway==lev_fieldy-1 && newax!=ax))
2331 Feld[newax][neway] = EL_AMOEBING;
2332 Store[newax][neway] = element;
2335 Feld[newax][neway] = EL_TROPFEN;
2338 InitMovingField(ax,ay,MV_DOWN);
2339 Feld[ax][ay] = EL_TROPFEN;
2340 Store[ax][ay] = EL_AMOEBE_NASS;
2341 ContinueMoving(ax,ay);
2345 DrawLevelField(newax,neway);
2348 void Life(int ax, int ay)
2351 static int life[4] = { 2,3,3,3 }; /* "Life"-Parameter */
2353 int element = Feld[ax][ay];
2358 if (!MovDelay[ax][ay]) /* neue Phase / noch nicht gewartet */
2359 MovDelay[ax][ay] = life_time;
2361 if (MovDelay[ax][ay]) /* neue Phase / in Wartezustand */
2364 if (MovDelay[ax][ay])
2368 for(y1=-1;y1<2;y1++) for(x1=-1;x1<2;x1++)
2370 int xx = ax+x1, yy = ay+y1;
2373 if (!IN_LEV_FIELD(xx,yy))
2376 for(y2=-1;y2<2;y2++) for(x2=-1;x2<2;x2++)
2378 int x = xx+x2, y = yy+y2;
2380 if (!IN_LEV_FIELD(x,y) || (x==xx && y==yy))
2383 if (((Feld[x][y]==element || (element==EL_LIFE && IS_PLAYER(x,y))) &&
2385 (IS_FREE(x,y) && Stop[x][y]))
2389 if (xx==ax && yy==ay) /* mittleres Feld mit Amoebe */
2391 if (nachbarn<life[0] || nachbarn>life[1])
2393 Feld[xx][yy] = EL_LEERRAUM;
2395 DrawLevelField(xx,yy);
2396 Stop[xx][yy] = TRUE;
2399 else if (IS_FREE(xx,yy) || Feld[xx][yy]==EL_ERDREICH)
2400 { /* Randfeld ohne Amoebe */
2401 if (nachbarn>=life[2] && nachbarn<=life[3])
2403 Feld[xx][yy] = element;
2404 MovDelay[xx][yy] = (element==EL_LIFE ? 0 : life_time-1);
2406 DrawLevelField(xx,yy);
2407 Stop[xx][yy] = TRUE;
2413 void Ablenk(int x, int y)
2415 if (!MovDelay[x][y]) /* neue Phase / noch nicht gewartet */
2416 MovDelay[x][y] = level.dauer_ablenk * FRAMES_PER_SECOND;
2418 if (MovDelay[x][y]) /* neue Phase / in Wartezustand */
2423 if (IN_SCR_FIELD(SCREENX(x),SCREENY(y)))
2424 DrawGraphic(SCREENX(x),SCREENY(y),GFX_ABLENK+MovDelay[x][y]%4);
2425 if (!(MovDelay[x][y]%4))
2426 PlaySoundLevel(x,y,SND_MIEP);
2431 Feld[x][y] = EL_ABLENK_AUS;
2432 DrawLevelField(x,y);
2437 void Birne(int x, int y)
2439 if (!MovDelay[x][y]) /* neue Phase / noch nicht gewartet */
2440 MovDelay[x][y] = 800;
2442 if (MovDelay[x][y]) /* neue Phase / in Wartezustand */
2447 if (!(MovDelay[x][y]%5))
2449 if (!(MovDelay[x][y]%10))
2450 Feld[x][y]=EL_ABLENK_EIN;
2452 Feld[x][y]=EL_ABLENK_AUS;
2453 DrawLevelField(x,y);
2454 Feld[x][y]=EL_ABLENK_EIN;
2460 Feld[x][y]=EL_ABLENK_AUS;
2461 DrawLevelField(x,y);
2466 void Blubber(int x, int y)
2468 if (y > 0 && IS_MOVING(x,y-1) && MovDir[x][y-1] == MV_DOWN)
2469 DrawLevelField(x,y-1);
2471 DrawGraphicAnimation(x,y, GFX_GEBLUBBER, 4, 10, ANIM_NORMAL);
2474 void NussKnacken(int x, int y)
2476 if (!MovDelay[x][y]) /* neue Phase / noch nicht gewartet */
2479 if (MovDelay[x][y]) /* neue Phase / in Wartezustand */
2482 if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x),SCREENY(y)))
2483 DrawGraphic(SCREENX(x),SCREENY(y),GFX_CRACKINGNUT+3-MovDelay[x][y]/2);
2485 if (!MovDelay[x][y])
2487 Feld[x][y] = EL_EDELSTEIN;
2488 DrawLevelField(x,y);
2493 void SiebAktivieren(int x, int y, int typ)
2495 if (!(SiebAktiv % 4) && IN_SCR_FIELD(SCREENX(x),SCREENY(y)))
2496 DrawGraphic(SCREENX(x),SCREENY(y),
2497 (typ==1 ? GFX_SIEB_VOLL : GFX_SIEB2_VOLL)+3-(SiebAktiv%16)/4);
2500 void AusgangstuerPruefen(int x, int y)
2502 if (!local_player->gems_still_needed &&
2503 !local_player->sokobanfields_still_needed &&
2504 !local_player->lights_still_needed)
2506 Feld[x][y] = EL_AUSGANG_ACT;
2508 PlaySoundLevel(x < LEVELX(BX1) ? LEVELX(BX1) :
2509 (x > LEVELX(BX2) ? LEVELX(BX2) : x),
2510 y < LEVELY(BY1) ? LEVELY(BY1) :
2511 (y > LEVELY(BY2) ? LEVELY(BY2) : y),
2516 void AusgangstuerOeffnen(int x, int y)
2520 if (!MovDelay[x][y]) /* neue Phase / noch nicht gewartet */
2521 MovDelay[x][y] = 5*delay;
2523 if (MovDelay[x][y]) /* neue Phase / in Wartezustand */
2528 tuer = MovDelay[x][y]/delay;
2529 if (!(MovDelay[x][y]%delay) && IN_SCR_FIELD(SCREENX(x),SCREENY(y)))
2530 DrawGraphic(SCREENX(x),SCREENY(y),GFX_AUSGANG_AUF-tuer);
2532 if (!MovDelay[x][y])
2534 Feld[x][y] = EL_AUSGANG_AUF;
2535 DrawLevelField(x,y);
2540 void AusgangstuerBlinken(int x, int y)
2542 DrawGraphicAnimation(x,y, GFX_AUSGANG_AUF, 4, 4, ANIM_OSCILLATE);
2545 void EdelsteinFunkeln(int x, int y)
2547 if (!IN_SCR_FIELD(SCREENX(x),SCREENY(y)) || IS_MOVING(x,y))
2550 if (Feld[x][y] == EL_EDELSTEIN_BD)
2551 DrawGraphicAnimation(x,y, GFX_EDELSTEIN_BD, 4, 4, ANIM_REVERSE);
2554 if (!MovDelay[x][y]) /* neue Phase / noch nicht gewartet */
2555 MovDelay[x][y] = 11 * !SimpleRND(500);
2557 if (MovDelay[x][y]) /* neue Phase / in Wartezustand */
2561 if (direct_draw_on && MovDelay[x][y])
2562 SetDrawtoField(DRAW_BUFFERED);
2564 DrawGraphic(SCREENX(x),SCREENY(y), el2gfx(Feld[x][y]));
2568 int phase = (MovDelay[x][y]-1)/2;
2573 DrawGraphicThruMask(SCREENX(x),SCREENY(y), GFX_FUNKELN_WEISS + phase);
2579 dest_x = FX + SCREENX(x)*TILEX;
2580 dest_y = FY + SCREENY(y)*TILEY;
2582 XCopyArea(display,drawto_field,window,gc,
2583 dest_x,dest_y, TILEX,TILEY, dest_x,dest_y);
2584 SetDrawtoField(DRAW_DIRECT);
2591 void MauerWaechst(int x, int y)
2595 if (!MovDelay[x][y]) /* neue Phase / noch nicht gewartet */
2596 MovDelay[x][y] = 3*delay;
2598 if (MovDelay[x][y]) /* neue Phase / in Wartezustand */
2603 phase = 2-MovDelay[x][y]/delay;
2604 if (!(MovDelay[x][y]%delay) && IN_SCR_FIELD(SCREENX(x),SCREENY(y)))
2605 DrawGraphic(SCREENX(x),SCREENY(y),
2606 (MovDir[x][y] == MV_LEFT ? GFX_MAUER_LEFT :
2607 MovDir[x][y] == MV_RIGHT ? GFX_MAUER_RIGHT :
2608 MovDir[x][y] == MV_UP ? GFX_MAUER_UP :
2609 GFX_MAUER_DOWN ) + phase);
2611 if (!MovDelay[x][y])
2613 if (MovDir[x][y] == MV_LEFT)
2615 if (IN_LEV_FIELD(x-1,y) && IS_MAUER(Feld[x-1][y]))
2616 DrawLevelField(x-1,y);
2618 else if (MovDir[x][y] == MV_RIGHT)
2620 if (IN_LEV_FIELD(x+1,y) && IS_MAUER(Feld[x+1][y]))
2621 DrawLevelField(x+1,y);
2623 else if (MovDir[x][y] == MV_UP)
2625 if (IN_LEV_FIELD(x,y-1) && IS_MAUER(Feld[x][y-1]))
2626 DrawLevelField(x,y-1);
2630 if (IN_LEV_FIELD(x,y+1) && IS_MAUER(Feld[x][y+1]))
2631 DrawLevelField(x,y+1);
2634 Feld[x][y] = Store[x][y];
2636 MovDir[x][y] = MV_NO_MOVING;
2637 DrawLevelField(x,y);
2642 void MauerAbleger(int ax, int ay)
2644 int element = Feld[ax][ay];
2645 BOOL oben_frei = FALSE, unten_frei = FALSE;
2646 BOOL links_frei = FALSE, rechts_frei = FALSE;
2647 BOOL oben_massiv = FALSE, unten_massiv = FALSE;
2648 BOOL links_massiv = FALSE, rechts_massiv = FALSE;
2650 if (!MovDelay[ax][ay]) /* neue Mauer / noch nicht gewartet */
2651 MovDelay[ax][ay] = 6;
2653 if (MovDelay[ax][ay]) /* neue Mauer / in Wartezustand */
2656 if (MovDelay[ax][ay])
2660 if (IN_LEV_FIELD(ax,ay-1) && IS_FREE(ax,ay-1))
2662 if (IN_LEV_FIELD(ax,ay+1) && IS_FREE(ax,ay+1))
2664 if (IN_LEV_FIELD(ax-1,ay) && IS_FREE(ax-1,ay))
2666 if (IN_LEV_FIELD(ax+1,ay) && IS_FREE(ax+1,ay))
2669 if (element == EL_MAUER_Y || element == EL_MAUER_XY)
2673 Feld[ax][ay-1] = EL_MAUERND;
2674 Store[ax][ay-1] = element;
2675 MovDir[ax][ay-1] = MV_UP;
2676 if (IN_SCR_FIELD(SCREENX(ax),SCREENY(ay-1)))
2677 DrawGraphic(SCREENX(ax),SCREENY(ay-1),GFX_MAUER_UP);
2681 Feld[ax][ay+1] = EL_MAUERND;
2682 Store[ax][ay+1] = element;
2683 MovDir[ax][ay+1] = MV_DOWN;
2684 if (IN_SCR_FIELD(SCREENX(ax),SCREENY(ay+1)))
2685 DrawGraphic(SCREENX(ax),SCREENY(ay+1),GFX_MAUER_DOWN);
2689 if (element == EL_MAUER_X || element == EL_MAUER_XY ||
2690 element == EL_MAUER_LEBT)
2694 Feld[ax-1][ay] = EL_MAUERND;
2695 Store[ax-1][ay] = element;
2696 MovDir[ax-1][ay] = MV_LEFT;
2697 if (IN_SCR_FIELD(SCREENX(ax-1),SCREENY(ay)))
2698 DrawGraphic(SCREENX(ax-1),SCREENY(ay),GFX_MAUER_LEFT);
2702 Feld[ax+1][ay] = EL_MAUERND;
2703 Store[ax+1][ay] = element;
2704 MovDir[ax+1][ay] = MV_RIGHT;
2705 if (IN_SCR_FIELD(SCREENX(ax+1),SCREENY(ay)))
2706 DrawGraphic(SCREENX(ax+1),SCREENY(ay),GFX_MAUER_RIGHT);
2710 if (element == EL_MAUER_LEBT && (links_frei || rechts_frei))
2711 DrawLevelField(ax,ay);
2713 if (!IN_LEV_FIELD(ax,ay-1) || IS_MAUER(Feld[ax][ay-1]))
2715 if (!IN_LEV_FIELD(ax,ay+1) || IS_MAUER(Feld[ax][ay+1]))
2716 unten_massiv = TRUE;
2717 if (!IN_LEV_FIELD(ax-1,ay) || IS_MAUER(Feld[ax-1][ay]))
2718 links_massiv = TRUE;
2719 if (!IN_LEV_FIELD(ax+1,ay) || IS_MAUER(Feld[ax+1][ay]))
2720 rechts_massiv = TRUE;
2722 if (((oben_massiv && unten_massiv) ||
2723 element == EL_MAUER_X || element == EL_MAUER_LEBT) &&
2724 ((links_massiv && rechts_massiv) ||
2725 element == EL_MAUER_Y))
2726 Feld[ax][ay] = EL_MAUERWERK;
2729 void CheckForDragon(int x, int y)
2732 BOOL dragon_found = FALSE;
2733 static int xy[4][2] =
2745 int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
2747 if (IN_LEV_FIELD(xx,yy) &&
2748 (Feld[xx][yy] == EL_BURNING || Feld[xx][yy] == EL_DRACHE))
2750 if (Feld[xx][yy] == EL_DRACHE)
2751 dragon_found = TRUE;
2764 int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
2766 if (IN_LEV_FIELD(xx,yy) && Feld[xx][yy] == EL_BURNING)
2768 Feld[xx][yy] = EL_LEERRAUM;
2769 DrawLevelField(xx,yy);
2778 void PlayerActions(struct PlayerInfo *player, byte player_action)
2780 static byte stored_player_action[MAX_PLAYERS];
2781 static int num_stored_actions = 0;
2782 BOOL moved = FALSE, snapped = FALSE, bombed = FALSE;
2783 int jx = player->jx, jy = player->jy;
2784 int left = player_action & JOY_LEFT;
2785 int right = player_action & JOY_RIGHT;
2786 int up = player_action & JOY_UP;
2787 int down = player_action & JOY_DOWN;
2788 int button1 = player_action & JOY_BUTTON_1;
2789 int button2 = player_action & JOY_BUTTON_2;
2790 int dx = (left ? -1 : right ? 1 : 0);
2791 int dy = (up ? -1 : down ? 1 : 0);
2793 stored_player_action[player->index_nr] = 0;
2794 num_stored_actions++;
2796 if (!player->active || player->gone)
2801 player->frame_reset_delay = 0;
2804 snapped = SnapField(player, dx,dy);
2808 bombed = PlaceBomb(player);
2809 moved = MoveFigure(player, dx,dy);
2812 if (tape.recording && (moved || snapped || bombed))
2814 if (bombed && !moved)
2815 player_action &= JOY_BUTTON;
2817 stored_player_action[player->index_nr] = player_action;
2819 /* this allows cycled sequences of PlayerActions() */
2820 if (num_stored_actions >= MAX_PLAYERS)
2822 TapeRecordAction(stored_player_action);
2823 num_stored_actions = 0;
2826 else if (tape.playing && snapped)
2827 SnapField(player, 0,0); /* stop snapping */
2831 DigField(player, 0,0, 0,0, DF_NO_PUSH);
2832 SnapField(player, 0,0);
2833 if (++player->frame_reset_delay > MoveSpeed)
2837 if (tape.playing && !tape.pausing && !player_action &&
2838 tape.counter < tape.length)
2841 tape.pos[tape.counter].action[player->index_nr] & (JOY_LEFT|JOY_RIGHT);
2843 if (next_joy == JOY_LEFT || next_joy == JOY_RIGHT)
2845 int dx = (next_joy == JOY_LEFT ? -1 : +1);
2847 if (IN_LEV_FIELD(jx+dx,jy) && IS_PUSHABLE(Feld[jx+dx][jy]))
2849 int el = Feld[jx+dx][jy];
2850 int push_delay = (IS_SB_ELEMENT(el) || el==EL_SONDE ? 2 : 10);
2852 if (tape.delay_played + push_delay >= tape.pos[tape.counter].delay)
2854 player->MovDir = next_joy;
2855 player->Frame = FrameCounter % 4;
2856 player->Pushing = TRUE;
2863 void GameActions(byte player_action)
2865 static long action_delay = 0;
2866 long action_delay_value;
2867 int sieb_x = 0, sieb_y = 0;
2868 int i, x,y, element;
2869 int *recorded_player_action;
2871 if (game_status != PLAYING)
2875 action_delay_value =
2876 (tape.playing && tape.fast_forward ? FFWD_FRAME_DELAY : GameFrameDelay);
2878 action_delay_value =
2879 (tape.playing && tape.fast_forward ? FFWD_FRAME_DELAY : GAME_FRAME_DELAY);
2882 /* main game synchronization point */
2883 WaitUntilDelayReached(&action_delay, action_delay_value);
2885 if (network_playing && !network_player_action_received)
2889 printf("DEBUG: try to get network player actions in time\n");
2893 /* last chance to get network player actions without main loop delay */
2896 if (game_status != PLAYING)
2899 if (!network_player_action_received)
2903 printf("DEBUG: failed to get network player actions in time\n");
2911 if (tape.pausing || (tape.playing && !TapePlayDelay()))
2913 else if (tape.recording)
2918 recorded_player_action = TapePlayAction();
2920 recorded_player_action = NULL;
2922 if (network_playing)
2923 SendToServer_MovePlayer(player_action);
2925 for(i=0; i<MAX_PLAYERS; i++)
2928 int actual_player_action =
2929 (network ? network_player_action[i] : player_action);
2932 int actual_player_action =
2933 (network_playing ? network_player_action[i] : player_action);
2936 int actual_player_action = network_player_action[i];
2940 int actual_player_action = player_action;
2943 /* TEST TEST TEST */
2946 if (i != TestPlayer && !stored_player[i].MovPos)
2947 actual_player_action = 0;
2950 if (!network && i != TestPlayer)
2951 actual_player_action = 0;
2953 /* TEST TEST TEST */
2955 if (recorded_player_action)
2956 actual_player_action = recorded_player_action[i];
2958 PlayerActions(&stored_player[i], actual_player_action);
2959 ScrollFigure(&stored_player[i], SCROLL_GO_ON);
2961 network_player_action[i] = 0;
2964 network_player_action_received = FALSE;
2966 ScrollScreen(NULL, SCROLL_GO_ON);
2969 if (tape.pausing || (tape.playing && !TapePlayDelay()))
2971 else if (tape.recording)
2980 printf("FrameCounter == %d, RND(100) == %d\n", FrameCounter, RND(100));
2984 for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
2987 if (JustHit[x][y]>0)
2991 if (IS_BLOCKED(x,y))
2995 Blocked2Moving(x,y,&oldx,&oldy);
2996 if (!IS_MOVING(oldx,oldy))
2998 printf("GameActions(): (BLOCKED=>MOVING) context corrupted!\n");
2999 printf("GameActions(): BLOCKED: x = %d, y = %d\n",x,y);
3000 printf("GameActions(): !MOVING: oldx = %d, oldy = %d\n",oldx,oldy);
3001 printf("GameActions(): This should never happen!\n");
3007 for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
3009 element = Feld[x][y];
3011 if (IS_INACTIVE(element))
3014 if (!IS_MOVING(x,y) && (CAN_FALL(element) || CAN_MOVE(element)))
3018 if (IS_GEM(element))
3019 EdelsteinFunkeln(x,y);
3021 else if (IS_MOVING(x,y))
3022 ContinueMoving(x,y);
3023 else if (element==EL_DYNAMIT || element==EL_DYNABOMB)
3025 else if (element==EL_EXPLODING)
3026 Explode(x,y,Frame[x][y],EX_NORMAL);
3027 else if (element==EL_AMOEBING)
3029 else if (IS_AMOEBALIVE(element))
3031 else if (element==EL_LIFE || element==EL_LIFE_ASYNC)
3033 else if (element==EL_ABLENK_EIN)
3035 else if (element==EL_SALZSAEURE)
3037 else if (element==EL_BLURB_LEFT || element==EL_BLURB_RIGHT)
3039 else if (element==EL_CRACKINGNUT)
3041 else if (element==EL_AUSGANG_ZU)
3042 AusgangstuerPruefen(x,y);
3043 else if (element==EL_AUSGANG_ACT)
3044 AusgangstuerOeffnen(x,y);
3045 else if (element==EL_AUSGANG_AUF)
3046 AusgangstuerBlinken(x,y);
3047 else if (element==EL_MAUERND)
3049 else if (element==EL_MAUER_LEBT ||
3050 element==EL_MAUER_X ||
3051 element==EL_MAUER_Y ||
3052 element==EL_MAUER_XY)
3054 else if (element==EL_BURNING)
3055 CheckForDragon(x,y);
3060 int jx = local_player->jx, jy = local_player->jy;
3062 if (element==EL_SIEB_LEER || element==EL_SIEB_VOLL ||
3063 Store[x][y]==EL_SIEB_LEER)
3065 SiebAktivieren(x, y, 1);
3068 else if (element==EL_SIEB2_LEER || element==EL_SIEB2_VOLL ||
3069 Store[x][y]==EL_SIEB2_LEER)
3071 SiebAktivieren(x, y, 2);
3075 /* play the element sound at the position nearest to the player */
3076 if (sieb && ABS(x-jx)+ABS(y-jy) < ABS(sieb_x-jx)+ABS(sieb_y-jy))
3087 PlaySoundLevel(sieb_x,sieb_y,SND_MIEP);
3091 for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
3093 element = Feld[x][y];
3094 if (element==EL_SIEB_LEER || element==EL_SIEB_VOLL)
3096 Feld[x][y] = EL_SIEB_TOT;
3097 DrawLevelField(x,y);
3099 else if (element==EL_SIEB2_LEER || element==EL_SIEB2_VOLL)
3101 Feld[x][y] = EL_SIEB2_TOT;
3102 DrawLevelField(x,y);
3108 if (TimeLeft>0 && TimeFrames>=(1000/GameFrameDelay) && !tape.pausing)
3113 if (tape.recording || tape.playing)
3114 DrawVideoDisplay(VIDEO_STATE_TIME_ON,level.time-TimeLeft);
3117 PlaySoundStereo(SND_GONG,PSND_MAX_RIGHT);
3119 DrawText(DX_TIME,DY_TIME,int2str(TimeLeft,3),FS_SMALL,FC_YELLOW);
3122 for(i=0; i<MAX_PLAYERS; i++)
3123 KillHero(&stored_player[i]);
3129 static BOOL AllPlayersInSight(struct PlayerInfo *player, int x, int y)
3131 int min_x = x, min_y = y, max_x = x, max_y = y;
3134 for(i=0; i<MAX_PLAYERS; i++)
3136 int jx = stored_player[i].jx, jy = stored_player[i].jy;
3138 if (!stored_player[i].active || stored_player[i].gone ||
3139 &stored_player[i] == player)
3142 min_x = MIN(min_x, jx);
3143 min_y = MIN(min_y, jy);
3144 max_x = MAX(max_x, jx);
3145 max_y = MAX(max_y, jy);
3148 return(max_x - min_x < SCR_FIELDX && max_y - min_y < SCR_FIELDY);
3151 static BOOL AllPlayersInVisibleScreen()
3155 for(i=0; i<MAX_PLAYERS; i++)
3157 int jx = stored_player[i].jx, jy = stored_player[i].jy;
3159 if (!stored_player[i].active || stored_player[i].gone)
3162 if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
3169 void ScrollLevel(int dx, int dy)
3171 int softscroll_offset = (soft_scrolling_on ? TILEX : 0);
3175 ScreenGfxPos = local_player->GfxPos;
3178 XCopyArea(display,drawto_field,drawto_field,gc,
3179 FX + TILEX*(dx==-1) - softscroll_offset,
3180 FY + TILEY*(dy==-1) - softscroll_offset,
3181 SXSIZE - TILEX*(dx!=0) + 2*softscroll_offset,
3182 SYSIZE - TILEY*(dy!=0) + 2*softscroll_offset,
3183 FX + TILEX*(dx==1) - softscroll_offset,
3184 FY + TILEY*(dy==1) - softscroll_offset);
3188 x = (dx==1 ? BX1 : BX2);
3189 for(y=BY1; y<=BY2; y++)
3190 DrawScreenField(x,y);
3194 y = (dy==1 ? BY1 : BY2);
3195 for(x=BX1; x<=BX2; x++)
3196 DrawScreenField(x,y);
3199 redraw_mask |= REDRAW_FIELD;
3202 BOOL MoveFigureOneStep(struct PlayerInfo *player,
3203 int dx, int dy, int real_dx, int real_dy)
3205 int jx = player->jx, jy = player->jy;
3206 int new_jx = jx+dx, new_jy = jy+dy;
3210 if (player->gone || (!dx && !dy))
3211 return(MF_NO_ACTION);
3213 player->MovDir = (dx < 0 ? MV_LEFT :
3216 dy > 0 ? MV_DOWN : MV_NO_MOVING);
3218 if (!IN_LEV_FIELD(new_jx,new_jy))
3219 return(MF_NO_ACTION);
3221 if (!network && !AllPlayersInSight(player, new_jx,new_jy))
3222 return(MF_NO_ACTION);
3224 element = MovingOrBlocked2Element(new_jx,new_jy);
3226 if (DONT_GO_TO(element))
3228 if (element==EL_SALZSAEURE && dx==0 && dy==1)
3231 Feld[jx][jy] = EL_SPIELFIGUR;
3232 InitMovingField(jx,jy,MV_DOWN);
3233 Store[jx][jy] = EL_SALZSAEURE;
3234 ContinueMoving(jx,jy);
3243 can_move = DigField(player, new_jx,new_jy, real_dx,real_dy, DF_DIG);
3244 if (can_move != MF_MOVING)
3247 StorePlayer[jx][jy] = 0;
3248 player->last_jx = jx;
3249 player->last_jy = jy;
3250 jx = player->jx = new_jx;
3251 jy = player->jy = new_jy;
3252 StorePlayer[jx][jy] = player->element_nr;
3254 player->MovPos = (dx > 0 || dy > 0 ? -1 : 1) * 7*TILEX/8;
3256 ScrollFigure(player, SCROLL_INIT);
3261 BOOL MoveFigure(struct PlayerInfo *player, int dx, int dy)
3263 int jx = player->jx, jy = player->jy;
3264 int old_jx = jx, old_jy = jy;
3265 int moved = MF_NO_ACTION;
3267 if (player->gone || (!dx && !dy))
3270 if (!FrameReached(&player->move_delay,MoveSpeed) && !tape.playing)
3273 if (player->last_move_dir & (MV_LEFT | MV_RIGHT))
3275 if (!(moved |= MoveFigureOneStep(player, 0,dy, dx,dy)))
3276 moved |= MoveFigureOneStep(player, dx,0, dx,dy);
3280 if (!(moved |= MoveFigureOneStep(player, dx,0, dx,dy)))
3281 moved |= MoveFigureOneStep(player, 0,dy, dx,dy);
3290 if (moved & MF_MOVING && player == local_player)
3293 if (moved & MF_MOVING && !ScreenMovPos &&
3294 (player == local_player || !network))
3296 int old_scroll_x = scroll_x, old_scroll_y = scroll_y;
3297 int offset = (scroll_delay_on ? 3 : 0);
3300 if (player == local_player)
3302 printf("MOVING LOCAL PLAYER && SCROLLING\n");
3306 if (!IN_VIS_FIELD(SCREENX(jx),SCREENY(jy)))
3308 /* actual player has left the screen -- scroll in that direction */
3309 if (jx != old_jx) /* player has moved horizontally */
3310 scroll_x += (jx - old_jx);
3311 else /* player has moved vertically */
3312 scroll_y += (jy - old_jy);
3316 if (jx != old_jx) /* player has moved horizontally */
3318 if ((scroll_x < jx-MIDPOSX-offset || scroll_x > jx-MIDPOSX+offset) &&
3319 jx >= MIDPOSX-1-offset && jx <= lev_fieldx-(MIDPOSX-offset))
3320 scroll_x = jx-MIDPOSX + (scroll_x < jx-MIDPOSX ? -offset : offset);
3322 /* don't scroll more than one field at a time */
3323 scroll_x = old_scroll_x + SIGN(scroll_x - old_scroll_x);
3325 /* don't scroll against the player's moving direction */
3326 if ((player->MovDir == MV_LEFT && scroll_x > old_scroll_x) ||
3327 (player->MovDir == MV_RIGHT && scroll_x < old_scroll_x))
3328 scroll_x = old_scroll_x;
3330 else /* player has moved vertically */
3332 if ((scroll_y < jy-MIDPOSY-offset || scroll_y > jy-MIDPOSY+offset) &&
3333 jy >= MIDPOSY-1-offset && jy <= lev_fieldy-(MIDPOSY-offset))
3334 scroll_y = jy-MIDPOSY + (scroll_y < jy-MIDPOSY ? -offset : offset);
3336 /* don't scroll more than one field at a time */
3337 scroll_y = old_scroll_y + SIGN(scroll_y - old_scroll_y);
3339 /* don't scroll against the player's moving direction */
3340 if ((player->MovDir == MV_UP && scroll_y > old_scroll_y) ||
3341 (player->MovDir == MV_DOWN && scroll_y < old_scroll_y))
3342 scroll_y = old_scroll_y;
3347 if (player == local_player)
3349 if ((scroll_x < jx-MIDPOSX-offset || scroll_x > jx-MIDPOSX+offset) &&
3350 jx >= MIDPOSX-1-offset && jx <= lev_fieldx-(MIDPOSX-offset))
3351 scroll_x = jx-MIDPOSX + (scroll_x < jx-MIDPOSX ? -offset : offset);
3352 if ((scroll_y < jy-MIDPOSY-offset || scroll_y > jy-MIDPOSY+offset) &&
3353 jy >= MIDPOSY-1-offset && jy <= lev_fieldy-(MIDPOSY-offset))
3354 scroll_y = jy-MIDPOSY + (scroll_y < jy-MIDPOSY ? -offset : offset);
3356 /* don't scroll more than one field at a time */
3357 scroll_x = old_scroll_x + SIGN(scroll_x - old_scroll_x);
3358 scroll_y = old_scroll_y + SIGN(scroll_y - old_scroll_y);
3362 if (scroll_x != old_scroll_x || scroll_y != old_scroll_y)
3364 if (!network && !AllPlayersInVisibleScreen())
3366 scroll_x = old_scroll_x;
3367 scroll_y = old_scroll_y;
3371 ScrollScreen(player, SCROLL_INIT);
3372 ScrollLevel(old_scroll_x - scroll_x, old_scroll_y - scroll_y);
3377 if (!(moved & MF_MOVING) && !player->Pushing)
3380 player->Frame = (player->Frame + 1) % 4;
3382 if (moved & MF_MOVING)
3384 if (old_jx != jx && old_jy == jy)
3385 player->MovDir = (old_jx < jx ? MV_RIGHT : MV_LEFT);
3386 else if (old_jx == jx && old_jy != jy)
3387 player->MovDir = (old_jy < jy ? MV_DOWN : MV_UP);
3389 DrawLevelField(jx,jy); /* für "ErdreichAnbroeckeln()" */
3391 player->last_move_dir = player->MovDir;
3394 player->last_move_dir = MV_NO_MOVING;
3396 TestIfHeroHitsBadThing(jx,jy);
3404 void ScrollFigure(struct PlayerInfo *player, int mode)
3406 int jx = player->jx, jy = player->jy;
3407 int last_jx = player->last_jx, last_jy = player->last_jy;
3409 if (!player->active || player->gone || !player->MovPos)
3412 if (mode == SCROLL_INIT)
3414 player->actual_frame_counter = FrameCounter;
3415 player->GfxPos = ScrollStepSize * (player->MovPos / ScrollStepSize);
3417 if (Feld[last_jx][last_jy] == EL_LEERRAUM)
3418 Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING;
3423 else if (!FrameReached(&player->actual_frame_counter,1))
3426 player->MovPos += (player->MovPos > 0 ? -1 : 1) * TILEX/8;
3427 player->GfxPos = ScrollStepSize * (player->MovPos / ScrollStepSize);
3429 if (Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING)
3430 Feld[last_jx][last_jy] = EL_LEERRAUM;
3434 if (!player->MovPos)
3436 player->last_jx = jx;
3437 player->last_jy = jy;
3439 if (Feld[jx][jy] == EL_AUSGANG_AUF)
3443 if (!local_player->friends_still_needed)
3444 player->LevelSolved = player->GameOver = TRUE;
3449 void ScrollScreen(struct PlayerInfo *player, int mode)
3451 static long screen_frame_counter = 0;
3453 if (mode == SCROLL_INIT)
3455 screen_frame_counter = FrameCounter;
3456 ScreenMovDir = player->MovDir;
3457 ScreenMovPos = player->MovPos;
3458 ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
3461 else if (!FrameReached(&screen_frame_counter,1))
3466 ScreenMovPos += (ScreenMovPos > 0 ? -1 : 1) * TILEX/8;
3467 ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
3468 redraw_mask |= REDRAW_FIELD;
3471 ScreenMovDir = MV_NO_MOVING;
3474 void TestIfGoodThingHitsBadThing(int goodx, int goody)
3476 int i, killx = goodx, killy = goody;
3477 static int xy[4][2] =
3484 static int harmless[4] =
3496 x = goodx + xy[i][0];
3497 y = goody + xy[i][1];
3498 if (!IN_LEV_FIELD(x,y))
3501 element = Feld[x][y];
3503 if (DONT_TOUCH(element))
3505 if (MovDir[x][y] == harmless[i])
3514 if (killx != goodx || killy != goody)
3516 if (IS_PLAYER(goodx,goody))
3517 KillHero(PLAYERINFO(goodx,goody));
3523 void TestIfBadThingHitsGoodThing(int badx, int bady)
3525 int i, killx = badx, killy = bady;
3526 static int xy[4][2] =
3533 static int harmless[4] =
3545 x = badx + xy[i][0];
3546 y = bady + xy[i][1];
3547 if (!IN_LEV_FIELD(x,y))
3550 element = Feld[x][y];
3558 else if (element == EL_PINGUIN)
3560 if (MovDir[x][y] == harmless[i] && IS_MOVING(x,y))
3569 if (killx != badx || killy != bady)
3571 if (IS_PLAYER(killx,killy))
3572 KillHero(PLAYERINFO(killx,killy));
3578 void TestIfHeroHitsBadThing(int x, int y)
3580 TestIfGoodThingHitsBadThing(x,y);
3583 void TestIfBadThingHitsHero(int x, int y)
3586 TestIfGoodThingHitsBadThing(JX,JY);
3589 TestIfBadThingHitsGoodThing(x,y);
3592 void TestIfFriendHitsBadThing(int x, int y)
3594 TestIfGoodThingHitsBadThing(x,y);
3597 void TestIfBadThingHitsFriend(int x, int y)
3599 TestIfBadThingHitsGoodThing(x,y);
3602 void TestIfBadThingHitsOtherBadThing(int badx, int bady)
3604 int i, killx = badx, killy = bady;
3605 static int xy[4][2] =
3619 if (!IN_LEV_FIELD(x,y))
3622 element = Feld[x][y];
3623 if (IS_AMOEBOID(element) || element == EL_LIFE ||
3624 element == EL_AMOEBING || element == EL_TROPFEN)
3632 if (killx != badx || killy != bady)
3636 void KillHero(struct PlayerInfo *player)
3638 int jx = player->jx, jy = player->jy;
3643 if (IS_PFORTE(Feld[jx][jy]))
3644 Feld[jx][jy] = EL_LEERRAUM;
3650 void BuryHero(struct PlayerInfo *player)
3652 int jx = player->jx, jy = player->jy;
3657 PlaySoundLevel(jx,jy, SND_AUTSCH);
3658 PlaySoundLevel(jx,jy, SND_LACHEN);
3660 player->GameOver = TRUE;
3664 void RemoveHero(struct PlayerInfo *player)
3666 int jx = player->jx, jy = player->jy;
3667 int i, found = FALSE;
3669 player->gone = TRUE;
3670 StorePlayer[jx][jy] = 0;
3672 for(i=0; i<MAX_PLAYERS; i++)
3673 if (stored_player[i].active && !stored_player[i].gone)
3677 AllPlayersGone = TRUE;
3683 int DigField(struct PlayerInfo *player,
3684 int x, int y, int real_dx, int real_dy, int mode)
3686 int jx = player->jx, jy = player->jy;
3687 int dx = x - jx, dy = y - jy;
3690 if (!player->MovPos)
3691 player->Pushing = FALSE;
3693 if (mode == DF_NO_PUSH)
3695 player->push_delay = 0;
3696 return(MF_NO_ACTION);
3699 if (IS_MOVING(x,y) || IS_PLAYER(x,y))
3700 return(MF_NO_ACTION);
3702 element = Feld[x][y];
3710 Feld[x][y] = EL_LEERRAUM;
3714 case EL_EDELSTEIN_BD:
3715 case EL_EDELSTEIN_GELB:
3716 case EL_EDELSTEIN_ROT:
3717 case EL_EDELSTEIN_LILA:
3720 local_player->gems_still_needed -= (element == EL_DIAMANT ? 3 : 1);
3721 if (local_player->gems_still_needed < 0)
3722 local_player->gems_still_needed = 0;
3723 RaiseScoreElement(element);
3724 DrawText(DX_EMERALDS, DY_EMERALDS,
3725 int2str(local_player->gems_still_needed, 3),
3726 FS_SMALL, FC_YELLOW);
3727 PlaySoundLevel(x, y, SND_PONG);
3730 case EL_DYNAMIT_AUS:
3733 RaiseScoreElement(EL_DYNAMIT);
3734 DrawText(DX_DYNAMITE, DY_DYNAMITE,
3735 int2str(local_player->dynamite, 3),
3736 FS_SMALL, FC_YELLOW);
3737 PlaySoundLevel(x,y,SND_PONG);
3740 case EL_DYNABOMB_NR:
3742 player->dynabomb_count++;
3743 player->dynabombs_left++;
3744 RaiseScoreElement(EL_DYNAMIT);
3745 PlaySoundLevel(x,y,SND_PONG);
3748 case EL_DYNABOMB_SZ:
3750 player->dynabomb_size++;
3751 RaiseScoreElement(EL_DYNAMIT);
3752 PlaySoundLevel(x,y,SND_PONG);
3755 case EL_DYNABOMB_XL:
3757 player->dynabomb_xl = TRUE;
3758 RaiseScoreElement(EL_DYNAMIT);
3759 PlaySoundLevel(x,y,SND_PONG);
3762 case EL_SCHLUESSEL1:
3763 case EL_SCHLUESSEL2:
3764 case EL_SCHLUESSEL3:
3765 case EL_SCHLUESSEL4:
3767 int key_nr = element-EL_SCHLUESSEL1;
3770 player->key[key_nr] = TRUE;
3771 RaiseScoreElement(EL_SCHLUESSEL);
3772 DrawMiniGraphicExt(drawto,gc,
3773 DX_KEYS+key_nr*MINI_TILEX,DY_KEYS,
3774 GFX_SCHLUESSEL1+key_nr);
3775 DrawMiniGraphicExt(window,gc,
3776 DX_KEYS+key_nr*MINI_TILEX,DY_KEYS,
3777 GFX_SCHLUESSEL1+key_nr);
3778 PlaySoundLevel(x,y,SND_PONG);
3783 Feld[x][y] = EL_ABLENK_EIN;
3786 DrawLevelField(x,y);
3790 case EL_FELSBROCKEN:
3794 if (dy || mode==DF_SNAP)
3795 return(MF_NO_ACTION);
3797 player->Pushing = TRUE;
3799 if (!IN_LEV_FIELD(x+dx,y+dy) || !IS_FREE(x+dx,y+dy))
3800 return(MF_NO_ACTION);
3804 if (IN_LEV_FIELD(jx,jy+real_dy) && !IS_SOLID(Feld[jx][jy+real_dy]))
3805 return(MF_NO_ACTION);
3808 if (player->push_delay == 0)
3809 player->push_delay = FrameCounter;
3810 if (!FrameReached(&player->push_delay, player->push_delay_value) &&
3812 return(MF_NO_ACTION);
3815 Feld[x+dx][y+dy] = element;
3817 player->push_delay_value = 2+RND(8);
3819 DrawLevelField(x+dx,y+dy);
3820 if (element==EL_FELSBROCKEN)
3821 PlaySoundLevel(x+dx,y+dy,SND_PUSCH);
3822 else if (element==EL_KOKOSNUSS)
3823 PlaySoundLevel(x+dx,y+dy,SND_KNURK);
3825 PlaySoundLevel(x+dx,y+dy,SND_KLOPF);
3832 if (!player->key[element-EL_PFORTE1])
3833 return(MF_NO_ACTION);
3840 if (!player->key[element-EL_PFORTE1X])
3841 return(MF_NO_ACTION);
3845 case EL_AUSGANG_ACT:
3846 /* Tür ist (noch) nicht offen! */
3847 return(MF_NO_ACTION);
3850 case EL_AUSGANG_AUF:
3852 return(MF_NO_ACTION);
3854 PlaySoundLevel(x,y,SND_BUING);
3857 player->gone = TRUE;
3858 PlaySoundLevel(x,y,SND_BUING);
3860 if (!local_player->friends_still_needed)
3861 player->LevelSolved = player->GameOver = TRUE;
3867 Feld[x][y] = EL_BIRNE_EIN;
3868 local_player->lights_still_needed--;
3869 DrawLevelField(x,y);
3870 PlaySoundLevel(x,y,SND_DENG);
3875 Feld[x][y] = EL_ZEIT_LEER;
3877 DrawText(DX_TIME,DY_TIME,int2str(TimeLeft,3),FS_SMALL,FC_YELLOW);
3878 DrawLevelField(x,y);
3879 PlaySoundStereo(SND_GONG,PSND_MAX_RIGHT);
3883 case EL_SOKOBAN_FELD_LEER:
3886 case EL_SOKOBAN_FELD_VOLL:
3887 case EL_SOKOBAN_OBJEKT:
3890 return(MF_NO_ACTION);
3892 player->Pushing = TRUE;
3894 if (!IN_LEV_FIELD(x+dx,y+dy)
3895 || (!IS_FREE(x+dx,y+dy)
3896 && (Feld[x+dx][y+dy] != EL_SOKOBAN_FELD_LEER
3897 || !IS_SB_ELEMENT(element))))
3898 return(MF_NO_ACTION);
3902 if (IN_LEV_FIELD(jx,jy+real_dy) && !IS_SOLID(Feld[jx][jy+real_dy]))
3903 return(MF_NO_ACTION);
3905 else if (dy && real_dx)
3907 if (IN_LEV_FIELD(jx+real_dx,jy) && !IS_SOLID(Feld[jx+real_dx][jy]))
3908 return(MF_NO_ACTION);
3911 if (player->push_delay == 0)
3912 player->push_delay = FrameCounter;
3913 if (!FrameReached(&player->push_delay, player->push_delay_value) &&
3915 return(MF_NO_ACTION);
3917 if (IS_SB_ELEMENT(element))
3919 if (element == EL_SOKOBAN_FELD_VOLL)
3921 Feld[x][y] = EL_SOKOBAN_FELD_LEER;
3922 local_player->sokobanfields_still_needed++;
3927 if (Feld[x+dx][y+dy] == EL_SOKOBAN_FELD_LEER)
3929 Feld[x+dx][y+dy] = EL_SOKOBAN_FELD_VOLL;
3930 local_player->sokobanfields_still_needed--;
3931 if (element == EL_SOKOBAN_OBJEKT)
3932 PlaySoundLevel(x,y,SND_DENG);
3935 Feld[x+dx][y+dy] = EL_SOKOBAN_OBJEKT;
3940 Feld[x+dx][y+dy] = element;
3943 player->push_delay_value = 2;
3945 DrawLevelField(x,y);
3946 DrawLevelField(x+dx,y+dy);
3947 PlaySoundLevel(x+dx,y+dy,SND_PUSCH);
3949 if (IS_SB_ELEMENT(element) &&
3950 local_player->sokobanfields_still_needed == 0 &&
3951 game_emulation == EMU_SOKOBAN)
3953 player->LevelSolved = player->GameOver = TRUE;
3954 PlaySoundLevel(x,y,SND_BUING);
3966 return(MF_NO_ACTION);
3970 player->push_delay = 0;
3975 BOOL SnapField(struct PlayerInfo *player, int dx, int dy)
3977 int jx = player->jx, jy = player->jy;
3978 int x = jx + dx, y = jy + dy;
3980 if (player->gone || !IN_LEV_FIELD(x,y))
3988 player->snapped = FALSE;
3992 if (player->snapped)
3995 player->MovDir = (dx < 0 ? MV_LEFT :
3998 dy > 0 ? MV_DOWN : MV_NO_MOVING);
4000 if (!DigField(player, x,y, 0,0, DF_SNAP))
4003 player->snapped = TRUE;
4004 DrawLevelField(x,y);
4010 BOOL PlaceBomb(struct PlayerInfo *player)
4012 int jx = player->jx, jy = player->jy;
4015 if (player->gone || player->MovPos)
4018 element = Feld[jx][jy];
4020 if ((player->dynamite==0 && player->dynabombs_left==0) ||
4021 element==EL_DYNAMIT || element==EL_DYNABOMB || element==EL_EXPLODING)
4024 if (element != EL_LEERRAUM)
4025 Store[jx][jy] = element;
4027 if (player->dynamite)
4029 Feld[jx][jy] = EL_DYNAMIT;
4030 MovDelay[jx][jy] = 96;
4032 DrawText(DX_DYNAMITE, DY_DYNAMITE, int2str(local_player->dynamite, 3),
4033 FS_SMALL, FC_YELLOW);
4034 if (IN_SCR_FIELD(SCREENX(jx),SCREENY(jy)))
4035 DrawGraphicThruMask(SCREENX(jx),SCREENY(jy),GFX_DYNAMIT);
4039 Feld[jx][jy] = EL_DYNABOMB;
4040 Store2[jx][jy] = player->element_nr; /* for DynaExplode() */
4041 MovDelay[jx][jy] = 96;
4042 player->dynabombs_left--;
4043 if (IN_SCR_FIELD(SCREENX(jx),SCREENY(jy)))
4044 DrawGraphicThruMask(SCREENX(jx),SCREENY(jy),GFX_DYNABOMB);
4050 void PlaySoundLevel(int x, int y, int sound_nr)
4052 int sx = SCREENX(x), sy = SCREENY(y);
4054 int silence_distance = 8;
4056 if ((!sound_simple_on && !IS_LOOP_SOUND(sound_nr)) ||
4057 (!sound_loops_on && IS_LOOP_SOUND(sound_nr)))
4060 if (!IN_LEV_FIELD(x,y) ||
4061 sx < -silence_distance || sx >= SCR_FIELDX+silence_distance ||
4062 sy < -silence_distance || sy >= SCR_FIELDY+silence_distance)
4065 volume = PSND_MAX_VOLUME;
4067 stereo = (sx-SCR_FIELDX/2)*12;
4069 stereo = PSND_MIDDLE+(2*sx-(SCR_FIELDX-1))*5;
4070 if(stereo > PSND_MAX_RIGHT) stereo = PSND_MAX_RIGHT;
4071 if(stereo < PSND_MAX_LEFT) stereo = PSND_MAX_LEFT;
4074 if (!IN_SCR_FIELD(sx,sy))
4076 int dx = ABS(sx-SCR_FIELDX/2)-SCR_FIELDX/2;
4077 int dy = ABS(sy-SCR_FIELDY/2)-SCR_FIELDY/2;
4079 volume -= volume*(dx > dy ? dx : dy)/silence_distance;
4082 PlaySoundExt(sound_nr, volume, stereo, PSND_NO_LOOP);
4085 void RaiseScore(int value)
4087 local_player->score += value;
4088 DrawText(DX_SCORE, DY_SCORE, int2str(local_player->score, 5),
4089 FS_SMALL, FC_YELLOW);
4092 void RaiseScoreElement(int element)
4097 case EL_EDELSTEIN_BD:
4098 case EL_EDELSTEIN_GELB:
4099 case EL_EDELSTEIN_ROT:
4100 case EL_EDELSTEIN_LILA:
4101 RaiseScore(level.score[SC_EDELSTEIN]);
4104 RaiseScore(level.score[SC_DIAMANT]);
4108 RaiseScore(level.score[SC_KAEFER]);
4112 RaiseScore(level.score[SC_FLIEGER]);
4116 RaiseScore(level.score[SC_MAMPFER]);
4119 RaiseScore(level.score[SC_ROBOT]);
4122 RaiseScore(level.score[SC_PACMAN]);
4125 RaiseScore(level.score[SC_KOKOSNUSS]);
4128 RaiseScore(level.score[SC_DYNAMIT]);
4131 RaiseScore(level.score[SC_SCHLUESSEL]);