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.
|
* 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user