Added options for global fixed difficulty settings (CS, HP, AR, OD).

- Added a new tab in Game Options screen containing the values.

Other changes:
- Corrected "Hard Rock" difficulty modifiers.

Signed-off-by: Jeffrey Han <itdelatrisu@gmail.com>
This commit is contained in:
Jeffrey Han 2014-07-05 01:24:01 -04:00
parent 06f8dae037
commit 83f13a8879
3 changed files with 176 additions and 37 deletions

View File

@ -213,7 +213,7 @@ public enum GameImage {
/** /**
* Returns whether or not the image has been scaled. * Returns whether or not the image has been scaled.
*/ */
public boolean isScaled() { return (skinImage != null) ? false : scaled; } public boolean isScaled() { return (skinImage != null) ? false : scaled; }
/** /**
* Sets the scaled status of the image. * Sets the scaled status of the image.

View File

@ -810,18 +810,31 @@ public class Game extends BasicGameState {
*/ */
private void setMapModifiers() { private void setMapModifiers() {
try { try {
// map-based properties, so re-initialize each game // map-based properties, re-initialized each game
float circleSize = osu.circleSize; float circleSize = osu.circleSize;
float approachRate = osu.approachRate; float approachRate = osu.approachRate;
float overallDifficulty = osu.overallDifficulty; float overallDifficulty = osu.overallDifficulty;
float HPDrainRate = osu.HPDrainRate; float HPDrainRate = osu.HPDrainRate;
if (Options.isModActive(Options.MOD_HARD_ROCK)) { // hard rock modifiers
circleSize = Math.max(circleSize - 1, 0); // fixed difficulty overrides
approachRate = Math.min(approachRate + 3, 10); if (Options.getFixedCS() > 0f)
overallDifficulty = Math.min(overallDifficulty + 3, 10); circleSize = Options.getFixedCS();
HPDrainRate = Math.min(HPDrainRate + 3, 10); if (Options.getFixedAR() > 0f)
approachRate = Options.getFixedAR();
if (Options.getFixedOD() > 0f)
overallDifficulty = Options.getFixedOD();
if (Options.getFixedHP() > 0f)
HPDrainRate = Options.getFixedHP();
// hard rock modifiers
if (Options.isModActive(Options.MOD_HARD_ROCK)) {
circleSize = Math.min(circleSize * 1.4f, 10);
approachRate = Math.min(approachRate * 1.4f, 10);
overallDifficulty = Math.min(overallDifficulty * 1.4f, 10);
HPDrainRate = Math.min(HPDrainRate * 1.4f, 10);
} }
// initialize objects
Circle.init(container, circleSize); Circle.init(container, circleSize);
Slider.init(container, circleSize, osu); Slider.init(container, circleSize, osu);
Spinner.init(container); Spinner.init(container);

View File

@ -130,7 +130,11 @@ public class Options extends BasicGameState {
SHOW_PERFECT_HIT, SHOW_PERFECT_HIT,
BACKGROUND_DIM, BACKGROUND_DIM,
FORCE_DEFAULT_PLAYFIELD, FORCE_DEFAULT_PLAYFIELD,
IGNORE_BEATMAP_SKINS; IGNORE_BEATMAP_SKINS,
FIXED_CS,
FIXED_HP,
FIXED_AR,
FIXED_OD;
}; };
/** /**
@ -140,7 +144,8 @@ public class Options extends BasicGameState {
TAB_DISPLAY = 0, TAB_DISPLAY = 0,
TAB_MUSIC = 1, TAB_MUSIC = 1,
TAB_GAMEPLAY = 2, TAB_GAMEPLAY = 2,
TAB_MAX = 3; // not a tab TAB_CUSTOM = 3,
TAB_MAX = 4; // not a tab
/** /**
* Option tab names. * Option tab names.
@ -148,7 +153,8 @@ public class Options extends BasicGameState {
private static final String[] TAB_NAMES = { private static final String[] TAB_NAMES = {
"Display", "Display",
"Music", "Music",
"Gameplay" "Gameplay",
"Custom"
}; };
/** /**
@ -196,12 +202,22 @@ public class Options extends BasicGameState {
GameOption.SHOW_PERFECT_HIT GameOption.SHOW_PERFECT_HIT
}; };
/**
* Custom options.
*/
private static final GameOption[] customOptions = {
GameOption.FIXED_CS,
GameOption.FIXED_HP,
GameOption.FIXED_AR,
GameOption.FIXED_OD
};
/** /**
* Max number of options displayed on one screen. * Max number of options displayed on one screen.
*/ */
private static int maxOptionsScreen = Math.max( private static int maxOptionsScreen = Math.max(
Math.max(displayOptions.length, musicOptions.length), Math.max(displayOptions.length, musicOptions.length),
gameplayOptions.length); Math.max(gameplayOptions.length, customOptions.length));
/** /**
* Screen resolutions. * Screen resolutions.
@ -318,6 +334,13 @@ public class Options extends BasicGameState {
*/ */
private static boolean ignoreBeatmapSkins = false; private static boolean ignoreBeatmapSkins = false;
/**
* Fixed difficulty overrides.
*/
private static float
fixedCS = 0f, fixedHP = 0f,
fixedAR = 0f, fixedOD = 0f;
/** /**
* Game option coordinate modifiers (for drawing). * Game option coordinate modifiers (for drawing).
*/ */
@ -351,9 +374,11 @@ public class Options extends BasicGameState {
// option tabs // option tabs
Image tab = Utils.getTabImage(); Image tab = Utils.getTabImage();
int subtextWidth = Utils.FONT_DEFAULT.getWidth("Click or drag an option to change it.");
float tabX = (width / 50) + (tab.getWidth() / 2f); float tabX = (width / 50) + (tab.getWidth() / 2f);
float tabY = 15 + Utils.FONT_XLARGE.getHeight() + (tab.getHeight() / 2f); float tabY = 15 + Utils.FONT_XLARGE.getHeight() + (tab.getHeight() / 2f);
float tabOffset = tab.getWidth() * 0.85f; float tabOffset = (float) Math.min(tab.getWidth(),
((width - subtextWidth - tab.getWidth()) / 2) / TAB_MAX);
for (int i = 0; i < optionTabs.length; i++) for (int i = 0; i < optionTabs.length; i++)
optionTabs[i] = new GUIMenuButton(tab, tabX + (i * tabOffset), tabY); optionTabs[i] = new GUIMenuButton(tab, tabX + (i * tabOffset), tabY);
@ -424,6 +449,10 @@ public class Options extends BasicGameState {
for (int i = 0; i < gameplayOptions.length; i++) for (int i = 0; i < gameplayOptions.length; i++)
drawOption(gameplayOptions[i], i); drawOption(gameplayOptions[i], i);
break; break;
case TAB_CUSTOM:
for (int i = 0; i < customOptions.length; i++)
drawOption(customOptions[i], i);
break;
} }
// option tabs // option tabs
@ -580,46 +609,72 @@ public class Options extends BasicGameState {
// options (drag only) // options (drag only)
switch (getClickedOption(oldy)) { switch (getClickedOption(oldy)) {
case MUSIC_VOLUME: case MUSIC_VOLUME:
musicVolume += diff; musicVolume = getBoundedValue(musicVolume, diff, 0, 100);
if (musicVolume < 0)
musicVolume = 0;
else if (musicVolume > 100)
musicVolume = 100;
container.setMusicVolume(getMusicVolume()); container.setMusicVolume(getMusicVolume());
break; break;
case EFFECT_VOLUME: case EFFECT_VOLUME:
effectVolume += diff; effectVolume = getBoundedValue(effectVolume, diff, 0, 100);
if (effectVolume < 0)
effectVolume = 0;
else if (effectVolume > 100)
effectVolume = 100;
break; break;
case HITSOUND_VOLUME: case HITSOUND_VOLUME:
hitSoundVolume += diff; hitSoundVolume = getBoundedValue(hitSoundVolume, diff, 0, 100);
if (hitSoundVolume < 0)
hitSoundVolume = 0;
else if (hitSoundVolume > 100)
hitSoundVolume = 100;
break; break;
case MUSIC_OFFSET: case MUSIC_OFFSET:
musicOffset += diff; musicOffset = getBoundedValue(musicOffset, diff, -500, 500);
if (musicOffset < -500)
musicOffset = -500;
else if (musicOffset > 500)
musicOffset = 500;
break; break;
case BACKGROUND_DIM: case BACKGROUND_DIM:
backgroundDim += diff; backgroundDim = getBoundedValue(backgroundDim, diff, 0, 100);
if (backgroundDim < 0) break;
backgroundDim = 0; case FIXED_CS:
else if (backgroundDim > 100) fixedCS = getBoundedValue(fixedCS, diff / 10f, 0f, 10f);
backgroundDim = 100; break;
case FIXED_HP:
fixedHP = getBoundedValue(fixedHP, diff / 10f, 0f, 10f);
break;
case FIXED_AR:
fixedAR = getBoundedValue(fixedAR, diff / 10f, 0f, 10f);
break;
case FIXED_OD:
fixedOD = getBoundedValue(fixedOD, diff / 10f, 0f, 10f);
break; break;
default: default:
break; break;
} }
} }
/**
* Returns a bounded value for when an option is dragged.
* @param var the initial value
* @param diff the value change
* @param min the minimum value
* @param max the maximum value
* @return the bounded value
*/
private int getBoundedValue(int var, int diff, int min, int max) {
int val = var + diff;
if (val < min)
val = min;
else if (val > max)
val = max;
return val;
}
/**
* Returns a bounded value for when an option is dragged.
* @param var the initial value
* @param diff the value change
* @param min the minimum value
* @param max the maximum value
* @return the bounded value
*/
private float getBoundedValue(float var, float diff, float min, float max) {
float val = var + diff;
if (val < min)
val = min;
else if (val > max)
val = max;
return val;
}
@Override @Override
public void keyPressed(int key, char c) { public void keyPressed(int key, char c) {
switch (key) { switch (key) {
@ -755,6 +810,30 @@ public class Options extends BasicGameState {
"Whether to show perfect hit result bursts (300s, slider ticks)." "Whether to show perfect hit result bursts (300s, slider ticks)."
); );
break; break;
case FIXED_CS:
drawOption(pos, "Fixed Circle Size (CS)",
(fixedCS == 0f) ? "Disabled" : String.format("%.1f", fixedCS),
"Determines the size of circles and sliders."
);
break;
case FIXED_HP:
drawOption(pos, "Fixed HP Drain Rate (HP)",
(fixedHP == 0f) ? "Disabled" : String.format("%.1f", fixedHP),
"Determines the rate at which health decreases."
);
break;
case FIXED_AR:
drawOption(pos, "Fixed Approach Rate (AR)",
(fixedAR == 0f) ? "Disabled" : String.format("%.1f", fixedAR),
"Determines how long hit circles stay on the screen."
);
break;
case FIXED_OD:
drawOption(pos, "Fixed Overall Difficulty (OD)",
(fixedOD == 0f) ? "Disabled" : String.format("%.1f", fixedOD),
"Determines the time window for hit results."
);
break;
default: default:
break; break;
} }
@ -806,6 +885,9 @@ public class Options extends BasicGameState {
if (index < gameplayOptions.length) if (index < gameplayOptions.length)
option = gameplayOptions[index]; option = gameplayOptions[index];
break; break;
case TAB_CUSTOM:
if (index < customOptions.length)
option = customOptions[index];
} }
return option; return option;
} }
@ -942,6 +1024,30 @@ public class Options extends BasicGameState {
*/ */
public static boolean isBeatmapSkinIgnored() { return ignoreBeatmapSkins; } public static boolean isBeatmapSkinIgnored() { return ignoreBeatmapSkins; }
/**
* Returns the fixed circle size override, if any.
* @return the CS value (0, 10], 0 if disabled
*/
public static float getFixedCS() { return fixedCS; }
/**
* Returns the fixed HP drain rate override, if any.
* @return the HP value (0, 10], 0 if disabled
*/
public static float getFixedHP() { return fixedHP; }
/**
* Returns the fixed approach rate override, if any.
* @return the AR value (0, 10], 0 if disabled
*/
public static float getFixedAR() { return fixedAR; }
/**
* Returns the fixed overall difficulty override, if any.
* @return the OD value (0, 10], 0 if disabled
*/
public static float getFixedOD() { return fixedOD; }
/** /**
* Returns the current beatmap directory. * Returns the current beatmap directory.
* If invalid, this will attempt to search for the directory, * If invalid, this will attempt to search for the directory,
@ -1078,6 +1184,18 @@ public class Options extends BasicGameState {
case "PerfectHit": case "PerfectHit":
showPerfectHit = Boolean.parseBoolean(value); showPerfectHit = Boolean.parseBoolean(value);
break; break;
case "FixedCS":
fixedCS = Float.parseFloat(value);
break;
case "FixedHP":
fixedHP = Float.parseFloat(value);
break;
case "FixedAR":
fixedAR = Float.parseFloat(value);
break;
case "FixedOD":
fixedOD = Float.parseFloat(value);
break;
} }
} }
} catch (IOException e) { } catch (IOException e) {
@ -1145,6 +1263,14 @@ public class Options extends BasicGameState {
writer.newLine(); writer.newLine();
writer.write(String.format("PerfectHit = %b", showPerfectHit)); writer.write(String.format("PerfectHit = %b", showPerfectHit));
writer.newLine(); writer.newLine();
writer.write(String.format("FixedCS = %.1f", fixedCS));
writer.newLine();
writer.write(String.format("FixedHP = %.1f", fixedHP));
writer.newLine();
writer.write(String.format("FixedAR = %.1f", fixedAR));
writer.newLine();
writer.write(String.format("FixedOD = %.1f", fixedOD));
writer.newLine();
writer.close(); writer.close();
} catch (IOException e) { } catch (IOException e) {
Log.error(String.format("Failed to write to file '%s'.", OPTIONS_FILE.getAbsolutePath()), e); Log.error(String.format("Failed to write to file '%s'.", OPTIONS_FILE.getAbsolutePath()), e);