Added "Easy" mod.

- Halves all difficulty values and grants 3 "lives" instead of 1, with a score multiplier of 0.5x.

Other changes:
- Fixed score display in game state if score exceeds 8 digits.
- Added a "HP_DRAIN_MULTIPLIER" constant for steady HP drain/increase (to replace numeric constants).

Signed-off-by: Jeffrey Han <itdelatrisu@gmail.com>
This commit is contained in:
Jeffrey Han 2014-07-16 16:56:23 -04:00
parent 7a187c4e4f
commit cb396e0d20
5 changed files with 73 additions and 16 deletions

View File

@ -29,11 +29,12 @@ import org.newdawn.slick.util.Log;
* Game mods. * Game mods.
*/ */
public enum GameMod { public enum GameMod {
NO_FAIL (0, "selection-mod-nofail.png"), EASY (0, "selection-mod-easy.png"),
HARD_ROCK (1, "selection-mod-hardrock.png"), NO_FAIL (1, "selection-mod-nofail.png"),
SUDDEN_DEATH (2, "selection-mod-suddendeath.png"), HARD_ROCK (2, "selection-mod-hardrock.png"),
SPUN_OUT (3, "selection-mod-spunout.png"), SUDDEN_DEATH (3, "selection-mod-suddendeath.png"),
AUTO (4, "selection-mod-autoplay.png"); SPUN_OUT (4, "selection-mod-spunout.png"),
AUTO (5, "selection-mod-autoplay.png");
/** /**
* The ID of the mod (used for positioning). * The ID of the mod (used for positioning).
@ -130,12 +131,19 @@ public enum GameMod {
if (active) if (active)
toggle(false); toggle(false);
} }
} else if (SUDDEN_DEATH.isActive() && NO_FAIL.isActive()) { }
if (SUDDEN_DEATH.isActive() && NO_FAIL.isActive()) {
if (this == SUDDEN_DEATH) if (this == SUDDEN_DEATH)
NO_FAIL.toggle(false); NO_FAIL.toggle(false);
else else
SUDDEN_DEATH.toggle(false); SUDDEN_DEATH.toggle(false);
} }
if (EASY.isActive() && HARD_ROCK.isActive()) {
if (this == EASY)
HARD_ROCK.toggle(false);
else
EASY.toggle(false);
}
} }
} }

View File

@ -48,6 +48,11 @@ public class GameScore {
GRADE_D = 7, GRADE_D = 7,
GRADE_MAX = 8; // not a grade GRADE_MAX = 8; // not a grade
/**
* Delta multiplier for steady HP drain.
*/
public static final float HP_DRAIN_MULTIPLIER = 1 / 200f;
/** /**
* Hit result types. * Hit result types.
*/ */
@ -437,6 +442,7 @@ public class GameScore {
n /= 10; n /= 10;
} }
} }
/** /**
* Draws a string of scoreSymbols. * Draws a string of scoreSymbols.
* @param str the string to draw * @param str the string to draw
@ -478,7 +484,7 @@ public class GameScore {
*/ */
public void drawGameElements(Graphics g, int mapLength, boolean breakPeriod, boolean firstObject) { public void drawGameElements(Graphics g, int mapLength, boolean breakPeriod, boolean firstObject) {
// score // score
drawSymbolString(String.format("%08d", scoreDisplay), drawSymbolString((scoreDisplay < 100000000) ? String.format("%08d", scoreDisplay) : Long.toString(scoreDisplay),
width - 2, 0, 1.0f, true); width - 2, 0, 1.0f, true);
// score percentage // score percentage
@ -594,7 +600,7 @@ public class GameScore {
float rankResultScale = (height * 0.03f) / hitResults[HIT_300].getHeight(); float rankResultScale = (height * 0.03f) / hitResults[HIT_300].getHeight();
// score // 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); (int) (width * 0.18f), height / 6, symbolTextScale, false);
// result counts // result counts
@ -688,7 +694,7 @@ public class GameScore {
health += percent; health += percent;
if (health > 100f) if (health > 100f)
health = 100f; health = 100f;
if (health < 0f) else if (health < 0f)
health = 0f; health = 0f;
} }
@ -904,6 +910,8 @@ public class GameScore {
// game mod score multipliers // game mod score multipliers
float modMultiplier = 1f; float modMultiplier = 1f;
if (GameMod.EASY.isActive())
modMultiplier *= 0.5f;
if (GameMod.NO_FAIL.isActive()) if (GameMod.NO_FAIL.isActive())
modMultiplier *= 0.5f; modMultiplier *= 0.5f;
if (GameMod.HARD_ROCK.isActive()) if (GameMod.HARD_ROCK.isActive())
@ -911,8 +919,7 @@ public class GameScore {
if (GameMod.SPUN_OUT.isActive()) if (GameMod.SPUN_OUT.isActive())
modMultiplier *= 0.9f; modMultiplier *= 0.9f;
// not implemented: // not implemented:
// EASY (0.5x), HALF_TIME (0.3x), // HALF_TIME (0.3x), DOUBLE_TIME (1.12x), HIDDEN (1.06x), FLASHLIGHT (1.12x)
// DOUBLE_TIME (1.12x), HIDDEN (1.06x), FLASHLIGHT (1.12x)
/** /**
* [SCORE FORMULA] * [SCORE FORMULA]

View File

@ -575,7 +575,7 @@ public class Slider {
if ((game.isInputKeyPressed() && distance < followCircleRadius) || isAutoMod) { if ((game.isInputKeyPressed() && distance < followCircleRadius) || isAutoMod) {
// mouse pressed and within follow circle // mouse pressed and within follow circle
followCircleActive = true; followCircleActive = true;
score.changeHealth(delta / 200f); score.changeHealth(delta * GameScore.HP_DRAIN_MULTIPLIER);
// held during new repeat // held during new repeat
if (isNewRepeat) { if (isNewRepeat) {

View File

@ -191,12 +191,12 @@ public class Spinner {
// spin automatically (TODO: correct rotation angles) // spin automatically (TODO: correct rotation angles)
if (GameMod.AUTO.isActive()) { if (GameMod.AUTO.isActive()) {
// "auto" mod (fast) // "auto" mod (fast)
score.changeHealth(delta / 200f); // maintain health (TODO) score.changeHealth(delta * GameScore.HP_DRAIN_MULTIPLIER);
rotate(delta / 20f); rotate(delta / 20f);
return false; return false;
} else if (GameMod.SPUN_OUT.isActive()) { } else if (GameMod.SPUN_OUT.isActive()) {
// "spun out" mod (slow) // "spun out" mod (slow)
score.changeHealth(delta / 200f); // maintain health (TODO) score.changeHealth(delta * GameScore.HP_DRAIN_MULTIPLIER);
rotate(delta / 32f); rotate(delta / 32f);
return false; return false;
} }
@ -215,7 +215,7 @@ public class Spinner {
if (lastAngle >= 0f) { // skip initial clicks if (lastAngle >= 0f) { // skip initial clicks
float angleDiff = Math.abs(lastAngle - angle); float angleDiff = Math.abs(lastAngle - angle);
if (angleDiff < Math.PI / 2) { // skip huge angle changes... 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); rotate(angleDiff);
} }
} }

View File

@ -187,6 +187,16 @@ public class Game extends BasicGameState {
*/ */
private boolean checkpointLoaded = false; 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 // game-related variables
private GameContainer container; private GameContainer container;
private StateBasedGame game; private StateBasedGame game;
@ -238,6 +248,8 @@ public class Game extends BasicGameState {
int trackPosition = MusicController.getPosition(); int trackPosition = MusicController.getPosition();
if (pauseTime > -1) // returning from pause screen if (pauseTime > -1) // returning from pause screen
trackPosition = pauseTime; trackPosition = pauseTime;
else if (deathTime > -1) // "Easy" mod: health bar increasing
trackPosition = deathTime;
// checkpoint // checkpoint
if (checkpointLoaded) { if (checkpointLoaded) {
@ -442,6 +454,16 @@ public class Game extends BasicGameState {
return; 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); score.updateScoreDisplay(delta);
// map complete! // map complete!
@ -509,8 +531,18 @@ public class Game extends BasicGameState {
score.updateComboBurst(delta); score.updateComboBurst(delta);
// drain health // drain health
score.changeHealth(delta / -200f); score.changeHealth(delta * -1 * GameScore.HP_DRAIN_MULTIPLIER);
if (!score.isAlive()) { if (!score.isAlive()) {
// "Easy" mod
if (GameMod.EASY.isActive()) {
deaths++;
if (deaths < 3) {
deathTime = trackPosition;
MusicController.pause();
return;
}
}
// game over, force a restart // game over, force a restart
restart = RESTART_LOSE; restart = RESTART_LOSE;
game.enterState(Opsu.STATE_GAMEPAUSEMENU); game.enterState(Opsu.STATE_GAMEPAUSEMENU);
@ -748,6 +780,8 @@ public class Game extends BasicGameState {
countdown2Sound = false; countdown2Sound = false;
countdownGoSound = false; countdownGoSound = false;
checkpointLoaded = false; checkpointLoaded = false;
deaths = 0;
deathTime = -1;
// load the first timingPoint // load the first timingPoint
if (!osu.timingPoints.isEmpty()) { if (!osu.timingPoints.isEmpty()) {
@ -892,6 +926,14 @@ public class Game extends BasicGameState {
HPDrainRate = Math.min(HPDrainRate * 1.4f, 10); HPDrainRate = Math.min(HPDrainRate * 1.4f, 10);
} }
// "Easy" modifiers
else if (GameMod.EASY.isActive()) {
circleSize /= 2f;
approachRate /= 2f;
overallDifficulty /= 2f;
HPDrainRate /= 2f;
}
// initialize objects // initialize objects
Circle.init(container, circleSize); Circle.init(container, circleSize);
Slider.init(container, circleSize, osu); Slider.init(container, circleSize, osu);