Implemented half/double time mod.

Dynamic bpm, map length in song select menu.
Fixed replay and spinner with these mods.
This commit is contained in:
Pavel Kolchev 2015-03-31 18:14:52 +03:00
parent e83e0da70f
commit 5f3ce74c64
6 changed files with 55 additions and 19 deletions

View File

@ -33,7 +33,7 @@ public enum GameMod {
"Easy", "Reduces overall difficulty - larger circles, more forgiving HP drain, less accuracy required."), "Easy", "Reduces overall difficulty - larger circles, more forgiving HP drain, less accuracy required."),
NO_FAIL (Category.EASY, 1, GameImage.MOD_NO_FAIL, "NF", 1, Input.KEY_W, 0.5f, NO_FAIL (Category.EASY, 1, GameImage.MOD_NO_FAIL, "NF", 1, Input.KEY_W, 0.5f,
"NoFail", "You can't fail. No matter what."), "NoFail", "You can't fail. No matter what."),
HALF_TIME (Category.EASY, 2, GameImage.MOD_HALF_TIME, "HT", 256, Input.KEY_E, 0.3f, false, HALF_TIME (Category.EASY, 2, GameImage.MOD_HALF_TIME, "HT", 256, Input.KEY_E, 0.3f,
"HalfTime", "Less zoom."), "HalfTime", "Less zoom."),
HARD_ROCK (Category.HARD, 0, GameImage.MOD_HARD_ROCK, "HR", 16, Input.KEY_A, 1.06f, HARD_ROCK (Category.HARD, 0, GameImage.MOD_HARD_ROCK, "HR", 16, Input.KEY_A, 1.06f,
"HardRock", "Everything just got a bit harder..."), "HardRock", "Everything just got a bit harder..."),
@ -41,7 +41,7 @@ public enum GameMod {
"SuddenDeath", "Miss a note and fail."), "SuddenDeath", "Miss a note and fail."),
// PERFECT (Category.HARD, 1, GameImage.MOD_PERFECT, "PF", 64, Input.KEY_S, 1f, // PERFECT (Category.HARD, 1, GameImage.MOD_PERFECT, "PF", 64, Input.KEY_S, 1f,
// "Perfect", "SS or quit."), // "Perfect", "SS or quit."),
DOUBLE_TIME (Category.HARD, 2, GameImage.MOD_DOUBLE_TIME, "DT", 64, Input.KEY_D, 1.12f, false, DOUBLE_TIME (Category.HARD, 2, GameImage.MOD_DOUBLE_TIME, "DT", 64, Input.KEY_D, 1.12f,
"DoubleTime", "Zoooooooooom."), "DoubleTime", "Zoooooooooom."),
// NIGHTCORE (Category.HARD, 2, GameImage.MOD_NIGHTCORE, "NT", 64, Input.KEY_D, 1.12f, // NIGHTCORE (Category.HARD, 2, GameImage.MOD_NIGHTCORE, "NT", 64, Input.KEY_D, 1.12f,
// "Nightcore", "uguuuuuuuu"), // "Nightcore", "uguuuuuuuu"),
@ -170,9 +170,14 @@ public enum GameMod {
Collections.reverse(Arrays.asList(VALUES_REVERSED)); Collections.reverse(Arrays.asList(VALUES_REVERSED));
} }
private static boolean justChanged = false;
/** The last calculated score multiplier, or -1f if it must be recalculated. */ /** The last calculated score multiplier, or -1f if it must be recalculated. */
private static float scoreMultiplier = -1f; private static float scoreMultiplier = -1f;
/** */
private static float speedMultiplier = -1f;
/** /**
* Initializes the game mods. * Initializes the game mods.
* @param width the container width * @param width the container width
@ -198,7 +203,7 @@ public enum GameMod {
mod.active = false; mod.active = false;
} }
scoreMultiplier = -1f; scoreMultiplier = speedMultiplier = -1f;
} }
/** /**
@ -216,6 +221,32 @@ public enum GameMod {
return scoreMultiplier; return scoreMultiplier;
} }
/**
*
*/
public static float getSpeedMultiplier() {
if (speedMultiplier < 0f) {
float multiplier = 1f;
if (DOUBLE_TIME.isActive())
multiplier = 1.5f;
else if (HALF_TIME.isActive())
multiplier = 0.75f;
speedMultiplier = multiplier;
}
return speedMultiplier;
}
/**
*
*/
public static boolean justChanged() {
if (justChanged) {
justChanged = false;
return true;
}
return false;
}
/** /**
* Returns the current game mod state (bitwise OR of active mods). * Returns the current game mod state (bitwise OR of active mods).
*/ */
@ -233,6 +264,7 @@ public enum GameMod {
* @param state the state (bitwise OR of active mods) * @param state the state (bitwise OR of active mods)
*/ */
public static void loadModState(int state) { public static void loadModState(int state) {
scoreMultiplier = speedMultiplier = -1f;
for (GameMod mod : GameMod.values()) for (GameMod mod : GameMod.values())
mod.active = ((state & mod.getBit()) > 0); mod.active = ((state & mod.getBit()) > 0);
} }
@ -352,7 +384,8 @@ public enum GameMod {
return; return;
active = !active; active = !active;
scoreMultiplier = -1f; scoreMultiplier = speedMultiplier = -1f;
justChanged = true;
if (checkInverse) { if (checkInverse) {
if (AUTO.isActive()) { if (AUTO.isActive()) {

View File

@ -118,16 +118,18 @@ public class OsuGroupNode {
return null; return null;
OsuFile osu = osuFiles.get(osuFileIndex); OsuFile osu = osuFiles.get(osuFileIndex);
long endTime = (long) (osu.endTime / GameMod.getSpeedMultiplier());
int bpmMin = (int) (osu.bpmMin * GameMod.getSpeedMultiplier());
int bpmMax = (int) (osu.bpmMax * GameMod.getSpeedMultiplier());
String[] info = new String[5]; String[] info = new String[5];
info[0] = osu.toString(); info[0] = osu.toString();
info[1] = String.format("Mapped by %s", info[1] = String.format("Mapped by %s",
osu.creator); osu.creator);
info[2] = String.format("Length: %d:%02d BPM: %s Objects: %d", info[2] = String.format("Length: %d:%02d BPM: %s Objects: %d",
TimeUnit.MILLISECONDS.toMinutes(osu.endTime), TimeUnit.MILLISECONDS.toMinutes(endTime),
TimeUnit.MILLISECONDS.toSeconds(osu.endTime) - TimeUnit.MILLISECONDS.toSeconds(endTime) -
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(osu.endTime)), TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(endTime)),
(osu.bpmMax <= 0) ? "--" : (bpmMax <= 0) ? "--" : ((bpmMin == bpmMax) ? bpmMin : String.format("%d-%d", bpmMin, bpmMax)),
((osu.bpmMin == osu.bpmMax) ? osu.bpmMin : String.format("%d-%d", osu.bpmMin, osu.bpmMax)),
(osu.hitObjectCircle + osu.hitObjectSlider + osu.hitObjectSpinner)); (osu.hitObjectCircle + osu.hitObjectSlider + osu.hitObjectSpinner));
info[3] = String.format("Circles: %d Sliders: %d Spinners: %d", info[3] = String.format("Circles: %d Sliders: %d Spinners: %d",
osu.hitObjectCircle, osu.hitObjectSlider, osu.hitObjectSpinner); osu.hitObjectCircle, osu.hitObjectSlider, osu.hitObjectSpinner);

View File

@ -279,13 +279,13 @@ public class MusicController {
* Plays the current track. * Plays the current track.
* @param loop whether or not to loop the track * @param loop whether or not to loop the track
*/ */
public static void play(boolean loop) { public static void play(float pitch, boolean loop) {
if (trackExists()) { if (trackExists()) {
trackEnded = false; trackEnded = false;
if (loop) if (loop)
player.loop(); player.loop();
else else
player.play(); player.play(pitch, 1f);
} }
} }

View File

@ -135,7 +135,7 @@ public class Spinner implements HitObject {
Utils.COLOR_BLACK_ALPHA.a = oldAlpha; Utils.COLOR_BLACK_ALPHA.a = oldAlpha;
// rpm // rpm
int rpm = Math.abs(Math.round(sumVelocity / storedVelocities.length * 60)); int rpm = Math.abs(Math.round(sumVelocity * GameMod.getSpeedMultiplier() / storedVelocities.length * 60));
Image rpmImg = GameImage.SPINNER_RPM.getImage(); Image rpmImg = GameImage.SPINNER_RPM.getImage();
rpmImg.setAlpha(alpha); rpmImg.setAlpha(alpha);
rpmImg.drawCentered(width / 2f, height - rpmImg.getHeight() / 2f); rpmImg.drawCentered(width / 2f, height - rpmImg.getHeight() / 2f);

View File

@ -1023,11 +1023,6 @@ public class Game extends BasicGameState {
// reset game data // reset game data
resetGameData(); resetGameData();
// needs to play before setting position to resume without lag later
MusicController.play(false);
MusicController.setPosition(0);
MusicController.pause();
// initialize object maps // initialize object maps
for (int i = 0; i < osu.objects.length; i++) { for (int i = 0; i < osu.objects.length; i++) {
OsuHitObject hitObject = osu.objects[i]; OsuHitObject hitObject = osu.objects[i];
@ -1119,6 +1114,11 @@ public class Game extends BasicGameState {
leadInTime = osu.audioLeadIn + approachTime; leadInTime = osu.audioLeadIn + approachTime;
restart = Restart.FALSE; restart = Restart.FALSE;
// needs to play before setting position to resume without lag later
MusicController.play(GameMod.getSpeedMultiplier(), false);
MusicController.setPosition(0);
MusicController.pause();
} }
skipButton.resetHover(); skipButton.resetHover();

View File

@ -336,7 +336,7 @@ public class SongMenu extends BasicGameState {
int iconWidth = musicNote.getWidth(); int iconWidth = musicNote.getWidth();
// song info text // song info text
if (songInfo == null) { if (songInfo == null || GameMod.justChanged()) {
songInfo = focusNode.getInfo(); songInfo = focusNode.getInfo();
if (Options.useUnicodeMetadata()) { // load glyphs if (Options.useUnicodeMetadata()) { // load glyphs
OsuFile osu = focusNode.osuFiles.get(0); OsuFile osu = focusNode.osuFiles.get(0);
@ -349,7 +349,8 @@ public class SongMenu extends BasicGameState {
headerTextY += Utils.FONT_LARGE.getLineHeight() - 8; headerTextY += Utils.FONT_LARGE.getLineHeight() - 8;
Utils.FONT_DEFAULT.drawString(marginX + iconWidth * 1.05f, headerTextY, songInfo[1], Color.white); Utils.FONT_DEFAULT.drawString(marginX + iconWidth * 1.05f, headerTextY, songInfo[1], Color.white);
headerTextY += Utils.FONT_DEFAULT.getLineHeight() - 2; headerTextY += Utils.FONT_DEFAULT.getLineHeight() - 2;
Utils.FONT_BOLD.drawString(marginX, headerTextY, songInfo[2], Color.white); Utils.FONT_BOLD.drawString(marginX, headerTextY, songInfo[2],
(GameMod.DOUBLE_TIME.isActive()) ? Color.red : (GameMod.HALF_TIME.isActive()) ? Color.green : Color.white);
headerTextY += Utils.FONT_BOLD.getLineHeight() - 4; headerTextY += Utils.FONT_BOLD.getLineHeight() - 4;
Utils.FONT_DEFAULT.drawString(marginX, headerTextY, songInfo[3], Color.white); Utils.FONT_DEFAULT.drawString(marginX, headerTextY, songInfo[3], Color.white);
headerTextY += Utils.FONT_DEFAULT.getLineHeight() - 4; headerTextY += Utils.FONT_DEFAULT.getLineHeight() - 4;