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:
parent
7a187c4e4f
commit
cb396e0d20
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue
Block a user