X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=c75171ba1306cd893467e33428f739e204f7a2ce;hb=adaabca253f2e76597725cdc86fc1fff6f0de1d2;hp=da36f241121571eb6a7a16494c5bdd776209cf15;hpb=370a25a79d2e8df1e6e3e4cb4be39496d0190c28;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index da36f241..c75171ba 100644 --- a/src/game.c +++ b/src/game.c @@ -103,7 +103,7 @@ /* forward declaration for internal use */ static void CloseAllOpenTimegates(void); static void CheckGravityMovement(struct PlayerInfo *); -static void KillHeroUnlessShield(struct PlayerInfo *); +static void KillHeroUnlessProtected(int, int); static void MapGameButtons(); static void HandleGameButtons(struct GadgetInfo *); @@ -1290,7 +1290,7 @@ void Explode(int ex, int ey, int phase, int mode) if (element == EL_EXPLODING) element = Store2[x][y]; - if (IS_PLAYER(ex, ey) && !SHIELD_ON(PLAYERINFO(ex, ey))) + if (IS_PLAYER(ex, ey) && !PLAYER_PROTECTED(ex, ey)) { switch(StorePlayer[ex][ey]) { @@ -1338,6 +1338,10 @@ void Explode(int ex, int ey, int phase, int mode) Store[x][y] = EL_EDELSTEIN_ROT; else if (element == EL_ERZ_EDEL_LILA) Store[x][y] = EL_EDELSTEIN_LILA; + else if (element == EL_WALL_PEARL) + Store[x][y] = EL_PEARL; + else if (element == EL_WALL_CRYSTAL) + Store[x][y] = EL_CRYSTAL; else if (!IS_PFORTE(Store[x][y])) Store[x][y] = EL_LEERRAUM; @@ -1391,7 +1395,7 @@ void Explode(int ex, int ey, int phase, int mode) int element = Store2[x][y]; if (IS_PLAYER(x, y)) - KillHeroUnlessShield(PLAYERINFO(x, y)); + KillHeroUnlessProtected(x, y); else if (IS_EXPLOSIVE(element)) { Feld[x][y] = Store2[x][y]; @@ -1768,17 +1772,25 @@ void Impact(int x, int y) return; } - if ((element == EL_BOMBE || element == EL_SP_DISK_ORANGE) && + if ((element == EL_BOMBE || + element == EL_SP_DISK_ORANGE || + element == EL_DX_SUPABOMB) && (lastline || object_hit)) /* element is bomb */ { Bang(x, y); return; } + else if (element == EL_PEARL) + { + Feld[x][y] = EL_PEARL_BREAKING; + PlaySoundLevel(x, y, SND_KNACK); + return; + } if (element == EL_TROPFEN && (lastline || object_hit)) /* acid drop */ { if (object_hit && IS_PLAYER(x, y+1)) - KillHeroUnlessShield(PLAYERINFO(x, y+1)); + KillHeroUnlessProtected(x, y+1); else if (object_hit && smashed == EL_PINGUIN) Bang(x, y+1); else @@ -1811,7 +1823,7 @@ void Impact(int x, int y) if (IS_PLAYER(x, y+1)) { - KillHeroUnlessShield(PLAYERINFO(x, y+1)); + KillHeroUnlessProtected(x, y+1); return; } else if (smashed == EL_PINGUIN) @@ -1827,10 +1839,13 @@ void Impact(int x, int y) return; } } - else if (element == EL_FELSBROCKEN || element == EL_SP_ZONK) + else if (element == EL_FELSBROCKEN || + element == EL_SP_ZONK || + element == EL_BD_ROCK) { if (IS_ENEMY(smashed) || smashed == EL_BOMBE || smashed == EL_SP_DISK_ORANGE || + smashed == EL_DX_SUPABOMB || smashed == EL_SONDE || smashed == EL_SCHWEIN || smashed == EL_DRACHE || smashed == EL_MOLE) { @@ -1851,6 +1866,12 @@ void Impact(int x, int y) RaiseScoreElement(EL_KOKOSNUSS); return; } + else if (smashed == EL_PEARL) + { + Feld[x][y+1] = EL_PEARL_BREAKING; + PlaySoundLevel(x, y, SND_KNACK); + return; + } else if (smashed == EL_DIAMANT) { Feld[x][y+1] = EL_LEERRAUM; @@ -1903,6 +1924,7 @@ void Impact(int x, int y) sound = SND_KLUMPF; break; case EL_FELSBROCKEN: + case EL_BD_ROCK: sound = SND_KLOPF; break; case EL_SP_ZONK: @@ -2219,6 +2241,16 @@ void TurnRound(int x, int y) MovDir[x][y] = game.balloon_dir; MovDelay[x][y] = 0; } + else if (element == EL_SPRING_MOVING) + { + if (!IN_LEV_FIELD(move_x, move_y) || !IS_FREE(move_x, move_y) || + (IN_LEV_FIELD(x, y+1) && IS_FREE(x, y+1))) + { + Feld[x][y] = EL_SPRING; + MovDir[x][y] = MV_NO_MOVING; + } + MovDelay[x][y] = 0; + } else if (element == EL_ROBOT || element == EL_SONDE || element == EL_PINGUIN) { int attr_x = -1, attr_y = -1; @@ -2402,7 +2434,8 @@ void StartMoving(int x, int y) Feld[x][y+1] = EL_MORAST_VOLL; } } - else if (element == EL_FELSBROCKEN && Feld[x][y+1] == EL_MORAST_LEER) + else if ((element == EL_FELSBROCKEN || element == EL_BD_ROCK) && + Feld[x][y+1] == EL_MORAST_LEER) { InitMovingField(x, y, MV_DOWN); Store[x][y] = EL_MORAST_VOLL; @@ -2491,7 +2524,8 @@ void StartMoving(int x, int y) else if (IS_SLIPPERY(Feld[x][y+1]) && !Store[x][y+1]) #else else if (IS_SLIPPERY(Feld[x][y+1]) && !Store[x][y+1] && - !IS_FALLING(x, y+1) && !JustStopped[x][y+1]) + !IS_FALLING(x, y+1) && !JustStopped[x][y+1] && + element != EL_DX_SUPABOMB) #endif { boolean left = (x>0 && IS_FREE(x-1, y) && @@ -2501,7 +2535,9 @@ void StartMoving(int x, int y) if (left || right) { - if (left && right && game.emulation != EMU_BOULDERDASH) + if (left && right && + (game.emulation != EMU_BOULDERDASH && + element != EL_BD_ROCK && element != EL_EDELSTEIN_BD)) left = !(right = RND(2)); InitMovingField(x, y, left ? MV_LEFT : MV_RIGHT); @@ -2523,7 +2559,8 @@ void StartMoving(int x, int y) { int newx, newy; - if ((element == EL_SONDE || element == EL_BALLOON) + if ((element == EL_SONDE || element == EL_BALLOON || + element == EL_SPRING_MOVING) && JustBeingPushed(x, y)) return; @@ -2626,7 +2663,7 @@ void StartMoving(int x, int y) Moving2Blocked(x, y, &newx, &newy); /* get next screen position */ if (IS_ENEMY(element) && IS_PLAYER(newx, newy) && - !SHIELD_ON(PLAYERINFO(newx, newy))) + !PLAYER_PROTECTED(newx, newy)) { #if 1 @@ -2852,6 +2889,8 @@ void ContinueMoving(int x, int y) else if (CAN_FALL(element) && horiz_move && y < lev_fieldy-1 && IS_BELT(Feld[x][y+1])) step /= 2; + else if (element == EL_SPRING_MOVING) + step*=2; #if OLD_GAME_BEHAVIOUR else if (CAN_FALL(element) && horiz_move && !IS_SP_ELEMENT(element)) @@ -3132,7 +3171,7 @@ void AmoebeUmwandelnBD(int ax, int ay, int new_element) if (done) PlaySoundLevel(ax, ay, - (new_element == EL_FELSBROCKEN ? SND_KLOPF : SND_PLING)); + (new_element == EL_BD_ROCK ? SND_KLOPF : SND_PLING)); } void AmoebeWaechst(int x, int y) @@ -3316,7 +3355,7 @@ void AmoebeAbleger(int ax, int ay) if (element == EL_AMOEBE_BD && AmoebaCnt2[new_group_nr] >= 200) { - AmoebeUmwandelnBD(newax, neway, EL_FELSBROCKEN); + AmoebeUmwandelnBD(newax, neway, EL_BD_ROCK); return; } } @@ -3503,7 +3542,8 @@ void NussKnacken(int x, int y) { MovDelay[x][y]--; if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) - DrawGraphic(SCREENX(x), SCREENY(y), GFX_CRACKINGNUT+3-MovDelay[x][y]/2); + DrawGraphic(SCREENX(x), SCREENY(y), + GFX_CRACKINGNUT + 3 - MovDelay[x][y]/2); if (!MovDelay[x][y]) { @@ -3513,6 +3553,26 @@ void NussKnacken(int x, int y) } } +void BreakingPearl(int x, int y) +{ + if (!MovDelay[x][y]) /* next animation frame */ + MovDelay[x][y] = 9; + + if (MovDelay[x][y]) /* wait some time before next frame */ + { + MovDelay[x][y]--; + if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) + DrawGraphic(SCREENX(x), SCREENY(y), + GFX_PEARL_BREAKING + 4 - MovDelay[x][y]/2); + + if (!MovDelay[x][y]) + { + Feld[x][y] = EL_LEERRAUM; + DrawLevelField(x, y); + } + } +} + void SiebAktivieren(int x, int y, int typ) { int graphic = (typ == 1 ? GFX_SIEB_VOLL : GFX_SIEB2_VOLL) + 3; @@ -3919,10 +3979,10 @@ static void CheckBuggyBase(int x, int y) if (element == EL_SP_BUG) { - if (!MovDelay[x][y]) /* start activating buggy base */ + if (!MovDelay[x][y]) /* wait some time before activating base */ MovDelay[x][y] = 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND); - if (MovDelay[x][y]) /* wait some time before activating base */ + if (MovDelay[x][y]) { MovDelay[x][y]--; if (MovDelay[x][y] < 5 && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) @@ -3938,7 +3998,7 @@ static void CheckBuggyBase(int x, int y) if (!MovDelay[x][y]) /* start activating buggy base */ MovDelay[x][y] = 1 * FRAMES_PER_SECOND + RND(1 * FRAMES_PER_SECOND); - if (MovDelay[x][y]) /* wait some time before activating base */ + if (MovDelay[x][y]) { MovDelay[x][y]--; if (MovDelay[x][y]) @@ -3975,6 +4035,61 @@ static void CheckBuggyBase(int x, int y) } } +static void CheckTrap(int x, int y) +{ + int element = Feld[x][y]; + + if (element == EL_TRAP_INACTIVE) + { + if (!MovDelay[x][y]) /* wait some time before activating trap */ + MovDelay[x][y] = 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND); + + if (MovDelay[x][y]) + { + MovDelay[x][y]--; + if (MovDelay[x][y]) + return; + + Feld[x][y] = EL_TRAP_ACTIVE; + } + } + else if (element == EL_TRAP_ACTIVE) + { + int delay = 4; + int num_frames = 8; + + if (!MovDelay[x][y]) /* start activating trap */ + MovDelay[x][y] = num_frames * delay; + + if (MovDelay[x][y]) + { + MovDelay[x][y]--; + + if (MovDelay[x][y]) + { + if (!(MovDelay[x][y] % delay)) + { + int phase = MovDelay[x][y]/delay; + + if (phase >= num_frames/2) + phase = num_frames - phase; + + if (IN_SCR_FIELD(SCREENX(x), SCREENY(y))) + { + DrawGraphic(SCREENX(x),SCREENY(y), GFX_TRAP_INACTIVE + phase - 1); + ErdreichAnbroeckeln(SCREENX(x), SCREENY(y)); + } + } + + return; + } + + Feld[x][y] = EL_TRAP_INACTIVE; + DrawLevelField(x, y); + } + } +} + static void DrawBeltAnimation(int x, int y, int element) { int belt_nr = getBeltNrFromElement(element); @@ -4070,7 +4185,7 @@ static void PlayerActions(struct PlayerInfo *player, byte player_action) { int el = Feld[jx+dx][jy]; int push_delay = (IS_SB_ELEMENT(el) || el == EL_SONDE ? 2 : - el == EL_BALLOON ? 0 : 10); + (el == EL_BALLOON || el == EL_SPRING) ? 0 : 10); if (tape.delay_played + push_delay >= tape.pos[tape.counter].delay) { @@ -4260,6 +4375,8 @@ void GameActions() Blurb(x, y); else if (element == EL_CRACKINGNUT) NussKnacken(x, y); + else if (element == EL_PEARL_BREAKING) + BreakingPearl(x, y); else if (element == EL_AUSGANG_ZU) AusgangstuerPruefen(x, y); else if (element == EL_AUSGANG_ACT) @@ -4277,6 +4394,8 @@ void GameActions() CheckForDragon(x, y); else if (element == EL_SP_BUG || element == EL_SP_BUG_ACTIVE) CheckBuggyBase(x, y); + else if (element == EL_TRAP_INACTIVE || element == EL_TRAP_ACTIVE) + CheckTrap(x, y); else if (element == EL_SP_TERMINAL) DrawGraphicAnimation(x, y, GFX2_SP_TERMINAL, 7, 12, ANIM_NORMAL); else if (element == EL_SP_TERMINAL_ACTIVE) @@ -4560,14 +4679,7 @@ boolean MoveFigureOneStep(struct PlayerInfo *player, BuryHero(player); } else - { -#if 1 TestIfBadThingHitsHero(new_jx, new_jy); -#else - if (player->shield_time_left == 0) - KillHero(player); -#endif - } return MF_MOVING; } @@ -4886,7 +4998,7 @@ void TestIfGoodThingHitsBadThing(int goodx, int goody) if (player->shield_active_time_left > 0) Bang(killx, killy); - else if (player->shield_passive_time_left == 0) + else if (!PLAYER_PROTECTED(goodx, goody)) KillHero(player); } else @@ -4951,7 +5063,7 @@ void TestIfBadThingHitsGoodThing(int badx, int bady) if (player->shield_active_time_left > 0) Bang(badx, bady); - else if (player->shield_passive_time_left == 0) + else if (!PLAYER_PROTECTED(killx, killy)) KillHero(player); } else @@ -5031,10 +5143,10 @@ void KillHero(struct PlayerInfo *player) BuryHero(player); } -static void KillHeroUnlessShield(struct PlayerInfo *player) +static void KillHeroUnlessProtected(int x, int y) { - if (!SHIELD_ON(player)) - KillHero(player); + if (!PLAYER_PROTECTED(x, y)) + KillHero(PLAYERINFO(x, y)); } void BuryHero(struct PlayerInfo *player) @@ -5096,6 +5208,36 @@ int DigField(struct PlayerInfo *player, if (IS_MOVING(x, y) || IS_PLAYER(x, y)) return MF_NO_ACTION; + if (IS_TUBE(Feld[jx][jy])) + { + int i = 0; + int tube_leave_directions[][2] = + { + { EL_TUBE_CROSS, MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN }, + { EL_TUBE_VERTICAL, MV_UP | MV_DOWN }, + { EL_TUBE_HORIZONTAL, MV_LEFT | MV_RIGHT }, + { EL_TUBE_VERT_LEFT, MV_LEFT | MV_UP | MV_DOWN }, + { EL_TUBE_VERT_RIGHT, MV_RIGHT | MV_UP | MV_DOWN }, + { EL_TUBE_HORIZ_UP, MV_LEFT | MV_RIGHT | MV_UP }, + { EL_TUBE_HORIZ_DOWN, MV_LEFT | MV_RIGHT | MV_DOWN }, + { EL_TUBE_LEFT_UP, MV_LEFT | MV_UP }, + { EL_TUBE_LEFT_DOWN, MV_LEFT | MV_DOWN }, + { EL_TUBE_RIGHT_UP, MV_RIGHT | MV_UP }, + { EL_TUBE_RIGHT_DOWN, MV_RIGHT | MV_DOWN }, + { -1, MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN } + }; + + while (tube_leave_directions[i][0] != Feld[jx][jy]) + { + i++; + if (tube_leave_directions[i][0] == -1) /* should not happen */ + break; + } + + if (!(tube_leave_directions[i][1] & move_direction)) + return MF_NO_ACTION; /* tube has no opening in this direction */ + } + element = Feld[x][y]; switch (element) @@ -5106,6 +5248,7 @@ int DigField(struct PlayerInfo *player, case EL_ERDREICH: case EL_SAND_INVISIBLE: + case EL_TRAP_INACTIVE: Feld[x][y] = EL_LEERRAUM; PlaySoundLevel(x, y, SND_SCHLURF); break; @@ -5123,8 +5266,12 @@ int DigField(struct PlayerInfo *player, case EL_EDELSTEIN_LILA: case EL_DIAMANT: case EL_SP_INFOTRON: + case EL_PEARL: + case EL_CRYSTAL: RemoveField(x, y); - local_player->gems_still_needed -= (element == EL_DIAMANT ? 3 : 1); + local_player->gems_still_needed -= (element == EL_DIAMANT ? 3 : + element == EL_PEARL ? 5 : + element == EL_CRYSTAL ? 8 : 1); if (local_player->gems_still_needed < 0) local_player->gems_still_needed = 0; RaiseScoreElement(element); @@ -5346,11 +5493,14 @@ int DigField(struct PlayerInfo *player, break; case EL_FELSBROCKEN: + case EL_BD_ROCK: case EL_BOMBE: + case EL_DX_SUPABOMB: case EL_KOKOSNUSS: case EL_ZEIT_LEER: case EL_SP_ZONK: case EL_SP_DISK_ORANGE: + case EL_SPRING: if (dy || mode == DF_SNAP) return MF_NO_ACTION; @@ -5368,16 +5518,22 @@ int DigField(struct PlayerInfo *player, if (player->push_delay == 0) player->push_delay = FrameCounter; if (!FrameReached(&player->push_delay, player->push_delay_value) && - !tape.playing) + !tape.playing && element != EL_SPRING) return MF_NO_ACTION; RemoveField(x, y); Feld[x+dx][y+dy] = element; - player->push_delay_value = 2+RND(8); + if (element == EL_SPRING) + { + Feld[x+dx][y+dy] = EL_SPRING_MOVING; + MovDir[x+dx][y+dy] = move_direction; + } + + player->push_delay_value = (element == EL_SPRING ? 0 : 2 + RND(8)); DrawLevelField(x+dx, y+dy); - if (element == EL_FELSBROCKEN) + if (element == EL_FELSBROCKEN || element == EL_BD_ROCK) PlaySoundLevel(x+dx, y+dy, SND_PUSCH); else if (element == EL_KOKOSNUSS) PlaySoundLevel(x+dx, y+dy, SND_KNURK); @@ -5490,7 +5646,47 @@ int DigField(struct PlayerInfo *player, DOUBLE_PLAYER_SPEED(player); PlaySoundLevel(x, y, SND_GATE); + break; + + case EL_TUBE_CROSS: + case EL_TUBE_VERTICAL: + case EL_TUBE_HORIZONTAL: + case EL_TUBE_VERT_LEFT: + case EL_TUBE_VERT_RIGHT: + case EL_TUBE_HORIZ_UP: + case EL_TUBE_HORIZ_DOWN: + case EL_TUBE_LEFT_UP: + case EL_TUBE_LEFT_DOWN: + case EL_TUBE_RIGHT_UP: + case EL_TUBE_RIGHT_DOWN: + { + int i = 0; + int tube_enter_directions[][2] = + { + { EL_TUBE_CROSS, MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN }, + { EL_TUBE_VERTICAL, MV_UP | MV_DOWN }, + { EL_TUBE_HORIZONTAL, MV_LEFT | MV_RIGHT }, + { EL_TUBE_VERT_LEFT, MV_RIGHT | MV_UP | MV_DOWN }, + { EL_TUBE_VERT_RIGHT, MV_LEFT | MV_UP | MV_DOWN }, + { EL_TUBE_HORIZ_UP, MV_LEFT | MV_RIGHT | MV_DOWN }, + { EL_TUBE_HORIZ_DOWN, MV_LEFT | MV_RIGHT | MV_UP }, + { EL_TUBE_LEFT_UP, MV_RIGHT | MV_DOWN }, + { EL_TUBE_LEFT_DOWN, MV_RIGHT | MV_UP }, + { EL_TUBE_RIGHT_UP, MV_LEFT | MV_DOWN }, + { EL_TUBE_RIGHT_DOWN, MV_LEFT | MV_UP }, + { -1, MV_NO_MOVING } + }; + + while (tube_enter_directions[i][0] != element) + { + i++; + if (tube_enter_directions[i][0] == -1) /* should not happen */ + break; + } + if (!(tube_enter_directions[i][1] & move_direction)) + return MF_NO_ACTION; /* tube has no opening in this direction */ + } break; case EL_AUSGANG_ZU: