diff --git a/src/itdelatrisu/opsu/GameMod.java b/src/itdelatrisu/opsu/GameMod.java index 3505b7a8..48bd2abc 100644 --- a/src/itdelatrisu/opsu/GameMod.java +++ b/src/itdelatrisu/opsu/GameMod.java @@ -29,11 +29,12 @@ import org.newdawn.slick.util.Log; * Game mods. */ public enum GameMod { - NO_FAIL (0, "selection-mod-nofail.png"), - HARD_ROCK (1, "selection-mod-hardrock.png"), - SUDDEN_DEATH (2, "selection-mod-suddendeath.png"), - SPUN_OUT (3, "selection-mod-spunout.png"), - AUTO (4, "selection-mod-autoplay.png"); + EASY (0, "selection-mod-easy.png"), + NO_FAIL (1, "selection-mod-nofail.png"), + HARD_ROCK (2, "selection-mod-hardrock.png"), + SUDDEN_DEATH (3, "selection-mod-suddendeath.png"), + SPUN_OUT (4, "selection-mod-spunout.png"), + AUTO (5, "selection-mod-autoplay.png"); /** * The ID of the mod (used for positioning). @@ -130,12 +131,19 @@ public enum GameMod { if (active) toggle(false); } - } else if (SUDDEN_DEATH.isActive() && NO_FAIL.isActive()) { + } + if (SUDDEN_DEATH.isActive() && NO_FAIL.isActive()) { if (this == SUDDEN_DEATH) NO_FAIL.toggle(false); else SUDDEN_DEATH.toggle(false); } + if (EASY.isActive() && HARD_ROCK.isActive()) { + if (this == EASY) + HARD_ROCK.toggle(false); + else + EASY.toggle(false); + } } } diff --git a/src/itdelatrisu/opsu/GameScore.java b/src/itdelatrisu/opsu/GameScore.java index a9c5149a..ec4ba962 100644 --- a/src/itdelatrisu/opsu/GameScore.java +++ b/src/itdelatrisu/opsu/GameScore.java @@ -48,6 +48,11 @@ public class GameScore { GRADE_D = 7, GRADE_MAX = 8; // not a grade + /** + * Delta multiplier for steady HP drain. + */ + public static final float HP_DRAIN_MULTIPLIER = 1 / 200f; + /** * Hit result types. */ @@ -437,6 +442,7 @@ public class GameScore { n /= 10; } } + /** * Draws a string of scoreSymbols. * @param str the string to draw @@ -478,7 +484,7 @@ public class GameScore { */ public void drawGameElements(Graphics g, int mapLength, boolean breakPeriod, boolean firstObject) { // score - drawSymbolString(String.format("%08d", scoreDisplay), + drawSymbolString((scoreDisplay < 100000000) ? String.format("%08d", scoreDisplay) : Long.toString(scoreDisplay), width - 2, 0, 1.0f, true); // score percentage @@ -594,7 +600,7 @@ public class GameScore { float rankResultScale = (height * 0.03f) / hitResults[HIT_300].getHeight(); // score - drawSymbolString((score / 100000000 == 0) ? String.format("%08d", score) : Long.toString(score), + drawSymbolString((score < 100000000) ? String.format("%08d", score) : Long.toString(score), (int) (width * 0.18f), height / 6, symbolTextScale, false); // result counts @@ -688,7 +694,7 @@ public class GameScore { health += percent; if (health > 100f) health = 100f; - if (health < 0f) + else if (health < 0f) health = 0f; } @@ -904,6 +910,8 @@ public class GameScore { // game mod score multipliers float modMultiplier = 1f; + if (GameMod.EASY.isActive()) + modMultiplier *= 0.5f; if (GameMod.NO_FAIL.isActive()) modMultiplier *= 0.5f; if (GameMod.HARD_ROCK.isActive()) @@ -911,8 +919,7 @@ public class GameScore { if (GameMod.SPUN_OUT.isActive()) modMultiplier *= 0.9f; // not implemented: - // EASY (0.5x), HALF_TIME (0.3x), - // DOUBLE_TIME (1.12x), HIDDEN (1.06x), FLASHLIGHT (1.12x) + // HALF_TIME (0.3x), DOUBLE_TIME (1.12x), HIDDEN (1.06x), FLASHLIGHT (1.12x) /** * [SCORE FORMULA] diff --git a/src/itdelatrisu/opsu/objects/Slider.java b/src/itdelatrisu/opsu/objects/Slider.java index f7b0f39c..3bd92b7d 100644 --- a/src/itdelatrisu/opsu/objects/Slider.java +++ b/src/itdelatrisu/opsu/objects/Slider.java @@ -575,7 +575,7 @@ public class Slider { if ((game.isInputKeyPressed() && distance < followCircleRadius) || isAutoMod) { // mouse pressed and within follow circle followCircleActive = true; - score.changeHealth(delta / 200f); + score.changeHealth(delta * GameScore.HP_DRAIN_MULTIPLIER); // held during new repeat if (isNewRepeat) { diff --git a/src/itdelatrisu/opsu/objects/Spinner.java b/src/itdelatrisu/opsu/objects/Spinner.java index 1442d153..e4aa1756 100644 --- a/src/itdelatrisu/opsu/objects/Spinner.java +++ b/src/itdelatrisu/opsu/objects/Spinner.java @@ -191,12 +191,12 @@ public class Spinner { // spin automatically (TODO: correct rotation angles) if (GameMod.AUTO.isActive()) { // "auto" mod (fast) - score.changeHealth(delta / 200f); // maintain health (TODO) + score.changeHealth(delta * GameScore.HP_DRAIN_MULTIPLIER); rotate(delta / 20f); return false; } else if (GameMod.SPUN_OUT.isActive()) { // "spun out" mod (slow) - score.changeHealth(delta / 200f); // maintain health (TODO) + score.changeHealth(delta * GameScore.HP_DRAIN_MULTIPLIER); rotate(delta / 32f); return false; } @@ -215,7 +215,7 @@ public class Spinner { if (lastAngle >= 0f) { // skip initial clicks float angleDiff = Math.abs(lastAngle - angle); if (angleDiff < Math.PI / 2) { // skip huge angle changes... - score.changeHealth(delta / 200f); // maintain health (TODO) + score.changeHealth(delta * GameScore.HP_DRAIN_MULTIPLIER); rotate(angleDiff); } } diff --git a/src/itdelatrisu/opsu/states/Game.java b/src/itdelatrisu/opsu/states/Game.java index f9d03ed2..3c910954 100644 --- a/src/itdelatrisu/opsu/states/Game.java +++ b/src/itdelatrisu/opsu/states/Game.java @@ -187,6 +187,16 @@ public class Game extends BasicGameState { */ private boolean checkpointLoaded = false; + /** + * Number of deaths, used if "Easy" mod is enabled. + */ + private byte deaths = 0; + + /** + * Track position at death, used if "Easy" mod is enabled. + */ + private int deathTime = -1; + // game-related variables private GameContainer container; private StateBasedGame game; @@ -238,6 +248,8 @@ public class Game extends BasicGameState { int trackPosition = MusicController.getPosition(); if (pauseTime > -1) // returning from pause screen trackPosition = pauseTime; + else if (deathTime > -1) // "Easy" mod: health bar increasing + trackPosition = deathTime; // checkpoint if (checkpointLoaded) { @@ -442,6 +454,16 @@ public class Game extends BasicGameState { return; } + // "Easy" mod: multiple "lives" + if (GameMod.EASY.isActive() && deathTime > -1) { + if (score.getHealth() < 99f) + score.changeHealth(delta / 10f); + else { + MusicController.resume(); + deathTime = -1; + } + } + score.updateScoreDisplay(delta); // map complete! @@ -509,8 +531,18 @@ public class Game extends BasicGameState { score.updateComboBurst(delta); // drain health - score.changeHealth(delta / -200f); + score.changeHealth(delta * -1 * GameScore.HP_DRAIN_MULTIPLIER); if (!score.isAlive()) { + // "Easy" mod + if (GameMod.EASY.isActive()) { + deaths++; + if (deaths < 3) { + deathTime = trackPosition; + MusicController.pause(); + return; + } + } + // game over, force a restart restart = RESTART_LOSE; game.enterState(Opsu.STATE_GAMEPAUSEMENU); @@ -748,6 +780,8 @@ public class Game extends BasicGameState { countdown2Sound = false; countdownGoSound = false; checkpointLoaded = false; + deaths = 0; + deathTime = -1; // load the first timingPoint if (!osu.timingPoints.isEmpty()) { @@ -892,6 +926,14 @@ public class Game extends BasicGameState { HPDrainRate = Math.min(HPDrainRate * 1.4f, 10); } + // "Easy" modifiers + else if (GameMod.EASY.isActive()) { + circleSize /= 2f; + approachRate /= 2f; + overallDifficulty /= 2f; + HPDrainRate /= 2f; + } + // initialize objects Circle.init(container, circleSize); Slider.init(container, circleSize, osu);