Merge branch 'master' into replaystuff
# Conflicts: # src/itdelatrisu/opsu/Options.java # src/itdelatrisu/opsu/ui/Cursor.java
This commit is contained in:
commit
3629dfd4d7
10
README.md
10
README.md
|
@ -1,4 +1,4 @@
|
||||||
#opsu!dance
|
# opsu!dance
|
||||||
[example video](https://www.youtube.com/watch?v=tqZqn7nx8N0)
|
[example video](https://www.youtube.com/watch?v=tqZqn7nx8N0)
|
||||||
|
|
||||||
Originally started as a fork of [opsu!](https://github.com/itdelatrisu/opsu) with cursordance stuff. I made a cursordancing bot in C# for osu!, and by adding it into this clone, it allows me to do even more stuff with it. This way I can also provide this client to other players so they can play with it too, as I will not give my bot to people because I don't want to endorse cheating in any way.
|
Originally started as a fork of [opsu!](https://github.com/itdelatrisu/opsu) with cursordance stuff. I made a cursordancing bot in C# for osu!, and by adding it into this clone, it allows me to do even more stuff with it. This way I can also provide this client to other players so they can play with it too, as I will not give my bot to people because I don't want to endorse cheating in any way.
|
||||||
|
@ -7,17 +7,17 @@ As of 2017 some major changes were made in this fork which changed the inner wor
|
||||||
|
|
||||||
My goal is to to add cool cursordancing things to this fork, but also make it possible to play the normal way.
|
My goal is to to add cool cursordancing things to this fork, but also make it possible to play the normal way.
|
||||||
|
|
||||||
###Downloads
|
### Downloads
|
||||||
Click on the releases link (scroll up) to go to the downloadpage with prebuilt jars.
|
Click on the releases link (scroll up) to go to the downloadpage with prebuilt jars.
|
||||||
|
|
||||||
###Building
|
### Building
|
||||||
You can find general (run/build) instructions in the original [opsu! README](README-OPSU.md).
|
You can find general (run/build) instructions in the original [opsu! README](README-OPSU.md).
|
||||||
Please note that I am only using maven, gradle scripts are not being updated.
|
Please note that I am only using maven, gradle scripts are not being updated.
|
||||||
|
|
||||||
###Credits
|
### Credits
|
||||||
opsu! was made by Jeffrey Han ([@itdelatrisu](https://github.com/itdelatrisu)). All game concepts and designs are based on work by osu! developer Dean Herbert. Other opsu! credits can be found [here](CREDITS.md).
|
opsu! was made by Jeffrey Han ([@itdelatrisu](https://github.com/itdelatrisu)). All game concepts and designs are based on work by osu! developer Dean Herbert. Other opsu! credits can be found [here](CREDITS.md).
|
||||||
opsu!dance (everything in the src package yugecin.opsudance) was made by me ([@yugecin](https://github.com/yugecin)). Edits were made in the opsu! sources, too.
|
opsu!dance (everything in the src package yugecin.opsudance) was made by me ([@yugecin](https://github.com/yugecin)). Edits were made in the opsu! sources, too.
|
||||||
|
|
||||||
###License
|
### License
|
||||||
**This software is licensed under GNU GPL version 3.**
|
**This software is licensed under GNU GPL version 3.**
|
||||||
You can find the full text of the license [here](LICENSE).
|
You can find the full text of the license [here](LICENSE).
|
||||||
|
|
|
@ -4,11 +4,11 @@ package awlex.ospu;
|
||||||
* Created by Awlex on 10.10.2016.
|
* Created by Awlex on 10.10.2016.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.objects.GameObject;
|
import itdelatrisu.opsu.objects.GameObject;
|
||||||
import itdelatrisu.opsu.objects.curves.Vec2f;
|
import itdelatrisu.opsu.objects.curves.Vec2f;
|
||||||
import org.newdawn.slick.Color;
|
import org.newdawn.slick.Color;
|
||||||
import org.newdawn.slick.Graphics;
|
import org.newdawn.slick.Graphics;
|
||||||
|
import yugecin.opsudance.options.Options;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is just a dummy {@link GameObject} to place in the middle of 2 GameObjects.
|
* This class is just a dummy {@link GameObject} to place in the middle of 2 GameObjects.
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
package awlex.ospu.movers;
|
package awlex.ospu.movers;
|
||||||
|
|
||||||
import awlex.ospu.FakeGameObject;
|
import awlex.ospu.FakeGameObject;
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.Utils;
|
import itdelatrisu.opsu.Utils;
|
||||||
import itdelatrisu.opsu.objects.GameObject;
|
import itdelatrisu.opsu.objects.GameObject;
|
||||||
import yugecin.opsudance.movers.Mover;
|
import yugecin.opsudance.movers.Mover;
|
||||||
import yugecin.opsudance.movers.factories.AutoMoverFactory;
|
import yugecin.opsudance.movers.factories.AutoMoverFactory;
|
||||||
|
import yugecin.opsudance.options.Options;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Alex Wieser on 09.10.2016.
|
* Created by Alex Wieser on 09.10.2016.
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package awlex.ospu.movers.factories;
|
package awlex.ospu.movers.factories;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.Utils;
|
import itdelatrisu.opsu.Utils;
|
||||||
import itdelatrisu.opsu.objects.GameObject;
|
import itdelatrisu.opsu.objects.GameObject;
|
||||||
import awlex.ospu.movers.CentralSpiralMover;
|
import awlex.ospu.movers.CentralSpiralMover;
|
||||||
|
@ -8,6 +7,7 @@ import awlex.ospu.movers.CombinedSpiralMover;
|
||||||
import yugecin.opsudance.movers.Mover;
|
import yugecin.opsudance.movers.Mover;
|
||||||
import awlex.ospu.movers.SpiralToMover;
|
import awlex.ospu.movers.SpiralToMover;
|
||||||
import yugecin.opsudance.movers.factories.MoverFactory;
|
import yugecin.opsudance.movers.factories.MoverFactory;
|
||||||
|
import yugecin.opsudance.options.Options;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Alex Wieser on 09.10.2016.
|
* Created by Alex Wieser on 09.10.2016.
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package awlex.ospu.spinners;
|
package awlex.ospu.spinners;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.Utils;
|
import itdelatrisu.opsu.Utils;
|
||||||
|
import yugecin.opsudance.options.Options;
|
||||||
import yugecin.opsudance.spinners.Spinner;
|
import yugecin.opsudance.spinners.Spinner;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -42,12 +42,25 @@ import org.newdawn.slick.Animation;
|
||||||
import org.newdawn.slick.Color;
|
import org.newdawn.slick.Color;
|
||||||
import org.newdawn.slick.Graphics;
|
import org.newdawn.slick.Graphics;
|
||||||
import org.newdawn.slick.Image;
|
import org.newdawn.slick.Image;
|
||||||
|
import yugecin.opsudance.core.inject.Inject;
|
||||||
|
import yugecin.opsudance.core.inject.InstanceContainer;
|
||||||
|
import yugecin.opsudance.options.Configuration;
|
||||||
|
import yugecin.opsudance.skinning.SkinService;
|
||||||
import yugecin.opsudance.utils.SlickUtil;
|
import yugecin.opsudance.utils.SlickUtil;
|
||||||
|
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds game data and renders all related elements.
|
* Holds game data and renders all related elements.
|
||||||
*/
|
*/
|
||||||
public class GameData {
|
public class GameData {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Configuration config;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private InstanceContainer instanceContainer;
|
||||||
|
|
||||||
/** Delta multiplier for steady HP drain. */
|
/** Delta multiplier for steady HP drain. */
|
||||||
public static final float HP_DRAIN_MULTIPLIER = 1 / 200f;
|
public static final float HP_DRAIN_MULTIPLIER = 1 / 200f;
|
||||||
|
|
||||||
|
@ -383,7 +396,7 @@ public class GameData {
|
||||||
hitResultCount[HIT_100K] = s.katu;
|
hitResultCount[HIT_100K] = s.katu;
|
||||||
hitResultCount[HIT_MISS] = s.miss;
|
hitResultCount[HIT_MISS] = s.miss;
|
||||||
this.replay = (s.replayString == null) ? null :
|
this.replay = (s.replayString == null) ? null :
|
||||||
new Replay(new File(Options.getReplayDir(), String.format("%s.osr", s.replayString)));
|
instanceContainer.injectFields(new Replay(new File(config.replayDir, String.format("%s.osr", s.replayString))));
|
||||||
|
|
||||||
loadImages();
|
loadImages();
|
||||||
}
|
}
|
||||||
|
@ -515,7 +528,7 @@ public class GameData {
|
||||||
if (digitWidth <= 1f) {
|
if (digitWidth <= 1f) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
digitWidth = (digitWidth - Options.getSkin().getHitCircleFontOverlap()) * scale;
|
digitWidth = (digitWidth - SkinService.skin.getHitCircleFontOverlap()) * scale;
|
||||||
float cx = x + ((length - 1) * (digitWidth / 2));
|
float cx = x + ((length - 1) * (digitWidth / 2));
|
||||||
|
|
||||||
for (int i = 0; i < length; i++) {
|
for (int i = 0; i < length; i++) {
|
||||||
|
@ -544,7 +557,7 @@ public class GameData {
|
||||||
Image digit = getScoreSymbolImage(c[i]);
|
Image digit = getScoreSymbolImage(c[i]);
|
||||||
if (scale != 1.0f)
|
if (scale != 1.0f)
|
||||||
digit = digit.getScaledCopy(scale);
|
digit = digit.getScaledCopy(scale);
|
||||||
cx -= digit.getWidth() + Options.getSkin().getScoreFontOverlap();
|
cx -= digit.getWidth() + SkinService.skin.getScoreFontOverlap();
|
||||||
digit.setAlpha(alpha);
|
digit.setAlpha(alpha);
|
||||||
digit.draw(cx, y);
|
digit.draw(cx, y);
|
||||||
digit.setAlpha(1f);
|
digit.setAlpha(1f);
|
||||||
|
@ -557,7 +570,7 @@ public class GameData {
|
||||||
digit.setAlpha(alpha);
|
digit.setAlpha(alpha);
|
||||||
digit.draw(cx, y);
|
digit.draw(cx, y);
|
||||||
digit.setAlpha(1f);
|
digit.setAlpha(1f);
|
||||||
cx += digit.getWidth() - Options.getSkin().getScoreFontOverlap();
|
cx += digit.getWidth() - SkinService.skin.getScoreFontOverlap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -679,7 +692,7 @@ public class GameData {
|
||||||
}
|
}
|
||||||
|
|
||||||
// hit error bar
|
// hit error bar
|
||||||
if (Options.isHitErrorBarEnabled() && !hitErrorList.isEmpty()) {
|
if (OPTION_SHOW_HIT_ERROR_BAR.state && !hitErrorList.isEmpty()) {
|
||||||
// fade out with last tick
|
// fade out with last tick
|
||||||
float hitErrorAlpha = 1f;
|
float hitErrorAlpha = 1f;
|
||||||
Color white = new Color(Color.white);
|
Color white = new Color(Color.white);
|
||||||
|
@ -914,10 +927,8 @@ public class GameData {
|
||||||
spinnerOsu.setAlpha(hitResult.alpha);
|
spinnerOsu.setAlpha(hitResult.alpha);
|
||||||
spinnerOsu.drawCentered(width / 2, height / 4);
|
spinnerOsu.drawCentered(width / 2, height / 4);
|
||||||
spinnerOsu.setAlpha(1f);
|
spinnerOsu.setAlpha(1f);
|
||||||
}
|
} else if (OPTION_SHOW_HIT_LIGHTING.state && !hitResult.hideResult && hitResult.result != HIT_MISS &&
|
||||||
|
|
||||||
// hit lighting
|
// hit lighting
|
||||||
else if (Options.isHitLightingEnabled() && !hitResult.hideResult && hitResult.result != HIT_MISS &&
|
|
||||||
hitResult.result != HIT_SLIDER30 && hitResult.result != HIT_SLIDER10) {
|
hitResult.result != HIT_SLIDER30 && hitResult.result != HIT_SLIDER10) {
|
||||||
// TODO: add particle system
|
// TODO: add particle system
|
||||||
Image lighting = GameImage.LIGHTING.getImage();
|
Image lighting = GameImage.LIGHTING.getImage();
|
||||||
|
@ -965,14 +976,14 @@ public class GameData {
|
||||||
private void drawHitAnimations(HitObjectResult hitResult, int trackPosition) {
|
private void drawHitAnimations(HitObjectResult hitResult, int trackPosition) {
|
||||||
// fade out slider curve
|
// fade out slider curve
|
||||||
if (hitResult.result != HIT_SLIDER_REPEAT && hitResult.result != HIT_SLIDER_REPEAT_M && hitResult.curve != null) {
|
if (hitResult.result != HIT_SLIDER_REPEAT && hitResult.result != HIT_SLIDER_REPEAT_M && hitResult.curve != null) {
|
||||||
if (!Options.isShrinkingSliders()) {
|
if (!OPTION_SHRINKING_SLIDERS.state) {
|
||||||
float progress = AnimationEquation.OUT_CUBIC.calc(
|
float progress = AnimationEquation.OUT_CUBIC.calc(
|
||||||
(float) Utils.clamp(trackPosition - hitResult.time, 0, HITCIRCLE_FADE_TIME) / HITCIRCLE_FADE_TIME);
|
(float) Utils.clamp(trackPosition - hitResult.time, 0, HITCIRCLE_FADE_TIME) / HITCIRCLE_FADE_TIME);
|
||||||
float alpha = 1f - progress;
|
float alpha = 1f - progress;
|
||||||
float oldWhiteAlpha = Colors.WHITE_FADE.a;
|
float oldWhiteAlpha = Colors.WHITE_FADE.a;
|
||||||
float oldColorAlpha = hitResult.color.a;
|
float oldColorAlpha = hitResult.color.a;
|
||||||
Colors.WHITE_FADE.a = hitResult.color.a = alpha;
|
Colors.WHITE_FADE.a = hitResult.color.a = alpha;
|
||||||
hitResult.curve.draw(hitResult.color);
|
hitResult.curve.draw(hitResult.color, (!OPTION_FALLBACK_SLIDERS.state && OPTION_MERGING_SLIDERS.state) ? 1 : 0, hitResult.curve.getCurvePoints().length);
|
||||||
Colors.WHITE_FADE.a = oldWhiteAlpha;
|
Colors.WHITE_FADE.a = oldWhiteAlpha;
|
||||||
hitResult.color.a = oldColorAlpha;
|
hitResult.color.a = oldColorAlpha;
|
||||||
}
|
}
|
||||||
|
@ -987,7 +998,7 @@ public class GameData {
|
||||||
fc.drawCentered(hitResult.x, hitResult.y);
|
fc.drawCentered(hitResult.x, hitResult.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Options.isDrawSliderEndCircles()) {
|
if (!OPTION_DRAW_SLIDER_ENDCIRCLES.state) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1024,7 +1035,7 @@ public class GameData {
|
||||||
}
|
}
|
||||||
scaledRepeat.rotate(ang);
|
scaledRepeat.rotate(ang);
|
||||||
scaledRepeat.drawCentered(hitResult.x, hitResult.y, hitResult.color);
|
scaledRepeat.drawCentered(hitResult.x, hitResult.y, hitResult.color);
|
||||||
if (!Options.isDrawSliderEndCircles()) {
|
if (!OPTION_DRAW_SLIDER_ENDCIRCLES.state) {
|
||||||
GameImage.HITCIRCLE.getImage().draw(-1000, -1000); // TODO this 'fixes' #114. Why? Get a better solution!
|
GameImage.HITCIRCLE.getImage().draw(-1000, -1000); // TODO this 'fixes' #114. Why? Get a better solution!
|
||||||
GameImage.HITCIRCLE_OVERLAY.getImage().draw(-1000, -1000);
|
GameImage.HITCIRCLE_OVERLAY.getImage().draw(-1000, -1000);
|
||||||
return;
|
return;
|
||||||
|
@ -1186,7 +1197,7 @@ public class GameData {
|
||||||
}
|
}
|
||||||
|
|
||||||
// combo burst
|
// combo burst
|
||||||
if (comboBurstIndex > -1 && Options.isComboBurstEnabled()) {
|
if (comboBurstIndex > -1 && OPTION_SHOW_COMBO_BURSTS.state) {
|
||||||
int leftX = 0;
|
int leftX = 0;
|
||||||
int rightX = width - comboBurstImages[comboBurstIndex].getWidth();
|
int rightX = width - comboBurstImages[comboBurstIndex].getWidth();
|
||||||
if (comboBurstX < leftX) {
|
if (comboBurstX < leftX) {
|
||||||
|
@ -1210,7 +1221,7 @@ public class GameData {
|
||||||
comboPopTime = COMBO_POP_TIME;
|
comboPopTime = COMBO_POP_TIME;
|
||||||
|
|
||||||
// hit error bar
|
// hit error bar
|
||||||
if (Options.isHitErrorBarEnabled()) {
|
if (OPTION_SHOW_HIT_ERROR_BAR.state) {
|
||||||
int trackPosition = MusicController.getPosition();
|
int trackPosition = MusicController.getPosition();
|
||||||
Iterator<HitErrorInfo> iter = hitErrorList.iterator();
|
Iterator<HitErrorInfo> iter = hitErrorList.iterator();
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
|
@ -1237,23 +1248,24 @@ public class GameData {
|
||||||
comboMax = combo;
|
comboMax = combo;
|
||||||
|
|
||||||
// combo bursts (at 30, 60, 100+50x)
|
// combo bursts (at 30, 60, 100+50x)
|
||||||
if (Options.isComboBurstEnabled() &&
|
if (OPTION_SHOW_COMBO_BURSTS.state && (combo == 30 || combo == 60 || (combo >= 100 && combo % 50 == 0))) {
|
||||||
(combo == 30 || combo == 60 || (combo >= 100 && combo % 50 == 0))) {
|
if (SkinService.skin.isComboBurstRandom()) {
|
||||||
if (Options.getSkin().isComboBurstRandom())
|
|
||||||
comboBurstIndex = (int) (Math.random() * comboBurstImages.length);
|
comboBurstIndex = (int) (Math.random() * comboBurstImages.length);
|
||||||
else {
|
} else {
|
||||||
if (combo == 30)
|
if (combo == 30) {
|
||||||
comboBurstIndex = 0;
|
comboBurstIndex = 0;
|
||||||
else
|
} else {
|
||||||
comboBurstIndex = (comboBurstIndex + 1) % comboBurstImages.length;
|
comboBurstIndex = (comboBurstIndex + 1) % comboBurstImages.length;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
comboBurstAlpha = 0.8f;
|
comboBurstAlpha = 0.8f;
|
||||||
if ((comboBurstIndex % 2) == 0)
|
if ((comboBurstIndex % 2) == 0) {
|
||||||
comboBurstX = width;
|
comboBurstX = width;
|
||||||
else
|
} else {
|
||||||
comboBurstX = comboBurstImages[0].getWidth() * -1;
|
comboBurstX = comboBurstImages[0].getWidth() * -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resets the combo streak to zero.
|
* Resets the combo streak to zero.
|
||||||
|
@ -1277,7 +1289,7 @@ public class GameData {
|
||||||
*/
|
*/
|
||||||
public void sendSliderRepeatResult(int time, float x, float y, Color color, Curve curve, HitObjectType type) {
|
public void sendSliderRepeatResult(int time, float x, float y, Color color, Curve curve, HitObjectType type) {
|
||||||
hitResultList.add(new HitObjectResult(time, HIT_SLIDER_REPEAT, x, y, color, type, curve, true, true));
|
hitResultList.add(new HitObjectResult(time, HIT_SLIDER_REPEAT, x, y, color, type, curve, true, true));
|
||||||
if (!Options.isMirror()) {
|
if (!OPTION_DANCE_MIRROR.state) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
float[] m = Utils.mirrorPoint(x, y);
|
float[] m = Utils.mirrorPoint(x, y);
|
||||||
|
@ -1294,7 +1306,7 @@ public class GameData {
|
||||||
*/
|
*/
|
||||||
public void sendSliderStartResult(int time, float x, float y, Color color, Color mirrorColor, boolean expand) {
|
public void sendSliderStartResult(int time, float x, float y, Color color, Color mirrorColor, boolean expand) {
|
||||||
hitResultList.add(new HitObjectResult(time, HIT_ANIMATION_RESULT, x, y, color, HitObjectType.CIRCLE, null, expand, true));
|
hitResultList.add(new HitObjectResult(time, HIT_ANIMATION_RESULT, x, y, color, HitObjectType.CIRCLE, null, expand, true));
|
||||||
if (!Options.isMirror()) {
|
if (!OPTION_DANCE_MIRROR.state) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
float[] m = Utils.mirrorPoint(x, y);
|
float[] m = Utils.mirrorPoint(x, y);
|
||||||
|
@ -1338,11 +1350,10 @@ public class GameData {
|
||||||
score += hitValue;
|
score += hitValue;
|
||||||
incrementComboStreak();
|
incrementComboStreak();
|
||||||
|
|
||||||
if (!Options.isPerfectHitBurstEnabled())
|
if (OPTION_SHOW_PERFECT_HIT.state) {
|
||||||
; // hide perfect hit results
|
|
||||||
else
|
|
||||||
hitResultList.add(new HitObjectResult(time, result, x, y, null, HitObjectType.SLIDERTICK, null, false, false));
|
hitResultList.add(new HitObjectResult(time, result, x, y, null, HitObjectType.SLIDERTICK, null, false, false));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
fullObjectCount++;
|
fullObjectCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1527,7 +1538,7 @@ public class GameData {
|
||||||
if (hitResult == HIT_MISS && (GameMod.RELAX.isActive() || GameMod.AUTOPILOT.isActive()))
|
if (hitResult == HIT_MISS && (GameMod.RELAX.isActive() || GameMod.AUTOPILOT.isActive()))
|
||||||
return; // "relax" and "autopilot" mods: hide misses
|
return; // "relax" and "autopilot" mods: hide misses
|
||||||
|
|
||||||
boolean hideResult = (hitResult == HIT_300 || hitResult == HIT_300G || hitResult == HIT_300K) && !Options.isPerfectHitBurstEnabled();
|
boolean hideResult = (hitResult == HIT_300 || hitResult == HIT_300G || hitResult == HIT_300K) && !OPTION_SHOW_PERFECT_HIT.state;
|
||||||
hitResultList.add(new HitObjectResult(time, hitResult, x, y, color, hitResultType, curve, expand, hideResult));
|
hitResultList.add(new HitObjectResult(time, hitResult, x, y, color, hitResultType, curve, expand, hideResult));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,8 +32,11 @@ import org.newdawn.slick.util.ResourceLoader;
|
||||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||||
import yugecin.opsudance.core.events.EventBus;
|
import yugecin.opsudance.core.events.EventBus;
|
||||||
import yugecin.opsudance.events.BubbleNotificationEvent;
|
import yugecin.opsudance.events.BubbleNotificationEvent;
|
||||||
|
import yugecin.opsudance.skinning.SkinService;
|
||||||
import yugecin.opsudance.utils.SlickUtil;
|
import yugecin.opsudance.utils.SlickUtil;
|
||||||
|
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Game images.
|
* Game images.
|
||||||
*/
|
*/
|
||||||
|
@ -546,7 +549,7 @@ public enum GameImage {
|
||||||
* and UI scale.
|
* and UI scale.
|
||||||
*/
|
*/
|
||||||
private static String[] getSuffixes() {
|
private static String[] getSuffixes() {
|
||||||
return (Options.loadHDImages() && uiscale >= 1) ? SUFFIXES_HD : SUFFIXES_SD;
|
return (OPTION_LOAD_HD_IMAGES.state && uiscale >= 1) ? SUFFIXES_HD : SUFFIXES_SD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -687,11 +690,12 @@ public enum GameImage {
|
||||||
* If the default image has already been loaded, this will do nothing.
|
* If the default image has already been loaded, this will do nothing.
|
||||||
*/
|
*/
|
||||||
public void setDefaultImage() {
|
public void setDefaultImage() {
|
||||||
if (defaultImage != null || defaultImages != null || Options.getSkin() == null)
|
if (defaultImage != null || defaultImages != null || SkinService.skin == null) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// try to load skin images
|
// try to load skin images
|
||||||
File skinDir = Options.getSkin().getDirectory();
|
File skinDir = SkinService.skin.getDirectory();
|
||||||
if (filenameFormat != null) {
|
if (filenameFormat != null) {
|
||||||
if (skinDir != null && ((defaultImages = loadImageArray(skinDir)) != null)) {
|
if (skinDir != null && ((defaultImages = loadImageArray(skinDir)) != null)) {
|
||||||
isSkinned = true;
|
isSkinned = true;
|
||||||
|
@ -739,15 +743,17 @@ public enum GameImage {
|
||||||
* @return true if a new skin image is loaded, false otherwise
|
* @return true if a new skin image is loaded, false otherwise
|
||||||
*/
|
*/
|
||||||
public boolean setBeatmapSkinImage(File dir) {
|
public boolean setBeatmapSkinImage(File dir) {
|
||||||
if (dir == null)
|
if (dir == null) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// destroy the existing images, if any
|
// destroy the existing images, if any
|
||||||
destroyBeatmapSkinImage();
|
destroyBeatmapSkinImage();
|
||||||
|
|
||||||
// beatmap skins disabled
|
// beatmap skins disabled
|
||||||
if (Options.isBeatmapSkinIgnored())
|
if (OPTION_IGNORE_BEATMAP_SKINS.state) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// try to load multiple images
|
// try to load multiple images
|
||||||
if ((skinImages = loadImageArray(dir)) != null) {
|
if ((skinImages = loadImageArray(dir)) != null) {
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -18,17 +18,8 @@
|
||||||
|
|
||||||
package itdelatrisu.opsu;
|
package itdelatrisu.opsu;
|
||||||
|
|
||||||
import itdelatrisu.opsu.audio.MusicController;
|
|
||||||
import itdelatrisu.opsu.audio.SoundController;
|
|
||||||
import itdelatrisu.opsu.audio.SoundEffect;
|
|
||||||
import itdelatrisu.opsu.beatmap.HitObject;
|
|
||||||
import itdelatrisu.opsu.downloads.Download;
|
import itdelatrisu.opsu.downloads.Download;
|
||||||
import itdelatrisu.opsu.downloads.DownloadNode;
|
|
||||||
import itdelatrisu.opsu.replay.PlaybackSpeed;
|
|
||||||
import itdelatrisu.opsu.ui.Fonts;
|
|
||||||
import itdelatrisu.opsu.ui.UI;
|
|
||||||
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.io.BufferedInputStream;
|
import java.io.BufferedInputStream;
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -41,18 +32,13 @@ import java.net.HttpURLConnection;
|
||||||
import java.net.SocketTimeoutException;
|
import java.net.SocketTimeoutException;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
import java.util.jar.JarFile;
|
import java.util.jar.JarFile;
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
import javax.net.ssl.HttpsURLConnection;
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
import javax.net.ssl.TrustManager;
|
import javax.net.ssl.TrustManager;
|
||||||
|
@ -61,21 +47,15 @@ import javax.net.ssl.X509TrustManager;
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import org.lwjgl.BufferUtils;
|
import org.lwjgl.input.Keyboard;
|
||||||
import org.lwjgl.opengl.Display;
|
|
||||||
import org.lwjgl.opengl.GL11;
|
|
||||||
import org.newdawn.slick.Animation;
|
import org.newdawn.slick.Animation;
|
||||||
import org.newdawn.slick.Color;
|
import org.newdawn.slick.Color;
|
||||||
import org.newdawn.slick.GameContainer;
|
|
||||||
import org.newdawn.slick.Input;
|
|
||||||
import org.newdawn.slick.state.StateBasedGame;
|
|
||||||
import org.newdawn.slick.util.Log;
|
import org.newdawn.slick.util.Log;
|
||||||
|
|
||||||
import com.sun.jna.platform.FileUtils;
|
import com.sun.jna.platform.FileUtils;
|
||||||
import yugecin.opsudance.core.DisplayContainer;
|
import yugecin.opsudance.core.DisplayContainer;
|
||||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||||
import yugecin.opsudance.core.events.EventBus;
|
import yugecin.opsudance.options.Options;
|
||||||
import yugecin.opsudance.events.BubbleNotificationEvent;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains miscellaneous utilities.
|
* Contains miscellaneous utilities.
|
||||||
|
@ -104,32 +84,6 @@ public class Utils {
|
||||||
// TODO clean this up
|
// TODO clean this up
|
||||||
|
|
||||||
// game settings
|
// game settings
|
||||||
displayContainer.setFPS(Options.getTargetFPS()); // TODO move this elsewhere
|
|
||||||
MusicController.setMusicVolume(Options.getMusicVolume() * Options.getMasterVolume());
|
|
||||||
|
|
||||||
// load skin
|
|
||||||
Options.loadSkin();
|
|
||||||
|
|
||||||
// initialize game images
|
|
||||||
for (GameImage img : GameImage.values()) {
|
|
||||||
if (img.isPreload())
|
|
||||||
img.setDefaultImage();
|
|
||||||
}
|
|
||||||
|
|
||||||
// initialize game mods
|
|
||||||
GameMod.init(displayContainer.width, displayContainer.height);
|
|
||||||
|
|
||||||
// initialize playback buttons
|
|
||||||
PlaybackSpeed.init(displayContainer.width, displayContainer.height);
|
|
||||||
|
|
||||||
// initialize hit objects
|
|
||||||
HitObject.init(displayContainer.width, displayContainer.height);
|
|
||||||
|
|
||||||
// initialize download nodes
|
|
||||||
DownloadNode.init(displayContainer.width, displayContainer.height);
|
|
||||||
|
|
||||||
// initialize UI components
|
|
||||||
UI.init(displayContainer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -240,55 +194,6 @@ public class Utils {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Takes a screenshot.
|
|
||||||
* @author http://wiki.lwjgl.org/index.php?title=Taking_Screen_Shots
|
|
||||||
*/
|
|
||||||
public static void takeScreenShot() {
|
|
||||||
// create the screenshot directory
|
|
||||||
File dir = Options.getScreenshotDir();
|
|
||||||
if (!dir.isDirectory() && !dir.mkdir()) {
|
|
||||||
EventBus.post(new BubbleNotificationEvent(String.format("Failed to create screenshot directory at '%s'.", dir.getAbsolutePath()), BubbleNotificationEvent.COMMONCOLOR_RED));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// create file name
|
|
||||||
SimpleDateFormat date = new SimpleDateFormat("yyyyMMdd_HHmmss");
|
|
||||||
final String fileName = String.format("screenshot_%s.%s", date.format(new Date()), Options.getScreenshotFormat());
|
|
||||||
final File file = new File(dir, fileName);
|
|
||||||
|
|
||||||
SoundController.playSound(SoundEffect.SHUTTER);
|
|
||||||
|
|
||||||
// copy the screen to file
|
|
||||||
final int width = Display.getWidth();
|
|
||||||
final int height = Display.getHeight();
|
|
||||||
final int bpp = 3; // assuming a 32-bit display with a byte each for red, green, blue, and alpha
|
|
||||||
final ByteBuffer buffer = BufferUtils.createByteBuffer(width * height * bpp);
|
|
||||||
GL11.glReadBuffer(GL11.GL_FRONT);
|
|
||||||
GL11.glPixelStorei(GL11.GL_PACK_ALIGNMENT, 1);
|
|
||||||
GL11.glReadPixels(0, 0, width, height, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, buffer);
|
|
||||||
new Thread() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
|
||||||
for (int x = 0; x < width; x++) {
|
|
||||||
for (int y = 0; y < height; y++) {
|
|
||||||
int i = (x + (width * y)) * bpp;
|
|
||||||
int r = buffer.get(i) & 0xFF;
|
|
||||||
int g = buffer.get(i + 1) & 0xFF;
|
|
||||||
int b = buffer.get(i + 2) & 0xFF;
|
|
||||||
image.setRGB(x, height - (y + 1), (0xFF << 24) | (r << 16) | (g << 8) | b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ImageIO.write(image, Options.getScreenshotFormat(), file);
|
|
||||||
EventBus.post(new BubbleNotificationEvent("Created " + fileName, BubbleNotificationEvent.COMMONCOLOR_PURPLE));
|
|
||||||
} catch (Exception e) {
|
|
||||||
ErrorHandler.error("Failed to take a screenshot.", e).show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a human-readable representation of a given number of bytes.
|
* Returns a human-readable representation of a given number of bytes.
|
||||||
|
@ -550,14 +455,6 @@ public class Utils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the current working directory.
|
|
||||||
* @return the directory
|
|
||||||
*/
|
|
||||||
public static File getWorkingDirectory() {
|
|
||||||
return Paths.get(".").toAbsolutePath().normalize().toFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the integer string argument as a boolean:
|
* Parses the integer string argument as a boolean:
|
||||||
* {@code 1} is {@code true}, and all other values are {@code false}.
|
* {@code 1} is {@code true}, and all other values are {@code false}.
|
||||||
|
@ -661,4 +558,19 @@ public class Utils {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the file extension of a file.
|
||||||
|
* @param file the file name
|
||||||
|
*/
|
||||||
|
public static String getFileExtension(String file) {
|
||||||
|
int i = file.lastIndexOf('.');
|
||||||
|
return (i != -1) ? file.substring(i + 1).toLowerCase() : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isValidGameKey(int key) {
|
||||||
|
return (key != Keyboard.KEY_ESCAPE && key != Keyboard.KEY_SPACE &&
|
||||||
|
key != Keyboard.KEY_UP && key != Keyboard.KEY_DOWN &&
|
||||||
|
key != Keyboard.KEY_F7 && key != Keyboard.KEY_F10 && key != Keyboard.KEY_F12);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,9 +18,8 @@
|
||||||
|
|
||||||
package itdelatrisu.opsu.audio;
|
package itdelatrisu.opsu.audio;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
import itdelatrisu.opsu.Utils;
|
||||||
import itdelatrisu.opsu.beatmap.Beatmap;
|
import itdelatrisu.opsu.beatmap.Beatmap;
|
||||||
import itdelatrisu.opsu.beatmap.BeatmapParser;
|
|
||||||
import itdelatrisu.opsu.beatmap.TimingPoint;
|
import itdelatrisu.opsu.beatmap.TimingPoint;
|
||||||
import itdelatrisu.opsu.states.Game;
|
import itdelatrisu.opsu.states.Game;
|
||||||
|
|
||||||
|
@ -50,6 +49,8 @@ import yugecin.opsudance.core.events.EventBus;
|
||||||
import yugecin.opsudance.events.BarNotificationEvent;
|
import yugecin.opsudance.events.BarNotificationEvent;
|
||||||
import yugecin.opsudance.events.BubbleNotificationEvent;
|
import yugecin.opsudance.events.BubbleNotificationEvent;
|
||||||
|
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller for all music.
|
* Controller for all music.
|
||||||
*/
|
*/
|
||||||
|
@ -109,7 +110,7 @@ public class MusicController {
|
||||||
reset();
|
reset();
|
||||||
System.gc();
|
System.gc();
|
||||||
|
|
||||||
switch (BeatmapParser.getExtension(beatmap.audioFilename.getName())) {
|
switch (Utils.getFileExtension(beatmap.audioFilename.getName())) {
|
||||||
case "ogg":
|
case "ogg":
|
||||||
case "mp3":
|
case "mp3":
|
||||||
trackLoader = new Thread() {
|
trackLoader = new Thread() {
|
||||||
|
@ -168,7 +169,7 @@ public class MusicController {
|
||||||
*/
|
*/
|
||||||
public static void playAt(final int position, final boolean loop) {
|
public static void playAt(final int position, final boolean loop) {
|
||||||
if (trackExists()) {
|
if (trackExists()) {
|
||||||
setVolume(Options.getMusicVolume() * Options.getMasterVolume());
|
setVolume(OPTION_MUSIC_VOLUME.val / 100f * OPTION_MASTER_VOLUME.val / 100f);
|
||||||
trackEnded = false;
|
trackEnded = false;
|
||||||
pauseTime = 0f;
|
pauseTime = 0f;
|
||||||
resetTimingPoint();
|
resetTimingPoint();
|
||||||
|
@ -348,9 +349,9 @@ public class MusicController {
|
||||||
*/
|
*/
|
||||||
public static int getPosition() {
|
public static int getPosition() {
|
||||||
if (isPlaying())
|
if (isPlaying())
|
||||||
return (int) (player.getPosition() * 1000 + Options.getMusicOffset() + Game.currentMapMusicOffset);
|
return (int) (player.getPosition() * 1000 + OPTION_MUSIC_OFFSET.val + Game.currentMapMusicOffset);
|
||||||
else if (isPaused())
|
else if (isPaused())
|
||||||
return Math.max((int) (pauseTime * 1000 + Options.getMusicOffset() + Game.currentMapMusicOffset), 0);
|
return Math.max((int) (pauseTime * 1000 + OPTION_MUSIC_OFFSET.val + Game.currentMapMusicOffset), 0);
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -443,13 +444,9 @@ public class MusicController {
|
||||||
playAt((preview) ? lastBeatmap.previewTime : 0, false);
|
playAt((preview) ? lastBeatmap.previewTime : 0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public static void playThemeSong(Beatmap themeBeatmap) {
|
||||||
* Plays the theme song.
|
if (themeBeatmap != null) {
|
||||||
*/
|
play(themeBeatmap, false, false);
|
||||||
public static void playThemeSong() {
|
|
||||||
Beatmap beatmap = Options.getThemeBeatmap();
|
|
||||||
if (beatmap != null) {
|
|
||||||
play(beatmap, false, false);
|
|
||||||
themePlaying = true;
|
themePlaying = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -470,7 +467,7 @@ public class MusicController {
|
||||||
* @param multiplier the volume multiplier when the track is dimmed
|
* @param multiplier the volume multiplier when the track is dimmed
|
||||||
*/
|
*/
|
||||||
public static void toggleTrackDimmed(float multiplier) {
|
public static void toggleTrackDimmed(float multiplier) {
|
||||||
float volume = Options.getMusicVolume() * Options.getMasterVolume();
|
float volume = OPTION_MUSIC_VOLUME.val / 100f * OPTION_MASTER_VOLUME.val / 100f;
|
||||||
dimLevel = (isTrackDimmed()) ? 1f : multiplier;
|
dimLevel = (isTrackDimmed()) ? 1f : multiplier;
|
||||||
trackDimmed = !trackDimmed;
|
trackDimmed = !trackDimmed;
|
||||||
setVolume(volume);
|
setVolume(volume);
|
||||||
|
|
|
@ -18,12 +18,10 @@
|
||||||
|
|
||||||
package itdelatrisu.opsu.audio;
|
package itdelatrisu.opsu.audio;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.audio.HitSound.SampleSet;
|
import itdelatrisu.opsu.audio.HitSound.SampleSet;
|
||||||
import itdelatrisu.opsu.beatmap.HitObject;
|
import itdelatrisu.opsu.beatmap.HitObject;
|
||||||
import itdelatrisu.opsu.downloads.Download;
|
import itdelatrisu.opsu.downloads.Download;
|
||||||
import itdelatrisu.opsu.downloads.Download.DownloadListener;
|
import itdelatrisu.opsu.downloads.Download.DownloadListener;
|
||||||
import itdelatrisu.opsu.ui.UI;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -44,6 +42,10 @@ import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||||
import yugecin.opsudance.core.events.EventBus;
|
import yugecin.opsudance.core.events.EventBus;
|
||||||
import yugecin.opsudance.events.BarNotificationEvent;
|
import yugecin.opsudance.events.BarNotificationEvent;
|
||||||
import yugecin.opsudance.events.BubbleNotificationEvent;
|
import yugecin.opsudance.events.BubbleNotificationEvent;
|
||||||
|
import yugecin.opsudance.options.Configuration;
|
||||||
|
import yugecin.opsudance.skinning.SkinService;
|
||||||
|
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller for all (non-music) sound components.
|
* Controller for all (non-music) sound components.
|
||||||
|
@ -190,7 +192,7 @@ public class SoundController {
|
||||||
*/
|
*/
|
||||||
private static String getSoundFileName(String filename) {
|
private static String getSoundFileName(String filename) {
|
||||||
String wav = String.format("%s.wav", filename), mp3 = String.format("%s.mp3", filename);
|
String wav = String.format("%s.wav", filename), mp3 = String.format("%s.mp3", filename);
|
||||||
File skinDir = Options.getSkin().getDirectory();
|
File skinDir = SkinService.skin.getDirectory();
|
||||||
if (skinDir != null) {
|
if (skinDir != null) {
|
||||||
File skinWAV = new File(skinDir, wav), skinMP3 = new File(skinDir, mp3);
|
File skinWAV = new File(skinDir, wav), skinMP3 = new File(skinDir, mp3);
|
||||||
if (skinWAV.isFile())
|
if (skinWAV.isFile())
|
||||||
|
@ -209,8 +211,9 @@ public class SoundController {
|
||||||
* Loads all sound files.
|
* Loads all sound files.
|
||||||
*/
|
*/
|
||||||
public static void init() {
|
public static void init() {
|
||||||
if (Options.isSoundDisabled())
|
if (OPTION_DISABLE_SOUNDS.state) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
currentFileIndex = 0;
|
currentFileIndex = 0;
|
||||||
|
|
||||||
|
@ -290,7 +293,7 @@ public class SoundController {
|
||||||
* @param s the sound effect
|
* @param s the sound effect
|
||||||
*/
|
*/
|
||||||
public static void playSound(SoundComponent s) {
|
public static void playSound(SoundComponent s) {
|
||||||
playClip(s.getClip(), Options.getEffectVolume() * Options.getMasterVolume(), null);
|
playClip(s.getClip(), OPTION_EFFECT_VOLUME.val / 100f * OPTION_MASTER_VOLUME.val / 100f, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -303,16 +306,16 @@ public class SoundController {
|
||||||
if (hitSound < 0)
|
if (hitSound < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Options.getSampleVolumeOverride() > 0) {
|
if (OPTION_SAMPLE_VOLUME_OVERRIDE.val > 0) {
|
||||||
sampleVolumeMultiplier = Options.getSampleVolumeOverride();
|
sampleVolumeMultiplier = OPTION_SAMPLE_VOLUME_OVERRIDE.val / 100f;
|
||||||
}
|
}
|
||||||
|
|
||||||
float volume = Options.getHitSoundVolume() * sampleVolumeMultiplier * Options.getMasterVolume();
|
float volume = OPTION_HITSOUND_VOLUME.val / 100f * sampleVolumeMultiplier * OPTION_MASTER_VOLUME.val / 100f;
|
||||||
if (volume == 0f)
|
if (volume == 0f)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// play all sounds
|
// play all sounds
|
||||||
if (hitSound == HitObject.SOUND_NORMAL || Options.getSkin().isLayeredHitSounds()) {
|
if (hitSound == HitObject.SOUND_NORMAL || SkinService.skin.isLayeredHitSounds()) {
|
||||||
HitSound.setSampleSet(sampleSet);
|
HitSound.setSampleSet(sampleSet);
|
||||||
playClip(HitSound.NORMAL.getClip(), volume, null);
|
playClip(HitSound.NORMAL.getClip(), volume, null);
|
||||||
}
|
}
|
||||||
|
@ -333,7 +336,7 @@ public class SoundController {
|
||||||
* @param s the hit sound
|
* @param s the hit sound
|
||||||
*/
|
*/
|
||||||
public static void playHitSound(SoundComponent s) {
|
public static void playHitSound(SoundComponent s) {
|
||||||
playClip(s.getClip(), Options.getHitSoundVolume() * sampleVolumeMultiplier * Options.getMasterVolume(), null);
|
playClip(s.getClip(), OPTION_HITSOUND_VOLUME.val / 100f * sampleVolumeMultiplier * OPTION_MASTER_VOLUME.val / 100f, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -370,15 +373,16 @@ public class SoundController {
|
||||||
* @return true if playing, false otherwise
|
* @return true if playing, false otherwise
|
||||||
* @throws SlickException if any error occurred
|
* @throws SlickException if any error occurred
|
||||||
*/
|
*/
|
||||||
public static synchronized boolean playTrack(String url, String name, boolean isMP3, LineListener listener)
|
public static synchronized boolean playTrack(Configuration config, String url, String name, boolean isMP3, LineListener listener)
|
||||||
throws SlickException {
|
throws SlickException {
|
||||||
// stop previous track
|
// stop previous track
|
||||||
stopTrack();
|
stopTrack();
|
||||||
|
|
||||||
// download new track
|
// download new track
|
||||||
File dir = Options.TEMP_DIR;
|
File dir = config.TEMP_DIR;
|
||||||
if (!dir.isDirectory())
|
if (!dir.isDirectory()) {
|
||||||
dir.mkdir();
|
dir.mkdir();
|
||||||
|
}
|
||||||
String filename = String.format("%s.%s", name, isMP3 ? "mp3" : "wav");
|
String filename = String.format("%s.%s", name, isMP3 ? "mp3" : "wav");
|
||||||
final File downloadFile = new File(dir, filename);
|
final File downloadFile = new File(dir, filename);
|
||||||
boolean complete;
|
boolean complete;
|
||||||
|
@ -406,7 +410,7 @@ public class SoundController {
|
||||||
try {
|
try {
|
||||||
AudioInputStream audioIn = AudioSystem.getAudioInputStream(downloadFile);
|
AudioInputStream audioIn = AudioSystem.getAudioInputStream(downloadFile);
|
||||||
currentTrack = loadClip(filename, audioIn, isMP3);
|
currentTrack = loadClip(filename, audioIn, isMP3);
|
||||||
playClip(currentTrack, Options.getMusicVolume() * Options.getMasterVolume(), listener);
|
playClip(currentTrack, OPTION_MUSIC_VOLUME.val / 100f * OPTION_MASTER_VOLUME.val / 100f, listener);
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new SlickException(String.format("Failed to load clip '%s'.", url));
|
throw new SlickException(String.format("Failed to load clip '%s'.", url));
|
||||||
|
|
|
@ -18,8 +18,6 @@
|
||||||
|
|
||||||
package itdelatrisu.opsu.beatmap;
|
package itdelatrisu.opsu.beatmap;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
@ -30,6 +28,8 @@ import org.newdawn.slick.Color;
|
||||||
import org.newdawn.slick.Image;
|
import org.newdawn.slick.Image;
|
||||||
import org.newdawn.slick.util.Log;
|
import org.newdawn.slick.util.Log;
|
||||||
|
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Beatmap structure storing data parsed from OSU files.
|
* Beatmap structure storing data parsed from OSU files.
|
||||||
*/
|
*/
|
||||||
|
@ -264,7 +264,7 @@ public class Beatmap implements Comparable<Beatmap> {
|
||||||
* @return the song title
|
* @return the song title
|
||||||
*/
|
*/
|
||||||
public String getTitle() {
|
public String getTitle() {
|
||||||
return (Options.useUnicodeMetadata() && !titleUnicode.isEmpty()) ? titleUnicode : title;
|
return (OPTION_SHOW_UNICODE.state && !titleUnicode.isEmpty()) ? titleUnicode : title;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -273,25 +273,23 @@ public class Beatmap implements Comparable<Beatmap> {
|
||||||
* @return the song artist
|
* @return the song artist
|
||||||
*/
|
*/
|
||||||
public String getArtist() {
|
public String getArtist() {
|
||||||
return (Options.useUnicodeMetadata() && !artistUnicode.isEmpty()) ? artistUnicode : artist;
|
return (OPTION_SHOW_UNICODE.state && !artistUnicode.isEmpty()) ? artistUnicode : artist;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the list of combo colors (max 8).
|
* Returns the list of combo colors (max 8).
|
||||||
* If the beatmap does not provide colors, the skin colors will be returned instead.
|
* @return the combo colors, or null if this beatmap does not have combo colors specified.
|
||||||
* @return the combo colors
|
|
||||||
*/
|
*/
|
||||||
public Color[] getComboColors() {
|
public Color[] getComboColors() {
|
||||||
return (combo != null) ? combo : Options.getSkin().getComboColors();
|
return combo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the slider border color.
|
* Returns the slider border color.
|
||||||
* If the beatmap does not provide a color, the skin color will be returned instead.
|
* @return the slider border color, or null if this beatmap does not have a slider border color specified.
|
||||||
* @return the slider border color
|
|
||||||
*/
|
*/
|
||||||
public Color getSliderBorderColor() {
|
public Color getSliderBorderColor() {
|
||||||
return (sliderBorder != null) ? sliderBorder : Options.getSkin().getSliderBorderColor();
|
return sliderBorder;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
|
|
||||||
package itdelatrisu.opsu.beatmap;
|
package itdelatrisu.opsu.beatmap;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.Utils;
|
import itdelatrisu.opsu.Utils;
|
||||||
import itdelatrisu.opsu.db.BeatmapDB;
|
import itdelatrisu.opsu.db.BeatmapDB;
|
||||||
import itdelatrisu.opsu.io.MD5InputStreamWrapper;
|
import itdelatrisu.opsu.io.MD5InputStreamWrapper;
|
||||||
|
@ -36,55 +35,69 @@ import org.newdawn.slick.Color;
|
||||||
import org.newdawn.slick.util.Log;
|
import org.newdawn.slick.util.Log;
|
||||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||||
import yugecin.opsudance.core.events.EventBus;
|
import yugecin.opsudance.core.events.EventBus;
|
||||||
import yugecin.opsudance.events.BarNotificationEvent;
|
import yugecin.opsudance.core.inject.Inject;
|
||||||
|
import yugecin.opsudance.core.inject.InstanceContainer;
|
||||||
import yugecin.opsudance.events.BubbleNotificationEvent;
|
import yugecin.opsudance.events.BubbleNotificationEvent;
|
||||||
|
import yugecin.opsudance.options.Configuration;
|
||||||
|
import yugecin.opsudance.skinning.SkinService;
|
||||||
|
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parser for beatmaps.
|
* Parser for beatmaps.
|
||||||
*/
|
*/
|
||||||
public class BeatmapParser {
|
public class BeatmapParser {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private InstanceContainer instanceContainer;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Configuration config;
|
||||||
|
|
||||||
/** The string lookup database. */
|
/** The string lookup database. */
|
||||||
private static HashMap<String, String> stringdb = new HashMap<String, String>();
|
private static HashMap<String, String> stringdb = new HashMap<String, String>();
|
||||||
|
|
||||||
/** The expected pattern for beatmap directories, used to find beatmap set IDs. */
|
/** The expected pattern for beatmap directories, used to find beatmap set IDs. */
|
||||||
private static final String DIR_MSID_PATTERN = "^\\d+ .*";
|
private final String DIR_MSID_PATTERN = "^\\d+ .*";
|
||||||
|
|
||||||
/** The current file being parsed. */
|
/** The current file being parsed. */
|
||||||
private static File currentFile;
|
private File currentFile;
|
||||||
|
|
||||||
/** The current directory number while parsing. */
|
/** The current directory number while parsing. */
|
||||||
private static int currentDirectoryIndex = -1;
|
private int currentDirectoryIndex = -1;
|
||||||
|
|
||||||
/** The total number of directories to parse. */
|
/** The total number of directories to parse. */
|
||||||
private static int totalDirectories = -1;
|
private int totalDirectories = -1;
|
||||||
|
|
||||||
/** Parser statuses. */
|
/** Parser statuses. */
|
||||||
public enum Status { NONE, PARSING, CACHE, INSERTING };
|
public enum Status { NONE, PARSING, CACHE, INSERTING };
|
||||||
|
|
||||||
/** The current status. */
|
/** The current status. */
|
||||||
private static Status status = Status.NONE;
|
private Status status = Status.NONE;
|
||||||
|
|
||||||
/** If no Provider supports a MessageDigestSpi implementation for the MD5 algorithm. */
|
/** If no Provider supports a MessageDigestSpi implementation for the MD5 algorithm. */
|
||||||
private static boolean hasNoMD5Algorithm = false;
|
private boolean hasNoMD5Algorithm = false;
|
||||||
|
|
||||||
// This class should not be instantiated.
|
@Inject
|
||||||
private BeatmapParser() {}
|
public BeatmapParser() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invokes parser for each OSU file in a root directory and
|
* Invokes parser for each OSU file in a root directory and
|
||||||
* adds the beatmaps to a new BeatmapSetList.
|
* adds the beatmaps to a new BeatmapSetList.
|
||||||
* @param root the root directory (search has depth 1)
|
* @param root the root directory (search has depth 1)
|
||||||
*/
|
*/
|
||||||
public static void parseAllFiles(File root) {
|
public void parseAll() {
|
||||||
// create a new BeatmapSetList
|
// create a new BeatmapSetList
|
||||||
BeatmapSetList.create();
|
BeatmapSetList.create();
|
||||||
|
|
||||||
// create a new watch service
|
// create a new watch service
|
||||||
if (Options.isWatchServiceEnabled())
|
if (OPTION_ENABLE_WATCH_SERVICE.state) {
|
||||||
BeatmapWatchService.create();
|
BeatmapWatchService.create(instanceContainer);
|
||||||
|
}
|
||||||
|
|
||||||
// parse all directories
|
// parse all directories
|
||||||
parseDirectories(root.listFiles());
|
parseDirectories(config.beatmapDir.listFiles());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -93,7 +106,7 @@ public class BeatmapParser {
|
||||||
* @param dirs the array of directories to parse
|
* @param dirs the array of directories to parse
|
||||||
* @return the last BeatmapSetNode parsed, or null if none
|
* @return the last BeatmapSetNode parsed, or null if none
|
||||||
*/
|
*/
|
||||||
public static BeatmapSetNode parseDirectories(File[] dirs) {
|
public BeatmapSetNode parseDirectories(File[] dirs) {
|
||||||
if (dirs == null)
|
if (dirs == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
@ -111,7 +124,7 @@ public class BeatmapParser {
|
||||||
List<Beatmap> parsedBeatmaps = new LinkedList<Beatmap>(); // loaded from parser
|
List<Beatmap> parsedBeatmaps = new LinkedList<Beatmap>(); // loaded from parser
|
||||||
|
|
||||||
// watch service
|
// watch service
|
||||||
BeatmapWatchService ws = (Options.isWatchServiceEnabled()) ? BeatmapWatchService.get() : null;
|
BeatmapWatchService ws = BeatmapWatchService.get();
|
||||||
|
|
||||||
// parse directories
|
// parse directories
|
||||||
BeatmapSetNode lastNode = null;
|
BeatmapSetNode lastNode = null;
|
||||||
|
@ -215,7 +228,7 @@ public class BeatmapParser {
|
||||||
return lastNode;
|
return lastNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void parseOnlyTimingPoints(Beatmap map) {
|
public void parseOnlyTimingPoints(Beatmap map) {
|
||||||
if (map == null || map.getFile() == null || !map.getFile().exists()) {
|
if (map == null || map.getFile() == null || !map.getFile().exists()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -259,7 +272,7 @@ public class BeatmapParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void parseSectionTimingPoints(Beatmap beatmap, String line) {
|
private void parseSectionTimingPoints(Beatmap beatmap, String line) {
|
||||||
TimingPoint timingPoint = new TimingPoint(line);
|
TimingPoint timingPoint = new TimingPoint(line);
|
||||||
if(!timingPoint.isInherited()) {
|
if(!timingPoint.isInherited()) {
|
||||||
int bpm = Math.round(60000 / timingPoint.getBeatLength());
|
int bpm = Math.round(60000 / timingPoint.getBeatLength());
|
||||||
|
@ -282,7 +295,7 @@ public class BeatmapParser {
|
||||||
* @param parseObjects if true, hit objects will be fully parsed now
|
* @param parseObjects if true, hit objects will be fully parsed now
|
||||||
* @return the new beatmap
|
* @return the new beatmap
|
||||||
*/
|
*/
|
||||||
private static Beatmap parseFile(File file, File dir, ArrayList<Beatmap> beatmaps, boolean parseObjects) {
|
private Beatmap parseFile(File file, File dir, ArrayList<Beatmap> beatmaps, boolean parseObjects) {
|
||||||
Beatmap beatmap = new Beatmap(file);
|
Beatmap beatmap = new Beatmap(file);
|
||||||
beatmap.timingPoints = new ArrayList<TimingPoint>();
|
beatmap.timingPoints = new ArrayList<TimingPoint>();
|
||||||
|
|
||||||
|
@ -523,7 +536,7 @@ public class BeatmapParser {
|
||||||
switch (tokens[0]) {
|
switch (tokens[0]) {
|
||||||
case "0": // background
|
case "0": // background
|
||||||
tokens[2] = tokens[2].replaceAll("^\"|\"$", "");
|
tokens[2] = tokens[2].replaceAll("^\"|\"$", "");
|
||||||
String ext = BeatmapParser.getExtension(tokens[2]);
|
String ext = Utils.getFileExtension(tokens[2]);
|
||||||
if (ext.equals("jpg") || ext.equals("png"))
|
if (ext.equals("jpg") || ext.equals("png"))
|
||||||
beatmap.bg = new File(dir, getDBString(tokens[2]));
|
beatmap.bg = new File(dir, getDBString(tokens[2]));
|
||||||
break;
|
break;
|
||||||
|
@ -767,6 +780,9 @@ public class BeatmapParser {
|
||||||
|
|
||||||
// combo info
|
// combo info
|
||||||
Color[] combo = beatmap.getComboColors();
|
Color[] combo = beatmap.getComboColors();
|
||||||
|
if (combo == null) {
|
||||||
|
combo = SkinService.skin.getComboColors();
|
||||||
|
}
|
||||||
int comboIndex = 0; // color index
|
int comboIndex = 0; // color index
|
||||||
int comboNumber = 1; // combo number
|
int comboNumber = 1; // combo number
|
||||||
|
|
||||||
|
@ -832,7 +848,7 @@ public class BeatmapParser {
|
||||||
* Splits line into two strings: tag, value.
|
* Splits line into two strings: tag, value.
|
||||||
* If no ':' character is present, null will be returned.
|
* If no ':' character is present, null will be returned.
|
||||||
*/
|
*/
|
||||||
private static String[] tokenize(String line) {
|
private String[] tokenize(String line) {
|
||||||
int index = line.indexOf(':');
|
int index = line.indexOf(':');
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
Log.debug(String.format("Failed to tokenize line: '%s'.", line));
|
Log.debug(String.format("Failed to tokenize line: '%s'.", line));
|
||||||
|
@ -845,19 +861,10 @@ public class BeatmapParser {
|
||||||
return tokens;
|
return tokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the file extension of a file.
|
|
||||||
* @param file the file name
|
|
||||||
*/
|
|
||||||
public static String getExtension(String file) {
|
|
||||||
int i = file.lastIndexOf('.');
|
|
||||||
return (i != -1) ? file.substring(i + 1).toLowerCase() : "";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the name of the current file being parsed, or null if none.
|
* Returns the name of the current file being parsed, or null if none.
|
||||||
*/
|
*/
|
||||||
public static String getCurrentFileName() {
|
public String getCurrentFileName() {
|
||||||
if (status == Status.PARSING)
|
if (status == Status.PARSING)
|
||||||
return (currentFile != null) ? currentFile.getName() : null;
|
return (currentFile != null) ? currentFile.getName() : null;
|
||||||
else
|
else
|
||||||
|
@ -868,7 +875,7 @@ public class BeatmapParser {
|
||||||
* Returns the progress of file parsing, or -1 if not parsing.
|
* Returns the progress of file parsing, or -1 if not parsing.
|
||||||
* @return the completion percent [0, 100] or -1
|
* @return the completion percent [0, 100] or -1
|
||||||
*/
|
*/
|
||||||
public static int getParserProgress() {
|
public int getParserProgress() {
|
||||||
if (currentDirectoryIndex == -1 || totalDirectories == -1)
|
if (currentDirectoryIndex == -1 || totalDirectories == -1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -878,7 +885,9 @@ public class BeatmapParser {
|
||||||
/**
|
/**
|
||||||
* Returns the current parser status.
|
* Returns the current parser status.
|
||||||
*/
|
*/
|
||||||
public static Status getStatus() { return status; }
|
public Status getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the String object in the database for the given String.
|
* Returns the String object in the database for the given String.
|
||||||
|
@ -894,4 +903,5 @@ public class BeatmapParser {
|
||||||
} else
|
} else
|
||||||
return DBString;
|
return DBString;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -18,7 +18,6 @@
|
||||||
|
|
||||||
package itdelatrisu.opsu.beatmap;
|
package itdelatrisu.opsu.beatmap;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.Utils;
|
import itdelatrisu.opsu.Utils;
|
||||||
import itdelatrisu.opsu.audio.MusicController;
|
import itdelatrisu.opsu.audio.MusicController;
|
||||||
import itdelatrisu.opsu.db.BeatmapDB;
|
import itdelatrisu.opsu.db.BeatmapDB;
|
||||||
|
@ -210,7 +209,7 @@ public class BeatmapSetList {
|
||||||
BeatmapDB.delete(dir.getName());
|
BeatmapDB.delete(dir.getName());
|
||||||
|
|
||||||
// delete the associated directory
|
// delete the associated directory
|
||||||
BeatmapWatchService ws = (Options.isWatchServiceEnabled()) ? BeatmapWatchService.get() : null;
|
BeatmapWatchService ws = BeatmapWatchService.get();
|
||||||
if (ws != null)
|
if (ws != null)
|
||||||
ws.pause();
|
ws.pause();
|
||||||
try {
|
try {
|
||||||
|
@ -265,9 +264,10 @@ public class BeatmapSetList {
|
||||||
BeatmapDB.delete(file.getParentFile().getName(), file.getName());
|
BeatmapDB.delete(file.getParentFile().getName(), file.getName());
|
||||||
|
|
||||||
// delete the associated file
|
// delete the associated file
|
||||||
BeatmapWatchService ws = (Options.isWatchServiceEnabled()) ? BeatmapWatchService.get() : null;
|
BeatmapWatchService ws = BeatmapWatchService.get();
|
||||||
if (ws != null)
|
if (ws != null) {
|
||||||
ws.pause();
|
ws.pause();
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
Utils.deleteToTrash(file);
|
Utils.deleteToTrash(file);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|
|
@ -20,12 +20,14 @@ package itdelatrisu.opsu.beatmap;
|
||||||
|
|
||||||
import itdelatrisu.opsu.GameData.Grade;
|
import itdelatrisu.opsu.GameData.Grade;
|
||||||
import itdelatrisu.opsu.GameImage;
|
import itdelatrisu.opsu.GameImage;
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.ui.Colors;
|
import itdelatrisu.opsu.ui.Colors;
|
||||||
import itdelatrisu.opsu.ui.Fonts;
|
import itdelatrisu.opsu.ui.Fonts;
|
||||||
|
|
||||||
import org.newdawn.slick.Color;
|
import org.newdawn.slick.Color;
|
||||||
import org.newdawn.slick.Image;
|
import org.newdawn.slick.Image;
|
||||||
|
import yugecin.opsudance.skinning.SkinService;
|
||||||
|
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Node in an BeatmapSetList representing a beatmap set.
|
* Node in an BeatmapSetList representing a beatmap set.
|
||||||
|
@ -78,14 +80,14 @@ public class BeatmapSetNode {
|
||||||
Beatmap beatmap = beatmapSet.get(expanded ? beatmapIndex : 0);
|
Beatmap beatmap = beatmapSet.get(expanded ? beatmapIndex : 0);
|
||||||
bg.setAlpha(0.9f);
|
bg.setAlpha(0.9f);
|
||||||
Color bgColor;
|
Color bgColor;
|
||||||
Color textColor = Options.getSkin().getSongSelectInactiveTextColor();
|
Color textColor = SkinService.skin.getSongSelectInactiveTextColor();
|
||||||
|
|
||||||
// get drawing parameters
|
// get drawing parameters
|
||||||
if (expanded) {
|
if (expanded) {
|
||||||
x -= bg.getWidth() / 10f;
|
x -= bg.getWidth() / 10f;
|
||||||
if (focus) {
|
if (focus) {
|
||||||
bgColor = Color.white;
|
bgColor = Color.white;
|
||||||
textColor = Options.getSkin().getSongSelectActiveTextColor();
|
textColor = SkinService.skin.getSongSelectActiveTextColor();
|
||||||
} else
|
} else
|
||||||
bgColor = Colors.BLUE_BUTTON;
|
bgColor = Colors.BLUE_BUTTON;
|
||||||
} else if (beatmapSet.isPlayed())
|
} else if (beatmapSet.isPlayed())
|
||||||
|
@ -105,7 +107,7 @@ public class BeatmapSetNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw text
|
// draw text
|
||||||
if (Options.useUnicodeMetadata()) { // load glyphs
|
if (OPTION_SHOW_UNICODE.state) {
|
||||||
Fonts.loadGlyphs(Fonts.MEDIUM, beatmap.titleUnicode);
|
Fonts.loadGlyphs(Fonts.MEDIUM, beatmap.titleUnicode);
|
||||||
Fonts.loadGlyphs(Fonts.DEFAULT, beatmap.artistUnicode);
|
Fonts.loadGlyphs(Fonts.DEFAULT, beatmap.artistUnicode);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,6 @@
|
||||||
|
|
||||||
package itdelatrisu.opsu.beatmap;
|
package itdelatrisu.opsu.beatmap;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.ClosedWatchServiceException;
|
import java.nio.file.ClosedWatchServiceException;
|
||||||
import java.nio.file.FileSystems;
|
import java.nio.file.FileSystems;
|
||||||
|
@ -42,7 +40,11 @@ import java.util.concurrent.Executors;
|
||||||
|
|
||||||
import org.newdawn.slick.util.Log;
|
import org.newdawn.slick.util.Log;
|
||||||
import yugecin.opsudance.core.events.EventBus;
|
import yugecin.opsudance.core.events.EventBus;
|
||||||
|
import yugecin.opsudance.core.inject.InstanceContainer;
|
||||||
import yugecin.opsudance.events.BubbleNotificationEvent;
|
import yugecin.opsudance.events.BubbleNotificationEvent;
|
||||||
|
import yugecin.opsudance.options.Configuration;
|
||||||
|
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
@ -88,14 +90,14 @@ public class BeatmapWatchService {
|
||||||
* Creates a new watch service instance (overwriting any previous instance),
|
* Creates a new watch service instance (overwriting any previous instance),
|
||||||
* registers the beatmap directory, and starts processing events.
|
* registers the beatmap directory, and starts processing events.
|
||||||
*/
|
*/
|
||||||
public static void create() {
|
public static void create(InstanceContainer instanceContainer) {
|
||||||
// close the existing watch service
|
// close the existing watch service
|
||||||
destroy();
|
destroy();
|
||||||
|
|
||||||
// create a new watch service
|
// create a new watch service
|
||||||
try {
|
try {
|
||||||
ws = new BeatmapWatchService();
|
ws = instanceContainer.provide(BeatmapWatchService.class);
|
||||||
ws.register(Options.getBeatmapDir().toPath());
|
ws.register(instanceContainer.provide(Configuration.class).beatmapDir.toPath());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.error("Could not create watch service", e);
|
Log.error("Could not create watch service", e);
|
||||||
EventBus.post(new BubbleNotificationEvent("Could not create watch service", BubbleNotificationEvent.COMMONCOLOR_RED));
|
EventBus.post(new BubbleNotificationEvent("Could not create watch service", BubbleNotificationEvent.COMMONCOLOR_RED));
|
||||||
|
@ -126,9 +128,14 @@ public class BeatmapWatchService {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the single instance of this class.
|
* Returns the single instance of this class, or null if not enabled.
|
||||||
*/
|
*/
|
||||||
public static BeatmapWatchService get() { return ws; }
|
public static BeatmapWatchService get() {
|
||||||
|
if (!OPTION_ENABLE_WATCH_SERVICE.state) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return ws;
|
||||||
|
}
|
||||||
|
|
||||||
/** Watch service listener interface. */
|
/** Watch service listener interface. */
|
||||||
public interface BeatmapWatchServiceListener {
|
public interface BeatmapWatchServiceListener {
|
||||||
|
|
|
@ -18,8 +18,6 @@
|
||||||
|
|
||||||
package itdelatrisu.opsu.beatmap;
|
package itdelatrisu.opsu.beatmap;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FilenameFilter;
|
import java.io.FilenameFilter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -29,20 +27,27 @@ import net.lingala.zip4j.core.ZipFile;
|
||||||
import net.lingala.zip4j.exception.ZipException;
|
import net.lingala.zip4j.exception.ZipException;
|
||||||
import org.newdawn.slick.util.Log;
|
import org.newdawn.slick.util.Log;
|
||||||
import yugecin.opsudance.core.events.EventBus;
|
import yugecin.opsudance.core.events.EventBus;
|
||||||
|
import yugecin.opsudance.core.inject.Inject;
|
||||||
import yugecin.opsudance.events.BubbleNotificationEvent;
|
import yugecin.opsudance.events.BubbleNotificationEvent;
|
||||||
|
import yugecin.opsudance.options.Configuration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unpacker for OSZ (ZIP) archives.
|
* Unpacker for OSZ (ZIP) archives.
|
||||||
*/
|
*/
|
||||||
public class OszUnpacker {
|
public class OszUnpacker {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Configuration config;
|
||||||
|
|
||||||
/** The index of the current file being unpacked. */
|
/** The index of the current file being unpacked. */
|
||||||
private static int fileIndex = -1;
|
private int fileIndex = -1;
|
||||||
|
|
||||||
/** The total number of files to unpack. */
|
/** The total number of files to unpack. */
|
||||||
private static File[] files;
|
private File[] files;
|
||||||
|
|
||||||
// This class should not be instantiated.
|
@Inject
|
||||||
private OszUnpacker() {}
|
public OszUnpacker() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invokes the unpacker for each OSZ archive in a root directory.
|
* Invokes the unpacker for each OSZ archive in a root directory.
|
||||||
|
@ -51,11 +56,11 @@ public class OszUnpacker {
|
||||||
* @return an array containing the new (unpacked) directories, or null
|
* @return an array containing the new (unpacked) directories, or null
|
||||||
* if no OSZs found
|
* if no OSZs found
|
||||||
*/
|
*/
|
||||||
public static File[] unpackAllFiles(File root, File dest) {
|
public File[] unpackAll() {
|
||||||
List<File> dirs = new ArrayList<File>();
|
List<File> dirs = new ArrayList<File>();
|
||||||
|
|
||||||
// find all OSZ files
|
// find all OSZ files
|
||||||
files = root.listFiles(new FilenameFilter() {
|
files = config.oszDir.listFiles(new FilenameFilter() {
|
||||||
@Override
|
@Override
|
||||||
public boolean accept(File dir, String name) {
|
public boolean accept(File dir, String name) {
|
||||||
return name.toLowerCase().endsWith(".osz");
|
return name.toLowerCase().endsWith(".osz");
|
||||||
|
@ -67,13 +72,13 @@ public class OszUnpacker {
|
||||||
}
|
}
|
||||||
|
|
||||||
// unpack OSZs
|
// unpack OSZs
|
||||||
BeatmapWatchService ws = (Options.isWatchServiceEnabled()) ? BeatmapWatchService.get() : null;
|
BeatmapWatchService ws = BeatmapWatchService.get();
|
||||||
if (ws != null)
|
if (ws != null)
|
||||||
ws.pause();
|
ws.pause();
|
||||||
for (File file : files) {
|
for (File file : files) {
|
||||||
fileIndex++;
|
fileIndex++;
|
||||||
String dirName = file.getName().substring(0, file.getName().lastIndexOf('.'));
|
String dirName = file.getName().substring(0, file.getName().lastIndexOf('.'));
|
||||||
File songDir = new File(dest, dirName);
|
File songDir = new File(config.beatmapDir, dirName);
|
||||||
if (!songDir.isDirectory()) {
|
if (!songDir.isDirectory()) {
|
||||||
songDir.mkdir();
|
songDir.mkdir();
|
||||||
unzip(file, songDir);
|
unzip(file, songDir);
|
||||||
|
@ -94,7 +99,7 @@ public class OszUnpacker {
|
||||||
* @param file the ZIP archive
|
* @param file the ZIP archive
|
||||||
* @param dest the destination directory
|
* @param dest the destination directory
|
||||||
*/
|
*/
|
||||||
private static void unzip(File file, File dest) {
|
private void unzip(File file, File dest) {
|
||||||
try {
|
try {
|
||||||
ZipFile zipFile = new ZipFile(file);
|
ZipFile zipFile = new ZipFile(file);
|
||||||
zipFile.extractAll(dest.getAbsolutePath());
|
zipFile.extractAll(dest.getAbsolutePath());
|
||||||
|
@ -108,7 +113,7 @@ public class OszUnpacker {
|
||||||
/**
|
/**
|
||||||
* Returns the name of the current file being unpacked, or null if none.
|
* Returns the name of the current file being unpacked, or null if none.
|
||||||
*/
|
*/
|
||||||
public static String getCurrentFileName() {
|
public String getCurrentFileName() {
|
||||||
if (files == null || fileIndex == -1)
|
if (files == null || fileIndex == -1)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
@ -119,10 +124,11 @@ public class OszUnpacker {
|
||||||
* Returns the progress of file unpacking, or -1 if not unpacking.
|
* Returns the progress of file unpacking, or -1 if not unpacking.
|
||||||
* @return the completion percent [0, 100] or -1
|
* @return the completion percent [0, 100] or -1
|
||||||
*/
|
*/
|
||||||
public static int getUnpackerProgress() {
|
public int getUnpackerProgress() {
|
||||||
if (files == null || fileIndex == -1)
|
if (files == null || fileIndex == -1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return (fileIndex + 1) * 100 / files.length;
|
return (fileIndex + 1) * 100 / files.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -18,7 +18,6 @@
|
||||||
|
|
||||||
package itdelatrisu.opsu.db;
|
package itdelatrisu.opsu.db;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.beatmap.Beatmap;
|
import itdelatrisu.opsu.beatmap.Beatmap;
|
||||||
import itdelatrisu.opsu.beatmap.BeatmapParser;
|
import itdelatrisu.opsu.beatmap.BeatmapParser;
|
||||||
|
|
||||||
|
@ -35,11 +34,13 @@ import java.util.Map;
|
||||||
|
|
||||||
import org.newdawn.slick.util.Log;
|
import org.newdawn.slick.util.Log;
|
||||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||||
|
import yugecin.opsudance.options.Configuration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles connections and queries with the cached beatmap database.
|
* Handles connections and queries with the cached beatmap database.
|
||||||
*/
|
*/
|
||||||
public class BeatmapDB {
|
public class BeatmapDB {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Current database version.
|
* Current database version.
|
||||||
* This value should be changed whenever the database format changes.
|
* This value should be changed whenever the database format changes.
|
||||||
|
@ -91,12 +92,16 @@ public class BeatmapDB {
|
||||||
// This class should not be instantiated.
|
// This class should not be instantiated.
|
||||||
private BeatmapDB() {}
|
private BeatmapDB() {}
|
||||||
|
|
||||||
|
private static Configuration config; // TODO
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the database connection.
|
* Initializes the database connection.
|
||||||
*/
|
*/
|
||||||
public static void init() {
|
public static void init(Configuration config) {
|
||||||
|
BeatmapDB.config = config;
|
||||||
|
|
||||||
// create a database connection
|
// create a database connection
|
||||||
connection = DBController.createConnection(Options.BEATMAP_DB.getPath());
|
connection = DBController.createConnection(config.BEATMAP_DB.getPath());
|
||||||
if (connection == null)
|
if (connection == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
package itdelatrisu.opsu.db;
|
package itdelatrisu.opsu.db;
|
||||||
|
|
||||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||||
|
import yugecin.opsudance.options.Configuration;
|
||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.DriverManager;
|
import java.sql.DriverManager;
|
||||||
|
@ -34,7 +35,7 @@ public class DBController {
|
||||||
/**
|
/**
|
||||||
* Initializes all databases.
|
* Initializes all databases.
|
||||||
*/
|
*/
|
||||||
public static void init() {
|
public static void init(Configuration config) {
|
||||||
// load the sqlite-JDBC driver using the current class loader
|
// load the sqlite-JDBC driver using the current class loader
|
||||||
try {
|
try {
|
||||||
Class.forName("org.sqlite.JDBC");
|
Class.forName("org.sqlite.JDBC");
|
||||||
|
@ -43,8 +44,8 @@ public class DBController {
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize the databases
|
// initialize the databases
|
||||||
BeatmapDB.init();
|
BeatmapDB.init(config);
|
||||||
ScoreDB.init();
|
ScoreDB.init(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -18,10 +18,10 @@
|
||||||
|
|
||||||
package itdelatrisu.opsu.db;
|
package itdelatrisu.opsu.db;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.ScoreData;
|
import itdelatrisu.opsu.ScoreData;
|
||||||
import itdelatrisu.opsu.beatmap.Beatmap;
|
import itdelatrisu.opsu.beatmap.Beatmap;
|
||||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||||
|
import yugecin.opsudance.options.Configuration;
|
||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
|
@ -83,9 +83,9 @@ public class ScoreDB {
|
||||||
/**
|
/**
|
||||||
* Initializes the database connection.
|
* Initializes the database connection.
|
||||||
*/
|
*/
|
||||||
public static void init() {
|
public static void init(Configuration config) {
|
||||||
// create a database connection
|
// create a database connection
|
||||||
connection = DBController.createConnection(Options.SCORE_DB.getPath());
|
connection = DBController.createConnection(config.SCORE_DB.getPath());
|
||||||
if (connection == null)
|
if (connection == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
package itdelatrisu.opsu.downloads;
|
package itdelatrisu.opsu.downloads;
|
||||||
|
|
||||||
import itdelatrisu.opsu.GameImage;
|
import itdelatrisu.opsu.GameImage;
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.Utils;
|
import itdelatrisu.opsu.Utils;
|
||||||
import itdelatrisu.opsu.beatmap.BeatmapSetList;
|
import itdelatrisu.opsu.beatmap.BeatmapSetList;
|
||||||
import itdelatrisu.opsu.downloads.Download.DownloadListener;
|
import itdelatrisu.opsu.downloads.Download.DownloadListener;
|
||||||
|
@ -35,13 +34,21 @@ import org.newdawn.slick.Color;
|
||||||
import org.newdawn.slick.Graphics;
|
import org.newdawn.slick.Graphics;
|
||||||
import org.newdawn.slick.Image;
|
import org.newdawn.slick.Image;
|
||||||
import yugecin.opsudance.core.events.EventBus;
|
import yugecin.opsudance.core.events.EventBus;
|
||||||
|
import yugecin.opsudance.core.inject.Inject;
|
||||||
import yugecin.opsudance.events.BarNotificationEvent;
|
import yugecin.opsudance.events.BarNotificationEvent;
|
||||||
import yugecin.opsudance.events.BubbleNotificationEvent;
|
import yugecin.opsudance.events.BubbleNotificationEvent;
|
||||||
|
import yugecin.opsudance.options.Configuration;
|
||||||
|
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Node containing song data and a Download object.
|
* Node containing song data and a Download object.
|
||||||
*/
|
*/
|
||||||
public class DownloadNode {
|
public class DownloadNode {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Configuration config;
|
||||||
|
|
||||||
/** The associated Download object. */
|
/** The associated Download object. */
|
||||||
private Download download;
|
private Download download;
|
||||||
|
|
||||||
|
@ -272,7 +279,7 @@ public class DownloadNode {
|
||||||
String url = server.getDownloadURL(beatmapSetID);
|
String url = server.getDownloadURL(beatmapSetID);
|
||||||
if (url == null)
|
if (url == null)
|
||||||
return;
|
return;
|
||||||
String path = String.format("%s%c%d", Options.getOSZDir(), File.separatorChar, beatmapSetID);
|
String path = String.format("%s%c%d", config.oszDir, File.separatorChar, beatmapSetID);
|
||||||
String rename = String.format("%d %s - %s.osz", beatmapSetID, artist, title);
|
String rename = String.format("%d %s - %s.osz", beatmapSetID, artist, title);
|
||||||
Download download = new Download(url, path, rename);
|
Download download = new Download(url, path, rename);
|
||||||
download.setListener(new DownloadListener() {
|
download.setListener(new DownloadListener() {
|
||||||
|
@ -287,9 +294,10 @@ public class DownloadNode {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.download = download;
|
this.download = download;
|
||||||
if (Options.useUnicodeMetadata()) // load glyphs
|
if (OPTION_SHOW_UNICODE.state) {
|
||||||
Fonts.loadGlyphs(Fonts.LARGE, getTitle());
|
Fonts.loadGlyphs(Fonts.LARGE, getTitle());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the associated download object, or null if none.
|
* Returns the associated download object, or null if none.
|
||||||
|
@ -318,7 +326,7 @@ public class DownloadNode {
|
||||||
* If configured, the Unicode string will be returned instead.
|
* If configured, the Unicode string will be returned instead.
|
||||||
*/
|
*/
|
||||||
public String getTitle() {
|
public String getTitle() {
|
||||||
return (Options.useUnicodeMetadata() && titleUnicode != null && !titleUnicode.isEmpty()) ? titleUnicode : title;
|
return (OPTION_SHOW_UNICODE.state && titleUnicode != null && !titleUnicode.isEmpty()) ? titleUnicode : title;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -326,7 +334,7 @@ public class DownloadNode {
|
||||||
* If configured, the Unicode string will be returned instead.
|
* If configured, the Unicode string will be returned instead.
|
||||||
*/
|
*/
|
||||||
public String getArtist() {
|
public String getArtist() {
|
||||||
return (Options.useUnicodeMetadata() && artistUnicode != null && !artistUnicode.isEmpty()) ? artistUnicode : artist;
|
return (OPTION_SHOW_UNICODE.state && artistUnicode != null && !artistUnicode.isEmpty()) ? artistUnicode : artist;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -375,7 +383,7 @@ public class DownloadNode {
|
||||||
|
|
||||||
// text
|
// text
|
||||||
// TODO: if the title/artist line is too long, shorten it (e.g. add "...") instead of just clipping
|
// TODO: if the title/artist line is too long, shorten it (e.g. add "...") instead of just clipping
|
||||||
if (Options.useUnicodeMetadata()) { // load glyphs
|
if (OPTION_SHOW_UNICODE.state) {
|
||||||
Fonts.loadGlyphs(Fonts.BOLD, getTitle());
|
Fonts.loadGlyphs(Fonts.BOLD, getTitle());
|
||||||
Fonts.loadGlyphs(Fonts.BOLD, getArtist());
|
Fonts.loadGlyphs(Fonts.BOLD, getArtist());
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,10 +18,8 @@
|
||||||
|
|
||||||
package itdelatrisu.opsu.downloads;
|
package itdelatrisu.opsu.downloads;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.Utils;
|
import itdelatrisu.opsu.Utils;
|
||||||
import itdelatrisu.opsu.downloads.Download.DownloadListener;
|
import itdelatrisu.opsu.downloads.Download.DownloadListener;
|
||||||
import itdelatrisu.opsu.ui.UI;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -39,23 +37,27 @@ import org.newdawn.slick.util.Log;
|
||||||
import org.newdawn.slick.util.ResourceLoader;
|
import org.newdawn.slick.util.ResourceLoader;
|
||||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||||
import yugecin.opsudance.core.events.EventBus;
|
import yugecin.opsudance.core.events.EventBus;
|
||||||
|
import yugecin.opsudance.core.inject.Inject;
|
||||||
import yugecin.opsudance.events.BarNotificationEvent;
|
import yugecin.opsudance.events.BarNotificationEvent;
|
||||||
|
import yugecin.opsudance.options.Configuration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles automatic program updates.
|
* Handles automatic program updates.
|
||||||
*/
|
*/
|
||||||
public class Updater {
|
public class Updater {
|
||||||
/** The single instance of this class. */
|
|
||||||
private static Updater updater = new Updater();
|
@Inject
|
||||||
|
private Configuration config;
|
||||||
|
|
||||||
|
private static Updater updater;
|
||||||
|
|
||||||
|
public static Updater get() {
|
||||||
|
return updater;
|
||||||
|
}
|
||||||
|
|
||||||
/** The exit confirmation message. */
|
/** The exit confirmation message. */
|
||||||
public static final String EXIT_CONFIRMATION = "An opsu! update is being downloaded.\nAre you sure you want to quit opsu!?";
|
public static final String EXIT_CONFIRMATION = "An opsu! update is being downloaded.\nAre you sure you want to quit opsu!?";
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the single instance of this class.
|
|
||||||
*/
|
|
||||||
public static Updater get() { return updater; }
|
|
||||||
|
|
||||||
/** Updater status. */
|
/** Updater status. */
|
||||||
public enum Status {
|
public enum Status {
|
||||||
INITIAL (""),
|
INITIAL (""),
|
||||||
|
@ -117,11 +119,10 @@ public class Updater {
|
||||||
return currentVersion.getMajorVersion() + "." + currentVersion.getMinorVersion() + "." + currentVersion.getIncrementalVersion();
|
return currentVersion.getMajorVersion() + "." + currentVersion.getMinorVersion() + "." + currentVersion.getIncrementalVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Inject
|
||||||
* Constructor.
|
public Updater() {
|
||||||
*/
|
|
||||||
private Updater() {
|
|
||||||
status = Status.INITIAL;
|
status = Status.INITIAL;
|
||||||
|
updater = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -144,7 +145,7 @@ public class Updater {
|
||||||
Date date = null;
|
Date date = null;
|
||||||
try {
|
try {
|
||||||
Properties props = new Properties();
|
Properties props = new Properties();
|
||||||
props.load(ResourceLoader.getResourceAsStream(Options.VERSION_FILE));
|
props.load(ResourceLoader.getResourceAsStream(config.VERSION_FILE));
|
||||||
String build = props.getProperty("build.date");
|
String build = props.getProperty("build.date");
|
||||||
if (build == null || build.equals("${timestamp}") || build.equals("${maven.build.timestamp}"))
|
if (build == null || build.equals("${timestamp}") || build.equals("${maven.build.timestamp}"))
|
||||||
date = new Date();
|
date = new Date();
|
||||||
|
@ -206,23 +207,23 @@ public class Updater {
|
||||||
* @throws IOException if an I/O exception occurs
|
* @throws IOException if an I/O exception occurs
|
||||||
*/
|
*/
|
||||||
public void checkForUpdates() throws IOException {
|
public void checkForUpdates() throws IOException {
|
||||||
if (status != Status.INITIAL || Options.USE_XDG)
|
if (status != Status.INITIAL || config.USE_XDG)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
status = Status.CHECKING;
|
status = Status.CHECKING;
|
||||||
|
|
||||||
// get current version
|
// get current version
|
||||||
Properties props = new Properties();
|
Properties props = new Properties();
|
||||||
props.load(ResourceLoader.getResourceAsStream(Options.VERSION_FILE));
|
props.load(ResourceLoader.getResourceAsStream(config.VERSION_FILE));
|
||||||
if ((currentVersion = getVersion(props)) == null)
|
if ((currentVersion = getVersion(props)) == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// get latest version
|
// get latest version
|
||||||
String s = null;
|
String s = null;
|
||||||
try {
|
try {
|
||||||
s = Utils.readDataFromUrl(new URL(Options.VERSION_REMOTE));
|
s = Utils.readDataFromUrl(new URL(config.VERSION_REMOTE));
|
||||||
} catch (UnknownHostException e) {
|
} catch (UnknownHostException e) {
|
||||||
Log.warn(String.format("Check for updates failed. Please check your internet connection, or your connection to %s.", Options.VERSION_REMOTE));
|
Log.warn(String.format("Check for updates failed. Please check your internet connection, or your connection to %s.", config.VERSION_REMOTE));
|
||||||
}
|
}
|
||||||
if (s == null) {
|
if (s == null) {
|
||||||
status = Status.CONNECTION_ERROR;
|
status = Status.CONNECTION_ERROR;
|
||||||
|
|
|
@ -34,11 +34,17 @@ import java.util.Date;
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||||
|
import yugecin.opsudance.core.inject.Inject;
|
||||||
|
import yugecin.opsudance.core.inject.InstanceContainer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Download server: http://bloodcat.com/osu/
|
* Download server: http://bloodcat.com/osu/
|
||||||
*/
|
*/
|
||||||
public class BloodcatServer extends DownloadServer {
|
public class BloodcatServer extends DownloadServer {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public InstanceContainer instanceContainer;
|
||||||
|
|
||||||
/** Server name. */
|
/** Server name. */
|
||||||
private static final String SERVER_NAME = "Bloodcat";
|
private static final String SERVER_NAME = "Bloodcat";
|
||||||
|
|
||||||
|
@ -54,8 +60,9 @@ public class BloodcatServer extends DownloadServer {
|
||||||
/** Total result count from the last query. */
|
/** Total result count from the last query. */
|
||||||
private int totalResults = -1;
|
private int totalResults = -1;
|
||||||
|
|
||||||
/** Constructor. */
|
@Inject
|
||||||
public BloodcatServer() {}
|
public BloodcatServer() {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() { return SERVER_NAME; }
|
public String getName() { return SERVER_NAME; }
|
||||||
|
@ -82,12 +89,12 @@ public class BloodcatServer extends DownloadServer {
|
||||||
nodes = new DownloadNode[arr.length()];
|
nodes = new DownloadNode[arr.length()];
|
||||||
for (int i = 0; i < nodes.length; i++) {
|
for (int i = 0; i < nodes.length; i++) {
|
||||||
JSONObject item = arr.getJSONObject(i);
|
JSONObject item = arr.getJSONObject(i);
|
||||||
nodes[i] = new DownloadNode(
|
nodes[i] = instanceContainer.injectFields(new DownloadNode(
|
||||||
item.getInt("id"), formatDate(item.getString("synced")), //"date"
|
item.getInt("id"), formatDate(item.getString("synced")), //"date"
|
||||||
item.getString("title"), item.isNull("titleU") ? null : item.getString("titleU"), //"titleUnicode"
|
item.getString("title"), item.isNull("titleU") ? null : item.getString("titleU"), //"titleUnicode"
|
||||||
item.getString("artist"), item.isNull("artistU") ? null : item.getString("artistU"), //"artistUnicode"
|
item.getString("artist"), item.isNull("artistU") ? null : item.getString("artistU"), //"artistUnicode"
|
||||||
item.getString("creator")
|
item.getString("creator")
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// store total result count
|
// store total result count
|
||||||
|
|
|
@ -30,6 +30,8 @@ import java.net.URLEncoder;
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||||
|
import yugecin.opsudance.core.inject.Inject;
|
||||||
|
import yugecin.opsudance.core.inject.InstanceContainer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Download server: https://osu.hexide.com/
|
* Download server: https://osu.hexide.com/
|
||||||
|
@ -37,6 +39,10 @@ import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||||
* <i>This server went offline in 2016.</i>
|
* <i>This server went offline in 2016.</i>
|
||||||
*/
|
*/
|
||||||
public class HexideServer extends DownloadServer {
|
public class HexideServer extends DownloadServer {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private InstanceContainer instanceContainer;
|
||||||
|
|
||||||
/** Server name. */
|
/** Server name. */
|
||||||
private static final String SERVER_NAME = "Hexide";
|
private static final String SERVER_NAME = "Hexide";
|
||||||
|
|
||||||
|
@ -58,8 +64,9 @@ public class HexideServer extends DownloadServer {
|
||||||
/** Total result count from the last query. */
|
/** Total result count from the last query. */
|
||||||
private int totalResults = -1;
|
private int totalResults = -1;
|
||||||
|
|
||||||
/** Constructor. */
|
@Inject
|
||||||
public HexideServer() {}
|
public HexideServer() {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() { return SERVER_NAME; }
|
public String getName() { return SERVER_NAME; }
|
||||||
|
@ -117,10 +124,10 @@ public class HexideServer extends DownloadServer {
|
||||||
artist = creator = "?";
|
artist = creator = "?";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nodes[i] = new DownloadNode(
|
nodes[i] = instanceContainer.injectFields(new DownloadNode(
|
||||||
item.getInt("ranked_id"), item.getString("date"),
|
item.getInt("ranked_id"), item.getString("date"),
|
||||||
title, null, artist, null, creator
|
title, null, artist, null, creator
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// store total result count
|
// store total result count
|
||||||
|
|
|
@ -30,11 +30,17 @@ import java.net.URLEncoder;
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||||
|
import yugecin.opsudance.core.inject.Inject;
|
||||||
|
import yugecin.opsudance.core.inject.InstanceContainer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Download server: http://osu.mengsky.net/
|
* Download server: http://osu.mengsky.net/
|
||||||
*/
|
*/
|
||||||
public class MengSkyServer extends DownloadServer {
|
public class MengSkyServer extends DownloadServer {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private InstanceContainer instanceContainer;
|
||||||
|
|
||||||
/** Server name. */
|
/** Server name. */
|
||||||
private static final String SERVER_NAME = "MengSky";
|
private static final String SERVER_NAME = "MengSky";
|
||||||
|
|
||||||
|
@ -50,8 +56,9 @@ public class MengSkyServer extends DownloadServer {
|
||||||
/** Total result count from the last query. */
|
/** Total result count from the last query. */
|
||||||
private int totalResults = -1;
|
private int totalResults = -1;
|
||||||
|
|
||||||
/** Constructor. */
|
@Inject
|
||||||
public MengSkyServer() {}
|
public MengSkyServer() {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() { return SERVER_NAME; }
|
public String getName() { return SERVER_NAME; }
|
||||||
|
@ -86,19 +93,18 @@ public class MengSkyServer extends DownloadServer {
|
||||||
// sometimes titleU is artistU instead of the proper title
|
// sometimes titleU is artistU instead of the proper title
|
||||||
if (titleU.equals(artistU) && !titleU.equals(title))
|
if (titleU.equals(artistU) && !titleU.equals(title))
|
||||||
titleU = title;
|
titleU = title;
|
||||||
nodes[i] = new DownloadNode(
|
nodes[i] = instanceContainer.injectFields(new DownloadNode(
|
||||||
item.getInt("id"), item.getString("syncedDateTime"),
|
item.getInt("id"), item.getString("syncedDateTime"),
|
||||||
title, titleU, artist, artistU, creator
|
title, titleU, artist, artistU, creator
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// store total result count
|
// store total result count
|
||||||
int pageTotal = json.getInt("pageTotal");
|
int pageTotal = json.getInt("pageTotal");
|
||||||
int resultCount = nodes.length;
|
int resultCount = 1 + (pageTotal - 1) * PAGE_LIMIT;
|
||||||
if (page == pageTotal)
|
if (page == pageTotal) {
|
||||||
resultCount = nodes.length + (pageTotal - 1) * PAGE_LIMIT;
|
resultCount += nodes.length - 1;
|
||||||
else
|
}
|
||||||
resultCount = 1 + (pageTotal - 1) * PAGE_LIMIT;
|
|
||||||
this.totalResults = resultCount;
|
this.totalResults = resultCount;
|
||||||
} catch (MalformedURLException | UnsupportedEncodingException e) {
|
} catch (MalformedURLException | UnsupportedEncodingException e) {
|
||||||
ErrorHandler.error(String.format("Problem loading result list for query '%s'.", query), e).show();
|
ErrorHandler.error(String.format("Problem loading result list for query '%s'.", query), e).show();
|
||||||
|
|
|
@ -21,6 +21,8 @@ package itdelatrisu.opsu.downloads.servers;
|
||||||
import itdelatrisu.opsu.Utils;
|
import itdelatrisu.opsu.Utils;
|
||||||
import itdelatrisu.opsu.downloads.DownloadNode;
|
import itdelatrisu.opsu.downloads.DownloadNode;
|
||||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||||
|
import yugecin.opsudance.core.inject.Inject;
|
||||||
|
import yugecin.opsudance.core.inject.InstanceContainer;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
@ -36,6 +38,10 @@ import java.util.regex.Pattern;
|
||||||
* Download server: http://osu.uu.gl/
|
* Download server: http://osu.uu.gl/
|
||||||
*/
|
*/
|
||||||
public class MnetworkServer extends DownloadServer {
|
public class MnetworkServer extends DownloadServer {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private InstanceContainer instanceContainer;
|
||||||
|
|
||||||
/** Server name. */
|
/** Server name. */
|
||||||
private static final String SERVER_NAME = "Mnetwork";
|
private static final String SERVER_NAME = "Mnetwork";
|
||||||
|
|
||||||
|
@ -51,8 +57,9 @@ public class MnetworkServer extends DownloadServer {
|
||||||
/** Beatmap pattern. */
|
/** Beatmap pattern. */
|
||||||
private Pattern BEATMAP_PATTERN = Pattern.compile("^(\\d+) ([^-]+) - (.+)\\.osz$");
|
private Pattern BEATMAP_PATTERN = Pattern.compile("^(\\d+) ([^-]+) - (.+)\\.osz$");
|
||||||
|
|
||||||
/** Constructor. */
|
@Inject
|
||||||
public MnetworkServer() {}
|
public MnetworkServer() {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() { return SERVER_NAME; }
|
public String getName() { return SERVER_NAME; }
|
||||||
|
@ -112,7 +119,7 @@ public class MnetworkServer extends DownloadServer {
|
||||||
if (!m.matches())
|
if (!m.matches())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
nodeList.add(new DownloadNode(Integer.parseInt(m.group(1)), date, m.group(3), null, m.group(2), null, ""));
|
nodeList.add(instanceContainer.injectFields(new DownloadNode(Integer.parseInt(m.group(1)), date, m.group(3), null, m.group(2), null, "")));
|
||||||
}
|
}
|
||||||
|
|
||||||
nodes = nodeList.toArray(new DownloadNode[nodeList.size()]);
|
nodes = nodeList.toArray(new DownloadNode[nodeList.size()]);
|
||||||
|
|
|
@ -36,6 +36,8 @@ import java.util.TimeZone;
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||||
|
import yugecin.opsudance.core.inject.Inject;
|
||||||
|
import yugecin.opsudance.core.inject.InstanceContainer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Download server: http://loli.al/
|
* Download server: http://loli.al/
|
||||||
|
@ -43,6 +45,10 @@ import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||||
* <i>This server went offline in August 2015.</i>
|
* <i>This server went offline in August 2015.</i>
|
||||||
*/
|
*/
|
||||||
public class OsuMirrorServer extends DownloadServer {
|
public class OsuMirrorServer extends DownloadServer {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private InstanceContainer instanceContainer;
|
||||||
|
|
||||||
/** Server name. */
|
/** Server name. */
|
||||||
private static final String SERVER_NAME = "osu!Mirror";
|
private static final String SERVER_NAME = "osu!Mirror";
|
||||||
|
|
||||||
|
@ -67,8 +73,9 @@ public class OsuMirrorServer extends DownloadServer {
|
||||||
/** Lookup table from beatmap set ID -> server download ID. */
|
/** Lookup table from beatmap set ID -> server download ID. */
|
||||||
private HashMap<Integer, Integer> idTable = new HashMap<Integer, Integer>();
|
private HashMap<Integer, Integer> idTable = new HashMap<Integer, Integer>();
|
||||||
|
|
||||||
/** Constructor. */
|
@Inject
|
||||||
public OsuMirrorServer() {}
|
public OsuMirrorServer() {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() { return SERVER_NAME; }
|
public String getName() { return SERVER_NAME; }
|
||||||
|
@ -106,12 +113,12 @@ public class OsuMirrorServer extends DownloadServer {
|
||||||
JSONObject item = arr.getJSONObject(i);
|
JSONObject item = arr.getJSONObject(i);
|
||||||
int beatmapSetID = item.getInt("OSUSetid");
|
int beatmapSetID = item.getInt("OSUSetid");
|
||||||
int serverID = item.getInt("id");
|
int serverID = item.getInt("id");
|
||||||
nodes[i] = new DownloadNode(
|
nodes[i] = instanceContainer.injectFields(new DownloadNode(
|
||||||
beatmapSetID, formatDate(item.getString("ModifyDate")),
|
beatmapSetID, formatDate(item.getString("ModifyDate")),
|
||||||
item.getString("Title"), null,
|
item.getString("Title"), null,
|
||||||
item.getString("Artist"), null,
|
item.getString("Artist"), null,
|
||||||
item.getString("Mapper")
|
item.getString("Mapper")
|
||||||
);
|
));
|
||||||
idTable.put(beatmapSetID, serverID);
|
idTable.put(beatmapSetID, serverID);
|
||||||
if (serverID > maxServerID)
|
if (serverID > maxServerID)
|
||||||
maxServerID = serverID;
|
maxServerID = serverID;
|
||||||
|
|
|
@ -34,11 +34,17 @@ import java.util.List;
|
||||||
|
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||||
|
import yugecin.opsudance.core.inject.Inject;
|
||||||
|
import yugecin.opsudance.core.inject.InstanceContainer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Download server: http://osu.yas-online.net/
|
* Download server: http://osu.yas-online.net/
|
||||||
*/
|
*/
|
||||||
public class YaSOnlineServer extends DownloadServer {
|
public class YaSOnlineServer extends DownloadServer {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public InstanceContainer instanceContainer;
|
||||||
|
|
||||||
/** Server name. */
|
/** Server name. */
|
||||||
private static final String SERVER_NAME = "YaS Online";
|
private static final String SERVER_NAME = "YaS Online";
|
||||||
|
|
||||||
|
@ -66,8 +72,9 @@ public class YaSOnlineServer extends DownloadServer {
|
||||||
/** Max server download ID seen (for approximating total pages). */
|
/** Max server download ID seen (for approximating total pages). */
|
||||||
private int maxServerID = 0;
|
private int maxServerID = 0;
|
||||||
|
|
||||||
/** Constructor. */
|
@Inject
|
||||||
public YaSOnlineServer() {}
|
public YaSOnlineServer() {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() { return SERVER_NAME; }
|
public String getName() { return SERVER_NAME; }
|
||||||
|
@ -176,7 +183,7 @@ public class YaSOnlineServer extends DownloadServer {
|
||||||
if (serverID > maxServerID)
|
if (serverID > maxServerID)
|
||||||
maxServerID = serverID;
|
maxServerID = serverID;
|
||||||
|
|
||||||
nodeList.add(new DownloadNode(item.getInt("mapid"), date, title, null, artist, null, ""));
|
nodeList.add(instanceContainer.injectFields(new DownloadNode(item.getInt("mapid"), date, title, null, artist, null, "")));
|
||||||
}
|
}
|
||||||
nodes = nodeList.toArray(new DownloadNode[nodeList.size()]);
|
nodes = nodeList.toArray(new DownloadNode[nodeList.size()]);
|
||||||
|
|
||||||
|
|
|
@ -20,9 +20,7 @@ package itdelatrisu.opsu.objects;
|
||||||
|
|
||||||
import itdelatrisu.opsu.GameData;
|
import itdelatrisu.opsu.GameData;
|
||||||
import itdelatrisu.opsu.GameData.HitObjectType;
|
import itdelatrisu.opsu.GameData.HitObjectType;
|
||||||
import itdelatrisu.opsu.GameImage;
|
|
||||||
import itdelatrisu.opsu.GameMod;
|
import itdelatrisu.opsu.GameMod;
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.Utils;
|
import itdelatrisu.opsu.Utils;
|
||||||
import itdelatrisu.opsu.beatmap.HitObject;
|
import itdelatrisu.opsu.beatmap.HitObject;
|
||||||
import itdelatrisu.opsu.objects.curves.Vec2f;
|
import itdelatrisu.opsu.objects.curves.Vec2f;
|
||||||
|
@ -30,16 +28,20 @@ import itdelatrisu.opsu.states.Game;
|
||||||
import itdelatrisu.opsu.ui.Colors;
|
import itdelatrisu.opsu.ui.Colors;
|
||||||
|
|
||||||
import org.newdawn.slick.Color;
|
import org.newdawn.slick.Color;
|
||||||
import org.newdawn.slick.GameContainer;
|
|
||||||
import org.newdawn.slick.Graphics;
|
import org.newdawn.slick.Graphics;
|
||||||
import yugecin.opsudance.Dancer;
|
import yugecin.opsudance.Dancer;
|
||||||
|
import yugecin.opsudance.core.inject.Inject;
|
||||||
|
import yugecin.opsudance.render.GameObjectRenderer;
|
||||||
|
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data type representing a circle object.
|
* Data type representing a circle object.
|
||||||
*/
|
*/
|
||||||
public class Circle extends GameObject {
|
public class Circle extends GameObject {
|
||||||
/** The diameter of hit circles. */
|
|
||||||
public static float diameter;
|
@Inject
|
||||||
|
private GameObjectRenderer gameObjectRenderer;
|
||||||
|
|
||||||
/** The associated HitObject. */
|
/** The associated HitObject. */
|
||||||
private HitObject hitObject;
|
private HitObject hitObject;
|
||||||
|
@ -62,18 +64,6 @@ public class Circle extends GameObject {
|
||||||
|
|
||||||
private int comboColorIndex;
|
private int comboColorIndex;
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the Circle data type with map modifiers, images, and dimensions.
|
|
||||||
* @param circleDiameter the circle diameter
|
|
||||||
*/
|
|
||||||
public static void init(float circleDiameter) {
|
|
||||||
diameter = circleDiameter * HitObject.getXMultiplier(); // convert from Osupixels (640x480)
|
|
||||||
int diameterInt = (int) diameter;
|
|
||||||
GameImage.HITCIRCLE.setImage(GameImage.HITCIRCLE.getImage().getScaledCopy(diameterInt, diameterInt));
|
|
||||||
GameImage.HITCIRCLE_OVERLAY.setImage(GameImage.HITCIRCLE_OVERLAY.getImage().getScaledCopy(diameterInt, diameterInt));
|
|
||||||
GameImage.APPROACHCIRCLE.setImage(GameImage.APPROACHCIRCLE.getImage().getScaledCopy(diameterInt, diameterInt));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
* @param hitObject the associated HitObject
|
* @param hitObject the associated HitObject
|
||||||
|
@ -129,16 +119,10 @@ public class Circle extends GameObject {
|
||||||
float oldAlpha = Colors.WHITE_FADE.a;
|
float oldAlpha = Colors.WHITE_FADE.a;
|
||||||
Colors.WHITE_FADE.a = color.a = alpha;
|
Colors.WHITE_FADE.a = color.a = alpha;
|
||||||
|
|
||||||
if (timeDiff >= 0 && !GameMod.HIDDEN.isActive() && Options.isDrawApproach())
|
if (timeDiff >= 0) {
|
||||||
GameImage.APPROACHCIRCLE.getImage().getScaledCopy(approachScale).drawCentered(x, y, color);
|
gameObjectRenderer.renderApproachCircle(x, y, color, approachScale);
|
||||||
GameImage.HITCIRCLE.getImage().drawCentered(x, y, color);
|
}
|
||||||
boolean overlayAboveNumber = Options.getSkin().isHitCircleOverlayAboveNumber();
|
gameObjectRenderer.renderHitCircle(x, y, color, hitObject.getComboNumber(), alpha);
|
||||||
if (!overlayAboveNumber)
|
|
||||||
GameImage.HITCIRCLE_OVERLAY.getImage().drawCentered(x, y, Colors.WHITE_FADE);
|
|
||||||
data.drawSymbolNumber(hitObject.getComboNumber(), x, y,
|
|
||||||
GameImage.HITCIRCLE.getImage().getWidth() * 0.40f / data.getDefaultSymbolImage(0).getHeight(), alpha);
|
|
||||||
if (overlayAboveNumber)
|
|
||||||
GameImage.HITCIRCLE_OVERLAY.getImage().drawCentered(x, y, Colors.WHITE_FADE);
|
|
||||||
|
|
||||||
Colors.WHITE_FADE.a = oldAlpha;
|
Colors.WHITE_FADE.a = oldAlpha;
|
||||||
|
|
||||||
|
@ -172,7 +156,7 @@ public class Circle extends GameObject {
|
||||||
@Override
|
@Override
|
||||||
public boolean mousePressed(int x, int y, int trackPosition) {
|
public boolean mousePressed(int x, int y, int trackPosition) {
|
||||||
double distance = Math.hypot(this.x - x, this.y - y);
|
double distance = Math.hypot(this.x - x, this.y - y);
|
||||||
if (distance < diameter / 2) {
|
if (distance < gameObjectRenderer.getCircleDiameter() / 2) {
|
||||||
int timeDiff = trackPosition - hitObject.getTime();
|
int timeDiff = trackPosition - hitObject.getTime();
|
||||||
int result = hitResult(timeDiff);
|
int result = hitResult(timeDiff);
|
||||||
|
|
||||||
|
@ -195,7 +179,7 @@ public class Circle extends GameObject {
|
||||||
if (trackPosition > time + hitResultOffset[GameData.HIT_50]) {
|
if (trackPosition > time + hitResultOffset[GameData.HIT_50]) {
|
||||||
if (isAutoMod) {// "auto" mod: catch any missed notes due to lag
|
if (isAutoMod) {// "auto" mod: catch any missed notes due to lag
|
||||||
data.sendHitResult(time, GameData.HIT_300, x, y, color, comboEnd, hitObject, HitObjectType.CIRCLE, true, 0, null, false);
|
data.sendHitResult(time, GameData.HIT_300, x, y, color, comboEnd, hitObject, HitObjectType.CIRCLE, true, 0, null, false);
|
||||||
if (Options.isMirror() && GameMod.AUTO.isActive()) {
|
if (OPTION_DANCE_MIRROR.state && GameMod.AUTO.isActive()) {
|
||||||
float[] m = Utils.mirrorPoint(x, y);
|
float[] m = Utils.mirrorPoint(x, y);
|
||||||
data.sendHitResult(time, GameData.HIT_300, m[0], m[1], mirrorColor, comboEnd, hitObject, HitObjectType.CIRCLE, true, 0, null, false, false);
|
data.sendHitResult(time, GameData.HIT_300, m[0], m[1], mirrorColor, comboEnd, hitObject, HitObjectType.CIRCLE, true, 0, null, false, false);
|
||||||
}
|
}
|
||||||
|
@ -210,7 +194,7 @@ public class Circle extends GameObject {
|
||||||
else if (isAutoMod) {
|
else if (isAutoMod) {
|
||||||
if (Math.abs(trackPosition - time) < hitResultOffset[GameData.HIT_300]) {
|
if (Math.abs(trackPosition - time) < hitResultOffset[GameData.HIT_300]) {
|
||||||
data.sendHitResult(time, GameData.HIT_300, x, y, color, comboEnd, hitObject, HitObjectType.CIRCLE, true, 0, null, false);
|
data.sendHitResult(time, GameData.HIT_300, x, y, color, comboEnd, hitObject, HitObjectType.CIRCLE, true, 0, null, false);
|
||||||
if (Options.isMirror() && GameMod.AUTO.isActive()) {
|
if (OPTION_DANCE_MIRROR.state && GameMod.AUTO.isActive()) {
|
||||||
float[] m = Utils.mirrorPoint(x, y);
|
float[] m = Utils.mirrorPoint(x, y);
|
||||||
data.sendHitResult(time, GameData.HIT_300, m[0], m[1], mirrorColor, comboEnd, hitObject, HitObjectType.CIRCLE, true, 0, null, false, false);
|
data.sendHitResult(time, GameData.HIT_300, m[0], m[1], mirrorColor, comboEnd, hitObject, HitObjectType.CIRCLE, true, 0, null, false, false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,6 @@ import itdelatrisu.opsu.GameData;
|
||||||
import itdelatrisu.opsu.GameData.HitObjectType;
|
import itdelatrisu.opsu.GameData.HitObjectType;
|
||||||
import itdelatrisu.opsu.GameImage;
|
import itdelatrisu.opsu.GameImage;
|
||||||
import itdelatrisu.opsu.GameMod;
|
import itdelatrisu.opsu.GameMod;
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.Utils;
|
import itdelatrisu.opsu.Utils;
|
||||||
import itdelatrisu.opsu.beatmap.Beatmap;
|
import itdelatrisu.opsu.beatmap.Beatmap;
|
||||||
import itdelatrisu.opsu.beatmap.HitObject;
|
import itdelatrisu.opsu.beatmap.HitObject;
|
||||||
|
@ -37,11 +36,23 @@ import org.newdawn.slick.Graphics;
|
||||||
import org.newdawn.slick.Image;
|
import org.newdawn.slick.Image;
|
||||||
import yugecin.opsudance.Dancer;
|
import yugecin.opsudance.Dancer;
|
||||||
import yugecin.opsudance.core.DisplayContainer;
|
import yugecin.opsudance.core.DisplayContainer;
|
||||||
|
import yugecin.opsudance.core.inject.Inject;
|
||||||
|
import yugecin.opsudance.render.GameObjectRenderer;
|
||||||
|
import yugecin.opsudance.skinning.SkinService;
|
||||||
|
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data type representing a slider object.
|
* Data type representing a slider object.
|
||||||
*/
|
*/
|
||||||
public class Slider extends GameObject {
|
public class Slider extends GameObject {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private DisplayContainer displayContainer;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private GameObjectRenderer gameObjectRenderer;
|
||||||
|
|
||||||
/** Slider ball frames. */
|
/** Slider ball frames. */
|
||||||
private static Image[] sliderBallImages;
|
private static Image[] sliderBallImages;
|
||||||
|
|
||||||
|
@ -54,9 +65,6 @@ public class Slider extends GameObject {
|
||||||
/** Follow circle radius. */
|
/** Follow circle radius. */
|
||||||
private static float followRadius;
|
private static float followRadius;
|
||||||
|
|
||||||
/** The diameter of hit circles. */
|
|
||||||
private static float diameter;
|
|
||||||
|
|
||||||
/** The associated HitObject. */
|
/** The associated HitObject. */
|
||||||
private HitObject hitObject;
|
private HitObject hitObject;
|
||||||
|
|
||||||
|
@ -116,9 +124,6 @@ public class Slider extends GameObject {
|
||||||
private static final int FOLLOW_EXPAND_TIME = 150;
|
private static final int FOLLOW_EXPAND_TIME = 150;
|
||||||
private static final int FOLLOW_SHRINK_TIME = 100;
|
private static final int FOLLOW_SHRINK_TIME = 100;
|
||||||
|
|
||||||
/** Container dimensions. */
|
|
||||||
private static int containerWidth, containerHeight;
|
|
||||||
|
|
||||||
private int repeats;
|
private int repeats;
|
||||||
|
|
||||||
private static Color curveColor = new Color(0, 0, 0, 20);
|
private static Color curveColor = new Color(0, 0, 0, 20);
|
||||||
|
@ -134,14 +139,9 @@ public class Slider extends GameObject {
|
||||||
* @param circleDiameter the circle diameter
|
* @param circleDiameter the circle diameter
|
||||||
* @param beatmap the associated beatmap
|
* @param beatmap the associated beatmap
|
||||||
*/
|
*/
|
||||||
public static void init(DisplayContainer displayContainer, float circleDiameter, Beatmap beatmap) {
|
public static void init(float circleDiameter, Beatmap beatmap) {
|
||||||
containerWidth = displayContainer.width;
|
followRadius = circleDiameter / 2 * 3f;
|
||||||
containerHeight = displayContainer.height;
|
int diameterInt = (int) circleDiameter;
|
||||||
|
|
||||||
diameter = circleDiameter * HitObject.getXMultiplier(); // convert from Osupixels (640x480)
|
|
||||||
int diameterInt = (int) diameter;
|
|
||||||
|
|
||||||
followRadius = diameter / 2 * 3f;
|
|
||||||
|
|
||||||
// slider ball
|
// slider ball
|
||||||
if (GameImage.SLIDER_BALL.hasBeatmapSkinImages() ||
|
if (GameImage.SLIDER_BALL.hasBeatmapSkinImages() ||
|
||||||
|
@ -216,11 +216,9 @@ public class Slider extends GameObject {
|
||||||
double fadeinScale = (timeDiff - approachTime + fadeInTime) / (double) fadeInTime;
|
double fadeinScale = (timeDiff - approachTime + fadeInTime) / (double) fadeInTime;
|
||||||
float alpha = Utils.clamp(1 - (float) fadeinScale, 0, 1);
|
float alpha = Utils.clamp(1 - (float) fadeinScale, 0, 1);
|
||||||
float decorationsAlpha = Utils.clamp(-2.0f * (float) fadeinScale, 0, 1);
|
float decorationsAlpha = Utils.clamp(-2.0f * (float) fadeinScale, 0, 1);
|
||||||
boolean overlayAboveNumber = Options.getSkin().isHitCircleOverlayAboveNumber();
|
boolean overlayAboveNumber = SkinService.skin.isHitCircleOverlayAboveNumber();
|
||||||
float oldAlpha = Colors.WHITE_FADE.a;
|
float oldAlpha = Colors.WHITE_FADE.a;
|
||||||
Colors.WHITE_FADE.a = color.a = alpha;
|
Colors.WHITE_FADE.a = color.a = alpha;
|
||||||
Image hitCircleOverlay = GameImage.HITCIRCLE_OVERLAY.getImage();
|
|
||||||
Image hitCircle = GameImage.HITCIRCLE.getImage();
|
|
||||||
Vec2f endPos = curve.pointAt(1);
|
Vec2f endPos = curve.pointAt(1);
|
||||||
|
|
||||||
float oldWhiteFadeAlpha = Colors.WHITE_FADE.a;
|
float oldWhiteFadeAlpha = Colors.WHITE_FADE.a;
|
||||||
|
@ -236,11 +234,11 @@ public class Slider extends GameObject {
|
||||||
color.a = alpha;
|
color.a = alpha;
|
||||||
|
|
||||||
// end circle (only draw if ball still has to go there)
|
// end circle (only draw if ball still has to go there)
|
||||||
if (Options.isDrawSliderEndCircles() && isCurveCompletelyDrawn && currentRepeats < repeatCount - (repeatCount % 2 == 0 ? 1 : 0)) {
|
if (OPTION_DRAW_SLIDER_ENDCIRCLES.state && isCurveCompletelyDrawn && currentRepeats < repeatCount - (repeatCount % 2 == 0 ? 1 : 0)) {
|
||||||
Color circleColor = new Color(color);
|
Color circleColor = new Color(color);
|
||||||
Color overlayColor = new Color(Colors.WHITE_FADE);
|
Color overlayColor = new Color(Colors.WHITE_FADE);
|
||||||
if (currentRepeats == 0) {
|
if (currentRepeats == 0) {
|
||||||
if (Options.isSliderSnaking()) {
|
if (OPTION_SNAKING_SLIDERS.state) {
|
||||||
// fade in end circle using decorationsAlpha when snaking sliders are enabled
|
// fade in end circle using decorationsAlpha when snaking sliders are enabled
|
||||||
circleColor.a = overlayColor.a = sliderAlpha * decorationsAlpha;
|
circleColor.a = overlayColor.a = sliderAlpha * decorationsAlpha;
|
||||||
}
|
}
|
||||||
|
@ -249,8 +247,8 @@ public class Slider extends GameObject {
|
||||||
circleColor.a = overlayColor.a = sliderAlpha * getCircleAlphaAfterRepeat(trackPosition, true);
|
circleColor.a = overlayColor.a = sliderAlpha * getCircleAlphaAfterRepeat(trackPosition, true);
|
||||||
}
|
}
|
||||||
Vec2f endCircPos = curve.pointAt(1f);
|
Vec2f endCircPos = curve.pointAt(1f);
|
||||||
hitCircle.drawCentered(endCircPos.x, endCircPos.y, circleColor);
|
gameObjectRenderer.renderHitCircleOnly(endCircPos.x, endCircPos.y, circleColor);
|
||||||
hitCircleOverlay.drawCentered(endCircPos.x, endCircPos.y, overlayColor);
|
gameObjectRenderer.renderHitCircleOverlayOnly(endCircPos.x, endCircPos.y, overlayColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
g.pushTransform();
|
g.pushTransform();
|
||||||
|
@ -267,10 +265,11 @@ public class Slider extends GameObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
// start circle, only draw if ball still has to go there
|
// start circle, only draw if ball still has to go there
|
||||||
if (!sliderClickedInitial || (Options.isDrawSliderEndCircles() && currentRepeats < repeatCount - (repeatCount % 2 == 1 ? 1 : 0))) {
|
if (!sliderClickedInitial || (OPTION_DRAW_SLIDER_ENDCIRCLES.state && currentRepeats < repeatCount - (repeatCount % 2 == 1 ? 1 : 0))) {
|
||||||
hitCircle.drawCentered(x, y, firstCircleColor);
|
gameObjectRenderer.renderHitCircleOnly(x, y, firstCircleColor);
|
||||||
if (!overlayAboveNumber || sliderClickedInitial)
|
if (!overlayAboveNumber || sliderClickedInitial) {
|
||||||
hitCircleOverlay.drawCentered(x, y, startCircleOverlayColor);
|
gameObjectRenderer.renderHitCircleOverlayOnly(x, y, startCircleOverlayColor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
g.popTransform();
|
g.popTransform();
|
||||||
|
@ -297,12 +296,11 @@ public class Slider extends GameObject {
|
||||||
|
|
||||||
// draw combo number and overlay if not initially clicked
|
// draw combo number and overlay if not initially clicked
|
||||||
if (!sliderClickedInitial) {
|
if (!sliderClickedInitial) {
|
||||||
data.drawSymbolNumber(hitObject.getComboNumber(), x, y,
|
gameObjectRenderer.renderComboNumberOnly(x, y, hitObject.getComboNumber(), alpha);
|
||||||
hitCircle.getWidth() * 0.40f / data.getDefaultSymbolImage(0).getHeight(), alpha);
|
|
||||||
|
|
||||||
if (overlayAboveNumber) {
|
if (overlayAboveNumber) {
|
||||||
startCircleOverlayColor.a = sliderAlpha;
|
startCircleOverlayColor.a = sliderAlpha;
|
||||||
hitCircleOverlay.drawCentered(x, y, startCircleOverlayColor);
|
gameObjectRenderer.renderHitCircleOverlayOnly(x, y, startCircleOverlayColor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,7 +312,7 @@ public class Slider extends GameObject {
|
||||||
Image arrow = GameImage.REVERSEARROW.getImage();
|
Image arrow = GameImage.REVERSEARROW.getImage();
|
||||||
arrow = arrow.getScaledCopy((float) (1 + 0.2d * ((trackPosition + sliderTime * tcurRepeat) % 292) / 292));
|
arrow = arrow.getScaledCopy((float) (1 + 0.2d * ((trackPosition + sliderTime * tcurRepeat) % 292) / 292));
|
||||||
if (tcurRepeat == 0) {
|
if (tcurRepeat == 0) {
|
||||||
arrow.setAlpha(Options.isSliderSnaking() ? decorationsAlpha : 1f);
|
arrow.setAlpha(OPTION_SNAKING_SLIDERS.state ? decorationsAlpha : 1f);
|
||||||
} else {
|
} else {
|
||||||
if (!sliderClickedInitial) {
|
if (!sliderClickedInitial) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -339,8 +337,8 @@ public class Slider extends GameObject {
|
||||||
if (mirror) {
|
if (mirror) {
|
||||||
g.rotate(x, y, -180f);
|
g.rotate(x, y, -180f);
|
||||||
}
|
}
|
||||||
if (!GameMod.HIDDEN.isActive() && Options.isDrawApproach()) {
|
if (!GameMod.HIDDEN.isActive() && OPTION_DANCE_DRAW_APPROACH.state) {
|
||||||
GameImage.APPROACHCIRCLE.getImage().getScaledCopy(approachScale).drawCentered(x, y, color);
|
gameObjectRenderer.renderApproachCircle(x, y, color, approachScale);
|
||||||
}
|
}
|
||||||
g.popTransform();
|
g.popTransform();
|
||||||
} else {
|
} else {
|
||||||
|
@ -362,7 +360,7 @@ public class Slider extends GameObject {
|
||||||
Image sliderBallFrame = sliderBallImages[(int) (t * sliderTime * 60 / 1000) % sliderBallImages.length];
|
Image sliderBallFrame = sliderBallImages[(int) (t * sliderTime * 60 / 1000) % sliderBallImages.length];
|
||||||
float angle = (float) (Math.atan2(c2.y - c.y, c2.x - c.x) * 180 / Math.PI);
|
float angle = (float) (Math.atan2(c2.y - c.y, c2.x - c.x) * 180 / Math.PI);
|
||||||
sliderBallFrame.setRotation(angle);
|
sliderBallFrame.setRotation(angle);
|
||||||
if (Options.getSkin().isAllowSliderBallTint()) {
|
if (SkinService.skin.isAllowSliderBallTint()) {
|
||||||
sliderBallFrame.drawCentered(c.x, c.y, color);
|
sliderBallFrame.drawCentered(c.x, c.y, color);
|
||||||
} else {
|
} else {
|
||||||
sliderBallFrame.drawCentered(c.x, c.y);
|
sliderBallFrame.drawCentered(c.x, c.y);
|
||||||
|
@ -373,13 +371,13 @@ public class Slider extends GameObject {
|
||||||
float followCircleScale = 1f + (tickExpandTime / (float) TICK_EXPAND_TIME) * 0.1f;
|
float followCircleScale = 1f + (tickExpandTime / (float) TICK_EXPAND_TIME) * 0.1f;
|
||||||
float followAlpha = 1f;
|
float followAlpha = 1f;
|
||||||
if (followCircleActive && followExpandTime < FOLLOW_EXPAND_TIME) {
|
if (followCircleActive && followExpandTime < FOLLOW_EXPAND_TIME) {
|
||||||
followExpandTime += DisplayContainer.instance.renderDelta;
|
followExpandTime += displayContainer.renderDelta;
|
||||||
followCircleScale *= 0.5f;
|
followCircleScale *= 0.5f;
|
||||||
float progress = AnimationEquation.OUT_QUAD.calc((float) followExpandTime / FOLLOW_EXPAND_TIME);
|
float progress = AnimationEquation.OUT_QUAD.calc((float) followExpandTime / FOLLOW_EXPAND_TIME);
|
||||||
followCircleScale = followCircleScale + followCircleScale * progress;
|
followCircleScale = followCircleScale + followCircleScale * progress;
|
||||||
followAlpha = progress;
|
followAlpha = progress;
|
||||||
} else if (!followCircleActive) {
|
} else if (!followCircleActive) {
|
||||||
followExpandTime -= DisplayContainer.instance.renderDelta;
|
followExpandTime -= displayContainer.renderDelta;
|
||||||
if (followExpandTime > FOLLOW_SHRINK_TIME) {
|
if (followExpandTime > FOLLOW_SHRINK_TIME) {
|
||||||
followExpandTime = FOLLOW_SHRINK_TIME;
|
followExpandTime = FOLLOW_SHRINK_TIME;
|
||||||
}
|
}
|
||||||
|
@ -394,7 +392,7 @@ public class Slider extends GameObject {
|
||||||
float oldAlphaBlack = Colors.BLACK_ALPHA.a;
|
float oldAlphaBlack = Colors.BLACK_ALPHA.a;
|
||||||
Colors.BLACK_ALPHA.a = 0.75f;
|
Colors.BLACK_ALPHA.a = 0.75f;
|
||||||
g.setColor(Colors.BLACK_ALPHA);
|
g.setColor(Colors.BLACK_ALPHA);
|
||||||
g.fillRect(0, 0, containerWidth, containerHeight);
|
g.fillRect(0, 0, displayContainer.width, displayContainer.height);
|
||||||
Colors.BLACK_ALPHA.a = oldAlphaBlack;
|
Colors.BLACK_ALPHA.a = oldAlphaBlack;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -459,27 +457,28 @@ public class Slider extends GameObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean drawSliderTrack(int trackPosition, double snakingSliderProgress) {
|
private boolean drawSliderTrack(int trackPosition, double snakingSliderProgress) {
|
||||||
double curveIntervalTo = Options.isSliderSnaking() ? snakingSliderProgress : 1d;
|
double curveIntervalTo = OPTION_SNAKING_SLIDERS.state ? snakingSliderProgress : 1d;
|
||||||
double curveIntervalFrom = 0d;
|
double curveIntervalFrom = 0d;
|
||||||
if (Options.isShrinkingSliders()) {
|
if (OPTION_SHRINKING_SLIDERS.state) {
|
||||||
double sliderprogress = (trackPosition - getTime() - ((double) sliderTime * (repeats - 1))) / (double) sliderTime;
|
double sliderprogress = (trackPosition - getTime() - ((double) sliderTime * (repeats - 1))) / (double) sliderTime;
|
||||||
if (sliderprogress > 0) {
|
if (sliderprogress > 0) {
|
||||||
curveIntervalFrom = sliderprogress;
|
curveIntervalFrom = sliderprogress;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int curvelen = curve.getCurvePoints().length;
|
int curvelen = curve.getCurvePoints().length;
|
||||||
if (Options.isMergingSliders()) {
|
if (!OPTION_FALLBACK_SLIDERS.state && OPTION_MERGING_SLIDERS.state) {
|
||||||
if (Options.isShrinkingSliders() && curveIntervalFrom > 0) {
|
if (OPTION_SHRINKING_SLIDERS.state && curveIntervalFrom > 0) {
|
||||||
if (repeats % 2 == 0) {
|
if (hitObject.getRepeatCount() % 2 == 0) {
|
||||||
game.spliceSliderCurve(baseSliderFrom + (int) ((1d - curveIntervalFrom) * curvelen) - 1, baseSliderFrom + curvelen);
|
game.addMergedSliderPointsToRender(baseSliderFrom, baseSliderFrom + (int) ((1d - curveIntervalFrom) * curvelen));
|
||||||
} else {
|
} else {
|
||||||
game.setSlidercurveFrom(baseSliderFrom + (int) (curveIntervalFrom * curvelen) + 1);
|
game.addMergedSliderPointsToRender(baseSliderFrom + (int) (curveIntervalFrom * curvelen) + 1, baseSliderFrom + (int) (curveIntervalTo * curve.getCurvePoints().length));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
game.setSlidercurveTo(baseSliderFrom + (int) (curveIntervalTo * curve.getCurvePoints().length));
|
|
||||||
} else {
|
} else {
|
||||||
if (Options.isShrinkingSliders() && curveIntervalFrom > 0 && repeats % 2 == 0) {
|
game.addMergedSliderPointsToRender(baseSliderFrom, baseSliderFrom + (int) (curveIntervalTo * curve.getCurvePoints().length));
|
||||||
if (Options.isFallbackSliders()) {
|
}
|
||||||
|
} else {
|
||||||
|
if (OPTION_SHRINKING_SLIDERS.state && curveIntervalFrom > 0 && repeats % 2 == 0) {
|
||||||
|
if (OPTION_FALLBACK_SLIDERS.state) {
|
||||||
curveIntervalTo = 1d - curveIntervalFrom;
|
curveIntervalTo = 1d - curveIntervalFrom;
|
||||||
} else {
|
} else {
|
||||||
curve.splice((int) ((1d - curveIntervalFrom) * curvelen), curvelen);
|
curve.splice((int) ((1d - curveIntervalFrom) * curvelen), curvelen);
|
||||||
|
@ -590,7 +589,7 @@ public class Slider extends GameObject {
|
||||||
data.sendHitResult(hitObject.getTime() + (int) sliderTimeTotal, result,
|
data.sendHitResult(hitObject.getTime() + (int) sliderTimeTotal, result,
|
||||||
cx, cy, color, comboEnd, hitObject, type, sliderHeldToEnd,
|
cx, cy, color, comboEnd, hitObject, type, sliderHeldToEnd,
|
||||||
currentRepeats + 1, curve, sliderHeldToEnd);
|
currentRepeats + 1, curve, sliderHeldToEnd);
|
||||||
if (Options.isMirror() && GameMod.AUTO.isActive()) {
|
if (OPTION_DANCE_MIRROR.state && GameMod.AUTO.isActive()) {
|
||||||
float[] m = Utils.mirrorPoint(cx, cy);
|
float[] m = Utils.mirrorPoint(cx, cy);
|
||||||
data.sendHitResult(hitObject.getTime() + (int) sliderTimeTotal, result,
|
data.sendHitResult(hitObject.getTime() + (int) sliderTimeTotal, result,
|
||||||
m[0], m[1], mirrorColor, comboEnd, hitObject, type, sliderHeldToEnd,
|
m[0], m[1], mirrorColor, comboEnd, hitObject, type, sliderHeldToEnd,
|
||||||
|
@ -606,7 +605,7 @@ public class Slider extends GameObject {
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
double distance = Math.hypot(this.x - x, this.y - y);
|
double distance = Math.hypot(this.x - x, this.y - y);
|
||||||
if (distance < diameter / 2) {
|
if (distance < gameObjectRenderer.getCircleDiameter() / 2) {
|
||||||
int timeDiff = Math.abs(trackPosition - hitObject.getTime());
|
int timeDiff = Math.abs(trackPosition - hitObject.getTime());
|
||||||
int[] hitResultOffset = game.getHitResultOffsets();
|
int[] hitResultOffset = game.getHitResultOffsets();
|
||||||
|
|
||||||
|
@ -691,9 +690,6 @@ public class Slider extends GameObject {
|
||||||
|
|
||||||
// calculate and send slider result
|
// calculate and send slider result
|
||||||
hitResult();
|
hitResult();
|
||||||
if (Options.isMergingSliders()) {
|
|
||||||
game.setSlidercurveFrom(baseSliderFrom + curve.getCurvePoints().length + 1);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,6 @@ import itdelatrisu.opsu.GameData;
|
||||||
import itdelatrisu.opsu.GameData.HitObjectType;
|
import itdelatrisu.opsu.GameData.HitObjectType;
|
||||||
import itdelatrisu.opsu.GameImage;
|
import itdelatrisu.opsu.GameImage;
|
||||||
import itdelatrisu.opsu.GameMod;
|
import itdelatrisu.opsu.GameMod;
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.Utils;
|
import itdelatrisu.opsu.Utils;
|
||||||
import itdelatrisu.opsu.audio.SoundController;
|
import itdelatrisu.opsu.audio.SoundController;
|
||||||
import itdelatrisu.opsu.audio.SoundEffect;
|
import itdelatrisu.opsu.audio.SoundEffect;
|
||||||
|
@ -32,10 +31,10 @@ import itdelatrisu.opsu.states.Game;
|
||||||
import itdelatrisu.opsu.ui.Colors;
|
import itdelatrisu.opsu.ui.Colors;
|
||||||
|
|
||||||
import org.newdawn.slick.Color;
|
import org.newdawn.slick.Color;
|
||||||
import org.newdawn.slick.GameContainer;
|
|
||||||
import org.newdawn.slick.Graphics;
|
import org.newdawn.slick.Graphics;
|
||||||
import org.newdawn.slick.Image;
|
import org.newdawn.slick.Image;
|
||||||
import yugecin.opsudance.core.DisplayContainer;
|
import yugecin.opsudance.core.DisplayContainer;
|
||||||
|
import yugecin.opsudance.skinning.SkinService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data type representing a spinner object.
|
* Data type representing a spinner object.
|
||||||
|
@ -189,7 +188,7 @@ public class Spinner extends GameObject {
|
||||||
float alpha = Utils.clamp(1 - (float) timeDiff / fadeInTime, 0f, 1f);
|
float alpha = Utils.clamp(1 - (float) timeDiff / fadeInTime, 0f, 1f);
|
||||||
|
|
||||||
// darken screen
|
// darken screen
|
||||||
if (Options.getSkin().isSpinnerFadePlayfield()) {
|
if (SkinService.skin.isSpinnerFadePlayfield()) {
|
||||||
float oldAlpha = Colors.BLACK_ALPHA.a;
|
float oldAlpha = Colors.BLACK_ALPHA.a;
|
||||||
if (timeDiff > 0)
|
if (timeDiff > 0)
|
||||||
Colors.BLACK_ALPHA.a *= alpha;
|
Colors.BLACK_ALPHA.a *= alpha;
|
||||||
|
|
|
@ -19,8 +19,6 @@
|
||||||
package itdelatrisu.opsu.objects.curves;
|
package itdelatrisu.opsu.objects.curves;
|
||||||
|
|
||||||
import itdelatrisu.opsu.GameImage;
|
import itdelatrisu.opsu.GameImage;
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.Utils;
|
|
||||||
import itdelatrisu.opsu.beatmap.HitObject;
|
import itdelatrisu.opsu.beatmap.HitObject;
|
||||||
import itdelatrisu.opsu.render.CurveRenderState;
|
import itdelatrisu.opsu.render.CurveRenderState;
|
||||||
import itdelatrisu.opsu.skins.Skin;
|
import itdelatrisu.opsu.skins.Skin;
|
||||||
|
@ -31,7 +29,9 @@ import org.lwjgl.opengl.GLContext;
|
||||||
import org.newdawn.slick.Color;
|
import org.newdawn.slick.Color;
|
||||||
import org.newdawn.slick.Image;
|
import org.newdawn.slick.Image;
|
||||||
import org.newdawn.slick.util.Log;
|
import org.newdawn.slick.util.Log;
|
||||||
import yugecin.opsudance.objects.curves.FakeCombinedCurve;
|
import yugecin.opsudance.skinning.SkinService;
|
||||||
|
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Representation of a curve.
|
* Representation of a curve.
|
||||||
|
@ -43,7 +43,7 @@ public abstract class Curve {
|
||||||
protected static float CURVE_POINTS_SEPERATION = 2.5f;
|
protected static float CURVE_POINTS_SEPERATION = 2.5f;
|
||||||
|
|
||||||
/** The curve border color. */
|
/** The curve border color. */
|
||||||
private static Color borderColor;
|
protected static Color borderColor;
|
||||||
|
|
||||||
/** Whether mmsliders are supported. */
|
/** Whether mmsliders are supported. */
|
||||||
private static boolean mmsliderSupported = false;
|
private static boolean mmsliderSupported = false;
|
||||||
|
@ -58,7 +58,7 @@ public abstract class Curve {
|
||||||
protected float[] sliderX, sliderY;
|
protected float[] sliderX, sliderY;
|
||||||
|
|
||||||
/** Per-curve render-state used for the new style curve renders. */
|
/** Per-curve render-state used for the new style curve renders. */
|
||||||
private CurveRenderState renderState;
|
protected CurveRenderState renderState;
|
||||||
|
|
||||||
/** Points along the curve (set by inherited classes). */
|
/** Points along the curve (set by inherited classes). */
|
||||||
public Vec2f[] curve;
|
public Vec2f[] curve;
|
||||||
|
@ -103,10 +103,9 @@ public abstract class Curve {
|
||||||
|
|
||||||
ContextCapabilities capabilities = GLContext.getCapabilities();
|
ContextCapabilities capabilities = GLContext.getCapabilities();
|
||||||
mmsliderSupported = capabilities.OpenGL30;
|
mmsliderSupported = capabilities.OpenGL30;
|
||||||
if (mmsliderSupported)
|
if (mmsliderSupported) {
|
||||||
CurveRenderState.init(width, height, circleDiameter);
|
CurveRenderState.init(width, height, circleDiameter);
|
||||||
else {
|
} else if (SkinService.skin.getSliderStyle() != Skin.STYLE_PEPPYSLIDER) {
|
||||||
if (Options.getSkin().getSliderStyle() != Skin.STYLE_PEPPYSLIDER)
|
|
||||||
Log.warn("New slider style requires OpenGL 3.0.");
|
Log.warn("New slider style requires OpenGL 3.0.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -134,8 +133,8 @@ public abstract class Curve {
|
||||||
if (curve == null)
|
if (curve == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (OPTION_FALLBACK_SLIDERS.state || SkinService.skin.getSliderStyle() == Skin.STYLE_PEPPYSLIDER || !mmsliderSupported) {
|
||||||
// peppysliders
|
// peppysliders
|
||||||
if (Options.isFallbackSliders() || Options.getSkin().getSliderStyle() == Skin.STYLE_PEPPYSLIDER || !mmsliderSupported) {
|
|
||||||
Image hitCircle = GameImage.HITCIRCLE.getImage();
|
Image hitCircle = GameImage.HITCIRCLE.getImage();
|
||||||
Image hitCircleOverlay = GameImage.HITCIRCLE_OVERLAY.getImage();
|
Image hitCircleOverlay = GameImage.HITCIRCLE_OVERLAY.getImage();
|
||||||
for (int i = from; i < to; i++)
|
for (int i = from; i < to; i++)
|
||||||
|
@ -145,19 +144,17 @@ public abstract class Curve {
|
||||||
for (int i = from; i < to; i++)
|
for (int i = from; i < to; i++)
|
||||||
hitCircle.drawCentered(curve[i].x, curve[i].y, fallbackSliderColor);
|
hitCircle.drawCentered(curve[i].x, curve[i].y, fallbackSliderColor);
|
||||||
fallbackSliderColor.a = a;
|
fallbackSliderColor.a = a;
|
||||||
}
|
} else {
|
||||||
|
|
||||||
// mmsliders
|
// mmsliders
|
||||||
else {
|
|
||||||
if (renderState == null)
|
if (renderState == null)
|
||||||
renderState = new CurveRenderState(hitObject, curve, this instanceof FakeCombinedCurve);
|
renderState = new CurveRenderState(hitObject, curve, false);
|
||||||
renderState.draw(color, borderColor, from, to);
|
renderState.draw(color, borderColor, from, to);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void splice(int from, int to) {
|
public void splice(int from, int to) {
|
||||||
if (renderState == null)
|
if (renderState == null)
|
||||||
renderState = new CurveRenderState(hitObject, curve, this instanceof FakeCombinedCurve);
|
renderState = new CurveRenderState(hitObject, curve, false);
|
||||||
renderState.splice(from, to);
|
renderState.splice(from, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,15 +18,15 @@
|
||||||
package itdelatrisu.opsu.render;
|
package itdelatrisu.opsu.render;
|
||||||
|
|
||||||
import itdelatrisu.opsu.GameImage;
|
import itdelatrisu.opsu.GameImage;
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.Utils;
|
import itdelatrisu.opsu.Utils;
|
||||||
import itdelatrisu.opsu.beatmap.HitObject;
|
import itdelatrisu.opsu.beatmap.HitObject;
|
||||||
import itdelatrisu.opsu.objects.Circle;
|
|
||||||
import itdelatrisu.opsu.objects.curves.Vec2f;
|
import itdelatrisu.opsu.objects.curves.Vec2f;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.FloatBuffer;
|
import java.nio.FloatBuffer;
|
||||||
import java.nio.IntBuffer;
|
import java.nio.IntBuffer;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.lwjgl.BufferUtils;
|
import org.lwjgl.BufferUtils;
|
||||||
import org.lwjgl.opengl.EXTFramebufferObject;
|
import org.lwjgl.opengl.EXTFramebufferObject;
|
||||||
|
@ -37,6 +37,9 @@ import org.lwjgl.opengl.GL20;
|
||||||
import org.newdawn.slick.Color;
|
import org.newdawn.slick.Color;
|
||||||
import org.newdawn.slick.Image;
|
import org.newdawn.slick.Image;
|
||||||
import org.newdawn.slick.util.Log;
|
import org.newdawn.slick.util.Log;
|
||||||
|
import yugecin.opsudance.render.GameObjectRenderer;
|
||||||
|
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hold the temporary render state that needs to be restored again after the new
|
* Hold the temporary render state that needs to be restored again after the new
|
||||||
|
@ -69,6 +72,8 @@ public class CurveRenderState {
|
||||||
private int spliceFrom;
|
private int spliceFrom;
|
||||||
private int spliceTo;
|
private int spliceTo;
|
||||||
|
|
||||||
|
protected List<Integer> pointsToRender;
|
||||||
|
|
||||||
private final int mirrors;
|
private final int mirrors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -96,7 +101,7 @@ public class CurveRenderState {
|
||||||
*/
|
*/
|
||||||
public static void shutdown() {
|
public static void shutdown() {
|
||||||
staticState.shutdown();
|
staticState.shutdown();
|
||||||
//FrameBufferCache.shutdown();
|
FrameBufferCache.shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -108,7 +113,7 @@ public class CurveRenderState {
|
||||||
this.hitObject = hitObject;
|
this.hitObject = hitObject;
|
||||||
this.curve = curve;
|
this.curve = curve;
|
||||||
if (isKnorkeSlider) {
|
if (isKnorkeSlider) {
|
||||||
this.mirrors = Options.getMergingSlidersMirrorPool();
|
this.mirrors = OPTION_MERGING_SLIDERS_MIRROR_POOL.val;
|
||||||
} else {
|
} else {
|
||||||
this.mirrors = 1;
|
this.mirrors = 1;
|
||||||
}
|
}
|
||||||
|
@ -138,6 +143,14 @@ public class CurveRenderState {
|
||||||
lastPointDrawn = -1; // force redraw
|
lastPointDrawn = -1; // force redraw
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void draw(Color color, Color borderColor, List<Integer> pointsToRender) {
|
||||||
|
lastPointDrawn = -1;
|
||||||
|
firstPointDrawn = -1;
|
||||||
|
this.pointsToRender = pointsToRender;
|
||||||
|
draw(color, borderColor, 0, curve.length);
|
||||||
|
this.pointsToRender = null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draw a curve to the screen that's tinted with `color`. The first time
|
* Draw a curve to the screen that's tinted with `color`. The first time
|
||||||
* this is called this caches the image result of the curve and on subsequent
|
* this is called this caches the image result of the curve and on subsequent
|
||||||
|
@ -303,7 +316,7 @@ public class CurveRenderState {
|
||||||
double diff_x = x - last_x;
|
double diff_x = x - last_x;
|
||||||
double diff_y = y - last_y;
|
double diff_y = y - last_y;
|
||||||
float dist = Utils.distance(x, y, last_x, last_y);
|
float dist = Utils.distance(x, y, last_x, last_y);
|
||||||
if (dist < Circle.diameter / 8) {
|
if (dist < GameObjectRenderer.instance.getCircleDiameter() / 8) {
|
||||||
x = (float) (x - diff_x / 2);
|
x = (float) (x - diff_x / 2);
|
||||||
y = (float) (y - diff_y / 2);
|
y = (float) (y - diff_y / 2);
|
||||||
} else {
|
} else {
|
||||||
|
@ -344,11 +357,15 @@ public class CurveRenderState {
|
||||||
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
|
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
|
||||||
}
|
}
|
||||||
int max = mirrors;
|
int max = mirrors;
|
||||||
if (!Options.isMirror()) {
|
if (!OPTION_DANCE_MIRROR.state) {
|
||||||
max = 1;
|
max = 1;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < max; i++) {
|
for (int i = 0; i < max; i++) {
|
||||||
|
if (pointsToRender == null) {
|
||||||
renderCurve(from, to, i);
|
renderCurve(from, to, i);
|
||||||
|
} else {
|
||||||
|
renderCurve(i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
GL11.glFlush();
|
GL11.glFlush();
|
||||||
GL20.glDisableVertexAttribArray(staticState.texCoordLoc);
|
GL20.glDisableVertexAttribArray(staticState.texCoordLoc);
|
||||||
|
@ -370,6 +387,16 @@ public class CurveRenderState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void renderCurve(int mirror) {
|
||||||
|
Iterator<Integer> iter = pointsToRender.iterator();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
for (int i = iter.next() * 2, end = iter.next() * 2 - 1; i < end; ++i) {
|
||||||
|
final int index = i + curve.length * 2 * mirror;
|
||||||
|
GL11.glDrawArrays(GL11.GL_TRIANGLE_FAN, index * (NewCurveStyleState.DIVIDES + 2), NewCurveStyleState.DIVIDES + 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fill {@code buff} with the texture coordinates and positions for a cone
|
* Fill {@code buff} with the texture coordinates and positions for a cone
|
||||||
* that has its center at the coordinates {@code (x1,y1)}.
|
* that has its center at the coordinates {@code (x1,y1)}.
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
|
|
||||||
package itdelatrisu.opsu.replay;
|
package itdelatrisu.opsu.replay;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.ScoreData;
|
import itdelatrisu.opsu.ScoreData;
|
||||||
import itdelatrisu.opsu.Utils;
|
import itdelatrisu.opsu.Utils;
|
||||||
import itdelatrisu.opsu.beatmap.Beatmap;
|
import itdelatrisu.opsu.beatmap.Beatmap;
|
||||||
|
@ -46,7 +45,9 @@ import org.newdawn.slick.util.Log;
|
||||||
import lzma.streams.LzmaOutputStream;
|
import lzma.streams.LzmaOutputStream;
|
||||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||||
import yugecin.opsudance.core.events.EventBus;
|
import yugecin.opsudance.core.events.EventBus;
|
||||||
|
import yugecin.opsudance.core.inject.Inject;
|
||||||
import yugecin.opsudance.events.BubbleNotificationEvent;
|
import yugecin.opsudance.events.BubbleNotificationEvent;
|
||||||
|
import yugecin.opsudance.options.Configuration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Captures osu! replay data.
|
* Captures osu! replay data.
|
||||||
|
@ -55,6 +56,10 @@ import yugecin.opsudance.events.BubbleNotificationEvent;
|
||||||
* @author smoogipooo (https://github.com/smoogipooo/osu-Replay-API/)
|
* @author smoogipooo (https://github.com/smoogipooo/osu-Replay-API/)
|
||||||
*/
|
*/
|
||||||
public class Replay {
|
public class Replay {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public Configuration config;
|
||||||
|
|
||||||
/** The associated file. */
|
/** The associated file. */
|
||||||
private File file;
|
private File file;
|
||||||
|
|
||||||
|
@ -272,16 +277,13 @@ public class Replay {
|
||||||
*/
|
*/
|
||||||
public void save() {
|
public void save() {
|
||||||
// create replay directory
|
// create replay directory
|
||||||
File dir = Options.getReplayDir();
|
if (!config.replayDir.isDirectory() && !config.replayDir.mkdir()) {
|
||||||
if (!dir.isDirectory()) {
|
|
||||||
if (!dir.mkdir()) {
|
|
||||||
EventBus.post(new BubbleNotificationEvent("Failed to create replay directory.", BubbleNotificationEvent.COMMONCOLOR_RED));
|
EventBus.post(new BubbleNotificationEvent("Failed to create replay directory.", BubbleNotificationEvent.COMMONCOLOR_RED));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// write file in new thread
|
// write file in new thread
|
||||||
final File file = new File(dir, String.format("%s.osr", getReplayFilename()));
|
final File file = new File(config.replayDir, String.format("%s.osr", getReplayFilename()));
|
||||||
new Thread() {
|
new Thread() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
|
|
||||||
package itdelatrisu.opsu.replay;
|
package itdelatrisu.opsu.replay;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.beatmap.Beatmap;
|
import itdelatrisu.opsu.beatmap.Beatmap;
|
||||||
import itdelatrisu.opsu.beatmap.BeatmapSetList;
|
import itdelatrisu.opsu.beatmap.BeatmapSetList;
|
||||||
import itdelatrisu.opsu.db.ScoreDB;
|
import itdelatrisu.opsu.db.ScoreDB;
|
||||||
|
@ -31,32 +30,42 @@ import java.nio.file.StandardCopyOption;
|
||||||
|
|
||||||
import org.newdawn.slick.util.Log;
|
import org.newdawn.slick.util.Log;
|
||||||
import yugecin.opsudance.core.events.EventBus;
|
import yugecin.opsudance.core.events.EventBus;
|
||||||
|
import yugecin.opsudance.core.inject.Inject;
|
||||||
|
import yugecin.opsudance.core.inject.InstanceContainer;
|
||||||
import yugecin.opsudance.events.BubbleNotificationEvent;
|
import yugecin.opsudance.events.BubbleNotificationEvent;
|
||||||
|
import yugecin.opsudance.options.Configuration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Importer for replay files.
|
* Importer for replay files.
|
||||||
*/
|
*/
|
||||||
public class ReplayImporter {
|
public class ReplayImporter {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private InstanceContainer instanceContainer;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Configuration config;
|
||||||
|
|
||||||
/** The subdirectory (within the replay import directory) to move replays that could not be imported. */
|
/** The subdirectory (within the replay import directory) to move replays that could not be imported. */
|
||||||
private static final String FAILED_IMPORT_DIR = "failed";
|
private final String FAILED_IMPORT_DIR = "failed";
|
||||||
|
|
||||||
/** The index of the current file being imported. */
|
/** The index of the current file being imported. */
|
||||||
private static int fileIndex = -1;
|
private int fileIndex = -1;
|
||||||
|
|
||||||
/** The total number of replays to import. */
|
/** The total number of replays to import. */
|
||||||
private static File[] files;
|
private File[] files;
|
||||||
|
|
||||||
// This class should not be instantiated.
|
@Inject
|
||||||
private ReplayImporter() {}
|
public ReplayImporter() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invokes the importer for each OSR file in a directory, adding the replay
|
* Invokes the importer for each OSR file in the replay import dir, adding the replay
|
||||||
* to the score database and moving the file into the replay directory.
|
* to the score database and moving the file into the replay directory.
|
||||||
* @param dir the directory
|
|
||||||
*/
|
*/
|
||||||
public static void importAllReplaysFromDir(File dir) {
|
public void importAll() {
|
||||||
// find all OSR files
|
// find all OSR files
|
||||||
files = dir.listFiles(new FilenameFilter() {
|
files = config.replayImportDir.listFiles(new FilenameFilter() {
|
||||||
@Override
|
@Override
|
||||||
public boolean accept(File dir, String name) {
|
public boolean accept(File dir, String name) {
|
||||||
return name.toLowerCase().endsWith(".osr");
|
return name.toLowerCase().endsWith(".osr");
|
||||||
|
@ -68,20 +77,17 @@ public class ReplayImporter {
|
||||||
}
|
}
|
||||||
|
|
||||||
// get replay directory
|
// get replay directory
|
||||||
File replayDir = Options.getReplayDir();
|
if (!config.replayDir.isDirectory() && !config.replayDir.mkdir()) {
|
||||||
if (!replayDir.isDirectory()) {
|
String err = String.format("Failed to create replay directory '%s'.", config.replayDir.getAbsolutePath());
|
||||||
if (!replayDir.mkdir()) {
|
|
||||||
String err = String.format("Failed to create replay directory '%s'.", replayDir.getAbsolutePath());
|
|
||||||
Log.error(err);
|
Log.error(err);
|
||||||
EventBus.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
|
EventBus.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// import OSRs
|
// import OSRs
|
||||||
for (File file : files) {
|
for (File file : files) {
|
||||||
fileIndex++;
|
fileIndex++;
|
||||||
Replay r = new Replay(file);
|
Replay r = instanceContainer.injectFields(new Replay(file));
|
||||||
try {
|
try {
|
||||||
r.loadHeader();
|
r.loadHeader();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -97,11 +103,11 @@ public class ReplayImporter {
|
||||||
ScoreDB.addScore(r.getScoreData(beatmap));
|
ScoreDB.addScore(r.getScoreData(beatmap));
|
||||||
|
|
||||||
// move to replay directory
|
// move to replay directory
|
||||||
File moveToFile = new File(replayDir, String.format("%s.osr", r.getReplayFilename()));
|
File moveToFile = new File(config.replayDir, String.format("%s.osr", r.getReplayFilename()));
|
||||||
try {
|
try {
|
||||||
Files.move(file.toPath(), moveToFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
Files.move(file.toPath(), moveToFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.warn(String.format("Failed to move replay '%s' to the replay directory '%s'.", file, replayDir), e);
|
Log.warn(String.format("Failed to move replay '%s' to the replay directory '%s'.", file, config.replayDir), e);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
moveToFailedDirectory(file);
|
moveToFailedDirectory(file);
|
||||||
|
@ -119,8 +125,8 @@ public class ReplayImporter {
|
||||||
* Moves a replay file into the failed import directory.
|
* Moves a replay file into the failed import directory.
|
||||||
* @param file the file to move
|
* @param file the file to move
|
||||||
*/
|
*/
|
||||||
private static void moveToFailedDirectory(File file) {
|
private void moveToFailedDirectory(File file) {
|
||||||
File dir = new File(Options.getReplayImportDir(), FAILED_IMPORT_DIR);
|
File dir = new File(config.replayImportDir, FAILED_IMPORT_DIR);
|
||||||
dir.mkdir();
|
dir.mkdir();
|
||||||
File moveToFile = new File(dir, file.getName());
|
File moveToFile = new File(dir, file.getName());
|
||||||
try {
|
try {
|
||||||
|
@ -133,7 +139,7 @@ public class ReplayImporter {
|
||||||
/**
|
/**
|
||||||
* Returns the name of the current file being imported, or null if none.
|
* Returns the name of the current file being imported, or null if none.
|
||||||
*/
|
*/
|
||||||
public static String getCurrentFileName() {
|
public String getCurrentFileName() {
|
||||||
if (files == null || fileIndex == -1)
|
if (files == null || fileIndex == -1)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
@ -144,10 +150,11 @@ public class ReplayImporter {
|
||||||
* Returns the progress of replay importing, or -1 if not importing.
|
* Returns the progress of replay importing, or -1 if not importing.
|
||||||
* @return the completion percent [0, 100] or -1
|
* @return the completion percent [0, 100] or -1
|
||||||
*/
|
*/
|
||||||
public static int getLoadingProgress() {
|
public int getLoadingProgress() {
|
||||||
if (files == null || fileIndex == -1)
|
if (files == null || fileIndex == -1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return (fileIndex + 1) * 100 / files.length;
|
return (fileIndex + 1) * 100 / files.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,9 +20,7 @@ package itdelatrisu.opsu.states;
|
||||||
|
|
||||||
import itdelatrisu.opsu.GameImage;
|
import itdelatrisu.opsu.GameImage;
|
||||||
import itdelatrisu.opsu.GameMod;
|
import itdelatrisu.opsu.GameMod;
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.ScoreData;
|
import itdelatrisu.opsu.ScoreData;
|
||||||
import itdelatrisu.opsu.Utils;
|
|
||||||
import itdelatrisu.opsu.audio.MusicController;
|
import itdelatrisu.opsu.audio.MusicController;
|
||||||
import itdelatrisu.opsu.audio.SoundController;
|
import itdelatrisu.opsu.audio.SoundController;
|
||||||
import itdelatrisu.opsu.audio.SoundEffect;
|
import itdelatrisu.opsu.audio.SoundEffect;
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
package itdelatrisu.opsu.states;
|
package itdelatrisu.opsu.states;
|
||||||
|
|
||||||
import itdelatrisu.opsu.GameImage;
|
import itdelatrisu.opsu.GameImage;
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.audio.MusicController;
|
import itdelatrisu.opsu.audio.MusicController;
|
||||||
import itdelatrisu.opsu.audio.SoundController;
|
import itdelatrisu.opsu.audio.SoundController;
|
||||||
import itdelatrisu.opsu.audio.SoundEffect;
|
import itdelatrisu.opsu.audio.SoundEffect;
|
||||||
|
@ -60,6 +59,7 @@ import yugecin.opsudance.core.inject.Inject;
|
||||||
import yugecin.opsudance.core.inject.InstanceContainer;
|
import yugecin.opsudance.core.inject.InstanceContainer;
|
||||||
import yugecin.opsudance.core.state.ComplexOpsuState;
|
import yugecin.opsudance.core.state.ComplexOpsuState;
|
||||||
import yugecin.opsudance.events.BarNotificationEvent;
|
import yugecin.opsudance.events.BarNotificationEvent;
|
||||||
|
import yugecin.opsudance.options.Configuration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Downloads menu.
|
* Downloads menu.
|
||||||
|
@ -72,6 +72,15 @@ public class DownloadsMenu extends ComplexOpsuState {
|
||||||
@Inject
|
@Inject
|
||||||
private InstanceContainer instanceContainer;
|
private InstanceContainer instanceContainer;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Configuration config;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private OszUnpacker oszUnpacker;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private BeatmapParser beatmapParser;
|
||||||
|
|
||||||
/** Delay time, in milliseconds, between each search. */
|
/** Delay time, in milliseconds, between each search. */
|
||||||
private static final int SEARCH_DELAY = 700;
|
private static final int SEARCH_DELAY = 700;
|
||||||
|
|
||||||
|
@ -82,12 +91,7 @@ public class DownloadsMenu extends ComplexOpsuState {
|
||||||
private static final int MIN_REQUEST_INTERVAL = 300;
|
private static final int MIN_REQUEST_INTERVAL = 300;
|
||||||
|
|
||||||
/** Available beatmap download servers. */
|
/** Available beatmap download servers. */
|
||||||
private static final DownloadServer[] SERVERS = {
|
private final DownloadServer[] SERVERS;
|
||||||
new BloodcatServer(),
|
|
||||||
new YaSOnlineServer(),
|
|
||||||
new MnetworkServer(),
|
|
||||||
new MengSkyServer()
|
|
||||||
};
|
|
||||||
|
|
||||||
/** The current list of search results. */
|
/** The current list of search results. */
|
||||||
private DownloadNode[] resultList;
|
private DownloadNode[] resultList;
|
||||||
|
@ -276,9 +280,9 @@ public class DownloadsMenu extends ComplexOpsuState {
|
||||||
/** Imports all packed beatmaps. */
|
/** Imports all packed beatmaps. */
|
||||||
private void importBeatmaps() {
|
private void importBeatmaps() {
|
||||||
// invoke unpacker and parser
|
// invoke unpacker and parser
|
||||||
File[] dirs = OszUnpacker.unpackAllFiles(Options.getOSZDir(), Options.getBeatmapDir());
|
File[] dirs = oszUnpacker.unpackAll();
|
||||||
if (dirs != null && dirs.length > 0) {
|
if (dirs != null && dirs.length > 0) {
|
||||||
this.importedNode = BeatmapParser.parseDirectories(dirs);
|
this.importedNode = beatmapParser.parseDirectories(dirs);
|
||||||
if (importedNode != null) {
|
if (importedNode != null) {
|
||||||
// send notification
|
// send notification
|
||||||
EventBus.post(new BarNotificationEvent((dirs.length == 1) ? "Imported 1 new song." :
|
EventBus.post(new BarNotificationEvent((dirs.length == 1) ? "Imported 1 new song." :
|
||||||
|
@ -290,6 +294,16 @@ public class DownloadsMenu extends ComplexOpsuState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public DownloadsMenu(InstanceContainer instanceContainer) {
|
||||||
|
SERVERS = new DownloadServer[] {
|
||||||
|
instanceContainer.provide(BloodcatServer.class),
|
||||||
|
instanceContainer.provide(YaSOnlineServer.class),
|
||||||
|
instanceContainer.provide(MnetworkServer.class),
|
||||||
|
instanceContainer.provide(MengSkyServer.class),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void revalidate() {
|
public void revalidate() {
|
||||||
super.revalidate();
|
super.revalidate();
|
||||||
|
@ -665,6 +679,7 @@ public class DownloadsMenu extends ComplexOpsuState {
|
||||||
try {
|
try {
|
||||||
previewID = -1;
|
previewID = -1;
|
||||||
boolean playing = SoundController.playTrack(
|
boolean playing = SoundController.playTrack(
|
||||||
|
config,
|
||||||
url,
|
url,
|
||||||
Integer.toString(node.getID()),
|
Integer.toString(node.getID()),
|
||||||
true,
|
true,
|
||||||
|
|
|
@ -18,12 +18,7 @@
|
||||||
|
|
||||||
package itdelatrisu.opsu.states;
|
package itdelatrisu.opsu.states;
|
||||||
|
|
||||||
import itdelatrisu.opsu.GameData;
|
import itdelatrisu.opsu.*;
|
||||||
import itdelatrisu.opsu.GameImage;
|
|
||||||
import itdelatrisu.opsu.GameMod;
|
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.ScoreData;
|
|
||||||
import itdelatrisu.opsu.Utils;
|
|
||||||
import itdelatrisu.opsu.audio.HitSound;
|
import itdelatrisu.opsu.audio.HitSound;
|
||||||
import itdelatrisu.opsu.audio.MusicController;
|
import itdelatrisu.opsu.audio.MusicController;
|
||||||
import itdelatrisu.opsu.audio.SoundController;
|
import itdelatrisu.opsu.audio.SoundController;
|
||||||
|
@ -34,7 +29,6 @@ import itdelatrisu.opsu.beatmap.HitObject;
|
||||||
import itdelatrisu.opsu.beatmap.TimingPoint;
|
import itdelatrisu.opsu.beatmap.TimingPoint;
|
||||||
import itdelatrisu.opsu.db.BeatmapDB;
|
import itdelatrisu.opsu.db.BeatmapDB;
|
||||||
import itdelatrisu.opsu.db.ScoreDB;
|
import itdelatrisu.opsu.db.ScoreDB;
|
||||||
import itdelatrisu.opsu.downloads.Updater;
|
|
||||||
import itdelatrisu.opsu.objects.Circle;
|
import itdelatrisu.opsu.objects.Circle;
|
||||||
import itdelatrisu.opsu.objects.DummyObject;
|
import itdelatrisu.opsu.objects.DummyObject;
|
||||||
import itdelatrisu.opsu.objects.GameObject;
|
import itdelatrisu.opsu.objects.GameObject;
|
||||||
|
@ -76,11 +70,17 @@ import yugecin.opsudance.core.state.transitions.FadeOutTransitionState;
|
||||||
import yugecin.opsudance.events.BarNotificationEvent;
|
import yugecin.opsudance.events.BarNotificationEvent;
|
||||||
import yugecin.opsudance.events.BubbleNotificationEvent;
|
import yugecin.opsudance.events.BubbleNotificationEvent;
|
||||||
import yugecin.opsudance.objects.curves.FakeCombinedCurve;
|
import yugecin.opsudance.objects.curves.FakeCombinedCurve;
|
||||||
|
import yugecin.opsudance.options.OptionGroups;
|
||||||
|
import yugecin.opsudance.options.Options;
|
||||||
|
import yugecin.opsudance.render.GameObjectRenderer;
|
||||||
import yugecin.opsudance.sbv2.MoveStoryboard;
|
import yugecin.opsudance.sbv2.MoveStoryboard;
|
||||||
|
import yugecin.opsudance.skinning.SkinService;
|
||||||
import yugecin.opsudance.ui.OptionsOverlay;
|
import yugecin.opsudance.ui.OptionsOverlay;
|
||||||
import yugecin.opsudance.ui.StoryboardOverlay;
|
import yugecin.opsudance.ui.StoryboardOverlay;
|
||||||
import yugecin.opsudance.utils.GLHelper;
|
import yugecin.opsudance.utils.GLHelper;
|
||||||
|
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* "Game" state.
|
* "Game" state.
|
||||||
*/
|
*/
|
||||||
|
@ -89,6 +89,12 @@ public class Game extends ComplexOpsuState {
|
||||||
@Inject
|
@Inject
|
||||||
private InstanceContainer instanceContainer;
|
private InstanceContainer instanceContainer;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private GameObjectRenderer gameObjectRenderer;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private BeatmapParser beatmapParser;
|
||||||
|
|
||||||
public static boolean isInGame; // TODO delete this when #79 is fixed
|
public static boolean isInGame; // TODO delete this when #79 is fixed
|
||||||
/** Game restart states. */
|
/** Game restart states. */
|
||||||
public enum Restart {
|
public enum Restart {
|
||||||
|
@ -330,7 +336,7 @@ public class Game extends ComplexOpsuState {
|
||||||
super();
|
super();
|
||||||
mirrorCursor = new Cursor(true);
|
mirrorCursor = new Cursor(true);
|
||||||
this.moveStoryboardOverlay = new MoveStoryboard(displayContainer);
|
this.moveStoryboardOverlay = new MoveStoryboard(displayContainer);
|
||||||
this.optionsOverlay = new OptionsOverlay(displayContainer, OptionsMenu.storyboardOptions);
|
this.optionsOverlay = new OptionsOverlay(displayContainer, OptionGroups.storyboardOptions);
|
||||||
this.storyboardOverlay = new StoryboardOverlay(displayContainer, moveStoryboardOverlay, optionsOverlay, this);
|
this.storyboardOverlay = new StoryboardOverlay(displayContainer, moveStoryboardOverlay, optionsOverlay, this);
|
||||||
storyboardOverlay.show();
|
storyboardOverlay.show();
|
||||||
moveStoryboardOverlay.show();
|
moveStoryboardOverlay.show();
|
||||||
|
@ -364,7 +370,8 @@ public class Game extends ComplexOpsuState {
|
||||||
scoreboardStarStream.setDurationSpread(700, 100);
|
scoreboardStarStream.setDurationSpread(700, 100);
|
||||||
|
|
||||||
// create the associated GameData object
|
// create the associated GameData object
|
||||||
data = new GameData(displayContainer.width, displayContainer.height);
|
data = instanceContainer.injectFields(new GameData(displayContainer.width, displayContainer.height));
|
||||||
|
gameObjectRenderer.setGameData(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -386,17 +393,6 @@ public class Game extends ComplexOpsuState {
|
||||||
if (objectIndex > 0) {
|
if (objectIndex > 0) {
|
||||||
objectIndex--;
|
objectIndex--;
|
||||||
}
|
}
|
||||||
if (Options.isMergingSliders()) {
|
|
||||||
int obj = objectIndex;
|
|
||||||
while (obj < gameObjects.length) {
|
|
||||||
if (gameObjects[obj] instanceof Slider) {
|
|
||||||
slidercurveFrom = slidercurveTo = ((Slider) gameObjects[obj]).baseSliderFrom;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
obj++;
|
|
||||||
}
|
|
||||||
spliceSliderCurve(-1, -1);
|
|
||||||
}
|
|
||||||
Dancer.instance.setObjectIndex(objectIndex);
|
Dancer.instance.setObjectIndex(objectIndex);
|
||||||
storyboardOverlay.updateIndex(objectIndex);
|
storyboardOverlay.updateIndex(objectIndex);
|
||||||
lastReplayTime = beatmap.objects[objectIndex].getTime();
|
lastReplayTime = beatmap.objects[objectIndex].getTime();
|
||||||
|
@ -409,7 +405,7 @@ public class Game extends ComplexOpsuState {
|
||||||
|
|
||||||
int trackPosition = MusicController.getPosition();
|
int trackPosition = MusicController.getPosition();
|
||||||
if (isLeadIn()) {
|
if (isLeadIn()) {
|
||||||
trackPosition -= leadInTime - currentMapMusicOffset - Options.getMusicOffset();
|
trackPosition -= leadInTime - currentMapMusicOffset - OPTION_MUSIC_OFFSET.val;
|
||||||
}
|
}
|
||||||
if (pauseTime > -1) // returning from pause screen
|
if (pauseTime > -1) // returning from pause screen
|
||||||
trackPosition = pauseTime;
|
trackPosition = pauseTime;
|
||||||
|
@ -427,15 +423,15 @@ public class Game extends ComplexOpsuState {
|
||||||
}
|
}
|
||||||
|
|
||||||
// background
|
// background
|
||||||
if (!Options.isRemoveBG() && GameMod.AUTO.isActive()) {
|
if (!OPTION_DANCE_REMOVE_BG.state && GameMod.AUTO.isActive()) {
|
||||||
float dimLevel = Options.getBackgroundDim();
|
float dimLevel = (100 - OPTION_BACKGROUND_DIM.val) / 100f;
|
||||||
if (trackPosition < firstObjectTime) {
|
if (trackPosition < firstObjectTime) {
|
||||||
if (timeDiff < approachTime)
|
if (timeDiff < approachTime)
|
||||||
dimLevel += (1f - dimLevel) * ((float) timeDiff / approachTime);
|
dimLevel += (1f - dimLevel) * ((float) timeDiff / approachTime);
|
||||||
else
|
else
|
||||||
dimLevel = 1f;
|
dimLevel = 1f;
|
||||||
}
|
}
|
||||||
if (Options.isDefaultPlayfieldForced() || !beatmap.drawBackground(width, height, dimLevel, false)) {
|
if (OPTION_FORCE_DEFAULT_PLAYFIELD.state || !beatmap.drawBackground(width, height, dimLevel, false)) {
|
||||||
Image playfield = GameImage.PLAYFIELD.getImage();
|
Image playfield = GameImage.PLAYFIELD.getImage();
|
||||||
playfield.setAlpha(dimLevel);
|
playfield.setAlpha(dimLevel);
|
||||||
playfield.draw();
|
playfield.draw();
|
||||||
|
@ -462,7 +458,7 @@ public class Game extends ComplexOpsuState {
|
||||||
if (GameMod.FLASHLIGHT.isActive()) {
|
if (GameMod.FLASHLIGHT.isActive()) {
|
||||||
// render hit objects offscreen
|
// render hit objects offscreen
|
||||||
Graphics.setCurrent(gOffscreen);
|
Graphics.setCurrent(gOffscreen);
|
||||||
int trackPos = (isLeadIn()) ? (leadInTime - Options.getMusicOffset()) * -1 : trackPosition;
|
int trackPos = (isLeadIn()) ? (leadInTime - OPTION_MUSIC_OFFSET.val) * -1 : trackPosition;
|
||||||
drawHitObjects(gOffscreen, trackPos);
|
drawHitObjects(gOffscreen, trackPos);
|
||||||
|
|
||||||
// restore original graphics context
|
// restore original graphics context
|
||||||
|
@ -519,7 +515,7 @@ public class Game extends ComplexOpsuState {
|
||||||
Colors.BLACK_ALPHA.a = a;
|
Colors.BLACK_ALPHA.a = a;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Options.isHideUI() || !GameMod.AUTO.isActive()) {
|
if (!OPTION_DANCE_HIDE_UI.state || !GameMod.AUTO.isActive()) {
|
||||||
data.drawGameElements(g, true, objectIndex == 0, 1f);
|
data.drawGameElements(g, true, objectIndex == 0, 1f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -557,7 +553,7 @@ public class Game extends ComplexOpsuState {
|
||||||
|
|
||||||
// non-break
|
// non-break
|
||||||
else {
|
else {
|
||||||
if (!GameMod.AUTO.isActive() || !Options.isHideUI()) {
|
if (!GameMod.AUTO.isActive() || !OPTION_DANCE_HIDE_UI.state) {
|
||||||
// game elements
|
// game elements
|
||||||
float gameElementAlpha = 1f;
|
float gameElementAlpha = 1f;
|
||||||
if (gameFinished) {
|
if (gameFinished) {
|
||||||
|
@ -590,7 +586,7 @@ public class Game extends ComplexOpsuState {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isLeadIn())
|
if (isLeadIn())
|
||||||
trackPosition = (leadInTime - Options.getMusicOffset()) * -1; // render approach circles during song lead-in
|
trackPosition = (leadInTime - OPTION_MUSIC_OFFSET.val) * -1; // render approach circles during song lead-in
|
||||||
|
|
||||||
// countdown
|
// countdown
|
||||||
if (beatmap.countdown > 0) {
|
if (beatmap.countdown > 0) {
|
||||||
|
@ -691,15 +687,15 @@ public class Game extends ComplexOpsuState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Options.isHideUI() && GameMod.AUTO.isActive())
|
if (!OPTION_DANCE_HIDE_UI.state && GameMod.AUTO.isActive())
|
||||||
GameImage.UNRANKED.getImage().drawCentered(width / 2, height * 0.077f);
|
GameImage.UNRANKED.getImage().drawCentered(width / 2, height * 0.077f);
|
||||||
|
|
||||||
// draw replay speed button
|
// draw replay speed button
|
||||||
if (isReplay || (!Options.isHideUI()&& GameMod.AUTO.isActive()))
|
if (isReplay || (!OPTION_DANCE_HIDE_UI.state&& GameMod.AUTO.isActive()))
|
||||||
playbackSpeed.getButton().draw();
|
playbackSpeed.getButton().draw();
|
||||||
|
|
||||||
// draw music position bar (for replay seeking)
|
// draw music position bar (for replay seeking)
|
||||||
if (isReplay && Options.isReplaySeekingEnabled()) {
|
if (isReplay && OPTION_REPLAY_SEEKING.state) {
|
||||||
g.setColor((musicPositionBarContains(displayContainer.mouseX, displayContainer.mouseY)) ? MUSICBAR_HOVER : MUSICBAR_NORMAL);
|
g.setColor((musicPositionBarContains(displayContainer.mouseX, displayContainer.mouseY)) ? MUSICBAR_HOVER : MUSICBAR_NORMAL);
|
||||||
g.fillRoundRect(musicBarX, musicBarY, musicBarWidth, musicBarHeight, 4);
|
g.fillRoundRect(musicBarX, musicBarY, musicBarWidth, musicBarHeight, 4);
|
||||||
if (!isLeadIn()) {
|
if (!isLeadIn()) {
|
||||||
|
@ -729,7 +725,7 @@ public class Game extends ComplexOpsuState {
|
||||||
displayContainer.cursor.draw(replayKeyPressed);
|
displayContainer.cursor.draw(replayKeyPressed);
|
||||||
} else if (GameMod.AUTO.isActive()) {
|
} else if (GameMod.AUTO.isActive()) {
|
||||||
displayContainer.cursor.draw(autoMousePressed);
|
displayContainer.cursor.draw(autoMousePressed);
|
||||||
if (Options.isMirror() && GameMod.AUTO.isActive()) {
|
if (OPTION_DANCE_MIRROR.state && GameMod.AUTO.isActive()) {
|
||||||
mirrorCursor.draw(autoMousePressed);
|
mirrorCursor.draw(autoMousePressed);
|
||||||
}
|
}
|
||||||
} else if (GameMod.AUTOPILOT.isActive()) {
|
} else if (GameMod.AUTOPILOT.isActive()) {
|
||||||
|
@ -876,7 +872,7 @@ public class Game extends ComplexOpsuState {
|
||||||
}
|
}
|
||||||
|
|
||||||
// update in-game scoreboard
|
// update in-game scoreboard
|
||||||
if (!Options.isHideUI() && previousScores != null && trackPosition > firstObjectTime) {
|
if (!OPTION_DANCE_HIDE_UI.state && previousScores != null && trackPosition > firstObjectTime) {
|
||||||
// show scoreboard if selected, and always in break
|
// show scoreboard if selected, and always in break
|
||||||
// hide when game ends
|
// hide when game ends
|
||||||
if ((scoreboardVisible || breakTime > 0) && !gameFinished) {
|
if ((scoreboardVisible || breakTime > 0) && !gameFinished) {
|
||||||
|
@ -945,7 +941,7 @@ public class Game extends ComplexOpsuState {
|
||||||
displayContainer.cursor.setCursorPosition(displayContainer.delta, replayX, replayY);
|
displayContainer.cursor.setCursorPosition(displayContainer.delta, replayX, replayY);
|
||||||
} else if (GameMod.AUTO.isActive()) {
|
} else if (GameMod.AUTO.isActive()) {
|
||||||
displayContainer.cursor.setCursorPosition(displayContainer.delta, (int) autoMousePosition.x, (int) autoMousePosition.y);
|
displayContainer.cursor.setCursorPosition(displayContainer.delta, (int) autoMousePosition.x, (int) autoMousePosition.y);
|
||||||
if (Options.isMirror() && GameMod.AUTO.isActive()) {
|
if (OPTION_DANCE_MIRROR.state && GameMod.AUTO.isActive()) {
|
||||||
double dx = autoMousePosition.x - Options.width / 2d;
|
double dx = autoMousePosition.x - Options.width / 2d;
|
||||||
double dy = autoMousePosition.y - Options.height / 2d;
|
double dy = autoMousePosition.y - Options.height / 2d;
|
||||||
double d = Math.sqrt(dx * dx + dy * dy);
|
double d = Math.sqrt(dx * dx + dy * dy);
|
||||||
|
@ -970,7 +966,7 @@ public class Game extends ComplexOpsuState {
|
||||||
boolean complete = objectIndex >= gameObjects.length;
|
boolean complete = objectIndex >= gameObjects.length;
|
||||||
if (GameMod.AUTO.isActive() && complete) {
|
if (GameMod.AUTO.isActive() && complete) {
|
||||||
if (gameObjects.length > 0) {
|
if (gameObjects.length > 0) {
|
||||||
complete = trackPosition >= gameObjects[gameObjects.length - 1].getEndTime() + Options.getMapEndDelay();
|
complete = trackPosition >= gameObjects[gameObjects.length - 1].getEndTime() + OPTION_MAP_END_DELAY.val * 100;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (complete || (MusicController.trackEnded() && objectIndex > 0)) {
|
if (complete || (MusicController.trackEnded() && objectIndex > 0)) {
|
||||||
|
@ -1115,7 +1111,9 @@ public class Game extends ComplexOpsuState {
|
||||||
objectIndex++; // done, so increment object index
|
objectIndex++; // done, so increment object index
|
||||||
storyboardOverlay.updateIndex(objectIndex);
|
storyboardOverlay.updateIndex(objectIndex);
|
||||||
if (objectIndex >= mirrorTo) {
|
if (objectIndex >= mirrorTo) {
|
||||||
Options.setMirror(false);
|
if (OPTION_DANCE_MIRROR.state) {
|
||||||
|
OPTION_DANCE_MIRROR.toggle();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
break;
|
break;
|
||||||
|
@ -1147,13 +1145,15 @@ public class Game extends ComplexOpsuState {
|
||||||
// game keys
|
// game keys
|
||||||
if (!Keyboard.isRepeatEvent()) {
|
if (!Keyboard.isRepeatEvent()) {
|
||||||
int keys = ReplayFrame.KEY_NONE;
|
int keys = ReplayFrame.KEY_NONE;
|
||||||
if (key == Options.getGameKeyLeft())
|
if (key == OPTION_KEY_LEFT.intval) {
|
||||||
keys = ReplayFrame.KEY_K1;
|
keys = ReplayFrame.KEY_K1;
|
||||||
else if (key == Options.getGameKeyRight())
|
} else if (key == OPTION_KEY_RIGHT.intval) {
|
||||||
keys = ReplayFrame.KEY_K2;
|
keys = ReplayFrame.KEY_K2;
|
||||||
if (keys != ReplayFrame.KEY_NONE)
|
}
|
||||||
|
if (keys != ReplayFrame.KEY_NONE) {
|
||||||
gameKeyPressed(keys, mouseX, mouseY, trackPosition);
|
gameKeyPressed(keys, mouseX, mouseY, trackPosition);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case Input.KEY_ESCAPE:
|
case Input.KEY_ESCAPE:
|
||||||
|
@ -1195,8 +1195,10 @@ public class Game extends ComplexOpsuState {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
int position = (pauseTime > -1) ? pauseTime : trackPosition;
|
int time = (pauseTime > -1) ? pauseTime : trackPosition;
|
||||||
if (Options.setCheckpoint(position / 1000)) {
|
time /= 1000;
|
||||||
|
if (0 <= time && time < 3600) {
|
||||||
|
OPTION_CHECKPOINT.setValue(time);
|
||||||
SoundController.playSound(SoundEffect.MENUCLICK);
|
SoundController.playSound(SoundEffect.MENUCLICK);
|
||||||
EventBus.post(new BarNotificationEvent("Checkpoint saved."));
|
EventBus.post(new BarNotificationEvent("Checkpoint saved."));
|
||||||
}
|
}
|
||||||
|
@ -1205,7 +1207,7 @@ public class Game extends ComplexOpsuState {
|
||||||
case Input.KEY_L:
|
case Input.KEY_L:
|
||||||
// load checkpoint
|
// load checkpoint
|
||||||
if (displayContainer.input.isKeyDown(Input.KEY_RCONTROL) || displayContainer.input.isKeyDown(Input.KEY_LCONTROL)) {
|
if (displayContainer.input.isKeyDown(Input.KEY_RCONTROL) || displayContainer.input.isKeyDown(Input.KEY_LCONTROL)) {
|
||||||
int checkpoint = Options.getCheckpoint();
|
int checkpoint = OPTION_CHECKPOINT.val * 1000;
|
||||||
if (checkpoint == 0 || checkpoint > beatmap.endTime)
|
if (checkpoint == 0 || checkpoint > beatmap.endTime)
|
||||||
break; // invalid checkpoint
|
break; // invalid checkpoint
|
||||||
loadCheckpoint(checkpoint);
|
loadCheckpoint(checkpoint);
|
||||||
|
@ -1227,31 +1229,29 @@ public class Game extends ComplexOpsuState {
|
||||||
UI.changeVolume(-1);
|
UI.changeVolume(-1);
|
||||||
break;
|
break;
|
||||||
case Input.KEY_TAB:
|
case Input.KEY_TAB:
|
||||||
if (!Options.isHideUI()) {
|
if (!OPTION_DANCE_HIDE_UI.state) {
|
||||||
scoreboardVisible = !scoreboardVisible;
|
scoreboardVisible = !scoreboardVisible;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Input.KEY_M:
|
case Input.KEY_M:
|
||||||
if (Options.isMirror()) {
|
if (OPTION_DANCE_MIRROR.state) {
|
||||||
mirrorTo = objectIndex;
|
mirrorTo = objectIndex;
|
||||||
Options.setMirror(false);
|
|
||||||
} else {
|
} else {
|
||||||
mirrorCursor.resetLocations((int) autoMousePosition.x, (int) autoMousePosition.y);
|
mirrorCursor.resetLocations((int) autoMousePosition.x, (int) autoMousePosition.y);
|
||||||
mirrorFrom = objectIndex;
|
mirrorFrom = objectIndex;
|
||||||
mirrorTo = gameObjects.length;
|
mirrorTo = gameObjects.length;
|
||||||
Options.setMirror(true);
|
|
||||||
}
|
}
|
||||||
|
OPTION_DANCE_MIRROR.toggle();
|
||||||
break;
|
break;
|
||||||
case Input.KEY_P:
|
case Input.KEY_P:
|
||||||
if (Options.isMirror()) {
|
if (OPTION_DANCE_MIRROR.state) {
|
||||||
mirrorTo = objectIndex;
|
mirrorTo = objectIndex;
|
||||||
Options.setMirror(false);
|
|
||||||
} else {
|
} else {
|
||||||
mirrorCursor.resetLocations((int) autoMousePosition.x, (int) autoMousePosition.y);
|
mirrorCursor.resetLocations((int) autoMousePosition.x, (int) autoMousePosition.y);
|
||||||
mirrorFrom = objectIndex;
|
mirrorFrom = objectIndex;
|
||||||
mirrorTo = mirrorFrom + 1;
|
mirrorTo = mirrorFrom + 1;
|
||||||
Options.setMirror(true);
|
|
||||||
}
|
}
|
||||||
|
OPTION_DANCE_MIRROR.toggle();
|
||||||
break;
|
break;
|
||||||
case Input.KEY_MINUS:
|
case Input.KEY_MINUS:
|
||||||
currentMapMusicOffset += 5;
|
currentMapMusicOffset += 5;
|
||||||
|
@ -1301,7 +1301,7 @@ public class Game extends ComplexOpsuState {
|
||||||
}
|
}
|
||||||
|
|
||||||
// replay seeking
|
// replay seeking
|
||||||
else if (Options.isReplaySeekingEnabled() && !GameMod.AUTO.isActive() && musicPositionBarContains(x, y)) {
|
else if (OPTION_REPLAY_SEEKING.state && !GameMod.AUTO.isActive() && musicPositionBarContains(x, y)) {
|
||||||
SoundController.mute(true); // mute sounds while seeking
|
SoundController.mute(true); // mute sounds while seeking
|
||||||
float pos = (y - musicBarY) / musicBarHeight * beatmap.endTime;
|
float pos = (y - musicBarY) / musicBarHeight * beatmap.endTime;
|
||||||
MusicController.setPosition((int) pos);
|
MusicController.setPosition((int) pos);
|
||||||
|
@ -1310,12 +1310,12 @@ public class Game extends ComplexOpsuState {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Options.isMouseDisabled()) {
|
if (OPTION_DISABLE_MOUSE_BUTTONS.state) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// mouse wheel: pause the game
|
// mouse wheel: pause the game
|
||||||
if (button == Input.MOUSE_MIDDLE_BUTTON && !Options.isMouseWheelDisabled()) {
|
if (button == Input.MOUSE_MIDDLE_BUTTON && !OPTION_DISABLE_MOUSE_WHEEL.state) {
|
||||||
int trackPosition = MusicController.getPosition();
|
int trackPosition = MusicController.getPosition();
|
||||||
if (pauseTime < 0 && breakTime <= 0 && trackPosition >= beatmap.objects[0].getTime()) {
|
if (pauseTime < 0 && breakTime <= 0 && trackPosition >= beatmap.objects[0].getTime()) {
|
||||||
pausedMousePosition = new Vec2f(x, y);
|
pausedMousePosition = new Vec2f(x, y);
|
||||||
|
@ -1389,7 +1389,7 @@ public class Game extends ComplexOpsuState {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Options.isMouseDisabled()) {
|
if (OPTION_DISABLE_MOUSE_BUTTONS.state) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1419,12 +1419,14 @@ public class Game extends ComplexOpsuState {
|
||||||
}
|
}
|
||||||
|
|
||||||
int keys = ReplayFrame.KEY_NONE;
|
int keys = ReplayFrame.KEY_NONE;
|
||||||
if (key == Options.getGameKeyLeft())
|
if (key == OPTION_KEY_LEFT.intval) {
|
||||||
keys = ReplayFrame.KEY_K1;
|
keys = ReplayFrame.KEY_K1;
|
||||||
else if (key == Options.getGameKeyRight())
|
} else if (key == OPTION_KEY_RIGHT.intval) {
|
||||||
keys = ReplayFrame.KEY_K2;
|
keys = ReplayFrame.KEY_K2;
|
||||||
if (keys != ReplayFrame.KEY_NONE)
|
}
|
||||||
|
if (keys != ReplayFrame.KEY_NONE) {
|
||||||
gameKeyReleased(keys, displayContainer.input.getMouseX(), displayContainer.input.getMouseY(), MusicController.getPosition());
|
gameKeyReleased(keys, displayContainer.input.getMouseX(), displayContainer.input.getMouseY(), MusicController.getPosition());
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1449,7 +1451,7 @@ public class Game extends ComplexOpsuState {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Options.isMouseWheelDisabled()) {
|
if (OPTION_DISABLE_MOUSE_WHEEL.state) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1461,7 +1463,7 @@ public class Game extends ComplexOpsuState {
|
||||||
@Override
|
@Override
|
||||||
public void enter() {
|
public void enter() {
|
||||||
overlays.clear();
|
overlays.clear();
|
||||||
if (Options.isEnableSB()) {
|
if (OPTION_DANCE_ENABLE_SB.state) {
|
||||||
overlays.add(optionsOverlay);
|
overlays.add(optionsOverlay);
|
||||||
overlays.add(moveStoryboardOverlay);
|
overlays.add(moveStoryboardOverlay);
|
||||||
overlays.add(storyboardOverlay);
|
overlays.add(storyboardOverlay);
|
||||||
|
@ -1537,7 +1539,7 @@ public class Game extends ComplexOpsuState {
|
||||||
}
|
}
|
||||||
|
|
||||||
// load epilepsy warning img
|
// load epilepsy warning img
|
||||||
epiImgTime = Options.getEpilepsyWarningLength();
|
epiImgTime = OPTION_EPILEPSY_WARNING.val * 100;
|
||||||
if (epiImgTime > 0) {
|
if (epiImgTime > 0) {
|
||||||
epiImg = GameImage.EPILEPSY_WARNING.getImage();
|
epiImg = GameImage.EPILEPSY_WARNING.getImage();
|
||||||
float desWidth = displayContainer.width / 2;
|
float desWidth = displayContainer.width / 2;
|
||||||
|
@ -1584,7 +1586,11 @@ public class Game extends ComplexOpsuState {
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize object maps
|
// initialize object maps
|
||||||
CursorColorOverrides.comboColors = ObjectColorOverrides.comboColors = beatmap.getComboColors();
|
Color[] comboColors = beatmap.getComboColors();
|
||||||
|
if (comboColors == null) {
|
||||||
|
comboColors = SkinService.skin.getComboColors();
|
||||||
|
}
|
||||||
|
CursorColorOverrides.comboColors = ObjectColorOverrides.comboColors = comboColors;
|
||||||
for (int i = 0; i < beatmap.objects.length; i++) {
|
for (int i = 0; i < beatmap.objects.length; i++) {
|
||||||
HitObject hitObject = beatmap.objects[i];
|
HitObject hitObject = beatmap.objects[i];
|
||||||
|
|
||||||
|
@ -1604,12 +1610,13 @@ public class Game extends ComplexOpsuState {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (hitObject.isCircle())
|
if (hitObject.isCircle()) {
|
||||||
gameObjects[i] = new Circle(hitObject, this, data, hitObject.getComboIndex(), comboEnd);
|
gameObjects[i] = instanceContainer.injectFields(new Circle(hitObject, this, data, hitObject.getComboIndex(), comboEnd));
|
||||||
else if (hitObject.isSlider())
|
} else if (hitObject.isSlider()) {
|
||||||
gameObjects[i] = new Slider(hitObject, this, data, hitObject.getComboIndex(), comboEnd);
|
gameObjects[i] = instanceContainer.injectFields(new Slider(hitObject, this, data, hitObject.getComboIndex(), comboEnd));
|
||||||
else if (hitObject.isSpinner())
|
} else if (hitObject.isSpinner()) {
|
||||||
gameObjects[i] = new Spinner(hitObject, this, data);
|
gameObjects[i] = new Spinner(hitObject, this, data);
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
String message = String.format("Failed to create %s at index %d:\n%s", hitObject.getTypeName(), i, hitObject.toString());
|
String message = String.format("Failed to create %s at index %d:\n%s", hitObject.getTypeName(), i, hitObject.toString());
|
||||||
Log.error(message, e);
|
Log.error(message, e);
|
||||||
|
@ -1688,7 +1695,7 @@ public class Game extends ComplexOpsuState {
|
||||||
MusicController.pause();
|
MusicController.pause();
|
||||||
|
|
||||||
if (gameObjects.length > 0) {
|
if (gameObjects.length > 0) {
|
||||||
int leadIntime = Options.getMapStartDelay() - gameObjects[0].getTime();
|
int leadIntime = OPTION_MAP_START_DELAY.val * 100 - gameObjects[0].getTime();
|
||||||
if (leadIntime > 0) {
|
if (leadIntime > 0) {
|
||||||
this.leadInTime = Math.max(leadIntime, this.leadInTime);
|
this.leadInTime = Math.max(leadIntime, this.leadInTime);
|
||||||
}
|
}
|
||||||
|
@ -1696,7 +1703,10 @@ public class Game extends ComplexOpsuState {
|
||||||
this.leadInTime += epiImgTime;
|
this.leadInTime += epiImgTime;
|
||||||
SoundController.mute(false);
|
SoundController.mute(false);
|
||||||
|
|
||||||
if (Options.isMergingSliders()) {
|
if (!OPTION_FALLBACK_SLIDERS.state && OPTION_MERGING_SLIDERS.state) {
|
||||||
|
if (!OPTION_SHRINKING_SLIDERS.state) {
|
||||||
|
knorkesliders = null; // workaround for issue-130
|
||||||
|
}
|
||||||
if (knorkesliders == null) {
|
if (knorkesliders == null) {
|
||||||
// let's create knorkesliders
|
// let's create knorkesliders
|
||||||
List<Vec2f> curvepoints = new ArrayList<>();
|
List<Vec2f> curvepoints = new ArrayList<>();
|
||||||
|
@ -1721,9 +1731,6 @@ public class Game extends ComplexOpsuState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
slidercurveFrom = 0;
|
|
||||||
slidercurveTo = 0;
|
|
||||||
|
|
||||||
Dancer.instance.setGameObjects(gameObjects);
|
Dancer.instance.setGameObjects(gameObjects);
|
||||||
storyboardOverlay.setGameObjects(gameObjects);
|
storyboardOverlay.setGameObjects(gameObjects);
|
||||||
if (!skippedToCheckpoint) {
|
if (!skippedToCheckpoint) {
|
||||||
|
@ -1752,7 +1759,7 @@ public class Game extends ComplexOpsuState {
|
||||||
MusicController.setPitch(1f);
|
MusicController.setPitch(1f);
|
||||||
MusicController.resume();
|
MusicController.resume();
|
||||||
|
|
||||||
if (Options.isEnableSB()) {
|
if (OPTION_DANCE_ENABLE_SB.state) {
|
||||||
storyboardOverlay.onLeave();
|
storyboardOverlay.onLeave();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1779,19 +1786,8 @@ public class Game extends ComplexOpsuState {
|
||||||
GameMod.loadModState(previousMods);
|
GameMod.loadModState(previousMods);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int slidercurveFrom;
|
public void addMergedSliderPointsToRender(int from, int to) {
|
||||||
private int slidercurveTo;
|
knorkesliders.addRange(from, to);
|
||||||
|
|
||||||
public void setSlidercurveFrom(int slidercurveFrom) {
|
|
||||||
this.slidercurveFrom = Math.max(slidercurveFrom, this.slidercurveFrom);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSlidercurveTo(int slidercurveTo) {
|
|
||||||
this.slidercurveTo = Math.max(slidercurveTo, this.slidercurveTo);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void spliceSliderCurve(int from, int to) {
|
|
||||||
this.knorkesliders.splice(from, to);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1800,15 +1796,18 @@ public class Game extends ComplexOpsuState {
|
||||||
* @param trackPosition the track position
|
* @param trackPosition the track position
|
||||||
*/
|
*/
|
||||||
private void drawHitObjects(Graphics g, int trackPosition) {
|
private void drawHitObjects(Graphics g, int trackPosition) {
|
||||||
|
gameObjectRenderer.initForFrame();
|
||||||
|
|
||||||
// draw result objects
|
// draw result objects
|
||||||
if (!Options.isHideObjects()) {
|
if (!OPTION_DANCE_HIDE_OBJECTS.state) {
|
||||||
data.drawHitResults(trackPosition);
|
data.drawHitResults(trackPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Options.isMergingSliders() && knorkesliders != null) {
|
if (!OPTION_FALLBACK_SLIDERS.state && OPTION_MERGING_SLIDERS.state && knorkesliders != null) {
|
||||||
knorkesliders.draw(Color.white, this.slidercurveFrom, this.slidercurveTo);
|
knorkesliders.draw(Color.white);
|
||||||
|
knorkesliders.initForFrame();
|
||||||
/*
|
/*
|
||||||
if (Options.isMirror()) {
|
if (OPTION_DANCE_MIRROR.state) {
|
||||||
g.pushTransform();
|
g.pushTransform();
|
||||||
g.rotate(Options.width / 2f, Options.height / 2f, 180f);
|
g.rotate(Options.width / 2f, Options.height / 2f, 180f);
|
||||||
knorkesliders.draw(Color.white, this.slidercurveFrom, this.slidercurveTo);
|
knorkesliders.draw(Color.white, this.slidercurveFrom, this.slidercurveTo);
|
||||||
|
@ -1833,7 +1832,7 @@ public class Game extends ComplexOpsuState {
|
||||||
stack.add(index);
|
stack.add(index);
|
||||||
|
|
||||||
// draw follow points
|
// draw follow points
|
||||||
if (!Options.isFollowPointEnabled() || loseState || !Options.isHideObjects())
|
if (!OPTION_SHOW_FOLLOW_POINTS.state || loseState || !OPTION_DANCE_HIDE_OBJECTS.state)
|
||||||
continue;
|
continue;
|
||||||
if (beatmap.objects[index].isSpinner()) {
|
if (beatmap.objects[index].isSpinner()) {
|
||||||
lastObjectIndex = -1;
|
lastObjectIndex = -1;
|
||||||
|
@ -1898,9 +1897,9 @@ public class Game extends ComplexOpsuState {
|
||||||
|
|
||||||
// normal case
|
// normal case
|
||||||
if (!loseState) {
|
if (!loseState) {
|
||||||
if (!Options.isHideObjects()) {
|
if (!OPTION_DANCE_HIDE_OBJECTS.state) {
|
||||||
gameObj.draw(g, trackPosition, false);
|
gameObj.draw(g, trackPosition, false);
|
||||||
if (Options.isMirror() && GameMod.AUTO.isActive() && idx < mirrorTo && idx >= mirrorFrom) {
|
if (OPTION_DANCE_MIRROR.state && GameMod.AUTO.isActive() && idx < mirrorTo && idx >= mirrorFrom) {
|
||||||
g.pushTransform();
|
g.pushTransform();
|
||||||
g.rotate(Options.width / 2f, Options.height / 2f, 180f);
|
g.rotate(Options.width / 2f, Options.height / 2f, 180f);
|
||||||
gameObj.draw(g, trackPosition, true);
|
gameObj.draw(g, trackPosition, true);
|
||||||
|
@ -1950,9 +1949,10 @@ public class Game extends ComplexOpsuState {
|
||||||
}
|
}
|
||||||
this.beatmap = beatmap;
|
this.beatmap = beatmap;
|
||||||
Display.setTitle(String.format("opsu!dance - %s", beatmap.toString()));
|
Display.setTitle(String.format("opsu!dance - %s", beatmap.toString()));
|
||||||
if (beatmap.breaks == null)
|
if (beatmap.breaks == null) {
|
||||||
BeatmapDB.load(beatmap, BeatmapDB.LOAD_ARRAY);
|
BeatmapDB.load(beatmap, BeatmapDB.LOAD_ARRAY);
|
||||||
BeatmapParser.parseHitObjects(beatmap);
|
}
|
||||||
|
beatmapParser.parseHitObjects(beatmap);
|
||||||
HitSound.setDefaultSampleSet(beatmap.sampleSet);
|
HitSound.setDefaultSampleSet(beatmap.sampleSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2053,22 +2053,26 @@ public class Game extends ComplexOpsuState {
|
||||||
* Set map modifiers.
|
* Set map modifiers.
|
||||||
*/
|
*/
|
||||||
private void setMapModifiers() {
|
private void setMapModifiers() {
|
||||||
|
// fixed difficulty overrides
|
||||||
|
float circleSize = OPTION_FIXED_CS.val / 10f;
|
||||||
|
float approachRate = OPTION_FIXED_AR.val / 10f;
|
||||||
|
float overallDifficulty = OPTION_FIXED_OD.val / 10f;
|
||||||
|
float HPDrainRate = OPTION_FIXED_HP.val / 10f;
|
||||||
|
|
||||||
// map-based properties, re-initialized each game
|
// map-based properties, re-initialized each game
|
||||||
float multiplier = GameMod.getDifficultyMultiplier();
|
float multiplier = GameMod.getDifficultyMultiplier();
|
||||||
float circleSize = Math.min(beatmap.circleSize * multiplier, 10f);
|
if (circleSize == 0f) {
|
||||||
float approachRate = Math.min(beatmap.approachRate * multiplier, 10f);
|
circleSize = Math.min(beatmap.circleSize * multiplier, 10f);
|
||||||
float overallDifficulty = Math.min(beatmap.overallDifficulty * multiplier, 10f);
|
}
|
||||||
float HPDrainRate = Math.min(beatmap.HPDrainRate * multiplier, 10f);
|
if (approachRate == 0f) {
|
||||||
|
approachRate = Math.min(beatmap.approachRate * multiplier, 10f);
|
||||||
// fixed difficulty overrides
|
}
|
||||||
if (Options.getFixedCS() > 0f)
|
if (overallDifficulty == 0f) {
|
||||||
circleSize = Options.getFixedCS();
|
overallDifficulty = Math.min(beatmap.overallDifficulty * multiplier, 10f);
|
||||||
if (Options.getFixedAR() > 0f)
|
}
|
||||||
approachRate = Options.getFixedAR();
|
if (HPDrainRate == 0f) {
|
||||||
if (Options.getFixedOD() > 0f)
|
HPDrainRate = Math.min(beatmap.HPDrainRate * multiplier, 10f);
|
||||||
overallDifficulty = Options.getFixedOD();
|
}
|
||||||
if (Options.getFixedHP() > 0f)
|
|
||||||
HPDrainRate = Options.getFixedHP();
|
|
||||||
|
|
||||||
// Stack modifier scales with hit object size
|
// Stack modifier scales with hit object size
|
||||||
// StackOffset = HitObjectRadius / 10
|
// StackOffset = HitObjectRadius / 10
|
||||||
|
@ -2077,11 +2081,14 @@ public class Game extends ComplexOpsuState {
|
||||||
HitObject.setStackOffset(diameter * STACK_OFFSET_MODIFIER);
|
HitObject.setStackOffset(diameter * STACK_OFFSET_MODIFIER);
|
||||||
|
|
||||||
// initialize objects
|
// initialize objects
|
||||||
Circle.init(diameter);
|
gameObjectRenderer.initForGame(data, diameter);
|
||||||
Slider.init(displayContainer, diameter, beatmap);
|
Slider.init(gameObjectRenderer.getCircleDiameter(), beatmap);
|
||||||
Spinner.init(displayContainer, overallDifficulty);
|
Spinner.init(displayContainer, overallDifficulty);
|
||||||
Curve.init(displayContainer.width, displayContainer.height, diameter, (Options.isBeatmapSkinIgnored()) ?
|
Color sliderBorderColor = SkinService.skin.getSliderBorderColor();
|
||||||
Options.getSkin().getSliderBorderColor() : beatmap.getSliderBorderColor());
|
if (!OPTION_IGNORE_BEATMAP_SKINS.state && beatmap.getSliderBorderColor() != null) {
|
||||||
|
sliderBorderColor = beatmap.getSliderBorderColor();
|
||||||
|
}
|
||||||
|
Curve.init(displayContainer.width, displayContainer.height, diameter, sliderBorderColor);
|
||||||
|
|
||||||
// approachRate (hit object approach time)
|
// approachRate (hit object approach time)
|
||||||
if (approachRate < 5)
|
if (approachRate < 5)
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
package itdelatrisu.opsu.states;
|
package itdelatrisu.opsu.states;
|
||||||
|
|
||||||
import itdelatrisu.opsu.GameImage;
|
import itdelatrisu.opsu.GameImage;
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.audio.MusicController;
|
import itdelatrisu.opsu.audio.MusicController;
|
||||||
import itdelatrisu.opsu.audio.SoundController;
|
import itdelatrisu.opsu.audio.SoundController;
|
||||||
import itdelatrisu.opsu.audio.SoundEffect;
|
import itdelatrisu.opsu.audio.SoundEffect;
|
||||||
|
@ -35,6 +34,8 @@ import yugecin.opsudance.core.inject.Inject;
|
||||||
import yugecin.opsudance.core.inject.InstanceContainer;
|
import yugecin.opsudance.core.inject.InstanceContainer;
|
||||||
import yugecin.opsudance.core.state.BaseOpsuState;
|
import yugecin.opsudance.core.state.BaseOpsuState;
|
||||||
|
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* "Game Pause/Fail" state.
|
* "Game Pause/Fail" state.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -93,9 +94,9 @@ public class GamePauseMenu extends BaseOpsuState {
|
||||||
|
|
||||||
// game keys
|
// game keys
|
||||||
if (!Keyboard.isRepeatEvent()) {
|
if (!Keyboard.isRepeatEvent()) {
|
||||||
if (key == Options.getGameKeyLeft()) {
|
if (key == OPTION_KEY_LEFT.intval) {
|
||||||
mousePressed(Input.MOUSE_LEFT_BUTTON, displayContainer.mouseX, displayContainer.mouseY);
|
mousePressed(Input.MOUSE_LEFT_BUTTON, displayContainer.mouseX, displayContainer.mouseY);
|
||||||
} else if (key == Options.getGameKeyRight()) {
|
} else if (key == OPTION_KEY_RIGHT.intval) {
|
||||||
mousePressed(Input.MOUSE_RIGHT_BUTTON, displayContainer.mouseX, displayContainer.mouseY);
|
mousePressed(Input.MOUSE_RIGHT_BUTTON, displayContainer.mouseX, displayContainer.mouseY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -166,7 +167,7 @@ public class GamePauseMenu extends BaseOpsuState {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Options.isMouseWheelDisabled()) {
|
if (OPTION_DISABLE_MOUSE_WHEEL.state) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
package itdelatrisu.opsu.states;
|
package itdelatrisu.opsu.states;
|
||||||
|
|
||||||
import itdelatrisu.opsu.GameImage;
|
import itdelatrisu.opsu.GameImage;
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.Utils;
|
import itdelatrisu.opsu.Utils;
|
||||||
import itdelatrisu.opsu.audio.MusicController;
|
import itdelatrisu.opsu.audio.MusicController;
|
||||||
import itdelatrisu.opsu.audio.SoundController;
|
import itdelatrisu.opsu.audio.SoundController;
|
||||||
|
@ -54,6 +53,8 @@ import yugecin.opsudance.core.state.OpsuState;
|
||||||
import yugecin.opsudance.events.BarNotificationEvent;
|
import yugecin.opsudance.events.BarNotificationEvent;
|
||||||
import yugecin.opsudance.events.BubbleNotificationEvent;
|
import yugecin.opsudance.events.BubbleNotificationEvent;
|
||||||
|
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* "Main Menu" state.
|
* "Main Menu" state.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -64,6 +65,9 @@ public class MainMenu extends BaseOpsuState {
|
||||||
@Inject
|
@Inject
|
||||||
private InstanceContainer instanceContainer;
|
private InstanceContainer instanceContainer;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Updater updater;
|
||||||
|
|
||||||
/** Idle time, in milliseconds, before returning the logo to its original position. */
|
/** Idle time, in milliseconds, before returning the logo to its original position. */
|
||||||
private static final short LOGO_IDLE_DELAY = 10000;
|
private static final short LOGO_IDLE_DELAY = 10000;
|
||||||
|
|
||||||
|
@ -232,7 +236,7 @@ public class MainMenu extends BaseOpsuState {
|
||||||
|
|
||||||
// draw background
|
// draw background
|
||||||
Beatmap beatmap = MusicController.getBeatmap();
|
Beatmap beatmap = MusicController.getBeatmap();
|
||||||
if (Options.isDynamicBackgroundEnabled() &&
|
if (OPTION_DYNAMIC_BACKGROUND.state &&
|
||||||
beatmap != null && beatmap.drawBackground(width, height, bgAlpha.getValue(), true))
|
beatmap != null && beatmap.drawBackground(width, height, bgAlpha.getValue(), true))
|
||||||
;
|
;
|
||||||
else {
|
else {
|
||||||
|
@ -262,7 +266,7 @@ public class MainMenu extends BaseOpsuState {
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw logo (pulsing)
|
// draw logo (pulsing)
|
||||||
Color color = Options.isColorMainMenuLogo() ? Cursor.lastCursorColor : Color.white;
|
Color color = OPTION_COLOR_MAIN_MENU_LOGO.state ? Cursor.lastCursorColor : Color.white;
|
||||||
Float position = MusicController.getBeatProgress();
|
Float position = MusicController.getBeatProgress();
|
||||||
boolean renderPiece = position != null;
|
boolean renderPiece = position != null;
|
||||||
if (position == null) {
|
if (position == null) {
|
||||||
|
@ -315,13 +319,14 @@ public class MainMenu extends BaseOpsuState {
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw update button
|
// draw update button
|
||||||
if (Updater.get().showButton()) {
|
if (updater.showButton()) {
|
||||||
Updater.Status status = Updater.get().getStatus();
|
Updater.Status status = updater.getStatus();
|
||||||
if (status == Updater.Status.UPDATE_AVAILABLE || status == Updater.Status.UPDATE_DOWNLOADING)
|
if (status == Updater.Status.UPDATE_AVAILABLE || status == Updater.Status.UPDATE_DOWNLOADING) {
|
||||||
updateButton.draw();
|
updateButton.draw();
|
||||||
else if (status == Updater.Status.UPDATE_DOWNLOADED)
|
} else if (status == Updater.Status.UPDATE_DOWNLOADED) {
|
||||||
restartButton.draw();
|
restartButton.draw();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// draw text
|
// draw text
|
||||||
float marginX = width * 0.015f, topMarginY = height * 0.01f, bottomMarginY = height * 0.015f;
|
float marginX = width * 0.015f, topMarginY = height * 0.01f, bottomMarginY = height * 0.015f;
|
||||||
|
@ -329,10 +334,10 @@ public class MainMenu extends BaseOpsuState {
|
||||||
float lineHeight = Fonts.MEDIUM.getLineHeight() * 0.925f;
|
float lineHeight = Fonts.MEDIUM.getLineHeight() * 0.925f;
|
||||||
g.drawString(String.format("Loaded %d songs and %d beatmaps.",
|
g.drawString(String.format("Loaded %d songs and %d beatmaps.",
|
||||||
BeatmapSetList.get().getMapSetCount(), BeatmapSetList.get().getMapCount()), marginX, topMarginY);
|
BeatmapSetList.get().getMapSetCount(), BeatmapSetList.get().getMapCount()), marginX, topMarginY);
|
||||||
if (MusicController.isTrackLoading())
|
if (MusicController.isTrackLoading()) {
|
||||||
g.drawString("Track loading...", marginX, topMarginY + lineHeight);
|
g.drawString("Track loading...", marginX, topMarginY + lineHeight);
|
||||||
else if (MusicController.trackExists()) {
|
} else if (MusicController.trackExists()) {
|
||||||
if (Options.useUnicodeMetadata()) { // load glyphs
|
if (OPTION_SHOW_UNICODE.state) {
|
||||||
Fonts.loadGlyphs(Fonts.MEDIUM, beatmap.titleUnicode);
|
Fonts.loadGlyphs(Fonts.MEDIUM, beatmap.titleUnicode);
|
||||||
Fonts.loadGlyphs(Fonts.MEDIUM, beatmap.artistUnicode);
|
Fonts.loadGlyphs(Fonts.MEDIUM, beatmap.artistUnicode);
|
||||||
}
|
}
|
||||||
|
@ -365,7 +370,7 @@ public class MainMenu extends BaseOpsuState {
|
||||||
repoButton.hoverUpdate(delta, mouseX, mouseY);
|
repoButton.hoverUpdate(delta, mouseX, mouseY);
|
||||||
danceRepoButton.hoverUpdate(delta, mouseX, mouseY);
|
danceRepoButton.hoverUpdate(delta, mouseX, mouseY);
|
||||||
}
|
}
|
||||||
if (Updater.get().showButton()) {
|
if (updater.showButton()) {
|
||||||
updateButton.autoHoverUpdate(delta, true);
|
updateButton.autoHoverUpdate(delta, true);
|
||||||
restartButton.autoHoverUpdate(delta, false);
|
restartButton.autoHoverUpdate(delta, false);
|
||||||
}
|
}
|
||||||
|
@ -387,7 +392,7 @@ public class MainMenu extends BaseOpsuState {
|
||||||
|
|
||||||
// fade in background
|
// fade in background
|
||||||
Beatmap beatmap = MusicController.getBeatmap();
|
Beatmap beatmap = MusicController.getBeatmap();
|
||||||
if (!(Options.isDynamicBackgroundEnabled() && beatmap != null && beatmap.isBackgroundLoading()))
|
if (!(OPTION_DYNAMIC_BACKGROUND.state && beatmap != null && beatmap.isBackgroundLoading()))
|
||||||
bgAlpha.update(delta);
|
bgAlpha.update(delta);
|
||||||
|
|
||||||
// check measure progress
|
// check measure progress
|
||||||
|
@ -445,8 +450,8 @@ public class MainMenu extends BaseOpsuState {
|
||||||
UI.updateTooltip(delta, "Next track", false);
|
UI.updateTooltip(delta, "Next track", false);
|
||||||
else if (musicPrevious.contains(mouseX, mouseY))
|
else if (musicPrevious.contains(mouseX, mouseY))
|
||||||
UI.updateTooltip(delta, "Previous track", false);
|
UI.updateTooltip(delta, "Previous track", false);
|
||||||
else if (Updater.get().showButton()) {
|
else if (updater.showButton()) {
|
||||||
Updater.Status status = Updater.get().getStatus();
|
Updater.Status status = updater.getStatus();
|
||||||
if (((status == Updater.Status.UPDATE_AVAILABLE || status == Updater.Status.UPDATE_DOWNLOADING) && updateButton.contains(mouseX, mouseY)) ||
|
if (((status == Updater.Status.UPDATE_AVAILABLE || status == Updater.Status.UPDATE_DOWNLOADING) && updateButton.contains(mouseX, mouseY)) ||
|
||||||
(status == Updater.Status.UPDATE_DOWNLOADED && restartButton.contains(mouseX, mouseY)))
|
(status == Updater.Status.UPDATE_DOWNLOADED && restartButton.contains(mouseX, mouseY)))
|
||||||
UI.updateTooltip(delta, status.getDescription(), true);
|
UI.updateTooltip(delta, status.getDescription(), true);
|
||||||
|
@ -466,10 +471,10 @@ public class MainMenu extends BaseOpsuState {
|
||||||
|
|
||||||
UI.enter();
|
UI.enter();
|
||||||
if (!enterNotification) {
|
if (!enterNotification) {
|
||||||
if (Updater.get().getStatus() == Updater.Status.UPDATE_AVAILABLE) {
|
if (updater.getStatus() == Updater.Status.UPDATE_AVAILABLE) {
|
||||||
EventBus.post(new BarNotificationEvent("An opsu! update is available."));
|
EventBus.post(new BarNotificationEvent("An opsu! update is available."));
|
||||||
enterNotification = true;
|
enterNotification = true;
|
||||||
} else if (Updater.get().justUpdated()) {
|
} else if (updater.justUpdated()) {
|
||||||
EventBus.post(new BarNotificationEvent("opsu! is now up to date!"));
|
EventBus.post(new BarNotificationEvent("opsu! is now up to date!"));
|
||||||
enterNotification = true;
|
enterNotification = true;
|
||||||
}
|
}
|
||||||
|
@ -547,10 +552,12 @@ public class MainMenu extends BaseOpsuState {
|
||||||
lastMeasureProgress = 0f;
|
lastMeasureProgress = 0f;
|
||||||
if (!previous.isEmpty()) {
|
if (!previous.isEmpty()) {
|
||||||
instanceContainer.provide(SongMenu.class).setFocus(BeatmapSetList.get().getBaseNode(previous.pop()), -1, true, false);
|
instanceContainer.provide(SongMenu.class).setFocus(BeatmapSetList.get().getBaseNode(previous.pop()), -1, true, false);
|
||||||
if (Options.isDynamicBackgroundEnabled())
|
if (OPTION_DYNAMIC_BACKGROUND.state) {
|
||||||
bgAlpha.setTime(0);
|
bgAlpha.setTime(0);
|
||||||
} else
|
}
|
||||||
|
} else {
|
||||||
MusicController.setPosition(0);
|
MusicController.setPosition(0);
|
||||||
|
}
|
||||||
EventBus.post(new BarNotificationEvent("<< Previous"));
|
EventBus.post(new BarNotificationEvent("<< Previous"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -565,7 +572,7 @@ public class MainMenu extends BaseOpsuState {
|
||||||
// repository button actions
|
// repository button actions
|
||||||
if (repoButton != null && repoButton.contains(x, y)) {
|
if (repoButton != null && repoButton.contains(x, y)) {
|
||||||
try {
|
try {
|
||||||
Desktop.getDesktop().browse(Options.REPOSITORY_URI);
|
Desktop.getDesktop().browse(config.REPOSITORY_URI);
|
||||||
} catch (UnsupportedOperationException e) {
|
} catch (UnsupportedOperationException e) {
|
||||||
EventBus.post(new BarNotificationEvent("The repository web page could not be opened."));
|
EventBus.post(new BarNotificationEvent("The repository web page could not be opened."));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -577,7 +584,7 @@ public class MainMenu extends BaseOpsuState {
|
||||||
|
|
||||||
if (danceRepoButton != null && danceRepoButton.contains(x, y)) {
|
if (danceRepoButton != null && danceRepoButton.contains(x, y)) {
|
||||||
try {
|
try {
|
||||||
Desktop.getDesktop().browse(Options.DANCE_REPOSITORY_URI);
|
Desktop.getDesktop().browse(config.DANCE_REPOSITORY_URI);
|
||||||
} catch (UnsupportedOperationException e) {
|
} catch (UnsupportedOperationException e) {
|
||||||
EventBus.post(new BarNotificationEvent("The repository web page could not be opened."));
|
EventBus.post(new BarNotificationEvent("The repository web page could not be opened."));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -588,11 +595,11 @@ public class MainMenu extends BaseOpsuState {
|
||||||
}
|
}
|
||||||
|
|
||||||
// update button actions
|
// update button actions
|
||||||
if (Updater.get().showButton()) {
|
if (updater.showButton()) {
|
||||||
Updater.Status status = Updater.get().getStatus();
|
Updater.Status status = updater.getStatus();
|
||||||
if (updateButton.contains(x, y) && status == Updater.Status.UPDATE_AVAILABLE) {
|
if (updateButton.contains(x, y) && status == Updater.Status.UPDATE_AVAILABLE) {
|
||||||
SoundController.playSound(SoundEffect.MENUHIT);
|
SoundController.playSound(SoundEffect.MENUHIT);
|
||||||
Updater.get().startDownload();
|
updater.startDownload();
|
||||||
updateButton.removeHoverEffects();
|
updateButton.removeHoverEffects();
|
||||||
updateButton.setHoverAnimationDuration(800);
|
updateButton.setHoverAnimationDuration(800);
|
||||||
updateButton.setHoverAnimationEquation(AnimationEquation.IN_OUT_QUAD);
|
updateButton.setHoverAnimationEquation(AnimationEquation.IN_OUT_QUAD);
|
||||||
|
@ -600,7 +607,7 @@ public class MainMenu extends BaseOpsuState {
|
||||||
return true;
|
return true;
|
||||||
} else if (restartButton.contains(x, y) && status == Updater.Status.UPDATE_DOWNLOADED) {
|
} else if (restartButton.contains(x, y) && status == Updater.Status.UPDATE_DOWNLOADED) {
|
||||||
SoundController.playSound(SoundEffect.MENUHIT);
|
SoundController.playSound(SoundEffect.MENUHIT);
|
||||||
Updater.get().prepareUpdate();
|
updater.prepareUpdate();
|
||||||
displayContainer.exitRequested = true;
|
displayContainer.exitRequested = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -719,9 +726,10 @@ public class MainMenu extends BaseOpsuState {
|
||||||
if (!isTheme && !sameAudio)
|
if (!isTheme && !sameAudio)
|
||||||
previous.add(node.index);
|
previous.add(node.index);
|
||||||
}
|
}
|
||||||
if (Options.isDynamicBackgroundEnabled() && !sameAudio && !MusicController.isThemePlaying())
|
if (OPTION_DYNAMIC_BACKGROUND.state && !sameAudio && !MusicController.isThemePlaying()) {
|
||||||
bgAlpha.setTime(0);
|
bgAlpha.setTime(0);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enters the song menu, or the downloads menu if no beatmaps are loaded.
|
* Enters the song menu, or the downloads menu if no beatmaps are loaded.
|
||||||
|
|
|
@ -1,237 +0,0 @@
|
||||||
/*
|
|
||||||
* opsu! - an open-source osu! client
|
|
||||||
* Copyright (C) 2014, 2015 Jeffrey Han
|
|
||||||
*
|
|
||||||
* opsu! is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* opsu! is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with opsu!. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package itdelatrisu.opsu.states;
|
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options.GameOption;
|
|
||||||
|
|
||||||
import yugecin.opsudance.ui.OptionsOverlay.OptionTab;
|
|
||||||
|
|
||||||
public class OptionsMenu {
|
|
||||||
|
|
||||||
public static final OptionTab[] normalOptions = new OptionTab[] {
|
|
||||||
new OptionTab("GENERAL", null),
|
|
||||||
new OptionTab("GENERAL", new GameOption[]{
|
|
||||||
GameOption.DISABLE_UPDATER,
|
|
||||||
GameOption.ENABLE_WATCH_SERVICE
|
|
||||||
}),
|
|
||||||
new OptionTab("LANGUAGE", new GameOption[]{
|
|
||||||
GameOption.SHOW_UNICODE,
|
|
||||||
}),
|
|
||||||
new OptionTab("GRAPHICS", null),
|
|
||||||
new OptionTab("RENDERER", new GameOption[] {
|
|
||||||
GameOption.SCREEN_RESOLUTION,
|
|
||||||
GameOption.ALLOW_LARGER_RESOLUTIONS,
|
|
||||||
GameOption.FULLSCREEN,
|
|
||||||
GameOption.TARGET_UPS,
|
|
||||||
GameOption.TARGET_FPS,
|
|
||||||
GameOption.SHOW_FPS,
|
|
||||||
GameOption.USE_FPS_DELTAS,
|
|
||||||
GameOption.SCREENSHOT_FORMAT,
|
|
||||||
}),
|
|
||||||
new OptionTab("SLIDER OPTIONS", new GameOption[]{
|
|
||||||
GameOption.SNAKING_SLIDERS,
|
|
||||||
GameOption.FALLBACK_SLIDERS,
|
|
||||||
GameOption.SHRINKING_SLIDERS,
|
|
||||||
GameOption.MERGING_SLIDERS,
|
|
||||||
//GameOption.MERGING_SLIDERS_MIRROR_POOL,
|
|
||||||
GameOption.DRAW_SLIDER_ENDCIRCLES,
|
|
||||||
}),
|
|
||||||
new OptionTab("SKIN", null),
|
|
||||||
new OptionTab("SKIN", new GameOption[]{
|
|
||||||
GameOption.SKIN,
|
|
||||||
GameOption.IGNORE_BEATMAP_SKINS,
|
|
||||||
GameOption.DYNAMIC_BACKGROUND,
|
|
||||||
GameOption.LOAD_HD_IMAGES,
|
|
||||||
GameOption.LOAD_VERBOSE,
|
|
||||||
GameOption.COLOR_MAIN_MENU_LOGO,
|
|
||||||
}),
|
|
||||||
new OptionTab("CURSOR", new GameOption[]{
|
|
||||||
GameOption.CURSOR_SIZE,
|
|
||||||
GameOption.NEW_CURSOR,
|
|
||||||
GameOption.DISABLE_CURSOR
|
|
||||||
// TODO use combo colour as tint for slider ball option
|
|
||||||
}),
|
|
||||||
new OptionTab("AUDIO", null),
|
|
||||||
new OptionTab("VOLUME", new GameOption[]{
|
|
||||||
GameOption.MASTER_VOLUME,
|
|
||||||
GameOption.MUSIC_VOLUME,
|
|
||||||
GameOption.EFFECT_VOLUME,
|
|
||||||
GameOption.HITSOUND_VOLUME,
|
|
||||||
GameOption.SAMPLE_VOLUME_OVERRIDE,
|
|
||||||
}),
|
|
||||||
new OptionTab("MISC", new GameOption[] {
|
|
||||||
GameOption.MUSIC_OFFSET,
|
|
||||||
GameOption.DISABLE_SOUNDS,
|
|
||||||
GameOption.ENABLE_THEME_SONG
|
|
||||||
}),
|
|
||||||
new OptionTab("GAMEPLAY", null),
|
|
||||||
new OptionTab("GENERAL", new GameOption[] {
|
|
||||||
GameOption.BACKGROUND_DIM,
|
|
||||||
GameOption.FORCE_DEFAULT_PLAYFIELD,
|
|
||||||
GameOption.SHOW_HIT_LIGHTING,
|
|
||||||
GameOption.SHOW_HIT_ANIMATIONS,
|
|
||||||
GameOption.SHOW_COMBO_BURSTS,
|
|
||||||
GameOption.SHOW_PERFECT_HIT,
|
|
||||||
GameOption.SHOW_FOLLOW_POINTS,
|
|
||||||
GameOption.SHOW_HIT_ERROR_BAR,
|
|
||||||
GameOption.MAP_START_DELAY,
|
|
||||||
GameOption.MAP_END_DELAY,
|
|
||||||
GameOption.EPILEPSY_WARNING,
|
|
||||||
}),
|
|
||||||
new OptionTab("INPUT", null),
|
|
||||||
new OptionTab("KEY MAPPING", new GameOption[]{
|
|
||||||
GameOption.KEY_LEFT,
|
|
||||||
GameOption.KEY_RIGHT,
|
|
||||||
}),
|
|
||||||
new OptionTab("MOUSE", new GameOption[] {
|
|
||||||
GameOption.DISABLE_MOUSE_WHEEL,
|
|
||||||
GameOption.DISABLE_MOUSE_BUTTONS,
|
|
||||||
}),
|
|
||||||
new OptionTab("CUSTOM", null),
|
|
||||||
new OptionTab("DIFFICULTY", new GameOption[]{
|
|
||||||
GameOption.FIXED_CS,
|
|
||||||
GameOption.FIXED_HP,
|
|
||||||
GameOption.FIXED_AR,
|
|
||||||
GameOption.FIXED_OD,
|
|
||||||
}),
|
|
||||||
new OptionTab("MISC", new GameOption[] {
|
|
||||||
GameOption.CHECKPOINT,
|
|
||||||
GameOption.REPLAY_SEEKING,
|
|
||||||
}),
|
|
||||||
new OptionTab("DANCE", null),
|
|
||||||
new OptionTab("MOVER", new GameOption[]{
|
|
||||||
GameOption.DANCE_MOVER,
|
|
||||||
GameOption.DANCE_EXGON_DELAY,
|
|
||||||
GameOption.DANCE_QUAD_BEZ_AGGRESSIVENESS,
|
|
||||||
GameOption.DANCE_QUAD_BEZ_SLIDER_AGGRESSIVENESS_FACTOR,
|
|
||||||
GameOption.DANCE_QUAD_BEZ_USE_CUBIC_ON_SLIDERS,
|
|
||||||
GameOption.DANCE_QUAD_BEZ_CUBIC_AGGRESSIVENESS_FACTOR,
|
|
||||||
GameOption.DANCE_MOVER_DIRECTION,
|
|
||||||
GameOption.DANCE_SLIDER_MOVER_TYPE,
|
|
||||||
}),
|
|
||||||
new OptionTab("SPINNER", new GameOption[]{
|
|
||||||
GameOption.DANCE_SPINNER,
|
|
||||||
GameOption.DANCE_SPINNER_DELAY,
|
|
||||||
}),
|
|
||||||
new OptionTab("SLIDER OPTIONS", new GameOption[]{
|
|
||||||
GameOption.DANCE_LAZY_SLIDERS,
|
|
||||||
GameOption.DANCE_CIRLCE_IN_SLOW_SLIDERS,
|
|
||||||
GameOption.DANCE_CIRLCE_IN_LAZY_SLIDERS,
|
|
||||||
}),
|
|
||||||
new OptionTab("CIRCLE MOVEMENTS", new GameOption[]{
|
|
||||||
GameOption.DANCE_CIRCLE_STREAMS,
|
|
||||||
GameOption.DANCE_ONLY_CIRCLE_STACKS,
|
|
||||||
}),
|
|
||||||
new OptionTab("MIRROR", new GameOption[] {
|
|
||||||
GameOption.DANCE_MIRROR,
|
|
||||||
}),
|
|
||||||
new OptionTab("ADVANCED DISPLAY", null),
|
|
||||||
new OptionTab("OBJECTS", new GameOption[]{
|
|
||||||
GameOption.DANCE_DRAW_APPROACH,
|
|
||||||
GameOption.DANCE_OBJECT_COLOR_OVERRIDE,
|
|
||||||
GameOption.DANCE_OBJECT_COLOR_OVERRIDE_MIRRORED,
|
|
||||||
GameOption.DANCE_RGB_OBJECT_INC,
|
|
||||||
GameOption.DANCE_HIDE_OBJECTS,
|
|
||||||
}),
|
|
||||||
new OptionTab("CURSOR", new GameOption[]{
|
|
||||||
GameOption.DANCE_CURSOR_COLOR_OVERRIDE,
|
|
||||||
GameOption.DANCE_CURSOR_MIRROR_COLOR_OVERRIDE,
|
|
||||||
GameOption.DANCE_CURSOR_ONLY_COLOR_TRAIL,
|
|
||||||
GameOption.DANCE_RGB_CURSOR_INC,
|
|
||||||
GameOption.DANCE_CURSOR_TRAIL_OVERRIDE,
|
|
||||||
}),
|
|
||||||
new OptionTab("MISC", new GameOption[] {
|
|
||||||
GameOption.DANCE_HIDE_UI,
|
|
||||||
GameOption.DANCE_REMOVE_BG,
|
|
||||||
GameOption.DANCE_ENABLE_SB,
|
|
||||||
}),
|
|
||||||
new OptionTab ("PIPPI", null),
|
|
||||||
new OptionTab ("GENERAL", new GameOption[]{
|
|
||||||
GameOption.PIPPI_ENABLE,
|
|
||||||
GameOption.PIPPI_RADIUS_PERCENT,
|
|
||||||
}),
|
|
||||||
new OptionTab ("ANGLE MULTIPLIERS", new GameOption[]{
|
|
||||||
GameOption.PIPPI_ANGLE_INC_MUL,
|
|
||||||
GameOption.PIPPI_ANGLE_INC_MUL_SLIDER,
|
|
||||||
}),
|
|
||||||
new OptionTab ("MISC", new GameOption[] {
|
|
||||||
GameOption.PIPPI_SLIDER_FOLLOW_EXPAND,
|
|
||||||
GameOption.PIPPI_PREVENT_WOBBLY_STREAMS,
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
public static final OptionTab[] storyboardOptions = new OptionTab[] {
|
|
||||||
new OptionTab("Gameplay", new GameOption[] {
|
|
||||||
GameOption.BACKGROUND_DIM,
|
|
||||||
GameOption.DANCE_REMOVE_BG,
|
|
||||||
GameOption.SNAKING_SLIDERS,
|
|
||||||
GameOption.SHRINKING_SLIDERS,
|
|
||||||
GameOption.SHOW_HIT_LIGHTING,
|
|
||||||
GameOption.SHOW_HIT_ANIMATIONS,
|
|
||||||
GameOption.SHOW_COMBO_BURSTS,
|
|
||||||
GameOption.SHOW_PERFECT_HIT,
|
|
||||||
GameOption.SHOW_FOLLOW_POINTS,
|
|
||||||
}),
|
|
||||||
new OptionTab("Input", new GameOption[] {
|
|
||||||
GameOption.CURSOR_SIZE,
|
|
||||||
GameOption.NEW_CURSOR,
|
|
||||||
GameOption.DISABLE_CURSOR
|
|
||||||
}),
|
|
||||||
new OptionTab("Dance", new GameOption[] {
|
|
||||||
GameOption.DANCE_MOVER,
|
|
||||||
GameOption.DANCE_EXGON_DELAY,
|
|
||||||
GameOption.DANCE_QUAD_BEZ_AGGRESSIVENESS,
|
|
||||||
GameOption.DANCE_QUAD_BEZ_SLIDER_AGGRESSIVENESS_FACTOR,
|
|
||||||
GameOption.DANCE_QUAD_BEZ_USE_CUBIC_ON_SLIDERS,
|
|
||||||
GameOption.DANCE_QUAD_BEZ_CUBIC_AGGRESSIVENESS_FACTOR,
|
|
||||||
GameOption.DANCE_MOVER_DIRECTION,
|
|
||||||
GameOption.DANCE_SLIDER_MOVER_TYPE,
|
|
||||||
GameOption.DANCE_SPINNER,
|
|
||||||
GameOption.DANCE_SPINNER_DELAY,
|
|
||||||
GameOption.DANCE_LAZY_SLIDERS,
|
|
||||||
GameOption.DANCE_CIRCLE_STREAMS,
|
|
||||||
GameOption.DANCE_ONLY_CIRCLE_STACKS,
|
|
||||||
GameOption.DANCE_CIRLCE_IN_SLOW_SLIDERS,
|
|
||||||
GameOption.DANCE_CIRLCE_IN_LAZY_SLIDERS,
|
|
||||||
GameOption.DANCE_MIRROR,
|
|
||||||
}),
|
|
||||||
new OptionTab("Dance display", new GameOption[] {
|
|
||||||
GameOption.DANCE_DRAW_APPROACH,
|
|
||||||
GameOption.DANCE_OBJECT_COLOR_OVERRIDE,
|
|
||||||
GameOption.DANCE_OBJECT_COLOR_OVERRIDE_MIRRORED,
|
|
||||||
GameOption.DANCE_RGB_OBJECT_INC,
|
|
||||||
GameOption.DANCE_CURSOR_COLOR_OVERRIDE,
|
|
||||||
GameOption.DANCE_CURSOR_MIRROR_COLOR_OVERRIDE,
|
|
||||||
GameOption.DANCE_CURSOR_ONLY_COLOR_TRAIL,
|
|
||||||
GameOption.DANCE_RGB_CURSOR_INC,
|
|
||||||
GameOption.DANCE_CURSOR_TRAIL_OVERRIDE,
|
|
||||||
GameOption.DANCE_HIDE_OBJECTS,
|
|
||||||
GameOption.DANCE_HIDE_UI,
|
|
||||||
}),
|
|
||||||
new OptionTab ("Pippi", new GameOption[] {
|
|
||||||
GameOption.PIPPI_ENABLE,
|
|
||||||
GameOption.PIPPI_RADIUS_PERCENT,
|
|
||||||
GameOption.PIPPI_ANGLE_INC_MUL,
|
|
||||||
GameOption.PIPPI_ANGLE_INC_MUL_SLIDER,
|
|
||||||
GameOption.PIPPI_SLIDER_FOLLOW_EXPAND,
|
|
||||||
GameOption.PIPPI_PREVENT_WOBBLY_STREAMS,
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -18,13 +18,8 @@
|
||||||
|
|
||||||
package itdelatrisu.opsu.states;
|
package itdelatrisu.opsu.states;
|
||||||
|
|
||||||
import itdelatrisu.opsu.GameData;
|
import itdelatrisu.opsu.*;
|
||||||
import itdelatrisu.opsu.GameData.Grade;
|
import itdelatrisu.opsu.GameData.Grade;
|
||||||
import itdelatrisu.opsu.GameImage;
|
|
||||||
import itdelatrisu.opsu.GameMod;
|
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.ScoreData;
|
|
||||||
import itdelatrisu.opsu.Utils;
|
|
||||||
import itdelatrisu.opsu.audio.MultiClip;
|
import itdelatrisu.opsu.audio.MultiClip;
|
||||||
import itdelatrisu.opsu.audio.MusicController;
|
import itdelatrisu.opsu.audio.MusicController;
|
||||||
import itdelatrisu.opsu.audio.SoundController;
|
import itdelatrisu.opsu.audio.SoundController;
|
||||||
|
@ -74,8 +69,12 @@ import yugecin.opsudance.core.inject.Inject;
|
||||||
import yugecin.opsudance.core.inject.InstanceContainer;
|
import yugecin.opsudance.core.inject.InstanceContainer;
|
||||||
import yugecin.opsudance.core.state.ComplexOpsuState;
|
import yugecin.opsudance.core.state.ComplexOpsuState;
|
||||||
import yugecin.opsudance.events.BarNotificationEvent;
|
import yugecin.opsudance.events.BarNotificationEvent;
|
||||||
|
import yugecin.opsudance.options.Configuration;
|
||||||
|
import yugecin.opsudance.options.OptionGroups;
|
||||||
import yugecin.opsudance.ui.OptionsOverlay;
|
import yugecin.opsudance.ui.OptionsOverlay;
|
||||||
|
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* "Song Selection" state.
|
* "Song Selection" state.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -87,6 +86,15 @@ public class SongMenu extends ComplexOpsuState {
|
||||||
@Inject
|
@Inject
|
||||||
private InstanceContainer instanceContainer;
|
private InstanceContainer instanceContainer;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Configuration config;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private OszUnpacker oszUnpacker;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private BeatmapParser beatmapParser;
|
||||||
|
|
||||||
/** The max number of song buttons to be shown on each screen. */
|
/** The max number of song buttons to be shown on each screen. */
|
||||||
public static final int MAX_SONG_BUTTONS = 6;
|
public static final int MAX_SONG_BUTTONS = 6;
|
||||||
|
|
||||||
|
@ -236,18 +244,11 @@ public class SongMenu extends ComplexOpsuState {
|
||||||
|
|
||||||
/** Reloads all beatmaps. */
|
/** Reloads all beatmaps. */
|
||||||
private void reloadBeatmaps() {
|
private void reloadBeatmaps() {
|
||||||
File beatmapDir = Options.getBeatmapDir();
|
|
||||||
|
|
||||||
if (fullReload) {
|
if (fullReload) {
|
||||||
// clear the beatmap cache
|
|
||||||
BeatmapDB.clearDatabase();
|
BeatmapDB.clearDatabase();
|
||||||
|
oszUnpacker.unpackAll();
|
||||||
// invoke unpacker
|
|
||||||
OszUnpacker.unpackAllFiles(Options.getOSZDir(), beatmapDir);
|
|
||||||
}
|
}
|
||||||
|
beatmapParser.parseAll();
|
||||||
// invoke parser
|
|
||||||
BeatmapParser.parseAllFiles(beatmapDir);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,7 +330,7 @@ public class SongMenu extends ComplexOpsuState {
|
||||||
|
|
||||||
public SongMenu(DisplayContainer displayContainer) {
|
public SongMenu(DisplayContainer displayContainer) {
|
||||||
super();
|
super();
|
||||||
optionsOverlay = new OptionsOverlay(displayContainer, OptionsMenu.normalOptions);
|
optionsOverlay = new OptionsOverlay(displayContainer, OptionGroups.normalOptions);
|
||||||
overlays.add(optionsOverlay);
|
overlays.add(optionsOverlay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -599,7 +600,7 @@ public class SongMenu extends ComplexOpsuState {
|
||||||
// song info text
|
// song info text
|
||||||
if (songInfo == null) {
|
if (songInfo == null) {
|
||||||
songInfo = focusNode.getInfo();
|
songInfo = focusNode.getInfo();
|
||||||
if (Options.useUnicodeMetadata()) { // load glyphs
|
if (OPTION_SHOW_UNICODE.state) {
|
||||||
Beatmap beatmap = focusNode.getBeatmapSet().get(0);
|
Beatmap beatmap = focusNode.getBeatmapSet().get(0);
|
||||||
Fonts.loadGlyphs(Fonts.LARGE, beatmap.titleUnicode);
|
Fonts.loadGlyphs(Fonts.LARGE, beatmap.titleUnicode);
|
||||||
Fonts.loadGlyphs(Fonts.LARGE, beatmap.artistUnicode);
|
Fonts.loadGlyphs(Fonts.LARGE, beatmap.artistUnicode);
|
||||||
|
@ -740,7 +741,7 @@ public class SongMenu extends ComplexOpsuState {
|
||||||
// initialize song list
|
// initialize song list
|
||||||
setFocus(BeatmapSetList.get().getRandomNode(), -1, true, true);
|
setFocus(BeatmapSetList.get().getRandomNode(), -1, true, true);
|
||||||
} else
|
} else
|
||||||
MusicController.playThemeSong();
|
MusicController.playThemeSong(config.themeBeatmap);
|
||||||
reloadThread = null;
|
reloadThread = null;
|
||||||
}
|
}
|
||||||
int mouseX = displayContainer.mouseX;
|
int mouseX = displayContainer.mouseX;
|
||||||
|
@ -1028,7 +1029,7 @@ public class SongMenu extends ComplexOpsuState {
|
||||||
SoundController.playSound(SoundEffect.MENUHIT);
|
SoundController.playSound(SoundEffect.MENUHIT);
|
||||||
if (button != Input.MOUSE_RIGHT_BUTTON) {
|
if (button != Input.MOUSE_RIGHT_BUTTON) {
|
||||||
// view score
|
// view score
|
||||||
instanceContainer.provide(GameRanking.class).setGameData(new GameData(focusScores[rank], displayContainer.width, displayContainer.height));
|
instanceContainer.provide(GameRanking.class).setGameData(instanceContainer.injectFields(new GameData(focusScores[rank], displayContainer.width, displayContainer.height)));
|
||||||
displayContainer.switchState(GameRanking.class);
|
displayContainer.switchState(GameRanking.class);
|
||||||
} else {
|
} else {
|
||||||
// score management
|
// score management
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
package itdelatrisu.opsu.states;
|
package itdelatrisu.opsu.states;
|
||||||
|
|
||||||
import itdelatrisu.opsu.GameImage;
|
import itdelatrisu.opsu.GameImage;
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.audio.MusicController;
|
import itdelatrisu.opsu.audio.MusicController;
|
||||||
import itdelatrisu.opsu.audio.SoundController;
|
import itdelatrisu.opsu.audio.SoundController;
|
||||||
import itdelatrisu.opsu.beatmap.BeatmapParser;
|
import itdelatrisu.opsu.beatmap.BeatmapParser;
|
||||||
|
@ -28,8 +27,6 @@ import itdelatrisu.opsu.beatmap.OszUnpacker;
|
||||||
import itdelatrisu.opsu.replay.ReplayImporter;
|
import itdelatrisu.opsu.replay.ReplayImporter;
|
||||||
import itdelatrisu.opsu.ui.UI;
|
import itdelatrisu.opsu.ui.UI;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
import org.newdawn.slick.Color;
|
import org.newdawn.slick.Color;
|
||||||
import org.newdawn.slick.Graphics;
|
import org.newdawn.slick.Graphics;
|
||||||
import org.newdawn.slick.Input;
|
import org.newdawn.slick.Input;
|
||||||
|
@ -38,6 +35,8 @@ import org.newdawn.slick.util.Log;
|
||||||
import yugecin.opsudance.core.inject.Inject;
|
import yugecin.opsudance.core.inject.Inject;
|
||||||
import yugecin.opsudance.core.state.BaseOpsuState;
|
import yugecin.opsudance.core.state.BaseOpsuState;
|
||||||
|
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* "Splash Screen" state.
|
* "Splash Screen" state.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -48,6 +47,15 @@ public class Splash extends BaseOpsuState {
|
||||||
@Inject
|
@Inject
|
||||||
private SongMenu songMenu;
|
private SongMenu songMenu;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private ReplayImporter replayImporter;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private OszUnpacker oszUnpacker;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private BeatmapParser beatmapParser;
|
||||||
|
|
||||||
/** Whether or not loading has completed. */
|
/** Whether or not loading has completed. */
|
||||||
private boolean finished;
|
private boolean finished;
|
||||||
|
|
||||||
|
@ -78,18 +86,10 @@ public class Splash extends BaseOpsuState {
|
||||||
thread = new Thread() {
|
thread = new Thread() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
File beatmapDir = Options.getBeatmapDir();
|
oszUnpacker.unpackAll();
|
||||||
|
beatmapParser.parseAll();
|
||||||
|
replayImporter.importAll();
|
||||||
|
|
||||||
// unpack all OSZ archives
|
|
||||||
OszUnpacker.unpackAllFiles(Options.getOSZDir(), beatmapDir);
|
|
||||||
|
|
||||||
// parse song directory
|
|
||||||
BeatmapParser.parseAllFiles(beatmapDir);
|
|
||||||
|
|
||||||
// import replays
|
|
||||||
ReplayImporter.importAllReplaysFromDir(Options.getReplayImportDir());
|
|
||||||
|
|
||||||
// load sounds
|
|
||||||
SoundController.init();
|
SoundController.init();
|
||||||
|
|
||||||
finished = true;
|
finished = true;
|
||||||
|
@ -108,14 +108,14 @@ public class Splash extends BaseOpsuState {
|
||||||
|
|
||||||
// initialize song list
|
// initialize song list
|
||||||
if (BeatmapSetList.get().size() == 0) {
|
if (BeatmapSetList.get().size() == 0) {
|
||||||
MusicController.playThemeSong();
|
MusicController.playThemeSong(config.themeBeatmap);
|
||||||
displayContainer.switchStateInstantly(MainMenu.class);
|
displayContainer.switchStateInstantly(MainMenu.class);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
BeatmapSetList.get().init();
|
BeatmapSetList.get().init();
|
||||||
if (Options.isThemeSongEnabled()) {
|
if (OPTION_ENABLE_THEME_SONG.state) {
|
||||||
MusicController.playThemeSong();
|
MusicController.playThemeSong(config.themeBeatmap);
|
||||||
} else {
|
} else {
|
||||||
songMenu.setFocus(BeatmapSetList.get().getRandomNode(), -1, true, true);
|
songMenu.setFocus(BeatmapSetList.get().getRandomNode(), -1, true, true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,9 +19,7 @@
|
||||||
package itdelatrisu.opsu.ui;
|
package itdelatrisu.opsu.ui;
|
||||||
|
|
||||||
import itdelatrisu.opsu.GameImage;
|
import itdelatrisu.opsu.GameImage;
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.Utils;
|
import itdelatrisu.opsu.Utils;
|
||||||
import itdelatrisu.opsu.skins.Skin;
|
|
||||||
import itdelatrisu.opsu.ui.animations.AnimationEquation;
|
import itdelatrisu.opsu.ui.animations.AnimationEquation;
|
||||||
|
|
||||||
import java.awt.Point;
|
import java.awt.Point;
|
||||||
|
@ -29,6 +27,9 @@ import java.util.LinkedList;
|
||||||
|
|
||||||
import org.newdawn.slick.*;
|
import org.newdawn.slick.*;
|
||||||
import yugecin.opsudance.Dancer;
|
import yugecin.opsudance.Dancer;
|
||||||
|
import yugecin.opsudance.skinning.SkinService;
|
||||||
|
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates and draws the cursor.
|
* Updates and draws the cursor.
|
||||||
|
@ -66,11 +67,6 @@ public class Cursor {
|
||||||
|
|
||||||
private boolean isMirrored;
|
private boolean isMirrored;
|
||||||
|
|
||||||
private Color filter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor.
|
|
||||||
*/
|
|
||||||
public Cursor() {
|
public Cursor() {
|
||||||
this(false);
|
this(false);
|
||||||
}
|
}
|
||||||
|
@ -80,29 +76,25 @@ public class Cursor {
|
||||||
this.isMirrored = isMirrored;
|
this.isMirrored = isMirrored;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Cursor(Color filter) {
|
|
||||||
this(false);
|
|
||||||
this.filter = filter;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draws the cursor.
|
* Draws the cursor.
|
||||||
* @param mousePressed whether or not the mouse button is pressed
|
* @param mousePressed whether or not the mouse button is pressed
|
||||||
*/
|
*/
|
||||||
public void draw(boolean mousePressed) {
|
public void draw(boolean mousePressed) {
|
||||||
if (Options.isCursorDisabled())
|
if (OPTION_DISABLE_CURSOR.state) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// determine correct cursor image
|
// determine correct cursor image
|
||||||
Image cursor, cursorMiddle = null, cursorTrail;
|
Image cursor, cursorMiddle = null, cursorTrail;
|
||||||
boolean beatmapSkinned = GameImage.CURSOR.hasBeatmapSkinImage();
|
boolean beatmapSkinned = GameImage.CURSOR.hasBeatmapSkinImage();
|
||||||
boolean hasMiddle;
|
boolean hasMiddle;
|
||||||
Skin skin = Options.getSkin();
|
|
||||||
if (beatmapSkinned) {
|
if (beatmapSkinned) {
|
||||||
newStyle = true; // osu! currently treats all beatmap cursors as new-style cursors
|
newStyle = true; // osu! currently treats all beatmap cursors as new-style cursors
|
||||||
hasMiddle = GameImage.CURSOR_MIDDLE.hasBeatmapSkinImage();
|
hasMiddle = GameImage.CURSOR_MIDDLE.hasBeatmapSkinImage();
|
||||||
} else
|
} else {
|
||||||
newStyle = hasMiddle = Options.isNewCursorEnabled();
|
newStyle = hasMiddle = OPTION_NEW_CURSOR.state;
|
||||||
|
}
|
||||||
if (beatmapSkinned || newStyle) {
|
if (beatmapSkinned || newStyle) {
|
||||||
cursor = GameImage.CURSOR.getImage();
|
cursor = GameImage.CURSOR.getImage();
|
||||||
cursorTrail = GameImage.CURSOR_TRAIL.getImage();
|
cursorTrail = GameImage.CURSOR_TRAIL.getImage();
|
||||||
|
@ -115,7 +107,7 @@ public class Cursor {
|
||||||
|
|
||||||
// scale cursor
|
// scale cursor
|
||||||
float cursorScaleAnimated = 1f;
|
float cursorScaleAnimated = 1f;
|
||||||
if (skin.isCursorExpanded()) {
|
if (SkinService.skin.isCursorExpanded()) {
|
||||||
if (lastCursorPressState != mousePressed) {
|
if (lastCursorPressState != mousePressed) {
|
||||||
lastCursorPressState = mousePressed;
|
lastCursorPressState = mousePressed;
|
||||||
lastCursorPressTime = System.currentTimeMillis();
|
lastCursorPressTime = System.currentTimeMillis();
|
||||||
|
@ -125,7 +117,7 @@ public class Cursor {
|
||||||
Utils.clamp(System.currentTimeMillis() - lastCursorPressTime, 0, CURSOR_SCALE_TIME) / CURSOR_SCALE_TIME);
|
Utils.clamp(System.currentTimeMillis() - lastCursorPressTime, 0, CURSOR_SCALE_TIME) / CURSOR_SCALE_TIME);
|
||||||
cursorScaleAnimated = 1f + ((mousePressed) ? cursorScaleChange : CURSOR_SCALE_CHANGE - cursorScaleChange);
|
cursorScaleAnimated = 1f + ((mousePressed) ? cursorScaleChange : CURSOR_SCALE_CHANGE - cursorScaleChange);
|
||||||
}
|
}
|
||||||
float cursorScale = cursorScaleAnimated * Options.getCursorScale();
|
float cursorScale = cursorScaleAnimated * OPTION_CURSOR_SIZE.val / 100f;
|
||||||
if (cursorScale != 1f) {
|
if (cursorScale != 1f) {
|
||||||
cursor = cursor.getScaledCopy(cursorScale);
|
cursor = cursor.getScaledCopy(cursorScale);
|
||||||
cursorTrail = cursorTrail.getScaledCopy(cursorScale);
|
cursorTrail = cursorTrail.getScaledCopy(cursorScale);
|
||||||
|
@ -138,19 +130,15 @@ public class Cursor {
|
||||||
lastCursorColor = filter = Dancer.cursorColorOverride.getColor();
|
lastCursorColor = filter = Dancer.cursorColorOverride.getColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.filter != null) {
|
|
||||||
filter = this.filter;
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw a fading trail
|
// draw a fading trail
|
||||||
float alpha = 0f;
|
float alpha = 0f;
|
||||||
float t = 2f / trail.size();
|
float t = 2f / trail.size();
|
||||||
int cursorTrailWidth = cursorTrail.getWidth(), cursorTrailHeight = cursorTrail.getHeight();
|
int cursorTrailWidth = cursorTrail.getWidth(), cursorTrailHeight = cursorTrail.getHeight();
|
||||||
float cursorTrailRotation = (skin.isCursorTrailRotated()) ? cursorAngle : 0;
|
float cursorTrailRotation = (SkinService.skin.isCursorTrailRotated()) ? cursorAngle : 0;
|
||||||
cursorTrail.startUse();
|
cursorTrail.startUse();
|
||||||
for (Point p : trail) {
|
for (Point p : trail) {
|
||||||
alpha += t;
|
alpha += t;
|
||||||
cursorTrail.setImageColor(filter.r, filter.g, filter.b, alpha * 0.1f);
|
cursorTrail.setImageColor(filter.r, filter.g, filter.b, alpha);
|
||||||
cursorTrail.drawEmbedded(
|
cursorTrail.drawEmbedded(
|
||||||
p.x - (cursorTrailWidth / 2f), p.y - (cursorTrailHeight / 2f),
|
p.x - (cursorTrailWidth / 2f), p.y - (cursorTrailHeight / 2f),
|
||||||
cursorTrailWidth, cursorTrailHeight, cursorTrailRotation);
|
cursorTrailWidth, cursorTrailHeight, cursorTrailRotation);
|
||||||
|
@ -161,11 +149,13 @@ public class Cursor {
|
||||||
cursorTrail.endUse();
|
cursorTrail.endUse();
|
||||||
|
|
||||||
// draw the other components
|
// draw the other components
|
||||||
if (newStyle && skin.isCursorRotated())
|
if (newStyle && SkinService.skin.isCursorRotated()) {
|
||||||
cursor.setRotation(cursorAngle);
|
cursor.setRotation(cursorAngle);
|
||||||
cursor.drawCentered(lastPosition.x, lastPosition.y, Options.isCursorOnlyColorTrail() ? Color.white : filter);
|
}
|
||||||
if (hasMiddle)
|
cursor.drawCentered(lastPosition.x, lastPosition.y, OPTION_DANCE_CURSOR_ONLY_COLOR_TRAIL.state ? Color.white : filter);
|
||||||
cursorMiddle.drawCentered(lastPosition.x, lastPosition.y, Options.isCursorOnlyColorTrail() ? Color.white : filter);
|
if (hasMiddle) {
|
||||||
|
cursorMiddle.drawCentered(lastPosition.x, lastPosition.y, OPTION_DANCE_CURSOR_ONLY_COLOR_TRAIL.state ? Color.white : filter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -194,7 +184,7 @@ public class Cursor {
|
||||||
removeCount = trail.size() - max;
|
removeCount = trail.size() - max;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cursortraillength = Options.getCursorTrailOverride();
|
int cursortraillength = OPTION_DANCE_CURSOR_TRAIL_OVERRIDE.val;
|
||||||
if (cursortraillength > 20) {
|
if (cursortraillength > 20) {
|
||||||
removeCount = trail.size() - cursortraillength;
|
removeCount = trail.size() - cursortraillength;
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,8 +93,9 @@ public class DropdownMenu<E> extends Component {
|
||||||
* @throws IllegalArgumentException if {@code index} is negative or greater than or equal to size
|
* @throws IllegalArgumentException if {@code index} is negative or greater than or equal to size
|
||||||
*/
|
*/
|
||||||
public void setSelectedIndex(int index) {
|
public void setSelectedIndex(int index) {
|
||||||
if (index < 0 || index >= items.length)
|
if (index < 0 || items.length <= index) {
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
this.selectedItemIndex = index;
|
this.selectedItemIndex = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,7 +253,7 @@ public class DropdownMenu<E> extends Component {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.expanded = (idx == -1) && !expanded;
|
this.expanded = (idx == -1) && !expanded;
|
||||||
if (idx >= 0 && selectedItemIndex != idx) {
|
if (0 <= idx && idx < items.length && selectedItemIndex != idx) {
|
||||||
this.selectedItemIndex = idx;
|
this.selectedItemIndex = idx;
|
||||||
itemSelected(idx, items[selectedItemIndex]);
|
itemSelected(idx, items[selectedItemIndex]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
package itdelatrisu.opsu.ui;
|
package itdelatrisu.opsu.ui;
|
||||||
|
|
||||||
import itdelatrisu.opsu.GameImage;
|
import itdelatrisu.opsu.GameImage;
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
|
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
import java.awt.FontFormatException;
|
import java.awt.FontFormatException;
|
||||||
|
@ -35,6 +34,7 @@ import org.newdawn.slick.font.effects.ColorEffect;
|
||||||
import org.newdawn.slick.font.effects.Effect;
|
import org.newdawn.slick.font.effects.Effect;
|
||||||
import org.newdawn.slick.util.Log;
|
import org.newdawn.slick.util.Log;
|
||||||
import org.newdawn.slick.util.ResourceLoader;
|
import org.newdawn.slick.util.ResourceLoader;
|
||||||
|
import yugecin.opsudance.options.Configuration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fonts used for drawing.
|
* Fonts used for drawing.
|
||||||
|
@ -54,9 +54,9 @@ public class Fonts {
|
||||||
* @throws FontFormatException if any font stream data does not contain the required font tables
|
* @throws FontFormatException if any font stream data does not contain the required font tables
|
||||||
* @throws IOException if a font stream cannot be completely read
|
* @throws IOException if a font stream cannot be completely read
|
||||||
*/
|
*/
|
||||||
public static void init() throws SlickException, FontFormatException, IOException {
|
public static void init(Configuration config) throws SlickException, FontFormatException, IOException {
|
||||||
float fontBase = 12f * GameImage.getUIscale();
|
float fontBase = 12f * GameImage.getUIscale();
|
||||||
Font javaFont = Font.createFont(Font.TRUETYPE_FONT, ResourceLoader.getResourceAsStream(Options.FONT_NAME));
|
Font javaFont = Font.createFont(Font.TRUETYPE_FONT, ResourceLoader.getResourceAsStream(config.FONT_NAME));
|
||||||
Font font = javaFont.deriveFont(Font.PLAIN, (int) (fontBase * 4 / 3));
|
Font font = javaFont.deriveFont(Font.PLAIN, (int) (fontBase * 4 / 3));
|
||||||
DEFAULT = new UnicodeFont(font);
|
DEFAULT = new UnicodeFont(font);
|
||||||
BOLD = new UnicodeFont(font.deriveFont(Font.BOLD));
|
BOLD = new UnicodeFont(font.deriveFont(Font.BOLD));
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
package itdelatrisu.opsu.ui;
|
package itdelatrisu.opsu.ui;
|
||||||
|
|
||||||
import itdelatrisu.opsu.GameImage;
|
import itdelatrisu.opsu.GameImage;
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.Utils;
|
import itdelatrisu.opsu.Utils;
|
||||||
import itdelatrisu.opsu.audio.SoundController;
|
import itdelatrisu.opsu.audio.SoundController;
|
||||||
import itdelatrisu.opsu.beatmap.BeatmapParser;
|
import itdelatrisu.opsu.beatmap.BeatmapParser;
|
||||||
|
@ -28,14 +27,14 @@ import itdelatrisu.opsu.replay.ReplayImporter;
|
||||||
import itdelatrisu.opsu.ui.animations.AnimatedValue;
|
import itdelatrisu.opsu.ui.animations.AnimatedValue;
|
||||||
import itdelatrisu.opsu.ui.animations.AnimationEquation;
|
import itdelatrisu.opsu.ui.animations.AnimationEquation;
|
||||||
|
|
||||||
import org.newdawn.slick.Animation;
|
|
||||||
import org.newdawn.slick.Color;
|
import org.newdawn.slick.Color;
|
||||||
import org.newdawn.slick.Graphics;
|
import org.newdawn.slick.Graphics;
|
||||||
import org.newdawn.slick.Image;
|
import org.newdawn.slick.Image;
|
||||||
import yugecin.opsudance.core.DisplayContainer;
|
import yugecin.opsudance.core.DisplayContainer;
|
||||||
import yugecin.opsudance.events.ResolutionOrSkinChangedEvent;
|
|
||||||
import yugecin.opsudance.ui.BackButton;
|
import yugecin.opsudance.ui.BackButton;
|
||||||
|
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draws common UI components.
|
* Draws common UI components.
|
||||||
*/
|
*/
|
||||||
|
@ -70,9 +69,6 @@ public class UI {
|
||||||
*/
|
*/
|
||||||
public static void init(DisplayContainer displayContainer) {
|
public static void init(DisplayContainer displayContainer) {
|
||||||
UI.displayContainer = displayContainer;
|
UI.displayContainer = displayContainer;
|
||||||
}
|
|
||||||
|
|
||||||
public static void revalidate() {
|
|
||||||
backButton = new BackButton(displayContainer);
|
backButton = new BackButton(displayContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,7 +147,7 @@ public class UI {
|
||||||
|
|
||||||
img.drawCentered(displayContainer.width - img.getWidth() / 2f + xOffset, displayContainer.height / 2f);
|
img.drawCentered(displayContainer.width - img.getWidth() / 2f + xOffset, displayContainer.height / 2f);
|
||||||
float barHeight = img.getHeight() * 0.9f;
|
float barHeight = img.getHeight() * 0.9f;
|
||||||
float volume = Options.getMasterVolume();
|
float volume = OPTION_MASTER_VOLUME.val / 100f;
|
||||||
g.setColor(Color.white);
|
g.setColor(Color.white);
|
||||||
g.fillRoundRect(
|
g.fillRoundRect(
|
||||||
displayContainer.width - (img.getWidth() * 0.368f) + xOffset,
|
displayContainer.width - (img.getWidth() * 0.368f) + xOffset,
|
||||||
|
@ -179,7 +175,8 @@ public class UI {
|
||||||
*/
|
*/
|
||||||
public static void changeVolume(int units) {
|
public static void changeVolume(int units) {
|
||||||
final float UNIT_OFFSET = 0.05f;
|
final float UNIT_OFFSET = 0.05f;
|
||||||
Options.setMasterVolume(Utils.clamp(Options.getMasterVolume() + (UNIT_OFFSET * units), 0f, 1f));
|
float volume = Utils.clamp(OPTION_MASTER_VOLUME.val / 100f + (UNIT_OFFSET * units), 0f, 1f);
|
||||||
|
OPTION_MASTER_VOLUME.setValue((int) (volume * 100f));
|
||||||
if (volumeDisplay == -1)
|
if (volumeDisplay == -1)
|
||||||
volumeDisplay = 0;
|
volumeDisplay = 0;
|
||||||
else if (volumeDisplay >= VOLUME_DISPLAY_TIME / 10)
|
else if (volumeDisplay >= VOLUME_DISPLAY_TIME / 10)
|
||||||
|
@ -196,6 +193,9 @@ public class UI {
|
||||||
int progress;
|
int progress;
|
||||||
|
|
||||||
// determine current action
|
// determine current action
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
TODO
|
||||||
if ((file = OszUnpacker.getCurrentFileName()) != null) {
|
if ((file = OszUnpacker.getCurrentFileName()) != null) {
|
||||||
text = "Unpacking new beatmaps...";
|
text = "Unpacking new beatmaps...";
|
||||||
progress = OszUnpacker.getUnpackerProgress();
|
progress = OszUnpacker.getUnpackerProgress();
|
||||||
|
@ -211,12 +211,17 @@ public class UI {
|
||||||
progress = SoundController.getLoadingProgress();
|
progress = SoundController.getLoadingProgress();
|
||||||
} else
|
} else
|
||||||
return;
|
return;
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (true) {
|
||||||
|
return; // TODO
|
||||||
|
}
|
||||||
|
|
||||||
// draw loading info
|
// draw loading info
|
||||||
float marginX = displayContainer.width * 0.02f, marginY = displayContainer.height * 0.02f;
|
float marginX = displayContainer.width * 0.02f, marginY = displayContainer.height * 0.02f;
|
||||||
float lineY = displayContainer.height - marginY;
|
float lineY = displayContainer.height - marginY;
|
||||||
int lineOffsetY = Fonts.MEDIUM.getLineHeight();
|
int lineOffsetY = Fonts.MEDIUM.getLineHeight();
|
||||||
if (Options.isLoadVerbose()) {
|
if (OPTION_LOAD_VERBOSE.state) {
|
||||||
// verbose: display percentages and file names
|
// verbose: display percentages and file names
|
||||||
Fonts.MEDIUM.drawString(
|
Fonts.MEDIUM.drawString(
|
||||||
marginX, lineY - (lineOffsetY * 2),
|
marginX, lineY - (lineOffsetY * 2),
|
||||||
|
|
|
@ -17,10 +17,11 @@
|
||||||
*/
|
*/
|
||||||
package yugecin.opsudance;
|
package yugecin.opsudance;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.ui.Cursor;
|
import itdelatrisu.opsu.ui.Cursor;
|
||||||
import org.newdawn.slick.Color;
|
import org.newdawn.slick.Color;
|
||||||
|
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
public enum CursorColorOverrides {
|
public enum CursorColorOverrides {
|
||||||
|
|
||||||
NONE ("Do not override", 0) {
|
NONE ("Do not override", 0) {
|
||||||
|
@ -111,12 +112,12 @@ public enum CursorColorOverrides {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Color nextRainbowColor() {
|
private static Color nextRainbowColor() {
|
||||||
hue += Options.getRGBCursorInc() / 1000f;
|
hue += OPTION_DANCE_RGB_CURSOR_INC.val / 1000f;
|
||||||
return new Color(java.awt.Color.getHSBColor(hue / 360f, 1.0f, 1.0f).getRGB());
|
return new Color(java.awt.Color.getHSBColor(hue / 360f, 1.0f, 1.0f).getRGB());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Color nextMirrorRainbowColor() {
|
private static Color nextMirrorRainbowColor() {
|
||||||
hue += Options.getRGBCursorInc() / 1000f;
|
hue += OPTION_DANCE_RGB_CURSOR_INC.val / 1000f;
|
||||||
return new Color(java.awt.Color.getHSBColor((hue + 180f) / 360f, 1.0f, 1.0f).getRGB());
|
return new Color(java.awt.Color.getHSBColor((hue + 180f) / 360f, 1.0f, 1.0f).getRGB());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,10 +22,8 @@ import awlex.ospu.movers.factories.SpiralMoverFactory;
|
||||||
import awlex.ospu.polymover.factory.ArcFactory;
|
import awlex.ospu.polymover.factory.ArcFactory;
|
||||||
import awlex.ospu.polymover.factory.PolyMoverFactory;
|
import awlex.ospu.polymover.factory.PolyMoverFactory;
|
||||||
import awlex.ospu.spinners.SpiralSpinner;
|
import awlex.ospu.spinners.SpiralSpinner;
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.Utils;
|
import itdelatrisu.opsu.Utils;
|
||||||
import itdelatrisu.opsu.audio.MusicController;
|
import itdelatrisu.opsu.audio.MusicController;
|
||||||
import itdelatrisu.opsu.objects.Circle;
|
|
||||||
import itdelatrisu.opsu.objects.DummyObject;
|
import itdelatrisu.opsu.objects.DummyObject;
|
||||||
import itdelatrisu.opsu.objects.GameObject;
|
import itdelatrisu.opsu.objects.GameObject;
|
||||||
import itdelatrisu.opsu.objects.Slider;
|
import itdelatrisu.opsu.objects.Slider;
|
||||||
|
@ -37,10 +35,13 @@ import yugecin.opsudance.movers.factories.*;
|
||||||
import yugecin.opsudance.movers.slidermovers.DefaultSliderMoverController;
|
import yugecin.opsudance.movers.slidermovers.DefaultSliderMoverController;
|
||||||
import yugecin.opsudance.movers.slidermovers.InheritedSliderMoverController;
|
import yugecin.opsudance.movers.slidermovers.InheritedSliderMoverController;
|
||||||
import yugecin.opsudance.movers.slidermovers.SliderMoverController;
|
import yugecin.opsudance.movers.slidermovers.SliderMoverController;
|
||||||
|
import yugecin.opsudance.render.GameObjectRenderer;
|
||||||
import yugecin.opsudance.spinners.*;
|
import yugecin.opsudance.spinners.*;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
public class Dancer {
|
public class Dancer {
|
||||||
|
|
||||||
public static MoverFactory[] moverFactories = new MoverFactory[] {
|
public static MoverFactory[] moverFactories = new MoverFactory[] {
|
||||||
|
@ -193,12 +194,12 @@ public class Dancer {
|
||||||
}
|
}
|
||||||
isCurrentLazySlider = false;
|
isCurrentLazySlider = false;
|
||||||
// detect lazy sliders, should work pretty good
|
// detect lazy sliders, should work pretty good
|
||||||
if (c.isSlider() && Options.isLazySliders() && Utils.distance(c.start.x, c.start.y, c.end.x, c.end.y) <= Circle.diameter * 0.8f) {
|
if (c.isSlider() && OPTION_DANCE_LAZY_SLIDERS.state && Utils.distance(c.start.x, c.start.y, c.end.x, c.end.y) <= GameObjectRenderer.instance.getCircleDiameter() * 0.8f) {
|
||||||
Slider s = (Slider) c;
|
Slider s = (Slider) c;
|
||||||
Vec2f mid = s.getCurve().pointAt(1f);
|
Vec2f mid = s.getCurve().pointAt(1f);
|
||||||
if (s.getRepeats() == 1 || Utils.distance(c.start.x, c.start.y, mid.x, mid.y) <= Circle.diameter * 0.8f) {
|
if (s.getRepeats() == 1 || Utils.distance(c.start.x, c.start.y, mid.x, mid.y) <= GameObjectRenderer.instance.getCircleDiameter() * 0.8f) {
|
||||||
mid = s.getCurve().pointAt(0.5f);
|
mid = s.getCurve().pointAt(0.5f);
|
||||||
if (Utils.distance(c.start.x, c.start.y, mid.x, mid.y) <= Circle.diameter * 0.8f) {
|
if (Utils.distance(c.start.x, c.start.y, mid.x, mid.y) <= GameObjectRenderer.instance.getCircleDiameter() * 0.8f) {
|
||||||
isCurrentLazySlider = true;
|
isCurrentLazySlider = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -250,8 +251,8 @@ public class Dancer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Pippi.dance(time, c, isCurrentLazySlider);
|
Pippi.dance(time, c, isCurrentLazySlider);
|
||||||
x = Utils.clamp(x, 10, Options.width - 10);
|
x = Utils.clamp(x, 10, width - 10);
|
||||||
y = Utils.clamp(y, 10, Options.height - 10);
|
y = Utils.clamp(y, 10, height - 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createNewMover() {
|
private void createNewMover() {
|
||||||
|
|
|
@ -17,9 +17,10 @@
|
||||||
*/
|
*/
|
||||||
package yugecin.opsudance;
|
package yugecin.opsudance;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import org.newdawn.slick.Color;
|
import org.newdawn.slick.Color;
|
||||||
|
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
public enum ObjectColorOverrides {
|
public enum ObjectColorOverrides {
|
||||||
|
|
||||||
NONE ("Do not override", 0) {
|
NONE ("Do not override", 0) {
|
||||||
|
@ -95,7 +96,7 @@ public enum ObjectColorOverrides {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Color nextRainbowColor() {
|
private static Color nextRainbowColor() {
|
||||||
hue += Options.getRGBObjInc() / 10f;
|
hue += OPTION_DANCE_RGB_OBJECT_INC.val / 10f;
|
||||||
return new Color(java.awt.Color.getHSBColor(hue / 360f, 1.0f, 1.0f).getRGB());
|
return new Color(java.awt.Color.getHSBColor(hue / 360f, 1.0f, 1.0f).getRGB());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
*/
|
*/
|
||||||
package yugecin.opsudance;
|
package yugecin.opsudance;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.Utils;
|
import itdelatrisu.opsu.Utils;
|
||||||
import itdelatrisu.opsu.beatmap.BeatmapWatchService;
|
import itdelatrisu.opsu.beatmap.BeatmapWatchService;
|
||||||
import itdelatrisu.opsu.db.DBController;
|
import itdelatrisu.opsu.db.DBController;
|
||||||
|
@ -27,6 +26,9 @@ import itdelatrisu.opsu.states.Splash;
|
||||||
import org.newdawn.slick.util.Log;
|
import org.newdawn.slick.util.Log;
|
||||||
import yugecin.opsudance.core.DisplayContainer;
|
import yugecin.opsudance.core.DisplayContainer;
|
||||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||||
|
import yugecin.opsudance.core.inject.Inject;
|
||||||
|
import yugecin.opsudance.options.Configuration;
|
||||||
|
import yugecin.opsudance.options.OptionsService;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -35,18 +37,29 @@ import java.net.ServerSocket;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
import static yugecin.opsudance.core.Entrypoint.sout;
|
import static yugecin.opsudance.core.Entrypoint.sout;
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* loosely based on itdelatrisu.opsu.Opsu
|
* loosely based on itdelatrisu.opsu.Opsu
|
||||||
*/
|
*/
|
||||||
public class OpsuDance {
|
public class OpsuDance {
|
||||||
|
|
||||||
private final DisplayContainer container;
|
@Inject
|
||||||
|
private DisplayContainer container;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private OptionsService optionsService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Configuration config;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Updater updater;
|
||||||
|
|
||||||
private ServerSocket singleInstanceSocket;
|
private ServerSocket singleInstanceSocket;
|
||||||
|
|
||||||
public OpsuDance(DisplayContainer container) {
|
@Inject
|
||||||
this.container = container;
|
public OpsuDance() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void start(String[] args) {
|
public void start(String[] args) {
|
||||||
|
@ -54,7 +67,7 @@ public class OpsuDance {
|
||||||
sout("initialized");
|
sout("initialized");
|
||||||
|
|
||||||
checkRunningDirectory();
|
checkRunningDirectory();
|
||||||
Options.parseOptions();
|
optionsService.loadOptions();
|
||||||
ensureSingleInstance();
|
ensureSingleInstance();
|
||||||
sout("prechecks done and options parsed");
|
sout("prechecks done and options parsed");
|
||||||
|
|
||||||
|
@ -70,12 +83,12 @@ public class OpsuDance {
|
||||||
while (rungame());
|
while (rungame());
|
||||||
container.teardownAL();
|
container.teardownAL();
|
||||||
|
|
||||||
Options.saveOptions();
|
optionsService.saveOptions();
|
||||||
closeSingleInstanceSocket();
|
closeSingleInstanceSocket();
|
||||||
DBController.closeConnections();
|
DBController.closeConnections();
|
||||||
DownloadList.get().cancelAllDownloads();
|
DownloadList.get().cancelAllDownloads();
|
||||||
Utils.deleteDirectory(Options.TEMP_DIR);
|
Utils.deleteDirectory(config.TEMP_DIR);
|
||||||
if (!Options.isWatchServiceEnabled()) {
|
if (!OPTION_ENABLE_WATCH_SERVICE.state) {
|
||||||
BeatmapWatchService.destroy();
|
BeatmapWatchService.destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,7 +114,7 @@ public class OpsuDance {
|
||||||
|
|
||||||
private void initDatabase() {
|
private void initDatabase() {
|
||||||
try {
|
try {
|
||||||
DBController.init();
|
DBController.init(config);
|
||||||
} catch (UnsatisfiedLinkError e) {
|
} catch (UnsatisfiedLinkError e) {
|
||||||
errorAndExit("Could not initialize database.", e);
|
errorAndExit("Could not initialize database.", e);
|
||||||
}
|
}
|
||||||
|
@ -109,18 +122,19 @@ public class OpsuDance {
|
||||||
|
|
||||||
private void initUpdater(String[] args) {
|
private void initUpdater(String[] args) {
|
||||||
// check if just updated
|
// check if just updated
|
||||||
if (args.length >= 2)
|
if (args.length >= 2) {
|
||||||
Updater.get().setUpdateInfo(args[0], args[1]);
|
updater.setUpdateInfo(args[0], args[1]);
|
||||||
|
}
|
||||||
|
|
||||||
// check for updates
|
// check for updates
|
||||||
if (Options.isUpdaterDisabled()) {
|
if (OPTION_DISABLE_UPDATER.state) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
new Thread() {
|
new Thread() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
Updater.get().checkForUpdates();
|
updater.checkForUpdates();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.warn("updatecheck failed.", e);
|
Log.warn("updatecheck failed.", e);
|
||||||
}
|
}
|
||||||
|
@ -143,18 +157,18 @@ public class OpsuDance {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ensureSingleInstance() {
|
private void ensureSingleInstance() {
|
||||||
if (Options.noSingleInstance()) {
|
if (OPTION_NOSINGLEINSTANCE.state) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
singleInstanceSocket = new ServerSocket(Options.getPort(), 1, InetAddress.getLocalHost());
|
singleInstanceSocket = new ServerSocket(OPTION_PORT.val, 1, InetAddress.getLocalHost());
|
||||||
} catch (UnknownHostException e) {
|
} catch (UnknownHostException e) {
|
||||||
// shouldn't happen
|
// shouldn't happen
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
errorAndExit(String.format(
|
errorAndExit(String.format(
|
||||||
"Could not launch. Either opsu! is already running or a different program uses port %d.\n" +
|
"Could not launch. Either opsu! is already running or a different program uses port %d.\n" +
|
||||||
"You can change the port opsu! uses by editing the 'Port' field in the .opsu.cfg configuration file.\n" +
|
"You can change the port opsu! uses by editing the 'Port' field in the .opsu.cfg configuration file.\n" +
|
||||||
"If that still does not resolve the problem, you can set 'NoSingleInstance' to 'true', but this is not recommended.", Options.getPort()), e);
|
"If that still does not resolve the problem, you can set 'NoSingleInstance' to 'true', but this is not recommended.", OPTION_PORT.val), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,10 +17,11 @@
|
||||||
*/
|
*/
|
||||||
package yugecin.opsudance;
|
package yugecin.opsudance;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.objects.Circle;
|
|
||||||
import itdelatrisu.opsu.objects.GameObject;
|
import itdelatrisu.opsu.objects.GameObject;
|
||||||
import itdelatrisu.opsu.objects.Slider;
|
import itdelatrisu.opsu.objects.Slider;
|
||||||
|
import yugecin.opsudance.render.GameObjectRenderer;
|
||||||
|
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
public class Pippi {
|
public class Pippi {
|
||||||
|
|
||||||
|
@ -37,30 +38,30 @@ public class Pippi {
|
||||||
|
|
||||||
public static void setRadiusPercent(int radiusPercent) {
|
public static void setRadiusPercent(int radiusPercent) {
|
||||||
Pippi.radiusPercent = radiusPercent;
|
Pippi.radiusPercent = radiusPercent;
|
||||||
pippiminrad = pippirad = (Circle.diameter / 2d - 10d) * radiusPercent / 100d;
|
pippiminrad = pippirad = (GameObjectRenderer.instance.getCircleDiameter() / 2d - 10d) * radiusPercent / 100d;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void reset() {
|
public static void reset() {
|
||||||
angle = 0;
|
angle = 0;
|
||||||
currentdelta = 0;
|
currentdelta = 0;
|
||||||
setRadiusPercent(radiusPercent);
|
setRadiusPercent(radiusPercent);
|
||||||
pippimaxrad = Circle.diameter - 10d;
|
pippimaxrad = GameObjectRenderer.instance.getCircleDiameter() - 10d;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void dance(int time, GameObject c, boolean isCurrentLazySlider) {
|
public static void dance(int time, GameObject c, boolean isCurrentLazySlider) {
|
||||||
boolean slowSlider = Options.isCircleInSlowSliders() && c.isSlider() && (((((Slider) c).pixelLength < 200 || c.getEndTime() - c.getTime() > 400)) || isCurrentLazySlider);
|
boolean slowSlider = OPTION_DANCE_CIRLCE_IN_SLOW_SLIDERS.state && c.isSlider() && (((((Slider) c).pixelLength < 200 || c.getEndTime() - c.getTime() > 400)) || isCurrentLazySlider);
|
||||||
if (!slowSlider) {
|
if (!slowSlider) {
|
||||||
slowSlider = Options.isCircleInLazySliders() && isCurrentLazySlider;
|
slowSlider = OPTION_DANCE_CIRLCE_IN_LAZY_SLIDERS.state && isCurrentLazySlider;
|
||||||
}
|
}
|
||||||
if ((!Options.isPippiEnabled() || c.isSpinner()) && !slowSlider) {
|
if ((!OPTION_PIPPI_ENABLE.state || c.isSpinner()) && !slowSlider) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (currentdelta >= targetdelta && c != previous) {
|
if (currentdelta >= targetdelta && c != previous) {
|
||||||
currentdelta = 0;
|
currentdelta = 0;
|
||||||
if (c.isSlider() && c.getTime() < time) {
|
if (c.isSlider() && c.getTime() < time) {
|
||||||
angle += Options.getPippiAngIncMultiplierSlider() / 1800d * Math.PI;
|
angle += OPTION_PIPPI_ANGLE_INC_MUL_SLIDER.val / 1800d * Math.PI;
|
||||||
if (!slowSlider) {
|
if (!slowSlider) {
|
||||||
if (Options.isPippiFollowcircleExpand()) {
|
if (OPTION_PIPPI_SLIDER_FOLLOW_EXPAND.state) {
|
||||||
if (c.getEndTime() - time < 40 && pippirad > pippimaxrad) {
|
if (c.getEndTime() - time < 40 && pippirad > pippimaxrad) {
|
||||||
pippirad -= 5d;
|
pippirad -= 5d;
|
||||||
} else if (time - c.getTime() > 10 && c.getEndTime() - c.getTime() > 600 && pippirad < pippimaxrad) {
|
} else if (time - c.getTime() > 10 && c.getEndTime() - c.getTime() > 600 && pippirad < pippimaxrad) {
|
||||||
|
@ -69,10 +70,10 @@ public class Pippi {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (!c.isSpinner()) {
|
} else if (!c.isSpinner()) {
|
||||||
if (Options.isPippiFollowcircleExpand() && pippirad != pippiminrad) {
|
if (OPTION_PIPPI_SLIDER_FOLLOW_EXPAND.state && pippirad != pippiminrad) {
|
||||||
pippirad = pippiminrad;
|
pippirad = pippiminrad;
|
||||||
}
|
}
|
||||||
angle += Options.getPippiAngIncMultiplier() / 1800d * Math.PI;
|
angle += OPTION_PIPPI_ANGLE_INC_MUL.val / 1800d * Math.PI;
|
||||||
}
|
}
|
||||||
// don't inc on long movements
|
// don't inc on long movements
|
||||||
if (c.getTime() - time > 400) {
|
if (c.getTime() - time > 400) {
|
||||||
|
@ -91,7 +92,7 @@ public class Pippi {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean shouldPreventWobblyStream(double distance) {
|
public static boolean shouldPreventWobblyStream(double distance) {
|
||||||
return Options.isPippiEnabled() && distance < Circle.diameter * 0.93f && Options.isPippiPreventWobblyStreams();
|
return OPTION_PIPPI_ENABLE.state && distance < GameObjectRenderer.instance.getCircleDiameter() * 0.93f && OPTION_PIPPI_PREVENT_WOBBLY_STREAMS.state;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,10 +18,11 @@
|
||||||
package yugecin.opsudance;
|
package yugecin.opsudance;
|
||||||
|
|
||||||
import itdelatrisu.opsu.NativeLoader;
|
import itdelatrisu.opsu.NativeLoader;
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import org.newdawn.slick.util.FileSystemLocation;
|
import org.newdawn.slick.util.FileSystemLocation;
|
||||||
import org.newdawn.slick.util.Log;
|
import org.newdawn.slick.util.Log;
|
||||||
import org.newdawn.slick.util.ResourceLoader;
|
import org.newdawn.slick.util.ResourceLoader;
|
||||||
|
import yugecin.opsudance.core.inject.Inject;
|
||||||
|
import yugecin.opsudance.options.Configuration;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -29,7 +30,11 @@ import java.lang.reflect.Field;
|
||||||
|
|
||||||
public class PreStartupInitializer {
|
public class PreStartupInitializer {
|
||||||
|
|
||||||
public PreStartupInitializer() {
|
private final Configuration config;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public PreStartupInitializer(Configuration config) {
|
||||||
|
this.config = config;
|
||||||
loadNatives();
|
loadNatives();
|
||||||
setResourcePath();
|
setResourcePath();
|
||||||
}
|
}
|
||||||
|
@ -52,7 +57,7 @@ public class PreStartupInitializer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private File loadNativesUsingOptionsPath() {
|
private File loadNativesUsingOptionsPath() {
|
||||||
File nativeDir = Options.NATIVE_DIR;
|
File nativeDir = config.NATIVE_DIR;
|
||||||
try {
|
try {
|
||||||
new NativeLoader(nativeDir).loadNatives();
|
new NativeLoader(nativeDir).loadNatives();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|
|
@ -17,15 +17,15 @@
|
||||||
*/
|
*/
|
||||||
package yugecin.opsudance.core;
|
package yugecin.opsudance.core;
|
||||||
|
|
||||||
import itdelatrisu.opsu.GameData;
|
import itdelatrisu.opsu.*;
|
||||||
import itdelatrisu.opsu.GameImage;
|
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.Utils;
|
|
||||||
import itdelatrisu.opsu.audio.MusicController;
|
import itdelatrisu.opsu.audio.MusicController;
|
||||||
import itdelatrisu.opsu.beatmap.Beatmap;
|
import itdelatrisu.opsu.beatmap.Beatmap;
|
||||||
|
import itdelatrisu.opsu.beatmap.HitObject;
|
||||||
import itdelatrisu.opsu.downloads.DownloadList;
|
import itdelatrisu.opsu.downloads.DownloadList;
|
||||||
|
import itdelatrisu.opsu.downloads.DownloadNode;
|
||||||
import itdelatrisu.opsu.downloads.Updater;
|
import itdelatrisu.opsu.downloads.Updater;
|
||||||
import itdelatrisu.opsu.render.CurveRenderState;
|
import itdelatrisu.opsu.render.CurveRenderState;
|
||||||
|
import itdelatrisu.opsu.replay.PlaybackSpeed;
|
||||||
import itdelatrisu.opsu.ui.Cursor;
|
import itdelatrisu.opsu.ui.Cursor;
|
||||||
import itdelatrisu.opsu.ui.Fonts;
|
import itdelatrisu.opsu.ui.Fonts;
|
||||||
import itdelatrisu.opsu.ui.UI;
|
import itdelatrisu.opsu.ui.UI;
|
||||||
|
@ -42,6 +42,7 @@ import org.newdawn.slick.util.Log;
|
||||||
import yugecin.opsudance.core.events.EventBus;
|
import yugecin.opsudance.core.events.EventBus;
|
||||||
import yugecin.opsudance.core.errorhandling.ErrorDumpable;
|
import yugecin.opsudance.core.errorhandling.ErrorDumpable;
|
||||||
import yugecin.opsudance.core.events.EventListener;
|
import yugecin.opsudance.core.events.EventListener;
|
||||||
|
import yugecin.opsudance.core.inject.Inject;
|
||||||
import yugecin.opsudance.core.inject.InstanceContainer;
|
import yugecin.opsudance.core.inject.InstanceContainer;
|
||||||
import yugecin.opsudance.core.state.OpsuState;
|
import yugecin.opsudance.core.state.OpsuState;
|
||||||
import yugecin.opsudance.core.state.specialstates.BarNotificationState;
|
import yugecin.opsudance.core.state.specialstates.BarNotificationState;
|
||||||
|
@ -50,19 +51,25 @@ import yugecin.opsudance.core.state.specialstates.FpsRenderState;
|
||||||
import yugecin.opsudance.core.state.transitions.*;
|
import yugecin.opsudance.core.state.transitions.*;
|
||||||
import yugecin.opsudance.events.BubbleNotificationEvent;
|
import yugecin.opsudance.events.BubbleNotificationEvent;
|
||||||
import yugecin.opsudance.events.ResolutionOrSkinChangedEvent;
|
import yugecin.opsudance.events.ResolutionOrSkinChangedEvent;
|
||||||
|
import yugecin.opsudance.options.Configuration;
|
||||||
|
import yugecin.opsudance.skinning.SkinService;
|
||||||
import yugecin.opsudance.utils.GLHelper;
|
import yugecin.opsudance.utils.GLHelper;
|
||||||
|
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
|
|
||||||
import static yugecin.opsudance.core.Entrypoint.sout;
|
import static yugecin.opsudance.core.Entrypoint.sout;
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* based on org.newdawn.slick.AppGameContainer
|
* based on org.newdawn.slick.AppGameContainer
|
||||||
*/
|
*/
|
||||||
public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListener {
|
public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListener {
|
||||||
|
|
||||||
@Deprecated
|
@Inject
|
||||||
public static DisplayContainer instance; // TODO d remove this
|
private SkinService skinService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Configuration config;
|
||||||
|
|
||||||
private static SGL GL = Renderer.get();
|
private static SGL GL = Renderer.get();
|
||||||
|
|
||||||
|
@ -116,11 +123,11 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
|
||||||
public final Cursor cursor;
|
public final Cursor cursor;
|
||||||
public boolean drawCursor;
|
public boolean drawCursor;
|
||||||
|
|
||||||
|
@Inject
|
||||||
public DisplayContainer(InstanceContainer instanceContainer) {
|
public DisplayContainer(InstanceContainer instanceContainer) {
|
||||||
this.instanceContainer = instanceContainer;
|
this.instanceContainer = instanceContainer;
|
||||||
this.cursor = new Cursor();
|
this.cursor = new Cursor();
|
||||||
drawCursor = true;
|
drawCursor = true;
|
||||||
instance = this;
|
|
||||||
|
|
||||||
outTransitionListener = new TransitionFinishedListener() {
|
outTransitionListener = new TransitionFinishedListener() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -145,8 +152,7 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
|
||||||
@Override
|
@Override
|
||||||
public void onEvent(ResolutionOrSkinChangedEvent event) {
|
public void onEvent(ResolutionOrSkinChangedEvent event) {
|
||||||
destroyImages();
|
destroyImages();
|
||||||
Utils.init(DisplayContainer.this); // TODO this shouldn't be here
|
reinit();
|
||||||
UI.revalidate(); // TODO this shouldn't be here
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -155,8 +161,29 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
|
||||||
lastFrame = getTime();
|
lastFrame = getTime();
|
||||||
delta = 1;
|
delta = 1;
|
||||||
renderDelta = 1;
|
renderDelta = 1;
|
||||||
|
}
|
||||||
|
|
||||||
Options.GameOption.displayContainer = this;
|
private void reinit() {
|
||||||
|
// this used to be in Utils.init
|
||||||
|
// TODO find a better place for this?
|
||||||
|
setFPS(targetFPS[targetFPSIndex]);
|
||||||
|
MusicController.setMusicVolume(OPTION_MUSIC_VOLUME.val / 100f * OPTION_MASTER_VOLUME.val / 100f);
|
||||||
|
|
||||||
|
skinService.loadSkin();
|
||||||
|
|
||||||
|
// initialize game images
|
||||||
|
for (GameImage img : GameImage.values()) {
|
||||||
|
if (img.isPreload()) {
|
||||||
|
img.setDefaultImage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO clean this up
|
||||||
|
GameMod.init(width, height);
|
||||||
|
PlaybackSpeed.init(width, height);
|
||||||
|
HitObject.init(width, height);
|
||||||
|
DownloadNode.init(width, height);
|
||||||
|
UI.init(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUPS(int ups) {
|
public void setUPS(int ups) {
|
||||||
|
@ -170,8 +197,8 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init(Class<? extends OpsuState> startingState) {
|
public void init(Class<? extends OpsuState> startingState) {
|
||||||
setUPS(Options.getTargetUPS());
|
setUPS(OPTION_TARGET_UPS.val);
|
||||||
setFPS(Options.getTargetFPS());
|
setFPS(targetFPS[targetFPSIndex]);
|
||||||
|
|
||||||
state = instanceContainer.provide(startingState);
|
state = instanceContainer.provide(startingState);
|
||||||
state.enter();
|
state.enter();
|
||||||
|
@ -245,7 +272,7 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
|
||||||
width = height = -1;
|
width = height = -1;
|
||||||
Input.disableControllers();
|
Input.disableControllers();
|
||||||
Display.setTitle("opsu!dance");
|
Display.setTitle("opsu!dance");
|
||||||
Options.setDisplayMode(this);
|
updateDisplayMode(OPTION_SCREEN_RESOLUTION.getValueString());
|
||||||
Display.create();
|
Display.create();
|
||||||
GLHelper.setIcons(new String[] { "icon16.png", "icon32.png" });
|
GLHelper.setIcons(new String[] { "icon16.png", "icon32.png" });
|
||||||
initGL();
|
initGL();
|
||||||
|
@ -303,6 +330,38 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updateDisplayMode(String resolutionString) {
|
||||||
|
int screenWidth = nativeDisplayMode.getWidth();
|
||||||
|
int screenHeight = nativeDisplayMode.getHeight();
|
||||||
|
|
||||||
|
int width = screenWidth;
|
||||||
|
int height = screenHeight;
|
||||||
|
if (resolutionString.matches("^[0-9]+x[0-9]+$")) {
|
||||||
|
String[] res = resolutionString.split("x");
|
||||||
|
width = Integer.parseInt(res[0]);
|
||||||
|
height = Integer.parseInt(res[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for larger-than-screen dimensions
|
||||||
|
if (!OPTION_ALLOW_LARGER_RESOLUTIONS.state && (screenWidth < width || screenHeight < height)) {
|
||||||
|
width = 800;
|
||||||
|
height = 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
setDisplayMode(width, height, OPTION_FULLSCREEN.state);
|
||||||
|
} catch (Exception e) {
|
||||||
|
EventBus.post(new BubbleNotificationEvent("Failed to change resolution", BubbleNotificationEvent.COMMONCOLOR_RED));
|
||||||
|
Log.error("Failed to set display mode.", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OPTION_FULLSCREEN.state) {
|
||||||
|
// set borderless window if dimensions match screen size
|
||||||
|
boolean borderless = (screenWidth == width && screenHeight == height);
|
||||||
|
System.setProperty("org.lwjgl.opengl.Window.undecorated", Boolean.toString(borderless));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void setDisplayMode(int width, int height, boolean fullscreen) throws Exception {
|
public void setDisplayMode(int width, int height, boolean fullscreen) throws Exception {
|
||||||
if (this.width == width && this.height == height) {
|
if (this.width == width && this.height == height) {
|
||||||
Display.setFullscreen(fullscreen);
|
Display.setFullscreen(fullscreen);
|
||||||
|
@ -353,9 +412,9 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
|
||||||
sout("GL ready");
|
sout("GL ready");
|
||||||
|
|
||||||
GameImage.init(width, height);
|
GameImage.init(width, height);
|
||||||
Fonts.init();
|
Fonts.init(config);
|
||||||
|
|
||||||
EventBus.post(new ResolutionOrSkinChangedEvent());
|
EventBus.post(new ResolutionOrSkinChangedEvent(null, width, height));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resetCursor() {
|
public void resetCursor() {
|
||||||
|
|
|
@ -17,10 +17,10 @@
|
||||||
*/
|
*/
|
||||||
package yugecin.opsudance.core.errorhandling;
|
package yugecin.opsudance.core.errorhandling;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.Utils;
|
import itdelatrisu.opsu.Utils;
|
||||||
import org.newdawn.slick.util.Log;
|
import org.newdawn.slick.util.Log;
|
||||||
import yugecin.opsudance.core.DisplayContainer;
|
import yugecin.opsudance.core.DisplayContainer;
|
||||||
|
import yugecin.opsudance.options.Configuration;
|
||||||
import yugecin.opsudance.utils.MiscUtils;
|
import yugecin.opsudance.utils.MiscUtils;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
@ -42,6 +42,7 @@ public class ErrorHandler {
|
||||||
|
|
||||||
private static ErrorHandler instance;
|
private static ErrorHandler instance;
|
||||||
|
|
||||||
|
private final Configuration config;
|
||||||
private final DisplayContainer displayContainer;
|
private final DisplayContainer displayContainer;
|
||||||
|
|
||||||
private String customMessage;
|
private String customMessage;
|
||||||
|
@ -54,8 +55,9 @@ public class ErrorHandler {
|
||||||
private boolean ignoreAndContinue;
|
private boolean ignoreAndContinue;
|
||||||
private boolean allowTerminate;
|
private boolean allowTerminate;
|
||||||
|
|
||||||
public ErrorHandler(DisplayContainer displayContainer) {
|
public ErrorHandler(DisplayContainer displayContainer, Configuration config) {
|
||||||
this.displayContainer = displayContainer;
|
this.displayContainer = displayContainer;
|
||||||
|
this.config = config;
|
||||||
instance = this;
|
instance = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,7 +166,7 @@ public class ErrorHandler {
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent event) {
|
public void actionPerformed(ActionEvent event) {
|
||||||
try {
|
try {
|
||||||
Desktop.getDesktop().open(Options.LOG_FILE);
|
Desktop.getDesktop().open(config.LOG_FILE);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.warn("Could not open log file", e);
|
Log.warn("Could not open log file", e);
|
||||||
JOptionPane.showMessageDialog(null, "whoops could not open log file", "errorception", JOptionPane.ERROR_MESSAGE);
|
JOptionPane.showMessageDialog(null, "whoops could not open log file", "errorception", JOptionPane.ERROR_MESSAGE);
|
||||||
|
@ -230,7 +232,7 @@ public class ErrorHandler {
|
||||||
} catch (UnsupportedEncodingException e) {
|
} catch (UnsupportedEncodingException e) {
|
||||||
Log.warn("URLEncoder failed to encode the auto-filled issue report URL.", e);
|
Log.warn("URLEncoder failed to encode the auto-filled issue report URL.", e);
|
||||||
}
|
}
|
||||||
return URI.create(String.format(Options.ISSUES_URL, issueTitle, issueBody));
|
return URI.create(String.format(config.ISSUES_URL, issueTitle, issueBody));
|
||||||
}
|
}
|
||||||
|
|
||||||
private String truncateGithubIssueBody(String body) {
|
private String truncateGithubIssueBody(String body) {
|
||||||
|
|
|
@ -101,6 +101,11 @@ public abstract class Injector implements InstanceContainer, Binder {
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T injectFields(T obj) {
|
||||||
|
return injectFields(obj, obj.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
public final <T> Binder<T> bind(Class<T> type) {
|
public final <T> Binder<T> bind(Class<T> type) {
|
||||||
lastType = type;
|
lastType = type;
|
||||||
return this;
|
return this;
|
||||||
|
|
|
@ -20,5 +20,6 @@ package yugecin.opsudance.core.inject;
|
||||||
public interface InstanceContainer {
|
public interface InstanceContainer {
|
||||||
|
|
||||||
<T> T provide(Class<T> type);
|
<T> T provide(Class<T> type);
|
||||||
|
<T> T injectFields(T instance);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,10 @@
|
||||||
*/
|
*/
|
||||||
package yugecin.opsudance.core.inject;
|
package yugecin.opsudance.core.inject;
|
||||||
|
|
||||||
|
import itdelatrisu.opsu.beatmap.BeatmapParser;
|
||||||
|
import itdelatrisu.opsu.beatmap.OszUnpacker;
|
||||||
|
import itdelatrisu.opsu.downloads.Updater;
|
||||||
|
import itdelatrisu.opsu.replay.ReplayImporter;
|
||||||
import itdelatrisu.opsu.states.*;
|
import itdelatrisu.opsu.states.*;
|
||||||
import yugecin.opsudance.PreStartupInitializer;
|
import yugecin.opsudance.PreStartupInitializer;
|
||||||
import yugecin.opsudance.core.DisplayContainer;
|
import yugecin.opsudance.core.DisplayContainer;
|
||||||
|
@ -27,10 +31,23 @@ import yugecin.opsudance.core.state.transitions.EmptyTransitionState;
|
||||||
import yugecin.opsudance.core.state.transitions.FadeInTransitionState;
|
import yugecin.opsudance.core.state.transitions.FadeInTransitionState;
|
||||||
import yugecin.opsudance.core.state.transitions.FadeOutTransitionState;
|
import yugecin.opsudance.core.state.transitions.FadeOutTransitionState;
|
||||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||||
|
import yugecin.opsudance.options.Configuration;
|
||||||
|
import yugecin.opsudance.options.OptionsService;
|
||||||
|
import yugecin.opsudance.render.GameObjectRenderer;
|
||||||
|
import yugecin.opsudance.skinning.SkinService;
|
||||||
|
|
||||||
public class OpsuDanceInjector extends Injector {
|
public class OpsuDanceInjector extends Injector {
|
||||||
|
|
||||||
protected void configure() {
|
protected void configure() {
|
||||||
|
bind(Configuration.class).asEagerSingleton();
|
||||||
|
|
||||||
|
bind(OptionsService.class).asLazySingleton();
|
||||||
|
bind(ReplayImporter.class).asLazySingleton();
|
||||||
|
bind(OszUnpacker.class).asLazySingleton();
|
||||||
|
bind(BeatmapParser.class).asLazySingleton();
|
||||||
|
bind(Updater.class).asLazySingleton();
|
||||||
|
bind(SkinService.class).asEagerSingleton();
|
||||||
|
|
||||||
bind(PreStartupInitializer.class).asEagerSingleton();
|
bind(PreStartupInitializer.class).asEagerSingleton();
|
||||||
bind(DisplayContainer.class).asEagerSingleton();
|
bind(DisplayContainer.class).asEagerSingleton();
|
||||||
|
|
||||||
|
@ -44,6 +61,8 @@ public class OpsuDanceInjector extends Injector {
|
||||||
bind(FadeInTransitionState.class).asEagerSingleton();
|
bind(FadeInTransitionState.class).asEagerSingleton();
|
||||||
bind(FadeOutTransitionState.class).asEagerSingleton();
|
bind(FadeOutTransitionState.class).asEagerSingleton();
|
||||||
|
|
||||||
|
bind(GameObjectRenderer.class).asEagerSingleton();
|
||||||
|
|
||||||
bind(Splash.class).asEagerSingleton();
|
bind(Splash.class).asEagerSingleton();
|
||||||
bind(MainMenu.class).asEagerSingleton();
|
bind(MainMenu.class).asEagerSingleton();
|
||||||
bind(ButtonMenu.class).asEagerSingleton();
|
bind(ButtonMenu.class).asEagerSingleton();
|
||||||
|
|
|
@ -17,8 +17,6 @@
|
||||||
*/
|
*/
|
||||||
package yugecin.opsudance.core.state;
|
package yugecin.opsudance.core.state;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.Utils;
|
|
||||||
import itdelatrisu.opsu.states.Game;
|
import itdelatrisu.opsu.states.Game;
|
||||||
import itdelatrisu.opsu.ui.UI;
|
import itdelatrisu.opsu.ui.UI;
|
||||||
import org.newdawn.slick.Graphics;
|
import org.newdawn.slick.Graphics;
|
||||||
|
@ -27,15 +25,26 @@ import yugecin.opsudance.core.DisplayContainer;
|
||||||
import yugecin.opsudance.core.events.EventBus;
|
import yugecin.opsudance.core.events.EventBus;
|
||||||
import yugecin.opsudance.core.events.EventListener;
|
import yugecin.opsudance.core.events.EventListener;
|
||||||
import yugecin.opsudance.core.inject.Inject;
|
import yugecin.opsudance.core.inject.Inject;
|
||||||
|
import yugecin.opsudance.events.BarNotificationEvent;
|
||||||
import yugecin.opsudance.events.ResolutionOrSkinChangedEvent;
|
import yugecin.opsudance.events.ResolutionOrSkinChangedEvent;
|
||||||
|
import yugecin.opsudance.options.Configuration;
|
||||||
|
import yugecin.opsudance.skinning.SkinService;
|
||||||
|
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
|
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
public abstract class BaseOpsuState implements OpsuState, EventListener<ResolutionOrSkinChangedEvent> {
|
public abstract class BaseOpsuState implements OpsuState, EventListener<ResolutionOrSkinChangedEvent> {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
protected DisplayContainer displayContainer;
|
protected DisplayContainer displayContainer;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
protected Configuration config;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
protected SkinService skinService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* state is dirty when resolution or skin changed but hasn't rendered yet
|
* state is dirty when resolution or skin changed but hasn't rendered yet
|
||||||
*/
|
*/
|
||||||
|
@ -97,20 +106,21 @@ public abstract class BaseOpsuState implements OpsuState, EventListener<Resoluti
|
||||||
@Override
|
@Override
|
||||||
public boolean keyReleased(int key, char c) {
|
public boolean keyReleased(int key, char c) {
|
||||||
if (key == Input.KEY_F7) {
|
if (key == Input.KEY_F7) {
|
||||||
Options.setNextFPS(displayContainer);
|
OPTION_TARGET_FPS.clickListItem((targetFPSIndex + 1) % targetFPS.length);
|
||||||
|
EventBus.post(new BarNotificationEvent(String.format("Frame limiter: %s", OPTION_TARGET_FPS.getValueString())));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (key == Input.KEY_F10) {
|
if (key == Input.KEY_F10) {
|
||||||
Options.toggleMouseDisabled();
|
OPTION_DISABLE_MOUSE_BUTTONS.toggle();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (key == Input.KEY_F12) {
|
if (key == Input.KEY_F12) {
|
||||||
Utils.takeScreenShot();
|
config.takeScreenShot();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
Input input = displayContainer.input;
|
Input input = displayContainer.input;
|
||||||
if (key == Input.KEY_S && input.isKeyDown(Input.KEY_LMENU) && input.isKeyDown(Input.KEY_LSHIFT) &&input.isKeyDown(Input.KEY_LCONTROL) && !displayContainer.isInState(Game.class)) {
|
if (key == Input.KEY_S && input.isKeyDown(Input.KEY_LMENU) && input.isKeyDown(Input.KEY_LSHIFT) &&input.isKeyDown(Input.KEY_LCONTROL) && !displayContainer.isInState(Game.class)) {
|
||||||
Options.reloadSkin();
|
skinService.reloadSkin();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
*/
|
*/
|
||||||
package yugecin.opsudance.core.state.specialstates;
|
package yugecin.opsudance.core.state.specialstates;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.ui.Fonts;
|
import itdelatrisu.opsu.ui.Fonts;
|
||||||
import org.newdawn.slick.Color;
|
import org.newdawn.slick.Color;
|
||||||
import org.newdawn.slick.Graphics;
|
import org.newdawn.slick.Graphics;
|
||||||
|
@ -27,6 +26,8 @@ import yugecin.opsudance.core.events.EventListener;
|
||||||
import yugecin.opsudance.events.ResolutionOrSkinChangedEvent;
|
import yugecin.opsudance.events.ResolutionOrSkinChangedEvent;
|
||||||
import yugecin.opsudance.utils.FPSMeter;
|
import yugecin.opsudance.utils.FPSMeter;
|
||||||
|
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
public class FpsRenderState implements EventListener<ResolutionOrSkinChangedEvent> {
|
public class FpsRenderState implements EventListener<ResolutionOrSkinChangedEvent> {
|
||||||
|
|
||||||
private final static Color GREEN = new Color(171, 218, 25);
|
private final static Color GREEN = new Color(171, 218, 25);
|
||||||
|
@ -54,17 +55,17 @@ public class FpsRenderState implements EventListener<ResolutionOrSkinChangedEven
|
||||||
|
|
||||||
public void render(Graphics g) {
|
public void render(Graphics g) {
|
||||||
fpsMeter.update(displayContainer.renderDelta);
|
fpsMeter.update(displayContainer.renderDelta);
|
||||||
if (!Options.isFPSCounterEnabled()) {
|
if (!OPTION_SHOW_FPS.state) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int x = this.x;
|
int x = this.x;
|
||||||
int fpsDeviation = displayContainer.delta % displayContainer.targetRenderInterval;
|
int fpsDeviation = displayContainer.delta % displayContainer.targetRenderInterval;
|
||||||
x = drawText(g, getColor((int) (Options.getTargetFPS() * 0.9f) - fpsDeviation, fpsMeter.getValue()), getText(fpsMeter.getValue(), "fps"), x, this.y);
|
x = drawText(g, getColor((int) (targetFPS[targetFPSIndex] * 0.9f) - fpsDeviation, fpsMeter.getValue()), getText(fpsMeter.getValue(), "fps"), x, this.y);
|
||||||
drawText(g, getColor((int) (Options.getTargetUPS() * 0.9f), upsMeter.getValue()), getText(upsMeter.getValue(), "ups"), x, this.y);
|
drawText(g, getColor((int) (OPTION_TARGET_UPS.val * 0.9f), upsMeter.getValue()), getText(upsMeter.getValue(), "ups"), x, this.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getText(int value, String unit) {
|
private String getText(int value, String unit) {
|
||||||
if (Options.useDeltasForFPSCounter()) {
|
if (OPTION_USE_FPS_DELTAS.state) {
|
||||||
return String.format("%.2fms", 1000f / value);
|
return String.format("%.2fms", 1000f / value);
|
||||||
}
|
}
|
||||||
return value + " " + unit;
|
return value + " " + unit;
|
||||||
|
|
|
@ -19,4 +19,14 @@ package yugecin.opsudance.events;
|
||||||
|
|
||||||
public class ResolutionOrSkinChangedEvent {
|
public class ResolutionOrSkinChangedEvent {
|
||||||
|
|
||||||
|
public final String skin;
|
||||||
|
public final int width;
|
||||||
|
public final int height;
|
||||||
|
|
||||||
|
public ResolutionOrSkinChangedEvent(String skin, int width, int height) {
|
||||||
|
this.skin = skin;
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,9 +17,9 @@
|
||||||
*/
|
*/
|
||||||
package yugecin.opsudance.movers;
|
package yugecin.opsudance.movers;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.Utils;
|
import itdelatrisu.opsu.Utils;
|
||||||
import itdelatrisu.opsu.objects.GameObject;
|
import itdelatrisu.opsu.objects.GameObject;
|
||||||
|
import yugecin.opsudance.options.Options;
|
||||||
|
|
||||||
public class CircleMover extends Mover {
|
public class CircleMover extends Mover {
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
*/
|
*/
|
||||||
package yugecin.opsudance.movers;
|
package yugecin.opsudance.movers;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.Utils;
|
import itdelatrisu.opsu.Utils;
|
||||||
import itdelatrisu.opsu.objects.GameObject;
|
import itdelatrisu.opsu.objects.GameObject;
|
||||||
import itdelatrisu.opsu.objects.Slider;
|
import itdelatrisu.opsu.objects.Slider;
|
||||||
|
@ -25,6 +24,8 @@ import itdelatrisu.opsu.objects.curves.Vec2f;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
public class CubicBezierMover extends Mover {
|
public class CubicBezierMover extends Mover {
|
||||||
|
|
||||||
private static Point p2 = new Point(0, 0);
|
private static Point p2 = new Point(0, 0);
|
||||||
|
@ -41,7 +42,7 @@ public class CubicBezierMover extends Mover {
|
||||||
double ang = s.getCurve().getStartAngle() * Math.PI / 180d + Math.PI;
|
double ang = s.getCurve().getStartAngle() * Math.PI / 180d + Math.PI;
|
||||||
Vec2f nextpos = s.getPointAt(s.getTime() + 10);
|
Vec2f nextpos = s.getPointAt(s.getTime() + 10);
|
||||||
double dist = Utils.distance(end.start.x, end.start.y, nextpos.x, nextpos.y);
|
double dist = Utils.distance(end.start.x, end.start.y, nextpos.x, nextpos.y);
|
||||||
double speed = dist * Options.getQuadBezAggressiveness() * Options.getQuadBezSliderEntryAggressiveness() / 10;
|
double speed = dist * OPTION_DANCE_QUAD_BEZ_AGGRESSIVENESS.val * OPTION_DANCE_QUAD_BEZ_CUBIC_AGGRESSIVENESS_FACTOR.val / 10;
|
||||||
p2.x = (int) (end.start.x + Math.cos(ang) * speed);
|
p2.x = (int) (end.start.x + Math.cos(ang) * speed);
|
||||||
p2.y = (int) (end.start.y + Math.sin(ang) * speed);
|
p2.y = (int) (end.start.y + Math.sin(ang) * speed);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,11 +17,13 @@
|
||||||
*/
|
*/
|
||||||
package yugecin.opsudance.movers;
|
package yugecin.opsudance.movers;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.objects.GameObject;
|
import itdelatrisu.opsu.objects.GameObject;
|
||||||
|
import yugecin.opsudance.options.Options;
|
||||||
|
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
public class ExgonMover extends Mover {
|
public class ExgonMover extends Mover {
|
||||||
|
|
||||||
private double[] pos;
|
private double[] pos;
|
||||||
|
@ -30,15 +32,15 @@ public class ExgonMover extends Mover {
|
||||||
|
|
||||||
public ExgonMover(GameObject start, GameObject end, int dir) {
|
public ExgonMover(GameObject start, GameObject end, int dir) {
|
||||||
super(start, end, dir);
|
super(start, end, dir);
|
||||||
nextTime = start.getEndTime() + Options.getExgonDelay();
|
nextTime = start.getEndTime() + OPTION_DANCE_EXGON_DELAY.val;
|
||||||
pos = new double[] { start.end.x, start.end.y };
|
pos = new double[] { start.end.x, start.end.y };
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double[] getPointAt(int time) {
|
public double[] getPointAt(int time) {
|
||||||
if (time > nextTime) {
|
if (time > nextTime) {
|
||||||
nextTime = time + Options.getExgonDelay();
|
nextTime = time + OPTION_DANCE_EXGON_DELAY.val;
|
||||||
if (time > getEnd().getEndTime() - Options.getExgonDelay()) {
|
if (time > getEnd().getEndTime() - OPTION_DANCE_EXGON_DELAY.val) {
|
||||||
pos[0] = endX;
|
pos[0] = endX;
|
||||||
pos[1] = endY;
|
pos[1] = endY;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -17,12 +17,13 @@
|
||||||
*/
|
*/
|
||||||
package yugecin.opsudance.movers;
|
package yugecin.opsudance.movers;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.Utils;
|
import itdelatrisu.opsu.Utils;
|
||||||
import itdelatrisu.opsu.objects.GameObject;
|
import itdelatrisu.opsu.objects.GameObject;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
public class QuadraticBezierMover extends Mover {
|
public class QuadraticBezierMover extends Mover {
|
||||||
|
|
||||||
public static Point p;
|
public static Point p;
|
||||||
|
@ -34,7 +35,7 @@ public class QuadraticBezierMover extends Mover {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setPrevspeed(double distance, int timedelta) {
|
public static void setPrevspeed(double distance, int timedelta) {
|
||||||
prevspeed = distance * Options.getQuadBezAggressiveness() * Options.getQuadBezSliderAggressiveness() / timedelta;
|
prevspeed = distance * OPTION_DANCE_QUAD_BEZ_AGGRESSIVENESS.val * OPTION_DANCE_QUAD_BEZ_SLIDER_AGGRESSIVENESS_FACTOR.val / timedelta;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static double getPrevspeed() {
|
public static double getPrevspeed() {
|
||||||
|
@ -53,7 +54,7 @@ public class QuadraticBezierMover extends Mover {
|
||||||
double dist = Utils.distance(startX, startY, endX, endY);
|
double dist = Utils.distance(startX, startY, endX, endY);
|
||||||
p.x = (int) (startX + Math.cos(startAngle) * prevspeed);
|
p.x = (int) (startX + Math.cos(startAngle) * prevspeed);
|
||||||
p.y = (int) (startY + Math.sin(startAngle) * prevspeed);
|
p.y = (int) (startY + Math.sin(startAngle) * prevspeed);
|
||||||
prevspeed = (dist / totalTime) * Options.getQuadBezAggressiveness();
|
prevspeed = (dist / totalTime) * OPTION_DANCE_QUAD_BEZ_AGGRESSIVENESS.val;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -17,13 +17,15 @@
|
||||||
*/
|
*/
|
||||||
package yugecin.opsudance.movers.factories;
|
package yugecin.opsudance.movers.factories;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.Utils;
|
import itdelatrisu.opsu.Utils;
|
||||||
import itdelatrisu.opsu.beatmap.HitObject;
|
import itdelatrisu.opsu.beatmap.HitObject;
|
||||||
import itdelatrisu.opsu.objects.Circle;
|
|
||||||
import itdelatrisu.opsu.objects.GameObject;
|
import itdelatrisu.opsu.objects.GameObject;
|
||||||
import yugecin.opsudance.Pippi;
|
import yugecin.opsudance.Pippi;
|
||||||
import yugecin.opsudance.movers.*;
|
import yugecin.opsudance.movers.*;
|
||||||
|
import yugecin.opsudance.options.Options;
|
||||||
|
import yugecin.opsudance.render.GameObjectRenderer;
|
||||||
|
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
public class AutoMoverFactory implements MoverFactory {
|
public class AutoMoverFactory implements MoverFactory {
|
||||||
|
|
||||||
|
@ -42,8 +44,8 @@ public class AutoMoverFactory implements MoverFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
// stacked: circles if not too quick
|
// stacked: circles if not too quick
|
||||||
int circle_stream = Options.isCircleStreams() ? 58: 85;
|
int circle_stream = OPTION_DANCE_CIRCLE_STREAMS.state ? 58: 85;
|
||||||
if (distance < Circle.diameter && ((dt > circle_stream && !Options.isOnlyCircleStacks()) || distance < HitObject.getStackOffset() * 5.2f)) { // TODO get the correct multiplier for stackoffsets
|
if (distance < GameObjectRenderer.instance.getCircleDiameter() && ((dt > circle_stream && !OPTION_DANCE_ONLY_CIRCLE_STACKS.state) || distance < HitObject.getStackOffset() * 5.2f)) { // TODO get the correct multiplier for stackoffsets
|
||||||
return new CircleMover(start, end, dir);
|
return new CircleMover(start, end, dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,16 +95,14 @@ public class AutoMoverFactory implements MoverFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("SimplifiableIfStatement")
|
@SuppressWarnings("SimplifiableIfStatement")
|
||||||
protected boolean inbounds(Mover m )
|
protected boolean inbounds(Mover m ) {
|
||||||
{
|
|
||||||
this.m = m;
|
this.m = m;
|
||||||
if (!checkBounds(m.getPointAt((int) (starttime + (endtime - starttime) * 0.3)))) return false;
|
if (!checkBounds(m.getPointAt((int) (starttime + (endtime - starttime) * 0.3)))) return false;
|
||||||
if (!checkBounds(m.getPointAt((int) (starttime + (endtime - starttime) * 0.7)))) return false;
|
if (!checkBounds(m.getPointAt((int) (starttime + (endtime - starttime) * 0.7)))) return false;
|
||||||
return checkBounds(m.getPointAt((int) (starttime + (endtime - starttime) * 0.5)));
|
return checkBounds(m.getPointAt((int) (starttime + (endtime - starttime) * 0.5)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkBounds( double[] pos )
|
private boolean checkBounds( double[] pos ) {
|
||||||
{
|
|
||||||
return 0 < pos[0] && pos[0] < Options.width - Options.width / 8 && 0 < pos[1] && pos[1] < Options.height - Options.height / 8;
|
return 0 < pos[0] && pos[0] < Options.width - Options.width / 8 && 0 < pos[1] && pos[1] < Options.height - Options.height / 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,17 +17,18 @@
|
||||||
*/
|
*/
|
||||||
package yugecin.opsudance.movers.factories;
|
package yugecin.opsudance.movers.factories;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.objects.GameObject;
|
import itdelatrisu.opsu.objects.GameObject;
|
||||||
import yugecin.opsudance.movers.CubicBezierMover;
|
import yugecin.opsudance.movers.CubicBezierMover;
|
||||||
import yugecin.opsudance.movers.Mover;
|
import yugecin.opsudance.movers.Mover;
|
||||||
import yugecin.opsudance.movers.QuadraticBezierMover;
|
import yugecin.opsudance.movers.QuadraticBezierMover;
|
||||||
|
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
public class QuadraticBezierMoverFactory implements MoverFactory {
|
public class QuadraticBezierMoverFactory implements MoverFactory {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mover create(GameObject start, GameObject end, int dir) {
|
public Mover create(GameObject start, GameObject end, int dir) {
|
||||||
if (Options.isQuadBezCubicEnabled() && end.isSlider()) {
|
if (OPTION_DANCE_QUAD_BEZ_USE_CUBIC_ON_SLIDERS.state && end.isSlider()) {
|
||||||
return new CubicBezierMover(start, end, dir);
|
return new CubicBezierMover(start, end, dir);
|
||||||
}
|
}
|
||||||
return new QuadraticBezierMover(start, end, dir);
|
return new QuadraticBezierMover(start, end, dir);
|
||||||
|
|
|
@ -20,12 +20,36 @@ package yugecin.opsudance.objects.curves;
|
||||||
import itdelatrisu.opsu.beatmap.HitObject;
|
import itdelatrisu.opsu.beatmap.HitObject;
|
||||||
import itdelatrisu.opsu.objects.curves.Curve;
|
import itdelatrisu.opsu.objects.curves.Curve;
|
||||||
import itdelatrisu.opsu.objects.curves.Vec2f;
|
import itdelatrisu.opsu.objects.curves.Vec2f;
|
||||||
|
import itdelatrisu.opsu.render.CurveRenderState;
|
||||||
|
import org.newdawn.slick.Color;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class FakeCombinedCurve extends Curve {
|
public class FakeCombinedCurve extends Curve {
|
||||||
|
|
||||||
|
private List<Integer> pointsToRender;
|
||||||
|
|
||||||
public FakeCombinedCurve(Vec2f[] points) {
|
public FakeCombinedCurve(Vec2f[] points) {
|
||||||
super(new HitObject(0, 0, 0), false);
|
super(new HitObject(0, 0, 0), false);
|
||||||
this.curve = points;
|
this.curve = points;
|
||||||
|
pointsToRender = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initForFrame() {
|
||||||
|
pointsToRender.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addRange(int from, int to) {
|
||||||
|
pointsToRender.add(from);
|
||||||
|
pointsToRender.add(to);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw(Color color) {
|
||||||
|
if (renderState == null)
|
||||||
|
renderState = new CurveRenderState(hitObject, curve, true);
|
||||||
|
renderState.draw(color, borderColor, pointsToRender);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
304
src/yugecin/opsudance/options/Configuration.java
Normal file
304
src/yugecin/opsudance/options/Configuration.java
Normal file
|
@ -0,0 +1,304 @@
|
||||||
|
/*
|
||||||
|
* opsu!dance - fork of opsu! with cursordance auto
|
||||||
|
* Copyright (C) 2017 yugecin
|
||||||
|
*
|
||||||
|
* opsu!dance is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* opsu!dance is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package yugecin.opsudance.options;
|
||||||
|
|
||||||
|
import com.sun.jna.platform.win32.Advapi32Util;
|
||||||
|
import com.sun.jna.platform.win32.Win32Exception;
|
||||||
|
import com.sun.jna.platform.win32.WinReg;
|
||||||
|
import itdelatrisu.opsu.Utils;
|
||||||
|
import itdelatrisu.opsu.audio.SoundController;
|
||||||
|
import itdelatrisu.opsu.audio.SoundEffect;
|
||||||
|
import itdelatrisu.opsu.beatmap.Beatmap;
|
||||||
|
import itdelatrisu.opsu.beatmap.TimingPoint;
|
||||||
|
import org.lwjgl.BufferUtils;
|
||||||
|
import org.lwjgl.opengl.Display;
|
||||||
|
import org.lwjgl.opengl.GL11;
|
||||||
|
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||||
|
import yugecin.opsudance.core.events.EventBus;
|
||||||
|
import yugecin.opsudance.core.inject.Inject;
|
||||||
|
import yugecin.opsudance.events.BubbleNotificationEvent;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.jar.Attributes;
|
||||||
|
import java.util.jar.JarFile;
|
||||||
|
import java.util.jar.Manifest;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
|
public class Configuration {
|
||||||
|
|
||||||
|
public final boolean USE_XDG;
|
||||||
|
public final File CONFIG_DIR;
|
||||||
|
public final File DATA_DIR;
|
||||||
|
public final File CACHE_DIR;
|
||||||
|
public final File BEATMAP_DIR;
|
||||||
|
public final File SKIN_ROOT_DIR;
|
||||||
|
public final File BEATMAP_DB;
|
||||||
|
public final File SCORE_DB;
|
||||||
|
public final File NATIVE_DIR;
|
||||||
|
public final File TEMP_DIR;
|
||||||
|
|
||||||
|
public final File LOG_FILE;
|
||||||
|
public final File OPTIONS_FILE;
|
||||||
|
|
||||||
|
public final String FONT_NAME;
|
||||||
|
public final String VERSION_FILE;
|
||||||
|
public final URI REPOSITORY_URI;
|
||||||
|
public final URI DANCE_REPOSITORY_URI;
|
||||||
|
public final String ISSUES_URL;
|
||||||
|
public final String VERSION_REMOTE;
|
||||||
|
|
||||||
|
public final File osuInstallationDirectory;
|
||||||
|
|
||||||
|
public final Beatmap themeBeatmap;
|
||||||
|
|
||||||
|
public File beatmapDir;
|
||||||
|
public File oszDir;
|
||||||
|
public File screenshotDir;
|
||||||
|
public File replayDir;
|
||||||
|
public File replayImportDir;
|
||||||
|
public File skinRootDir;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public Configuration() {
|
||||||
|
USE_XDG = areXDGDirectoriesEnabled();
|
||||||
|
|
||||||
|
CONFIG_DIR = getXDGBaseDir("XDG_CONFIG_HOME", ".config");
|
||||||
|
DATA_DIR = getXDGBaseDir("XDG_DATA_HOME", ".local/share");
|
||||||
|
CACHE_DIR = getXDGBaseDir("XDG_CACHE_HOME", ".cache");
|
||||||
|
|
||||||
|
BEATMAP_DIR = new File(DATA_DIR, "Songs/");
|
||||||
|
SKIN_ROOT_DIR = new File(DATA_DIR, "Skins/");
|
||||||
|
BEATMAP_DB = new File(DATA_DIR, ".opsu.db");
|
||||||
|
SCORE_DB = new File(DATA_DIR, ".opsu_scores.db");
|
||||||
|
NATIVE_DIR = new File(CACHE_DIR, "Natives/");
|
||||||
|
TEMP_DIR = new File(CACHE_DIR, "Temp/");
|
||||||
|
|
||||||
|
LOG_FILE = new File(CONFIG_DIR, ".opsu.log");
|
||||||
|
OPTIONS_FILE = new File(CONFIG_DIR, ".opsu.cfg");
|
||||||
|
|
||||||
|
FONT_NAME = "DroidSansFallback.ttf";
|
||||||
|
VERSION_FILE = "version";
|
||||||
|
REPOSITORY_URI = URI.create("https://github.com/itdelatrisu/opsu");
|
||||||
|
DANCE_REPOSITORY_URI = URI.create("https://github.com/yugecin/opsu-dance");
|
||||||
|
ISSUES_URL = "https://github.com/yugecin/opsu-dance/issues/new?title=%s&body=%s";
|
||||||
|
VERSION_REMOTE = "https://raw.githubusercontent.com/yugecin/opsu-dance/master/version";
|
||||||
|
|
||||||
|
osuInstallationDirectory = loadOsuInstallationDirectory();
|
||||||
|
|
||||||
|
themeBeatmap = createThemeBeatmap();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Beatmap createThemeBeatmap() {
|
||||||
|
try {
|
||||||
|
String[] tokens = {"theme.mp3", "Rainbows", "Kevin MacLeod", "219350"};
|
||||||
|
Beatmap beatmap = new Beatmap(null);
|
||||||
|
beatmap.audioFilename = new File(tokens[0]);
|
||||||
|
beatmap.title = tokens[1];
|
||||||
|
beatmap.artist = tokens[2];
|
||||||
|
beatmap.endTime = Integer.parseInt(tokens[3]);
|
||||||
|
beatmap.timingPoints = new ArrayList<>(1);
|
||||||
|
beatmap.timingPoints.add(new TimingPoint("1080,545.454545454545,4,1,0,100,0,0"));
|
||||||
|
return beatmap;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private File loadOsuInstallationDirectory() {
|
||||||
|
if (!System.getProperty("os.name").startsWith("Win")) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final WinReg.HKEY rootKey = WinReg.HKEY_CLASSES_ROOT;
|
||||||
|
final String regKey = "osu\\DefaultIcon";
|
||||||
|
final String regValue = null; // default value
|
||||||
|
final String regPathPattern = "\"(.+)\\\\[^\\/]+\\.exe\"";
|
||||||
|
|
||||||
|
String value;
|
||||||
|
try {
|
||||||
|
value = Advapi32Util.registryGetStringValue(rootKey, regKey, regValue);
|
||||||
|
} catch (Win32Exception ignored) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Pattern pattern = Pattern.compile(regPathPattern);
|
||||||
|
Matcher m = pattern.matcher(value);
|
||||||
|
if (!m.find()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
File dir = new File(m.group(1));
|
||||||
|
if (dir.isDirectory()) {
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadDirectories() {
|
||||||
|
replayImportDir = loadDirectory(replayImportDir, new File(DATA_DIR, "ReplayImport"), "replay import");
|
||||||
|
oszDir = loadDirectory(oszDir, new File(DATA_DIR, "SongPacks"), "song packs");
|
||||||
|
screenshotDir = loadDirectory(screenshotDir, new File(DATA_DIR, "Screenshots"), "screenshots");
|
||||||
|
replayDir = loadDirectory(replayDir, new File(DATA_DIR, "Replays"), "replays");
|
||||||
|
beatmapDir = loadOsuDirectory(beatmapDir, BEATMAP_DIR, "beatmap");
|
||||||
|
skinRootDir = loadOsuDirectory(skinRootDir, SKIN_ROOT_DIR, "skin root");
|
||||||
|
}
|
||||||
|
|
||||||
|
private File loadDirectory(File dir, File defaultDir, String kind) {
|
||||||
|
if (dir.exists() && dir.isDirectory()) {
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
if (!defaultDir.isDirectory() && !defaultDir.mkdir()) {
|
||||||
|
String msg = String.format("Failed to create %s directory at '%s'.", kind, defaultDir.getAbsolutePath());
|
||||||
|
EventBus.post(new BubbleNotificationEvent(msg, BubbleNotificationEvent.COMMONCOLOR_RED));
|
||||||
|
}
|
||||||
|
return defaultDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
private File loadOsuDirectory(File dir, File defaultDir, String kind) {
|
||||||
|
if (dir != null && dir.isDirectory()) {
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (osuInstallationDirectory != null) {
|
||||||
|
dir = new File(osuInstallationDirectory, defaultDir.getName());
|
||||||
|
if (dir.isDirectory()) {
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return loadDirectory(dir, defaultDir, kind);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean areXDGDirectoriesEnabled() {
|
||||||
|
JarFile jarFile = Utils.getJarFile();
|
||||||
|
if (jarFile == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Manifest manifest = jarFile.getManifest();
|
||||||
|
if (manifest == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Attributes attributes = manifest.getMainAttributes();
|
||||||
|
String value = attributes.getValue("Use-XDG");
|
||||||
|
return (value != null && value.equalsIgnoreCase("true"));
|
||||||
|
} catch (IOException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the directory based on the XDG base directory specification for
|
||||||
|
* Unix-like operating systems, only if the "XDG" flag is enabled.
|
||||||
|
* @param env the environment variable to check (XDG_*_*)
|
||||||
|
* @param fallback the fallback directory relative to ~home
|
||||||
|
* @return the XDG base directory, or the working directory if unavailable
|
||||||
|
*/
|
||||||
|
private File getXDGBaseDir(String env, String fallback) {
|
||||||
|
File workingdir;
|
||||||
|
if (Utils.isJarRunning()) {
|
||||||
|
workingdir = Utils.getRunningDirectory().getParentFile();
|
||||||
|
} else {
|
||||||
|
workingdir = Paths.get(".").toAbsolutePath().normalize().toFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!USE_XDG) {
|
||||||
|
return workingdir;
|
||||||
|
}
|
||||||
|
|
||||||
|
String OS = System.getProperty("os.name").toLowerCase();
|
||||||
|
if (OS.indexOf("nix") == -1 && OS.indexOf("nux") == -1 && OS.indexOf("aix") == -1){
|
||||||
|
return workingdir;
|
||||||
|
}
|
||||||
|
|
||||||
|
String rootPath = System.getenv(env);
|
||||||
|
if (rootPath == null) {
|
||||||
|
String home = System.getProperty("user.home");
|
||||||
|
if (home == null) {
|
||||||
|
return new File("./");
|
||||||
|
}
|
||||||
|
rootPath = String.format("%s/%s", home, fallback);
|
||||||
|
}
|
||||||
|
File dir = new File(rootPath, "opsu");
|
||||||
|
if (!dir.isDirectory() && !dir.mkdir()) {
|
||||||
|
ErrorHandler.error(String.format("Failed to create configuration folder at '%s/opsu'.", rootPath), new Exception("empty")).preventReport().show();
|
||||||
|
}
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author http://wiki.lwjgl.org/index.php?title=Taking_Screen_Shots
|
||||||
|
*/
|
||||||
|
public void takeScreenShot() {
|
||||||
|
// TODO: get a decent place for this
|
||||||
|
// create the screenshot directory
|
||||||
|
if (!screenshotDir.isDirectory() && !screenshotDir.mkdir()) {
|
||||||
|
EventBus.post(new BubbleNotificationEvent(String.format("Failed to create screenshot directory at '%s'.", screenshotDir.getAbsolutePath()), BubbleNotificationEvent.COMMONCOLOR_RED));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create file name
|
||||||
|
SimpleDateFormat date = new SimpleDateFormat("yyyyMMdd_HHmmss");
|
||||||
|
final String fileName = String.format("screenshot_%s.%s", date.format(new Date()), OPTION_SCREENSHOT_FORMAT.getValueString().toLowerCase());
|
||||||
|
final File file = new File(screenshotDir, fileName);
|
||||||
|
|
||||||
|
SoundController.playSound(SoundEffect.SHUTTER);
|
||||||
|
|
||||||
|
// copy the screen to file
|
||||||
|
final int width = Display.getWidth();
|
||||||
|
final int height = Display.getHeight();
|
||||||
|
final int bpp = 3; // assuming a 32-bit display with a byte each for red, green, blue, and alpha
|
||||||
|
final ByteBuffer buffer = BufferUtils.createByteBuffer(width * height * bpp);
|
||||||
|
GL11.glReadBuffer(GL11.GL_FRONT);
|
||||||
|
GL11.glPixelStorei(GL11.GL_PACK_ALIGNMENT, 1);
|
||||||
|
GL11.glReadPixels(0, 0, width, height, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, buffer);
|
||||||
|
new Thread() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
int i = (x + (width * y)) * bpp;
|
||||||
|
int r = buffer.get(i) & 0xFF;
|
||||||
|
int g = buffer.get(i + 1) & 0xFF;
|
||||||
|
int b = buffer.get(i + 2) & 0xFF;
|
||||||
|
image.setRGB(x, height - (y + 1), (0xFF << 24) | (r << 16) | (g << 8) | b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImageIO.write(image, OPTION_SCREENSHOT_FORMAT.getValueString().toLowerCase(), file);
|
||||||
|
EventBus.post(new BubbleNotificationEvent("Created " + fileName, BubbleNotificationEvent.COMMONCOLOR_PURPLE));
|
||||||
|
} catch (Exception e) {
|
||||||
|
ErrorHandler.error("Failed to take a screenshot.", e).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
40
src/yugecin/opsudance/options/GenericOption.java
Normal file
40
src/yugecin/opsudance/options/GenericOption.java
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* opsu!dance - fork of opsu! with cursordance auto
|
||||||
|
* Copyright (C) 2017 yugecin
|
||||||
|
*
|
||||||
|
* opsu!dance is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* opsu!dance is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package yugecin.opsudance.options;
|
||||||
|
|
||||||
|
public abstract class GenericOption extends Option {
|
||||||
|
|
||||||
|
public int intval;
|
||||||
|
public String strval;
|
||||||
|
public boolean boolval;
|
||||||
|
|
||||||
|
public GenericOption(String name, String configurationName, String description, int intval, String strval, boolean boolval) {
|
||||||
|
super(name, configurationName, description);
|
||||||
|
this.intval = intval;
|
||||||
|
this.strval = strval;
|
||||||
|
this.boolval = boolval;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public abstract String getValueString();
|
||||||
|
@Override
|
||||||
|
public abstract void read(String s);
|
||||||
|
@Override
|
||||||
|
public abstract String write();
|
||||||
|
|
||||||
|
}
|
33
src/yugecin/opsudance/options/ListOption.java
Normal file
33
src/yugecin/opsudance/options/ListOption.java
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* opsu!dance - fork of opsu! with cursordance auto
|
||||||
|
* Copyright (C) 2017 yugecin
|
||||||
|
*
|
||||||
|
* opsu!dance is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* opsu!dance is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package yugecin.opsudance.options;
|
||||||
|
|
||||||
|
public abstract class ListOption extends Option {
|
||||||
|
|
||||||
|
public ListOption(String name, String configurationName, String description) {
|
||||||
|
super(name, configurationName, description);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public abstract String write();
|
||||||
|
@Override
|
||||||
|
public abstract void read(String s);
|
||||||
|
public abstract Object[] getListItems();
|
||||||
|
public abstract void clickListItem(int index);
|
||||||
|
|
||||||
|
}
|
60
src/yugecin/opsudance/options/NumericOption.java
Normal file
60
src/yugecin/opsudance/options/NumericOption.java
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* opsu!dance - fork of opsu! with cursordance auto
|
||||||
|
* Copyright (C) 2017 yugecin
|
||||||
|
*
|
||||||
|
* opsu!dance is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* opsu!dance is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package yugecin.opsudance.options;
|
||||||
|
|
||||||
|
import itdelatrisu.opsu.Utils;
|
||||||
|
import yugecin.opsudance.core.events.EventBus;
|
||||||
|
import yugecin.opsudance.events.BubbleNotificationEvent;
|
||||||
|
|
||||||
|
public class NumericOption extends Option {
|
||||||
|
|
||||||
|
public final int min;
|
||||||
|
public final int max;
|
||||||
|
public int val;
|
||||||
|
|
||||||
|
public NumericOption(String name, String configurationName, String description, int val, int min, int max) {
|
||||||
|
super(name, configurationName, description);
|
||||||
|
this.min = min;
|
||||||
|
this.max = max;
|
||||||
|
this.val = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(int val) {
|
||||||
|
this.val = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getValueString() {
|
||||||
|
return String.format("%d%%", val);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String write() {
|
||||||
|
return Integer.toString(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(String s) {
|
||||||
|
try {
|
||||||
|
val = Utils.clamp(Integer.parseInt(s), min, max);
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
EventBus.post(new BubbleNotificationEvent("Failed to parse " + configurationName + " option", BubbleNotificationEvent.COMMONCOLOR_RED));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
102
src/yugecin/opsudance/options/Option.java
Normal file
102
src/yugecin/opsudance/options/Option.java
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
/*
|
||||||
|
* opsu!dance - fork of opsu! with cursordance auto
|
||||||
|
* Copyright (C) 2017 yugecin
|
||||||
|
*
|
||||||
|
* opsu!dance is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* opsu!dance is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package yugecin.opsudance.options;
|
||||||
|
|
||||||
|
import yugecin.opsudance.core.DisplayContainer;
|
||||||
|
import yugecin.opsudance.core.inject.InstanceContainer;
|
||||||
|
|
||||||
|
public class Option {
|
||||||
|
|
||||||
|
// keep a reference to the instancecontainer so that not every option instance needs to be injected
|
||||||
|
protected static InstanceContainer instanceContainer;
|
||||||
|
// caching some commonly used classes
|
||||||
|
protected static Configuration config;
|
||||||
|
protected static DisplayContainer displayContainer;
|
||||||
|
public static void setInstanceContainer(InstanceContainer instanceContainer) {
|
||||||
|
Option.instanceContainer = instanceContainer;
|
||||||
|
Option.config = instanceContainer.provide(Configuration.class);
|
||||||
|
Option.displayContainer = instanceContainer.provide(DisplayContainer.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final String name;
|
||||||
|
public final String configurationName;
|
||||||
|
public final String description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this option should not be shown in the optionsmenu because it does
|
||||||
|
* not match the search string.
|
||||||
|
*/
|
||||||
|
private boolean filtered;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for internal options (not displayed in-game).
|
||||||
|
*/
|
||||||
|
public Option(String configurationName) {
|
||||||
|
this(null, configurationName, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Option(String name, String configurationName, String description) {
|
||||||
|
this.name = name;
|
||||||
|
this.configurationName = configurationName;
|
||||||
|
this.description = description;
|
||||||
|
OptionsService.registerOption(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* should the option be shown
|
||||||
|
* @return true if the option should be shown
|
||||||
|
*/
|
||||||
|
public boolean showCondition() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValueString() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String write() {
|
||||||
|
return getValueString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void read(String s) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the filtered flag for this option based on the given searchString.
|
||||||
|
* @param searchString the searched string or null to reset the filtered flag
|
||||||
|
* @return true if this option does need to be filtered
|
||||||
|
*/
|
||||||
|
public boolean filter(String searchString) {
|
||||||
|
if (searchString == null || searchString.length() == 0) {
|
||||||
|
filtered = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
filtered = !name.toLowerCase().contains(searchString) && !description.toLowerCase().contains(searchString);
|
||||||
|
return filtered;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if this option should be filtered (= not shown) because it does not
|
||||||
|
* match the search string.
|
||||||
|
* @return true if the option shouldn't be shown.
|
||||||
|
*/
|
||||||
|
public boolean isFiltered() {
|
||||||
|
return filtered;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
239
src/yugecin/opsudance/options/OptionGroups.java
Normal file
239
src/yugecin/opsudance/options/OptionGroups.java
Normal file
|
@ -0,0 +1,239 @@
|
||||||
|
/*
|
||||||
|
* opsu! - an open-source osu! client
|
||||||
|
* Copyright (C) 2014, 2015 Jeffrey Han
|
||||||
|
*
|
||||||
|
* opsu! is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* opsu! is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with opsu!. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package yugecin.opsudance.options;
|
||||||
|
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
|
public class OptionGroups {
|
||||||
|
|
||||||
|
public static final OptionTab[] normalOptions = new OptionTab[] {
|
||||||
|
new OptionTab("GENERAL", null),
|
||||||
|
new OptionTab("GENERAL", new Option[]{
|
||||||
|
OPTION_DISABLE_UPDATER,
|
||||||
|
OPTION_ENABLE_WATCH_SERVICE
|
||||||
|
}),
|
||||||
|
new OptionTab("LANGUAGE", new Option[]{
|
||||||
|
OPTION_SHOW_UNICODE,
|
||||||
|
}),
|
||||||
|
new OptionTab("GRAPHICS", null),
|
||||||
|
new OptionTab("RENDERER", new Option[] {
|
||||||
|
OPTION_SCREEN_RESOLUTION,
|
||||||
|
OPTION_ALLOW_LARGER_RESOLUTIONS,
|
||||||
|
OPTION_FULLSCREEN,
|
||||||
|
OPTION_TARGET_UPS,
|
||||||
|
OPTION_TARGET_FPS,
|
||||||
|
OPTION_SHOW_FPS,
|
||||||
|
OPTION_USE_FPS_DELTAS,
|
||||||
|
OPTION_SCREENSHOT_FORMAT,
|
||||||
|
}),
|
||||||
|
new OptionTab("SLIDER OPTIONS", new Option[]{
|
||||||
|
OPTION_SNAKING_SLIDERS,
|
||||||
|
OPTION_FALLBACK_SLIDERS,
|
||||||
|
OPTION_SHRINKING_SLIDERS,
|
||||||
|
OPTION_MERGING_SLIDERS,
|
||||||
|
//OPTION_MERGING_SLIDERS_MIRROR_POOL,
|
||||||
|
OPTION_DRAW_SLIDER_ENDCIRCLES,
|
||||||
|
}),
|
||||||
|
new OptionTab("DANCING HITCIRCLES", new Option[] {
|
||||||
|
OPTION_DANCING_CIRCLES,
|
||||||
|
OPTION_DANCING_CIRCLES_MULTIPLIER,
|
||||||
|
}),
|
||||||
|
new OptionTab("SKIN", null),
|
||||||
|
new OptionTab("SKIN", new Option[]{
|
||||||
|
OPTION_SKIN,
|
||||||
|
OPTION_IGNORE_BEATMAP_SKINS,
|
||||||
|
OPTION_DYNAMIC_BACKGROUND,
|
||||||
|
OPTION_LOAD_HD_IMAGES,
|
||||||
|
OPTION_LOAD_VERBOSE,
|
||||||
|
OPTION_COLOR_MAIN_MENU_LOGO,
|
||||||
|
}),
|
||||||
|
new OptionTab("CURSOR", new Option[]{
|
||||||
|
OPTION_CURSOR_SIZE,
|
||||||
|
OPTION_NEW_CURSOR,
|
||||||
|
OPTION_DISABLE_CURSOR
|
||||||
|
// TODO use combo colour as tint for slider ball option
|
||||||
|
}),
|
||||||
|
new OptionTab("AUDIO", null),
|
||||||
|
new OptionTab("VOLUME", new Option[]{
|
||||||
|
OPTION_MASTER_VOLUME,
|
||||||
|
OPTION_MUSIC_VOLUME,
|
||||||
|
OPTION_EFFECT_VOLUME,
|
||||||
|
OPTION_HITSOUND_VOLUME,
|
||||||
|
OPTION_SAMPLE_VOLUME_OVERRIDE,
|
||||||
|
}),
|
||||||
|
new OptionTab("MISC", new Option[] {
|
||||||
|
OPTION_MUSIC_OFFSET,
|
||||||
|
OPTION_DISABLE_SOUNDS,
|
||||||
|
OPTION_ENABLE_THEME_SONG
|
||||||
|
}),
|
||||||
|
new OptionTab("GAMEPLAY", null),
|
||||||
|
new OptionTab("GENERAL", new Option[] {
|
||||||
|
OPTION_BACKGROUND_DIM,
|
||||||
|
OPTION_FORCE_DEFAULT_PLAYFIELD,
|
||||||
|
OPTION_SHOW_HIT_LIGHTING,
|
||||||
|
OPTION_SHOW_HIT_ANIMATIONS,
|
||||||
|
OPTION_SHOW_COMBO_BURSTS,
|
||||||
|
OPTION_SHOW_PERFECT_HIT,
|
||||||
|
OPTION_SHOW_FOLLOW_POINTS,
|
||||||
|
OPTION_SHOW_HIT_ERROR_BAR,
|
||||||
|
OPTION_MAP_START_DELAY,
|
||||||
|
OPTION_MAP_END_DELAY,
|
||||||
|
OPTION_EPILEPSY_WARNING,
|
||||||
|
}),
|
||||||
|
new OptionTab("INPUT", null),
|
||||||
|
new OptionTab("KEY MAPPING", new Option[]{
|
||||||
|
OPTION_KEY_LEFT,
|
||||||
|
OPTION_KEY_RIGHT,
|
||||||
|
}),
|
||||||
|
new OptionTab("MOUSE", new Option[] {
|
||||||
|
OPTION_DISABLE_MOUSE_WHEEL,
|
||||||
|
OPTION_DISABLE_MOUSE_BUTTONS,
|
||||||
|
}),
|
||||||
|
new OptionTab("CUSTOM", null),
|
||||||
|
new OptionTab("DIFFICULTY", new Option[]{
|
||||||
|
OPTION_FIXED_CS,
|
||||||
|
OPTION_FIXED_HP,
|
||||||
|
OPTION_FIXED_AR,
|
||||||
|
OPTION_FIXED_OD,
|
||||||
|
}),
|
||||||
|
new OptionTab("MISC", new Option[] {
|
||||||
|
OPTION_CHECKPOINT,
|
||||||
|
OPTION_REPLAY_SEEKING,
|
||||||
|
}),
|
||||||
|
new OptionTab("DANCE", null),
|
||||||
|
new OptionTab("MOVER", new Option[]{
|
||||||
|
OPTION_DANCE_MOVER,
|
||||||
|
OPTION_DANCE_EXGON_DELAY,
|
||||||
|
OPTION_DANCE_QUAD_BEZ_AGGRESSIVENESS,
|
||||||
|
OPTION_DANCE_QUAD_BEZ_SLIDER_AGGRESSIVENESS_FACTOR,
|
||||||
|
OPTION_DANCE_QUAD_BEZ_USE_CUBIC_ON_SLIDERS,
|
||||||
|
OPTION_DANCE_QUAD_BEZ_CUBIC_AGGRESSIVENESS_FACTOR,
|
||||||
|
OPTION_DANCE_MOVER_DIRECTION,
|
||||||
|
OPTION_DANCE_SLIDER_MOVER_TYPE,
|
||||||
|
}),
|
||||||
|
new OptionTab("SPINNER", new Option[]{
|
||||||
|
OPTION_DANCE_SPINNER,
|
||||||
|
OPTION_DANCE_SPINNER_DELAY,
|
||||||
|
}),
|
||||||
|
new OptionTab("SLIDER OPTIONS", new Option[]{
|
||||||
|
OPTION_DANCE_LAZY_SLIDERS,
|
||||||
|
OPTION_DANCE_CIRLCE_IN_SLOW_SLIDERS,
|
||||||
|
OPTION_DANCE_CIRLCE_IN_LAZY_SLIDERS,
|
||||||
|
}),
|
||||||
|
new OptionTab("CIRCLE MOVEMENTS", new Option[]{
|
||||||
|
OPTION_DANCE_CIRCLE_STREAMS,
|
||||||
|
OPTION_DANCE_ONLY_CIRCLE_STACKS,
|
||||||
|
}),
|
||||||
|
new OptionTab("MIRROR", new Option[] {
|
||||||
|
OPTION_DANCE_MIRROR,
|
||||||
|
}),
|
||||||
|
new OptionTab("ADVANCED DISPLAY", null),
|
||||||
|
new OptionTab("OBJECTS", new Option[]{
|
||||||
|
OPTION_DANCE_DRAW_APPROACH,
|
||||||
|
OPTION_DANCE_OBJECT_COLOR_OVERRIDE,
|
||||||
|
OPTION_DANCE_OBJECT_COLOR_OVERRIDE_MIRRORED,
|
||||||
|
OPTION_DANCE_RGB_OBJECT_INC,
|
||||||
|
OPTION_DANCE_HIDE_OBJECTS,
|
||||||
|
}),
|
||||||
|
new OptionTab("CURSOR", new Option[]{
|
||||||
|
OPTION_DANCE_CURSOR_COLOR_OVERRIDE,
|
||||||
|
OPTION_DANCE_CURSOR_MIRROR_COLOR_OVERRIDE,
|
||||||
|
OPTION_DANCE_CURSOR_ONLY_COLOR_TRAIL,
|
||||||
|
OPTION_DANCE_RGB_CURSOR_INC,
|
||||||
|
OPTION_DANCE_CURSOR_TRAIL_OVERRIDE,
|
||||||
|
}),
|
||||||
|
new OptionTab("MISC", new Option[] {
|
||||||
|
OPTION_DANCE_HIDE_UI,
|
||||||
|
OPTION_DANCE_REMOVE_BG,
|
||||||
|
OPTION_DANCE_ENABLE_SB,
|
||||||
|
}),
|
||||||
|
new OptionTab ("PIPPI", null),
|
||||||
|
new OptionTab ("GENERAL", new Option[]{
|
||||||
|
OPTION_PIPPI_ENABLE,
|
||||||
|
OPTION_PIPPI_RADIUS_PERCENT,
|
||||||
|
}),
|
||||||
|
new OptionTab ("ANGLE MULTIPLIERS", new Option[]{
|
||||||
|
OPTION_PIPPI_ANGLE_INC_MUL,
|
||||||
|
OPTION_PIPPI_ANGLE_INC_MUL_SLIDER,
|
||||||
|
}),
|
||||||
|
new OptionTab ("MISC", new Option[] {
|
||||||
|
OPTION_PIPPI_SLIDER_FOLLOW_EXPAND,
|
||||||
|
OPTION_PIPPI_PREVENT_WOBBLY_STREAMS,
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final OptionTab[] storyboardOptions = new OptionTab[] {
|
||||||
|
new OptionTab("Gameplay", new Option[] {
|
||||||
|
OPTION_BACKGROUND_DIM,
|
||||||
|
OPTION_DANCE_REMOVE_BG,
|
||||||
|
OPTION_SNAKING_SLIDERS,
|
||||||
|
OPTION_SHRINKING_SLIDERS,
|
||||||
|
OPTION_SHOW_HIT_LIGHTING,
|
||||||
|
OPTION_SHOW_HIT_ANIMATIONS,
|
||||||
|
OPTION_SHOW_COMBO_BURSTS,
|
||||||
|
OPTION_SHOW_PERFECT_HIT,
|
||||||
|
OPTION_SHOW_FOLLOW_POINTS,
|
||||||
|
}),
|
||||||
|
new OptionTab("Input", new Option[] {
|
||||||
|
OPTION_CURSOR_SIZE,
|
||||||
|
OPTION_NEW_CURSOR,
|
||||||
|
OPTION_DISABLE_CURSOR
|
||||||
|
}),
|
||||||
|
new OptionTab("Dance", new Option[] {
|
||||||
|
OPTION_DANCE_MOVER,
|
||||||
|
OPTION_DANCE_EXGON_DELAY,
|
||||||
|
OPTION_DANCE_QUAD_BEZ_AGGRESSIVENESS,
|
||||||
|
OPTION_DANCE_QUAD_BEZ_SLIDER_AGGRESSIVENESS_FACTOR,
|
||||||
|
OPTION_DANCE_QUAD_BEZ_USE_CUBIC_ON_SLIDERS,
|
||||||
|
OPTION_DANCE_QUAD_BEZ_CUBIC_AGGRESSIVENESS_FACTOR,
|
||||||
|
OPTION_DANCE_MOVER_DIRECTION,
|
||||||
|
OPTION_DANCE_SLIDER_MOVER_TYPE,
|
||||||
|
OPTION_DANCE_SPINNER,
|
||||||
|
OPTION_DANCE_SPINNER_DELAY,
|
||||||
|
OPTION_DANCE_LAZY_SLIDERS,
|
||||||
|
OPTION_DANCE_CIRCLE_STREAMS,
|
||||||
|
OPTION_DANCE_ONLY_CIRCLE_STACKS,
|
||||||
|
OPTION_DANCE_CIRLCE_IN_SLOW_SLIDERS,
|
||||||
|
OPTION_DANCE_CIRLCE_IN_LAZY_SLIDERS,
|
||||||
|
OPTION_DANCE_MIRROR,
|
||||||
|
}),
|
||||||
|
new OptionTab("Dance display", new Option[] {
|
||||||
|
OPTION_DANCE_DRAW_APPROACH,
|
||||||
|
OPTION_DANCE_OBJECT_COLOR_OVERRIDE,
|
||||||
|
OPTION_DANCE_OBJECT_COLOR_OVERRIDE_MIRRORED,
|
||||||
|
OPTION_DANCE_RGB_OBJECT_INC,
|
||||||
|
OPTION_DANCE_CURSOR_COLOR_OVERRIDE,
|
||||||
|
OPTION_DANCE_CURSOR_MIRROR_COLOR_OVERRIDE,
|
||||||
|
OPTION_DANCE_CURSOR_ONLY_COLOR_TRAIL,
|
||||||
|
OPTION_DANCE_RGB_CURSOR_INC,
|
||||||
|
OPTION_DANCE_CURSOR_TRAIL_OVERRIDE,
|
||||||
|
OPTION_DANCE_HIDE_OBJECTS,
|
||||||
|
OPTION_DANCE_HIDE_UI,
|
||||||
|
}),
|
||||||
|
new OptionTab ("Pippi", new Option[] {
|
||||||
|
OPTION_PIPPI_ENABLE,
|
||||||
|
OPTION_PIPPI_RADIUS_PERCENT,
|
||||||
|
OPTION_PIPPI_ANGLE_INC_MUL,
|
||||||
|
OPTION_PIPPI_ANGLE_INC_MUL_SLIDER,
|
||||||
|
OPTION_PIPPI_SLIDER_FOLLOW_EXPAND,
|
||||||
|
OPTION_PIPPI_PREVENT_WOBBLY_STREAMS,
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
31
src/yugecin/opsudance/options/OptionTab.java
Normal file
31
src/yugecin/opsudance/options/OptionTab.java
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* opsu!dance - fork of opsu! with cursordance auto
|
||||||
|
* Copyright (C) 2017 yugecin
|
||||||
|
*
|
||||||
|
* opsu!dance is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* opsu!dance is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package yugecin.opsudance.options;
|
||||||
|
|
||||||
|
public class OptionTab {
|
||||||
|
|
||||||
|
public final String name;
|
||||||
|
public final Option[] options;
|
||||||
|
public boolean filtered;
|
||||||
|
|
||||||
|
public OptionTab(String name, Option[] options) {
|
||||||
|
this.name = name;
|
||||||
|
this.options = options;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
978
src/yugecin/opsudance/options/Options.java
Normal file
978
src/yugecin/opsudance/options/Options.java
Normal file
|
@ -0,0 +1,978 @@
|
||||||
|
/*
|
||||||
|
* opsu!dance - fork of opsu! with cursordance auto
|
||||||
|
* Copyright (C) 2017 yugecin
|
||||||
|
*
|
||||||
|
* opsu!dance is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* opsu!dance is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package yugecin.opsudance.options;
|
||||||
|
|
||||||
|
import awlex.ospu.polymover.factory.PolyMoverFactory;
|
||||||
|
import itdelatrisu.opsu.GameImage;
|
||||||
|
import itdelatrisu.opsu.Utils;
|
||||||
|
import itdelatrisu.opsu.states.Game;
|
||||||
|
import itdelatrisu.opsu.ui.Fonts;
|
||||||
|
import org.lwjgl.input.Keyboard;
|
||||||
|
import org.newdawn.slick.Input;
|
||||||
|
import org.newdawn.slick.SlickException;
|
||||||
|
import org.newdawn.slick.openal.SoundStore;
|
||||||
|
import org.newdawn.slick.util.Log;
|
||||||
|
import yugecin.opsudance.*;
|
||||||
|
import yugecin.opsudance.core.events.EventBus;
|
||||||
|
import yugecin.opsudance.core.events.EventListener;
|
||||||
|
import yugecin.opsudance.events.BarNotificationEvent;
|
||||||
|
import yugecin.opsudance.events.ResolutionOrSkinChangedEvent;
|
||||||
|
import yugecin.opsudance.movers.factories.ExgonMoverFactory;
|
||||||
|
import yugecin.opsudance.movers.factories.QuadraticBezierMoverFactory;
|
||||||
|
import yugecin.opsudance.movers.slidermovers.DefaultSliderMoverController;
|
||||||
|
import yugecin.opsudance.skinning.SkinService;
|
||||||
|
import yugecin.opsudance.utils.CachedVariable;
|
||||||
|
import yugecin.opsudance.utils.CachedVariable.Getter;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author itdelatrisu (https://github.com/itdelatrisu) most functions are copied from itdelatrisu.opsu.Options.java
|
||||||
|
*/
|
||||||
|
public class Options {
|
||||||
|
|
||||||
|
// TODO remove this?
|
||||||
|
public static int width;
|
||||||
|
public static int height;
|
||||||
|
|
||||||
|
static {
|
||||||
|
EventBus.subscribe(ResolutionOrSkinChangedEvent.class, new EventListener<ResolutionOrSkinChangedEvent>() {
|
||||||
|
@Override
|
||||||
|
public void onEvent(ResolutionOrSkinChangedEvent event) {
|
||||||
|
if (event.width > 0) {
|
||||||
|
width = event.width;
|
||||||
|
height = event.height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// internal options (not displayed in-game)
|
||||||
|
public static final Option OPTION_BEATMAP_DIRECTORY = new Option("BeatmapDirectory") {
|
||||||
|
@Override
|
||||||
|
public String write() {
|
||||||
|
return config.BEATMAP_DIR.getAbsolutePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(String s) {
|
||||||
|
config.beatmapDir = new File(s);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final Option OPTION_OSZ_DIRECTORY = new Option("OSZDirectory") {
|
||||||
|
@Override
|
||||||
|
public String write() {
|
||||||
|
return config.oszDir.getAbsolutePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(String s) {
|
||||||
|
config.oszDir = new File(s);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final Option OPTION_SCREENSHOT_DIRECTORY = new Option("ScreenshotDirectory") {
|
||||||
|
@Override
|
||||||
|
public String write() {
|
||||||
|
return config.screenshotDir.getAbsolutePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(String s) {
|
||||||
|
config.screenshotDir = new File(s);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final Option OPTION_REPLAY_DIRECTORY = new Option("ReplayDirectory") {
|
||||||
|
@Override
|
||||||
|
public String write() {
|
||||||
|
return config.replayDir.getAbsolutePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(String s) {
|
||||||
|
config.replayDir = new File(s);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final Option OPTION_REPLAY_IMPORT_DIRECTORY = new Option("ReplayImportDirectory") {
|
||||||
|
@Override
|
||||||
|
public String write() {
|
||||||
|
return config.replayImportDir.getAbsolutePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(String s) {
|
||||||
|
config.replayImportDir = new File(s);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final Option OPTION_SKIN_DIRECTORY = new Option("SkinDirectory") {
|
||||||
|
@Override
|
||||||
|
public String write() {
|
||||||
|
return config.skinRootDir.getAbsolutePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(String s) {
|
||||||
|
config.skinRootDir = new File(s);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final NumericOption OPTION_PORT = new NumericOption("-", "Port", "-", 49250, 1024, 65535) {
|
||||||
|
@Override
|
||||||
|
public void read (String s){
|
||||||
|
super.read(s);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final ToggleOption OPTION_NOSINGLEINSTANCE = new ToggleOption("-", "NoSingleInstance", "-", false);
|
||||||
|
|
||||||
|
// in-game options
|
||||||
|
public static final Option OPTION_SCREEN_RESOLUTION = new ListOption("Screen Resolution", "ScreenResolution", "Change the size of the game.") {
|
||||||
|
private final String[] resolutions = {
|
||||||
|
null,
|
||||||
|
"800x600",
|
||||||
|
"1024x600",
|
||||||
|
"1024x768",
|
||||||
|
"1280x720",
|
||||||
|
"1280x800",
|
||||||
|
"1280x960",
|
||||||
|
"1280x1024",
|
||||||
|
"1366x768",
|
||||||
|
"1440x900",
|
||||||
|
"1600x900",
|
||||||
|
"1600x1200",
|
||||||
|
"1680x1050",
|
||||||
|
"1920x1080",
|
||||||
|
"1920x1200",
|
||||||
|
"2560x1440",
|
||||||
|
"2560x1600",
|
||||||
|
"3840x2160"
|
||||||
|
};
|
||||||
|
|
||||||
|
private int idx;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
return resolutions[idx]; // do not change (see DisplayContainer#setup)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object[] getListItems () {
|
||||||
|
return resolutions;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clickListItem(int index){
|
||||||
|
idx = index;
|
||||||
|
displayContainer.updateDisplayMode(resolutions[idx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read (String s){
|
||||||
|
resolutions[0] = displayContainer.nativeDisplayMode.getWidth() + "x" + displayContainer.nativeDisplayMode.getHeight();
|
||||||
|
try {
|
||||||
|
idx = Integer.parseInt(s);
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
idx = Utils.clamp(idx, 0, resolutions.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String write () {
|
||||||
|
return String.valueOf(idx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final ToggleOption OPTION_ALLOW_LARGER_RESOLUTIONS = new ToggleOption("Allow large resolutions", "AllowLargeRes", "Allow resolutions larger than the native resolution", false);
|
||||||
|
public static final ToggleOption OPTION_FULLSCREEN = new ToggleOption("Fullscreen Mode", "Fullscreen", "Restart to apply changes.", false);
|
||||||
|
public static final ListOption OPTION_SKIN = new ListOption("Skin", "Skin", "Change how the game looks.") {
|
||||||
|
private CachedVariable<SkinService> skinService = new CachedVariable<>(new Getter<SkinService>() {
|
||||||
|
@Override
|
||||||
|
public SkinService get() {
|
||||||
|
return instanceContainer.provide(SkinService.class);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
return skinService.get().usedSkinName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object[] getListItems () {
|
||||||
|
return skinService.get().availableSkinDirectories;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clickListItem(int index){
|
||||||
|
skinService.get().usedSkinName = skinService.get().availableSkinDirectories[index];
|
||||||
|
skinService.get().reloadSkin();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read (String s){
|
||||||
|
skinService.get().usedSkinName = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String write() {
|
||||||
|
return skinService.get().usedSkinName;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final NumericOption OPTION_TARGET_UPS = new NumericOption("target UPS", "targetUPS", "Higher values result in less input lag and smoother cursor trail, but may cause high CPU usage.", 480, 20, 1000) {
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
return String.format("%dups", val);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setValue ( int value){
|
||||||
|
super.setValue(value);
|
||||||
|
displayContainer.setUPS(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final int[] targetFPS = {60, 120, 240, 1000};
|
||||||
|
public static int targetFPSIndex = 0;
|
||||||
|
|
||||||
|
public static final ListOption OPTION_TARGET_FPS = new ListOption("FPS limit", "FPSlimit", "Higher values may cause high CPU usage. A value higher than the UPS has no effect.") {
|
||||||
|
private CachedVariable<String[]> $_getListItems = new CachedVariable<>(new Getter<String[]>() {
|
||||||
|
@Override
|
||||||
|
public String[] get() {
|
||||||
|
String[] list = new String[targetFPS.length];
|
||||||
|
for (int i = 0; i < targetFPS.length; i++) {
|
||||||
|
list[i] = String.format("%dfps", targetFPS[i]);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
return $_getListItems.get()[targetFPSIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object[] getListItems () {
|
||||||
|
return $_getListItems.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clickListItem(int index){
|
||||||
|
targetFPSIndex = index;
|
||||||
|
displayContainer.setFPS(targetFPS[targetFPSIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String write () {
|
||||||
|
return Integer.toString(targetFPS[targetFPSIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read (String s){
|
||||||
|
int i = Integer.parseInt(s);
|
||||||
|
for (int j = 0; j < targetFPS.length; j++) {
|
||||||
|
if (i == targetFPS[j]) {
|
||||||
|
targetFPSIndex = j;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final ToggleOption OPTION_SHOW_FPS = new ToggleOption("Show FPS Counters", "FpsCounter", "Show FPS and UPS counters in the bottom-right hand corner.", true);
|
||||||
|
public static final ToggleOption OPTION_USE_FPS_DELTAS = new ToggleOption("Use deltas for FPS counters", "FpsCounterDeltas", "Show time between updates instead of updates per second.", false) {
|
||||||
|
@Override
|
||||||
|
public boolean showCondition () {
|
||||||
|
return OPTION_SHOW_FPS.state;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final ToggleOption OPTION_SHOW_UNICODE = new ToggleOption("Prefer Non-English Metadata", "ShowUnicode", "Where available, song titles will be shown in their native language.", false) {
|
||||||
|
@Override
|
||||||
|
public void toggle () {
|
||||||
|
super.toggle();
|
||||||
|
if (!state) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Fonts.LARGE.loadGlyphs();
|
||||||
|
Fonts.MEDIUM.loadGlyphs();
|
||||||
|
Fonts.DEFAULT.loadGlyphs();
|
||||||
|
} catch (SlickException e) {
|
||||||
|
Log.warn("Failed to load glyphs.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final ListOption OPTION_SCREENSHOT_FORMAT = new ListOption("Screenshot Format", "ScreenshotFormat", "Press F12 to take a screenshot.") {
|
||||||
|
private String[] formats = { "PNG", "JPG", "BMP" };
|
||||||
|
private int index = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
return formats[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object[] getListItems () {
|
||||||
|
return formats;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clickListItem(int index){
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String write () {
|
||||||
|
return Integer.toString(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read (String s){
|
||||||
|
int i = Integer.parseInt(s);
|
||||||
|
if (0 <= i && i < formats.length) {
|
||||||
|
index = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final NumericOption OPTION_CURSOR_SIZE = new NumericOption("Size", "CursorSize", "Change the cursor scale.", 100, 50, 200) {
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
return String.format("%.2fx", val / 100f);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String write () {
|
||||||
|
return String.format("%.2f", val / 100f);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read (String s){
|
||||||
|
int i = (int) (Float.parseFloat(s.replace(',', '.')) * 100f);
|
||||||
|
if (i >= 50 && i <= 200)
|
||||||
|
val = i;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final ToggleOption OPTION_NEW_CURSOR = new ToggleOption("Enable New Cursor", "NewCursor", "Use the new cursor style (may cause higher CPU usage).", true);
|
||||||
|
public static final ToggleOption OPTION_DYNAMIC_BACKGROUND = new ToggleOption("Enable Dynamic Backgrounds", "DynamicBackground", "The song background will be used as the main menu background.", true);
|
||||||
|
public static final ToggleOption OPTION_LOAD_VERBOSE = new ToggleOption("Show Detailed Loading Progress", "LoadVerbose", "Display more specific loading information in the splash screen.", false);
|
||||||
|
public static final ToggleOption OPTION_COLOR_MAIN_MENU_LOGO = new ToggleOption("Use cursor color as main menu logo tint", "ColorMainMenuLogo", "Colorful main menu logo", false);
|
||||||
|
public static final NumericOption OPTION_MASTER_VOLUME = new NumericOption("Master", "VolumeUniversal", "Global volume level.", 35, 0, 100) {
|
||||||
|
@Override
|
||||||
|
public void setValue(int value){
|
||||||
|
super.setValue(value);
|
||||||
|
// changing mastervolume, so music volume should change too
|
||||||
|
OPTION_MUSIC_VOLUME.setValue(OPTION_MUSIC_VOLUME.val);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final NumericOption OPTION_MUSIC_VOLUME = new NumericOption("Music", "VolumeMusic", "Volume of music.", 80, 0, 100) {
|
||||||
|
@Override
|
||||||
|
public void setValue(int value){
|
||||||
|
super.setValue(value);
|
||||||
|
SoundStore.get().setMusicVolume(OPTION_MASTER_VOLUME.val * OPTION_MUSIC_VOLUME.val / 10000f);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final NumericOption OPTION_SAMPLE_VOLUME_OVERRIDE = new NumericOption("Sample override", "BMSampleOverride", "Override beatmap hitsound volume", 100, 0, 100) {
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
if (val == 0) {
|
||||||
|
return "Disabled";
|
||||||
|
}
|
||||||
|
return super.getValueString();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final NumericOption OPTION_EFFECT_VOLUME = new NumericOption("Effects", "VolumeEffect", "Volume of menu and game sounds.", 70, 0, 100);
|
||||||
|
public static final NumericOption OPTION_HITSOUND_VOLUME = new NumericOption("Hit Sounds", "VolumeHitSound", "Volume of hit sounds.", 30, 0, 100);
|
||||||
|
public static final NumericOption OPTION_MUSIC_OFFSET = new NumericOption("Music Offset", "Offset", "Adjust this value if hit objects are out of sync.", -75, -500, 500) {
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
return String.format("%dms", val);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final ToggleOption OPTION_DISABLE_SOUNDS = new ToggleOption("Disable All Sound Effects", "DisableSound", "May resolve Linux sound driver issues. Requires a restart.", (System.getProperty("os.name").toLowerCase().contains("linux")));
|
||||||
|
public static final GenericOption OPTION_KEY_LEFT = new GenericOption("Left Game Key", "keyOsuLeft", "Select this option to input a key.", Input.KEY_Z, null, false) {
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
return Keyboard.getKeyName(intval);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String write () {
|
||||||
|
return Keyboard.getKeyName(intval);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(String s){
|
||||||
|
intval = Keyboard.getKeyIndex(s);
|
||||||
|
if (intval == Keyboard.KEY_NONE) {
|
||||||
|
intval = Input.KEY_Y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final GenericOption OPTION_KEY_RIGHT = new GenericOption("Right Game Key", "keyOsuRight", "Select this option to input a key.", Input.KEY_X, null, false) {
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
return Keyboard.getKeyName(intval);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String write () {
|
||||||
|
return Keyboard.getKeyName(intval);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(String s){
|
||||||
|
intval = Keyboard.getKeyIndex(s);
|
||||||
|
if (intval == Keyboard.KEY_NONE) {
|
||||||
|
intval = Input.KEY_X;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final NumericOption OPTION_BACKGROUND_DIM = new NumericOption("Background Dim", "DimLevel", "Percentage to dim the background image during gameplay.", 50, 0, 100);
|
||||||
|
public static final ToggleOption OPTION_DISABLE_MOUSE_WHEEL = new ToggleOption("Disable mouse wheel in play mode", "MouseDisableWheel", "During play, you can use the mouse wheel to adjust the volume and pause the game. This will disable that functionality.", false);
|
||||||
|
public static final ToggleOption OPTION_DISABLE_MOUSE_BUTTONS = new ToggleOption("Disable mouse buttons in play mode", "MouseDisableButtons", "This option will disable all mouse buttons. Specifically for people who use their keyboard to click.", false) {
|
||||||
|
@Override
|
||||||
|
public void toggle() {
|
||||||
|
EventBus.post(new BarNotificationEvent(state ? "Mouse buttons are disabled." : "Mouse buttons are enabled."));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
public static final ToggleOption OPTION_DISABLE_CURSOR = new ToggleOption("Disable Cursor", "DisableCursor", "Hide the cursor sprite.", false);
|
||||||
|
public static final ToggleOption OPTION_DANCE_REMOVE_BG = new ToggleOption("Use black background instead of image", "RemoveBG", "Hello darkness my old friend", true);
|
||||||
|
public static final ToggleOption OPTION_FORCE_DEFAULT_PLAYFIELD = new ToggleOption("Force Default Playfield", "ForceDefaultPlayfield", "Override the song background with the default playfield background.", false);
|
||||||
|
public static final ToggleOption OPTION_IGNORE_BEATMAP_SKINS = new ToggleOption("Ignore All Beatmap Skins", "IgnoreBeatmapSkins", "Never use skin element overrides provided by beatmaps.", false);
|
||||||
|
public static final ToggleOption OPTION_SNAKING_SLIDERS = new ToggleOption("Snaking sliders", "SnakingSliders", "Sliders gradually snake out from their starting point.", true);
|
||||||
|
public static final ToggleOption OPTION_SHRINKING_SLIDERS = new ToggleOption("Shrinking sliders", "ShrinkingSliders", "Sliders shrinks when sliderball passes (aka knorkesliders)", true);
|
||||||
|
public static final ToggleOption OPTION_FALLBACK_SLIDERS = new ToggleOption("Fallback sliders", "FallbackSliders", "Enable this if sliders won't render", false);
|
||||||
|
public static final ToggleOption OPTION_MERGING_SLIDERS = new ToggleOption("Merging sliders", "MergingSliders", "Merge sliders (aka knorkesliders)", true) {
|
||||||
|
@Override
|
||||||
|
public boolean showCondition () {
|
||||||
|
return !OPTION_FALLBACK_SLIDERS.state;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final NumericOption OPTION_MERGING_SLIDERS_MIRROR_POOL = new NumericOption("Merging sliders mirror pool", "MergingSliderMirrorPool", "Amount of mirrors to calculate for merging sliders (impacts performance)", 2, 1, 5) {
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
return String.valueOf(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean showCondition () {
|
||||||
|
return OPTION_MERGING_SLIDERS.showCondition() && OPTION_MERGING_SLIDERS.state;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final ToggleOption OPTION_DRAW_SLIDER_ENDCIRCLES = new ToggleOption("Draw endcircles", "DrawSliderEndCircles", "Old slider style", false);
|
||||||
|
public static final ToggleOption OPTION_DANCING_CIRCLES = new ToggleOption("Enable", "DancingHitcircles", "Make hitcircles dance to the beat", false);
|
||||||
|
public static final NumericOption OPTION_DANCING_CIRCLES_MULTIPLIER = new NumericOption("Multiplier", "DancingHitcirclesMP", "Multiplier to expand the hitcircles when dancing to the beat", 50, 1, 200) {
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
return String.format("%.1f%%", val / 10f);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final ToggleOption OPTION_SHOW_HIT_LIGHTING = new ToggleOption("Show Hit Lighting", "HitLighting", "Adds an effect behind hit explosions.", true);
|
||||||
|
public static final ToggleOption OPTION_SHOW_HIT_ANIMATIONS = new ToggleOption("Show Hit Animations", "HitAnimations", "Fade out circles and curves.", true);
|
||||||
|
public static final ToggleOption OPTION_SHOW_REVERSEARROW_ANIMATIONS = new ToggleOption("Show reverse arrow animations", "ReverseArrowAnimations", "Fade out reverse arrows after passing.", true);
|
||||||
|
public static final ToggleOption OPTION_SHOW_COMBO_BURSTS = new ToggleOption("Show Combo Bursts", "ComboBurst", "A character image is displayed at combo milestones.", true);
|
||||||
|
public static final ToggleOption OPTION_SHOW_PERFECT_HIT = new ToggleOption("Show Perfect Hits", "PerfectHit", "Whether to show perfect hit result bursts (300s, slider ticks).", true);
|
||||||
|
public static final ToggleOption OPTION_SHOW_FOLLOW_POINTS = new ToggleOption("Show Follow Points", "FollowPoints", "Whether to show follow points between hit objects.", true);
|
||||||
|
public static final ToggleOption OPTION_SHOW_HIT_ERROR_BAR = new ToggleOption("Show Hit Error Bar", "ScoreMeter", "Shows precisely how accurate you were with each hit.", false);
|
||||||
|
public static final NumericOption OPTION_MAP_START_DELAY = new NumericOption("Map start delay", "StartDelay", "Have a fix amount of time to prepare your play/record", 20, 1, 50) {
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
return (val * 100) + "ms";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final NumericOption OPTION_MAP_END_DELAY = new NumericOption("Map end delay", "EndDelay", "Have a fix amount of time at the and of the map for a smooth finish", 50, 1, 150) {
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
return (val * 100) + "ms";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final NumericOption OPTION_EPILEPSY_WARNING = new NumericOption("Epilepsy warning image", "EpiWarn", "Show a little warning for flashing colours in the beginning", 0, 0, 20) {
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
if (val == 0) {
|
||||||
|
return "Disabled";
|
||||||
|
}
|
||||||
|
return (val * 100) + "ms";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final ToggleOption OPTION_LOAD_HD_IMAGES = new ToggleOption("Load HD Images", "LoadHDImages", String.format("Loads HD (%s) images when available. Increases memory usage and loading times.", GameImage.HD_SUFFIX), true);
|
||||||
|
public static final NumericOption OPTION_FIXED_CS = new NumericOption("Fixed CS", "FixedCS", "Determines the size of circles and sliders.", 0, 0, 100) {
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
return (val == 0) ? "Disabled" : String.format("%.1f", val / 10f);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String write () {
|
||||||
|
return String.format("%.1f", val / 10f);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read (String s){
|
||||||
|
int i = (int) (Float.parseFloat(s.replace(',', '.')) * 10f);
|
||||||
|
if (i >= 0 && i <= 100)
|
||||||
|
val = i;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final NumericOption OPTION_FIXED_HP = new NumericOption("Fixed HP", "FixedHP", "Determines the rate at which health decreases.", 0, 0, 100) {
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
return (val == 0) ? "Disabled" : String.format("%.1f", val / 10f);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String write () {
|
||||||
|
return String.format("%.1f", val / 10f);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read (String s){
|
||||||
|
int i = (int) (Float.parseFloat(s.replace(',', '.')) * 10f);
|
||||||
|
if (i >= 0 && i <= 100)
|
||||||
|
val = i;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final NumericOption OPTION_FIXED_AR = new NumericOption("Fixed AR", "FixedAR", "Determines how long hit circles stay on the screen.", 0, 0, 100) {
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
return (val == 0) ? "Disabled" : String.format("%.1f", val / 10f);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String write () {
|
||||||
|
return String.format("%.1f", val / 10f);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read (String s){
|
||||||
|
int i = (int) (Float.parseFloat(s.replace(',', '.')) * 10f);
|
||||||
|
if (i >= 0 && i <= 100)
|
||||||
|
val = i;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final NumericOption OPTION_FIXED_OD = new NumericOption("Fixed OD", "FixedOD", "Determines the time window for hit results.", 0, 0, 100) {
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
return (val == 0) ? "Disabled" : String.format("%.1f", val / 10f);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String write () {
|
||||||
|
return String.format("%.1f", val / 10f);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read (String s){
|
||||||
|
int i = (int) (Float.parseFloat(s.replace(',', '.')) * 10f);
|
||||||
|
if (i >= 0 && i <= 100)
|
||||||
|
val = i;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final NumericOption OPTION_CHECKPOINT = new NumericOption("Track Checkpoint", "Checkpoint", "Press Ctrl+L while playing to load a checkpoint, and Ctrl+S to set one.", 0, 0, 3599) {
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
return (val == 0) ? "Disabled" : String.format("%02d:%02d",
|
||||||
|
TimeUnit.SECONDS.toMinutes(val),
|
||||||
|
val - TimeUnit.MINUTES.toSeconds(TimeUnit.SECONDS.toMinutes(val)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final ToggleOption OPTION_ENABLE_THEME_SONG = new ToggleOption("Enable Theme Song", "MenuMusic", "Whether to play the theme song upon starting opsu!", true);
|
||||||
|
public static final ToggleOption OPTION_REPLAY_SEEKING = new ToggleOption("Replay Seeking", "ReplaySeeking", "Enable a seeking bar on the left side of the screen during replays.", false);
|
||||||
|
public static final ToggleOption OPTION_DISABLE_UPDATER = new ToggleOption("Disable Automatic Updates", "DisableUpdater", "Disable automatic checking for updates upon starting opsu!.", false);
|
||||||
|
public static final ToggleOption OPTION_ENABLE_WATCH_SERVICE = new ToggleOption("Enable Watch Service", "WatchService", "Watch the beatmap directory for changes. Requires a restart.", false);
|
||||||
|
public static final ListOption OPTION_DANCE_MOVER = new ListOption("Algorithm", "Mover", "Algorithm that decides how to move from note to note" ) {
|
||||||
|
@Override
|
||||||
|
public Object[] getListItems () {
|
||||||
|
return Dancer.moverFactories;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clickListItem(int index){
|
||||||
|
if (Game.isInGame && Dancer.moverFactories[index] instanceof PolyMoverFactory) {
|
||||||
|
// TODO remove this when #79 is fixed
|
||||||
|
EventBus.post(new BarNotificationEvent("This mover is disabled in the storyboard right now"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Dancer.instance.setMoverFactoryIndex(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
return Dancer.moverFactories[Dancer.instance.getMoverFactoryIndex()].toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String write () {
|
||||||
|
return String.valueOf(Dancer.instance.getMoverFactoryIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read (String s){
|
||||||
|
int i = Integer.parseInt(s);
|
||||||
|
Dancer.instance.setMoverFactoryIndex(i);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final NumericOption OPTION_DANCE_EXGON_DELAY = new NumericOption("ExGon delay", "ExGonDelay", "Delay between moves for the ExGon mover", 25, 2, 750) {
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
return String.valueOf(val);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean showCondition () {
|
||||||
|
return Dancer.moverFactories[Dancer.instance.getMoverFactoryIndex()] instanceof ExgonMoverFactory;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final NumericOption OPTION_DANCE_QUAD_BEZ_AGGRESSIVENESS = new NumericOption("Bezier aggressiveness", "QuadBezAgr", "AKA initial D factor", 50, 0, 200) {
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
return String.valueOf(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean showCondition () {
|
||||||
|
return Dancer.moverFactories[Dancer.instance.getMoverFactoryIndex()] instanceof QuadraticBezierMoverFactory;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final NumericOption OPTION_DANCE_QUAD_BEZ_SLIDER_AGGRESSIVENESS_FACTOR = new NumericOption("Exit aggressiveness", "CubBezSliderExitAgr", "AKA initial D factor for sliderexits", 4, 1, 6) {
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
return String.valueOf(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean showCondition () {
|
||||||
|
return OPTION_DANCE_QUAD_BEZ_AGGRESSIVENESS.showCondition()
|
||||||
|
&& Dancer.sliderMoverController instanceof DefaultSliderMoverController;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final ToggleOption OPTION_DANCE_QUAD_BEZ_USE_CUBIC_ON_SLIDERS = new ToggleOption("Use cubic bezier before sliders", "QuadBezCubicSliders", "Slider entry looks better using this", true) {
|
||||||
|
@Override
|
||||||
|
public boolean showCondition () {
|
||||||
|
return OPTION_DANCE_QUAD_BEZ_SLIDER_AGGRESSIVENESS_FACTOR.showCondition();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final NumericOption OPTION_DANCE_QUAD_BEZ_CUBIC_AGGRESSIVENESS_FACTOR = new NumericOption("Entry aggressiveness", "CubBezSliderEntryAgr", "AKA initial D factor for sliderentries", 4, 1, 6) {
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
return String.valueOf(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean showCondition () {
|
||||||
|
return OPTION_DANCE_QUAD_BEZ_USE_CUBIC_ON_SLIDERS.showCondition()
|
||||||
|
&& OPTION_DANCE_QUAD_BEZ_USE_CUBIC_ON_SLIDERS.state;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final ListOption OPTION_DANCE_MOVER_DIRECTION = new ListOption("Direction", "MoverDirection", "The direction the mover goes" ) {
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
return Dancer.moverDirection.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object[] getListItems () {
|
||||||
|
return MoverDirection.values();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clickListItem(int index){
|
||||||
|
Dancer.moverDirection = MoverDirection.values()[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String write () {
|
||||||
|
return "" + Dancer.moverDirection.nr;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read (String s){
|
||||||
|
Dancer.moverDirection = MoverDirection.values()[Integer.parseInt(s)];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final ListOption OPTION_DANCE_SLIDER_MOVER_TYPE = new ListOption("Slider mover", "SliderMover", "How to move in sliders") {
|
||||||
|
private int val;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
return Dancer.sliderMoverController.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object[] getListItems () {
|
||||||
|
return Dancer.sliderMovers;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clickListItem(int index){
|
||||||
|
val = index;
|
||||||
|
Dancer.sliderMoverController = Dancer.sliderMovers[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String write () {
|
||||||
|
return String.valueOf(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read (String s){
|
||||||
|
Dancer.sliderMoverController = Dancer.sliderMovers[val = Integer.parseInt(s)];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final ListOption OPTION_DANCE_SPINNER = new ListOption("Algorithm", "Spinner", "Spinner style") {
|
||||||
|
@Override
|
||||||
|
public Object[] getListItems () {
|
||||||
|
return Dancer.spinners;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clickListItem(int index){
|
||||||
|
Dancer.instance.setSpinnerIndex(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
return Dancer.spinners[Dancer.instance.getSpinnerIndex()].toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String write () {
|
||||||
|
return Dancer.instance.getSpinnerIndex() + "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read (String s){
|
||||||
|
Dancer.instance.setSpinnerIndex(Integer.parseInt(s));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final NumericOption OPTION_DANCE_SPINNER_DELAY = new NumericOption("Delay", "SpinnerDelay", "Fiddle with this if spinner goes too fast.", 3, 0, 20) {
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
return String.format("%dms", val);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final ToggleOption OPTION_DANCE_LAZY_SLIDERS = new ToggleOption("Lazy sliders", "LazySliders", "Don't do short sliders", false);
|
||||||
|
public static final ToggleOption OPTION_DANCE_ONLY_CIRCLE_STACKS = new ToggleOption("Only circle stacks", "CircleStacks", "Only do circle movement on stacks", false);
|
||||||
|
public static final ToggleOption OPTION_DANCE_CIRCLE_STREAMS = new ToggleOption("Circle streams", "CircleStreams", "Make circles while streaming", false);
|
||||||
|
public static final ToggleOption OPTION_DANCE_MIRROR = new ToggleOption("Mirror collage", "MirrorCollage", "Hypnotizing stuff. Toggle this ingame by pressing the M key.", false);
|
||||||
|
public static final ToggleOption OPTION_DANCE_DRAW_APPROACH = new ToggleOption("Draw approach circles", "DrawApproach", "Can get a bit busy when using mirror collage", true);
|
||||||
|
public static final ListOption OPTION_DANCE_OBJECT_COLOR_OVERRIDE = new ListOption("Color", "ObjColorOverride", "Override object colors") {
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
return Dancer.colorOverride.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object[] getListItems () {
|
||||||
|
return ObjectColorOverrides.values();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clickListItem(int index){
|
||||||
|
Dancer.colorOverride = ObjectColorOverrides.values()[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String write () {
|
||||||
|
return "" + Dancer.colorOverride.nr;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read (String s){
|
||||||
|
Dancer.colorOverride = ObjectColorOverrides.values()[Integer.parseInt(s)];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final ListOption OPTION_DANCE_OBJECT_COLOR_OVERRIDE_MIRRORED = new ListOption("Mirror color", "ObjColorMirroredOverride", "Override collage object colors") {
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
return Dancer.colorMirrorOverride.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object[] getListItems () {
|
||||||
|
return ObjectColorOverrides.values();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clickListItem(int index){
|
||||||
|
Dancer.colorMirrorOverride = ObjectColorOverrides.values()[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String write () {
|
||||||
|
return "" + Dancer.colorMirrorOverride.nr;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read (String s){
|
||||||
|
Dancer.colorMirrorOverride = ObjectColorOverrides.values()[Integer.parseInt(s)];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final NumericOption OPTION_DANCE_RGB_OBJECT_INC = new NumericOption("RGB increment", "RGBInc", "Amount of hue to shift, used for rainbow object override", 70, -1800, 1800) {
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
return String.format("%.1f°", val / 10f);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final ListOption OPTION_DANCE_CURSOR_COLOR_OVERRIDE = new ListOption("Color", "CursorColorOverride", "Override cursor color") {
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
return Dancer.cursorColorOverride.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object[] getListItems () {
|
||||||
|
return CursorColorOverrides.values();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clickListItem(int index){
|
||||||
|
Dancer.cursorColorOverride = CursorColorOverrides.values()[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String write () {
|
||||||
|
return "" + Dancer.cursorColorOverride.nr;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read (String s){
|
||||||
|
Dancer.cursorColorOverride = CursorColorOverrides.values()[Integer.parseInt(s)];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final ListOption OPTION_DANCE_CURSOR_MIRROR_COLOR_OVERRIDE = new ListOption("Mirror color", "CursorMirrorColorOverride", "Override mirror cursor color") {
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
return Dancer.cursorColorMirrorOverride.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object[] getListItems () {
|
||||||
|
return CursorColorOverrides.values();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clickListItem(int index){
|
||||||
|
Dancer.cursorColorMirrorOverride = CursorColorOverrides.values()[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String write () {
|
||||||
|
return "" + Dancer.cursorColorMirrorOverride.nr;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read (String s){
|
||||||
|
Dancer.cursorColorMirrorOverride = CursorColorOverrides.values()[Integer.parseInt(s)];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final ToggleOption OPTION_DANCE_CURSOR_ONLY_COLOR_TRAIL = new ToggleOption("Only color cursor trail", "OnlyColorTrail", "Don't color the cursor, only the trail", false);
|
||||||
|
public static final NumericOption OPTION_DANCE_RGB_CURSOR_INC = new NumericOption("RGB cursor increment", "RGBCursorInc", "Amount of hue to shift, used for rainbow cursor override", 100, -2000, 2000) {
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
return String.format("%.2f°", val / 1000f);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final NumericOption OPTION_DANCE_CURSOR_TRAIL_OVERRIDE = new NumericOption("Trail length", "CursorTrailOverride", "Override cursor trail length", 20, 20, 600) {
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
if (val == 20) {
|
||||||
|
return "Disabled";
|
||||||
|
}
|
||||||
|
return "" + val;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final ToggleOption OPTION_DANCE_HIDE_OBJECTS = new ToggleOption("Don't draw objects", "HideObj", "If you only want to see cursors :)", false);
|
||||||
|
public static final ToggleOption OPTION_DANCE_CIRLCE_IN_SLOW_SLIDERS = new ToggleOption("Do circles in slow sliders", "CircleInSlider", "Circle around sliderball in lazy & slow sliders", false);
|
||||||
|
public static final ToggleOption OPTION_DANCE_CIRLCE_IN_LAZY_SLIDERS = new ToggleOption("Do circles in lazy sliders", "CircleInLazySlider", "Circle in hitcircle in lazy sliders", false);
|
||||||
|
public static final ToggleOption OPTION_DANCE_HIDE_UI = new ToggleOption("Hide all UI", "HideUI", ".", true);
|
||||||
|
public static final ToggleOption OPTION_DANCE_ENABLE_SB = new ToggleOption("Enable storyboard editor", "EnableStoryBoard", "Dance storyboard", false);
|
||||||
|
public static final ToggleOption OPTION_PIPPI_ENABLE = new ToggleOption("Enable", "Pippi", "Move in circles like dancing pippi (osu! april fools joke 2016)", false);
|
||||||
|
public static final NumericOption OPTION_PIPPI_RADIUS_PERCENT = new NumericOption("Radius", "PippiRad", "Radius of pippi, percentage of circle radius", 100, 0, 100) {
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
return val + "%";
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void setValue ( int value){
|
||||||
|
super.setValue(value);
|
||||||
|
Pippi.setRadiusPercent(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final NumericOption OPTION_PIPPI_ANGLE_INC_MUL = new NumericOption("Normal", "PippiAngIncMul", "How fast pippi's angle increments", 10, -200, 200) {
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
return String.format("x%.1f", val / 10f);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final NumericOption OPTION_PIPPI_ANGLE_INC_MUL_SLIDER = new NumericOption("In slider", "PippiAngIncMulSlider", "Same as above, but in sliders", 50, -200, 200) {
|
||||||
|
@Override
|
||||||
|
public String getValueString () {
|
||||||
|
return String.format("x%.1f", val / 10f);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final ToggleOption OPTION_PIPPI_SLIDER_FOLLOW_EXPAND = new ToggleOption("Followcircle expand", "PippiFollowExpand", "Increase radius in followcircles", false);
|
||||||
|
public static final ToggleOption OPTION_PIPPI_PREVENT_WOBBLY_STREAMS = new ToggleOption("Prevent wobbly streams", "PippiPreventWobblyStreams", "Force linear mover while doing streams to prevent wobbly pippi", true);
|
||||||
|
|
||||||
|
}
|
118
src/yugecin/opsudance/options/OptionsService.java
Normal file
118
src/yugecin/opsudance/options/OptionsService.java
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
/*
|
||||||
|
* opsu!dance - fork of opsu! with cursordance auto
|
||||||
|
* Copyright (C) 2017 yugecin
|
||||||
|
*
|
||||||
|
* opsu!dance is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* opsu!dance is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package yugecin.opsudance.options;
|
||||||
|
|
||||||
|
import org.newdawn.slick.util.Log;
|
||||||
|
import yugecin.opsudance.core.events.EventBus;
|
||||||
|
import yugecin.opsudance.core.inject.Inject;
|
||||||
|
import yugecin.opsudance.core.inject.InstanceContainer;
|
||||||
|
import yugecin.opsudance.events.BubbleNotificationEvent;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author itdelatrisu (https://github.com/itdelatrisu) most functions are copied from itdelatrisu.opsu.Options.java
|
||||||
|
*/
|
||||||
|
public class OptionsService {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Configuration config;
|
||||||
|
|
||||||
|
public static final HashMap<String, Option> optionMap = new HashMap<>();
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public OptionsService(InstanceContainer instanceContainer) {
|
||||||
|
Option.setInstanceContainer(instanceContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void registerOption(Option option) {
|
||||||
|
optionMap.put(option.configurationName, option);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadOptions() {
|
||||||
|
// if no config file, use default settings
|
||||||
|
if (!config.OPTIONS_FILE.isFile()) {
|
||||||
|
saveOptions();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read file
|
||||||
|
try (BufferedReader in = new BufferedReader(new FileReader(config.OPTIONS_FILE))) {
|
||||||
|
String line;
|
||||||
|
while ((line = in.readLine()) != null) {
|
||||||
|
line = line.trim();
|
||||||
|
if (line.length() < 2 || line.charAt(0) == '#') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int index = line.indexOf('=');
|
||||||
|
if (index == -1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read option
|
||||||
|
String name = line.substring(0, index).trim();
|
||||||
|
Option option = optionMap.get(name);
|
||||||
|
if (option != null) {
|
||||||
|
try {
|
||||||
|
String value = line.substring(index + 1).trim();
|
||||||
|
option.read(value);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.warn(String.format("Format error in options file for line: '%s'.", line), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
String err = String.format("Failed to read option file '%s'.", config.OPTIONS_FILE.getAbsolutePath());
|
||||||
|
Log.error(err, e);
|
||||||
|
EventBus.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
|
||||||
|
}
|
||||||
|
config.loadDirectories();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveOptions() {
|
||||||
|
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
|
||||||
|
new FileOutputStream(config.OPTIONS_FILE), "utf-8"))) {
|
||||||
|
// header
|
||||||
|
SimpleDateFormat dateFormat = new SimpleDateFormat("EEEE, MMMM dd, yyyy");
|
||||||
|
String date = dateFormat.format(new Date());
|
||||||
|
writer.write("# opsu! configuration");
|
||||||
|
writer.newLine();
|
||||||
|
writer.write("# last updated on ");
|
||||||
|
writer.write(date);
|
||||||
|
writer.newLine();
|
||||||
|
writer.newLine();
|
||||||
|
|
||||||
|
// options
|
||||||
|
for (Option option : optionMap.values()) {
|
||||||
|
writer.write(option.configurationName);
|
||||||
|
writer.write(" = ");
|
||||||
|
writer.write(option.write());
|
||||||
|
writer.newLine();
|
||||||
|
}
|
||||||
|
writer.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
String err = String.format("Failed to write to file '%s'.", config.OPTIONS_FILE.getAbsolutePath());
|
||||||
|
Log.error(err, e);
|
||||||
|
EventBus.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
43
src/yugecin/opsudance/options/ToggleOption.java
Normal file
43
src/yugecin/opsudance/options/ToggleOption.java
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* opsu!dance - fork of opsu! with cursordance auto
|
||||||
|
* Copyright (C) 2017 yugecin
|
||||||
|
*
|
||||||
|
* opsu!dance is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* opsu!dance is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package yugecin.opsudance.options;
|
||||||
|
|
||||||
|
public class ToggleOption extends Option {
|
||||||
|
|
||||||
|
public boolean state;
|
||||||
|
|
||||||
|
public ToggleOption(String name, String configurationName, String description, boolean state) {
|
||||||
|
super(name, configurationName, description);
|
||||||
|
this.state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void toggle() {
|
||||||
|
this.state = !this.state;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String write() {
|
||||||
|
return Boolean.toString(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(String s) {
|
||||||
|
state = Boolean.parseBoolean(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
121
src/yugecin/opsudance/render/GameObjectRenderer.java
Normal file
121
src/yugecin/opsudance/render/GameObjectRenderer.java
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
/*
|
||||||
|
* opsu!dance - fork of opsu! with cursordance auto
|
||||||
|
* Copyright (C) 2017 yugecin
|
||||||
|
*
|
||||||
|
* opsu!dance is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* opsu!dance is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package yugecin.opsudance.render;
|
||||||
|
|
||||||
|
import itdelatrisu.opsu.GameData;
|
||||||
|
import itdelatrisu.opsu.GameImage;
|
||||||
|
import itdelatrisu.opsu.GameMod;
|
||||||
|
import itdelatrisu.opsu.audio.MusicController;
|
||||||
|
import itdelatrisu.opsu.beatmap.HitObject;
|
||||||
|
import itdelatrisu.opsu.ui.Colors;
|
||||||
|
import itdelatrisu.opsu.ui.animations.AnimationEquation;
|
||||||
|
import org.newdawn.slick.Color;
|
||||||
|
import org.newdawn.slick.Image;
|
||||||
|
import yugecin.opsudance.core.DisplayContainer;
|
||||||
|
import yugecin.opsudance.core.inject.Inject;
|
||||||
|
import yugecin.opsudance.skinning.SkinService;
|
||||||
|
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
|
public class GameObjectRenderer {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private DisplayContainer displayContainer;
|
||||||
|
|
||||||
|
private GameData gameData;
|
||||||
|
|
||||||
|
private float circleDiameter;
|
||||||
|
private int circleDiameterInt;
|
||||||
|
|
||||||
|
private Image hitcircle;
|
||||||
|
private Image hitcircleOverlay;
|
||||||
|
private Image approachCircle;
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public static GameObjectRenderer instance;
|
||||||
|
|
||||||
|
public GameObjectRenderer() {
|
||||||
|
instance = this; // TODO get rid of this
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initForGame(GameData gameData, float circleDiameter) {
|
||||||
|
this.gameData = gameData;
|
||||||
|
this.circleDiameter = circleDiameter * HitObject.getXMultiplier(); // convert from Osupixels (640x480)
|
||||||
|
this.circleDiameterInt = (int) this.circleDiameter;
|
||||||
|
GameImage.HITCIRCLE.setImage(GameImage.HITCIRCLE.getImage().getScaledCopy(circleDiameterInt, circleDiameterInt));
|
||||||
|
GameImage.HITCIRCLE_OVERLAY.setImage(GameImage.HITCIRCLE_OVERLAY.getImage().getScaledCopy(circleDiameterInt, circleDiameterInt));
|
||||||
|
GameImage.APPROACHCIRCLE.setImage(GameImage.APPROACHCIRCLE.getImage().getScaledCopy(circleDiameterInt, circleDiameterInt));
|
||||||
|
hitcircle = GameImage.HITCIRCLE.getImage();
|
||||||
|
hitcircleOverlay = GameImage.HITCIRCLE_OVERLAY.getImage();
|
||||||
|
approachCircle = GameImage.APPROACHCIRCLE.getImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getCircleDiameter() {
|
||||||
|
return circleDiameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGameData(GameData gameData) {
|
||||||
|
this.gameData = gameData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initForFrame() {
|
||||||
|
if (!OPTION_DANCING_CIRCLES.state) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Float position = MusicController.getBeatProgress();
|
||||||
|
if (position == null) {
|
||||||
|
position = 0f;
|
||||||
|
}
|
||||||
|
int size = circleDiameterInt + (int) (circleDiameter * OPTION_DANCING_CIRCLES_MULTIPLIER.val / 1000f * AnimationEquation.IN_OUT_QUAD.calc(position));
|
||||||
|
hitcircle = GameImage.HITCIRCLE.getImage().getScaledCopy(size, size);
|
||||||
|
hitcircleOverlay = GameImage.HITCIRCLE_OVERLAY.getImage().getScaledCopy(size, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void renderHitCircle(float x, float y, Color color, int comboNumber, float comboNumberAlpha) {
|
||||||
|
renderHitCircleOnly(x, y, color);
|
||||||
|
boolean overlayAboveNumber = SkinService.skin.isHitCircleOverlayAboveNumber();
|
||||||
|
if (!overlayAboveNumber) {
|
||||||
|
renderHitCircleOverlayOnly(x, y, Colors.WHITE_FADE);
|
||||||
|
}
|
||||||
|
renderComboNumberOnly(x, y, comboNumber, comboNumberAlpha);
|
||||||
|
if (overlayAboveNumber) {
|
||||||
|
renderHitCircleOverlayOnly(x, y, Colors.WHITE_FADE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void renderHitCircleOnly(float x, float y, Color color) {
|
||||||
|
hitcircle.drawCentered(x, y, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void renderHitCircleOverlayOnly(float x, float y, Color color) {
|
||||||
|
hitcircleOverlay.drawCentered(x, y, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void renderComboNumberOnly(float x, float y, int number, float alpha) {
|
||||||
|
if (number > 0) {
|
||||||
|
gameData.drawSymbolNumber(number, x, y, GameImage.HITCIRCLE.getImage().getWidth() * 0.40f / gameData.getDefaultSymbolImage(0).getHeight(), alpha);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void renderApproachCircle(float x, float y, Color color, float approachScale) {
|
||||||
|
if (!GameMod.HIDDEN.isActive() && OPTION_DANCE_DRAW_APPROACH.state) {
|
||||||
|
approachCircle.getScaledCopy(approachScale).drawCentered(x, y, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
102
src/yugecin/opsudance/skinning/SkinService.java
Normal file
102
src/yugecin/opsudance/skinning/SkinService.java
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
/*
|
||||||
|
* opsu!dance - fork of opsu! with cursordance auto
|
||||||
|
* Copyright (C) 2017 yugecin
|
||||||
|
*
|
||||||
|
* opsu!dance is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* opsu!dance is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package yugecin.opsudance.skinning;
|
||||||
|
|
||||||
|
import itdelatrisu.opsu.audio.SoundController;
|
||||||
|
import itdelatrisu.opsu.skins.Skin;
|
||||||
|
import itdelatrisu.opsu.skins.SkinLoader;
|
||||||
|
import org.newdawn.slick.util.ClasspathLocation;
|
||||||
|
import org.newdawn.slick.util.FileSystemLocation;
|
||||||
|
import org.newdawn.slick.util.ResourceLoader;
|
||||||
|
import yugecin.opsudance.core.events.EventBus;
|
||||||
|
import yugecin.opsudance.core.inject.Inject;
|
||||||
|
import yugecin.opsudance.events.ResolutionOrSkinChangedEvent;
|
||||||
|
import yugecin.opsudance.options.Configuration;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author itdelatrisu (https://github.com/itdelatrisu) most functions are copied from itdelatrisu.opsu.Options.java
|
||||||
|
*/
|
||||||
|
public class SkinService {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Configuration config;
|
||||||
|
|
||||||
|
public String[] availableSkinDirectories;
|
||||||
|
public String usedSkinName = "Default";
|
||||||
|
public static Skin skin;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public SkinService() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reloadSkin() {
|
||||||
|
loadSkin();
|
||||||
|
SoundController.init();
|
||||||
|
EventBus.post(new ResolutionOrSkinChangedEvent(usedSkinName, -1, -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the skin given by the current skin directory.
|
||||||
|
* If the directory is invalid, the default skin will be loaded.
|
||||||
|
*/
|
||||||
|
public void loadSkin() {
|
||||||
|
File skinDir = getCurrentSkinDirectory();
|
||||||
|
if (skinDir == null) {
|
||||||
|
// invalid skin name
|
||||||
|
usedSkinName = Skin.DEFAULT_SKIN_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create available skins list
|
||||||
|
File[] dirs = SkinLoader.getSkinDirectories(config.skinRootDir);
|
||||||
|
availableSkinDirectories = new String[dirs.length + 1];
|
||||||
|
availableSkinDirectories[0] = Skin.DEFAULT_SKIN_NAME;
|
||||||
|
for (int i = 0; i < dirs.length; i++) {
|
||||||
|
availableSkinDirectories[i + 1] = dirs[i].getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
// set skin and modify resource locations
|
||||||
|
ResourceLoader.removeAllResourceLocations();
|
||||||
|
if (skinDir == null) {
|
||||||
|
skin = new Skin(null);
|
||||||
|
} else {
|
||||||
|
// load the skin
|
||||||
|
skin = SkinLoader.loadSkin(skinDir);
|
||||||
|
ResourceLoader.addResourceLocation(new FileSystemLocation(skinDir));
|
||||||
|
}
|
||||||
|
ResourceLoader.addResourceLocation(new ClasspathLocation());
|
||||||
|
ResourceLoader.addResourceLocation(new FileSystemLocation(new File(".")));
|
||||||
|
ResourceLoader.addResourceLocation(new FileSystemLocation(new File("./res/")));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current skin directory.
|
||||||
|
* <p>
|
||||||
|
* NOTE: This directory will differ from that of the currently loaded skin
|
||||||
|
* if {@link #loadSkin()} has not been called after a directory change.
|
||||||
|
* Use {@link Skin#getDirectory()} to get the directory of the currently
|
||||||
|
* loaded skin.
|
||||||
|
* @return the skin directory, or null for the default skin
|
||||||
|
*/
|
||||||
|
public File getCurrentSkinDirectory() {
|
||||||
|
File dir = new File(config.skinRootDir, usedSkinName);
|
||||||
|
return (dir.isDirectory()) ? dir : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -17,7 +17,7 @@
|
||||||
*/
|
*/
|
||||||
package yugecin.opsudance.spinners;
|
package yugecin.opsudance.spinners;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
import yugecin.opsudance.options.Options;
|
||||||
|
|
||||||
public class ApproachCircleSpinner extends Spinner {
|
public class ApproachCircleSpinner extends Spinner {
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
*/
|
*/
|
||||||
package yugecin.opsudance.spinners;
|
package yugecin.opsudance.spinners;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
import yugecin.opsudance.options.Options;
|
||||||
|
|
||||||
public class BeamSpinner extends Spinner {
|
public class BeamSpinner extends Spinner {
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
*/
|
*/
|
||||||
package yugecin.opsudance.spinners;
|
package yugecin.opsudance.spinners;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
import yugecin.opsudance.options.Options;
|
||||||
|
|
||||||
public class CircleSpinner extends Spinner {
|
public class CircleSpinner extends Spinner {
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
*/
|
*/
|
||||||
package yugecin.opsudance.spinners;
|
package yugecin.opsudance.spinners;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
import yugecin.opsudance.options.Options;
|
||||||
|
|
||||||
public class CubeSpinner extends Spinner {
|
public class CubeSpinner extends Spinner {
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
*/
|
*/
|
||||||
package yugecin.opsudance.spinners;
|
package yugecin.opsudance.spinners;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
import yugecin.opsudance.options.Options;
|
||||||
|
|
||||||
public class DonutSpinner extends Spinner {
|
public class DonutSpinner extends Spinner {
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
*/
|
*/
|
||||||
package yugecin.opsudance.spinners;
|
package yugecin.opsudance.spinners;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
import yugecin.opsudance.options.Options;
|
||||||
|
|
||||||
public class FivePointStarApproachSpinner extends Spinner {
|
public class FivePointStarApproachSpinner extends Spinner {
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
*/
|
*/
|
||||||
package yugecin.opsudance.spinners;
|
package yugecin.opsudance.spinners;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
import yugecin.opsudance.options.Options;
|
||||||
|
|
||||||
public class FivePointStarSpinner extends Spinner {
|
public class FivePointStarSpinner extends Spinner {
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
*/
|
*/
|
||||||
package yugecin.opsudance.spinners;
|
package yugecin.opsudance.spinners;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
import yugecin.opsudance.options.Options;
|
||||||
|
|
||||||
public class HalfCircleSpinner extends Spinner {
|
public class HalfCircleSpinner extends Spinner {
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
*/
|
*/
|
||||||
package yugecin.opsudance.spinners;
|
package yugecin.opsudance.spinners;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
import yugecin.opsudance.options.Options;
|
||||||
|
|
||||||
public class IlluminatiSpinner extends Spinner {
|
public class IlluminatiSpinner extends Spinner {
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
*/
|
*/
|
||||||
package yugecin.opsudance.spinners;
|
package yugecin.opsudance.spinners;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
import yugecin.opsudance.options.Options;
|
||||||
|
|
||||||
public class LessThanThreeSpinner extends Spinner {
|
public class LessThanThreeSpinner extends Spinner {
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
*/
|
*/
|
||||||
package yugecin.opsudance.spinners;
|
package yugecin.opsudance.spinners;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
import yugecin.opsudance.options.Options;
|
||||||
|
|
||||||
public class RektCircleSpinner extends Spinner {
|
public class RektCircleSpinner extends Spinner {
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
*/
|
*/
|
||||||
package yugecin.opsudance.spinners;
|
package yugecin.opsudance.spinners;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
import yugecin.opsudance.options.Options;
|
||||||
|
|
||||||
public class RektSpinner extends Spinner {
|
public class RektSpinner extends Spinner {
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
*/
|
*/
|
||||||
package yugecin.opsudance.spinners;
|
package yugecin.opsudance.spinners;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
public abstract class Spinner {
|
public abstract class Spinner {
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ public abstract class Spinner {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean waitForDelay() {
|
public boolean waitForDelay() {
|
||||||
if (delay >= Options.getSpinnerDelay()) {
|
if (delay >= OPTION_DANCE_SPINNER_DELAY.val) {
|
||||||
delay = 0;
|
delay = 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,9 +18,6 @@
|
||||||
package yugecin.opsudance.ui;
|
package yugecin.opsudance.ui;
|
||||||
|
|
||||||
import itdelatrisu.opsu.GameImage;
|
import itdelatrisu.opsu.GameImage;
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.Options.GameOption;
|
|
||||||
import itdelatrisu.opsu.Options.GameOption.OptionType;
|
|
||||||
import itdelatrisu.opsu.Utils;
|
import itdelatrisu.opsu.Utils;
|
||||||
import itdelatrisu.opsu.audio.SoundController;
|
import itdelatrisu.opsu.audio.SoundController;
|
||||||
import itdelatrisu.opsu.audio.SoundEffect;
|
import itdelatrisu.opsu.audio.SoundEffect;
|
||||||
|
@ -30,11 +27,14 @@ import org.newdawn.slick.*;
|
||||||
import org.newdawn.slick.gui.TextField;
|
import org.newdawn.slick.gui.TextField;
|
||||||
import yugecin.opsudance.core.DisplayContainer;
|
import yugecin.opsudance.core.DisplayContainer;
|
||||||
import yugecin.opsudance.core.state.OverlayOpsuState;
|
import yugecin.opsudance.core.state.OverlayOpsuState;
|
||||||
|
import yugecin.opsudance.options.*;
|
||||||
import yugecin.opsudance.utils.FontUtil;
|
import yugecin.opsudance.utils.FontUtil;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
public class OptionsOverlay extends OverlayOpsuState {
|
public class OptionsOverlay extends OverlayOpsuState {
|
||||||
|
|
||||||
private final DisplayContainer displayContainer;
|
private final DisplayContainer displayContainer;
|
||||||
|
@ -84,14 +84,14 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||||
|
|
||||||
private OptionTab[] sections;
|
private OptionTab[] sections;
|
||||||
|
|
||||||
private GameOption hoverOption;
|
private Option hoverOption;
|
||||||
private GameOption selectedOption;
|
private Option selectedOption;
|
||||||
|
|
||||||
private int sliderOptionStartX;
|
private int sliderOptionStartX;
|
||||||
private int sliderOptionLength;
|
private int sliderOptionLength;
|
||||||
private boolean isAdjustingSlider;
|
private boolean isAdjustingSlider;
|
||||||
|
|
||||||
private final HashMap<GameOption, DropdownMenu<Object>> dropdownMenus;
|
private final HashMap<ListOption, DropdownMenu<Object>> dropdownMenus;
|
||||||
private final LinkedList<DropdownMenu<Object>> visibleDropdownMenus;
|
private final LinkedList<DropdownMenu<Object>> visibleDropdownMenus;
|
||||||
private int dropdownMenuPaddingY;
|
private int dropdownMenuPaddingY;
|
||||||
private DropdownMenu<Object> openDropdownMenu;
|
private DropdownMenu<Object> openDropdownMenu;
|
||||||
|
@ -195,15 +195,16 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||||
if (section.options == null) {
|
if (section.options == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (final GameOption option : section.options) {
|
for (final Option option : section.options) {
|
||||||
Object[] items = option.getListItems();
|
if (!(option instanceof ListOption)) {
|
||||||
if (items == null) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
final ListOption listOption = (ListOption) option;
|
||||||
|
Object[] items = listOption.getListItems();
|
||||||
DropdownMenu<Object> menu = new DropdownMenu<Object>(displayContainer, items, 0, 0, 0) {
|
DropdownMenu<Object> menu = new DropdownMenu<Object>(displayContainer, items, 0, 0, 0) {
|
||||||
@Override
|
@Override
|
||||||
public void itemSelected(int index, Object item) {
|
public void itemSelected(int index, Object item) {
|
||||||
option.clickListItem(index);
|
listOption.clickListItem(index);
|
||||||
openDropdownMenu = null;
|
openDropdownMenu = null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -224,7 +225,7 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||||
menu.setHighlightColor(COL_COMBOBOX_HOVER);
|
menu.setHighlightColor(COL_COMBOBOX_HOVER);
|
||||||
menu.setTextColor(COL_WHITE);
|
menu.setTextColor(COL_WHITE);
|
||||||
dropdownMenuPaddingY = (optionHeight - menu.getHeight()) / 2;
|
dropdownMenuPaddingY = (optionHeight - menu.getHeight()) / 2;
|
||||||
dropdownMenus.put(option, menu);
|
dropdownMenus.put(listOption, menu);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,8 +302,8 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||||
|
|
||||||
private void renderTooltip(Graphics g) {
|
private void renderTooltip(Graphics g) {
|
||||||
if (hoverOption != null) {
|
if (hoverOption != null) {
|
||||||
String tip = hoverOption.getDescription();
|
String tip = hoverOption.description;
|
||||||
if (hoverOption.getType() == OptionType.NUMERIC) {
|
if (hoverOption instanceof NumericOption) {
|
||||||
tip = "(" + hoverOption.getValueString() + ") " + tip;
|
tip = "(" + hoverOption.getValueString() + ") " + tip;
|
||||||
}
|
}
|
||||||
UI.updateTooltip(displayContainer.renderDelta, tip, true);
|
UI.updateTooltip(displayContainer.renderDelta, tip, true);
|
||||||
|
@ -336,7 +337,7 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||||
}
|
}
|
||||||
int lineHeight = (int) (Fonts.LARGE.getLineHeight() * 0.9f);
|
int lineHeight = (int) (Fonts.LARGE.getLineHeight() * 0.9f);
|
||||||
for (int optionIndex = 0; optionIndex < section.options.length; optionIndex++) {
|
for (int optionIndex = 0; optionIndex < section.options.length; optionIndex++) {
|
||||||
GameOption option = section.options[optionIndex];
|
Option option = section.options[optionIndex];
|
||||||
if (!option.showCondition() || option.isFiltered()) {
|
if (!option.showCondition() || option.isFiltered()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -368,7 +369,7 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||||
if (sections[sectionIndex].options == null) {
|
if (sections[sectionIndex].options == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (GameOption option : sections[sectionIndex].options) {
|
for (Option option : sections[sectionIndex].options) {
|
||||||
if (option.showCondition() && !option.isFiltered()) {
|
if (option.showCondition() && !option.isFiltered()) {
|
||||||
maxScrollOffset += optionHeight;
|
maxScrollOffset += optionHeight;
|
||||||
}
|
}
|
||||||
|
@ -384,24 +385,22 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||||
scrollHandler.setMinMax(0, maxScrollOffset);
|
scrollHandler.setMinMax(0, maxScrollOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderOption(Graphics g, GameOption option, int y) {
|
private void renderOption(Graphics g, Option option, int y) {
|
||||||
OptionType type = option.getType();
|
if (option instanceof ListOption) {
|
||||||
Object[] listItems = option.getListItems();
|
renderListOption(g, (ListOption) option, y);
|
||||||
if (listItems != null) {
|
} else if (option instanceof ToggleOption) {
|
||||||
renderListOption(g, option, y);
|
renderCheckOption((ToggleOption) option, y);
|
||||||
} else if (type == OptionType.BOOLEAN) {
|
} else if (option instanceof NumericOption) {
|
||||||
renderCheckOption(option, y);
|
renderSliderOption(g, (NumericOption) option, y);
|
||||||
} else if (type == OptionType.NUMERIC) {
|
} else if (option instanceof GenericOption) {
|
||||||
renderSliderOption(g, option, y);
|
renderGenericOption((GenericOption) option, y);
|
||||||
} else {
|
|
||||||
renderGenericOption(option, y);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderListOption(Graphics g, GameOption option, int y) {
|
private void renderListOption(Graphics g, ListOption option, int y) {
|
||||||
// draw option name
|
// draw option name
|
||||||
int nameWith = Fonts.MEDIUM.getWidth(option.getName());
|
int nameWith = Fonts.MEDIUM.getWidth(option.name);
|
||||||
Fonts.MEDIUM.drawString(optionStartX, y + optionTextOffsetY, option.getName(), COL_WHITE);
|
Fonts.MEDIUM.drawString(optionStartX, y + optionTextOffsetY, option.name, COL_WHITE);
|
||||||
nameWith += 15;
|
nameWith += 15;
|
||||||
int comboboxStartX = optionStartX + nameWith;
|
int comboboxStartX = optionStartX + nameWith;
|
||||||
int comboboxWidth = optionWidth - nameWith;
|
int comboboxWidth = optionWidth - nameWith;
|
||||||
|
@ -424,19 +423,19 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||||
dropdown.render(g);
|
dropdown.render(g);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderCheckOption(GameOption option, int y) {
|
private void renderCheckOption(ToggleOption option, int y) {
|
||||||
if (option.getBooleanValue()) {
|
if (option.state) {
|
||||||
checkOnImg.draw(optionStartX, y + controlImagePadding, COL_PINK);
|
checkOnImg.draw(optionStartX, y + controlImagePadding, COL_PINK);
|
||||||
} else {
|
} else {
|
||||||
checkOffImg.draw(optionStartX, y + controlImagePadding, COL_PINK);
|
checkOffImg.draw(optionStartX, y + controlImagePadding, COL_PINK);
|
||||||
}
|
}
|
||||||
Fonts.MEDIUM.drawString(optionStartX + 30, y + optionTextOffsetY, option.getName(), COL_WHITE);
|
Fonts.MEDIUM.drawString(optionStartX + 30, y + optionTextOffsetY, option.name, COL_WHITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderSliderOption(Graphics g, GameOption option, int y) {
|
private void renderSliderOption(Graphics g, NumericOption option, int y) {
|
||||||
final int padding = 10;
|
final int padding = 10;
|
||||||
int nameLen = Fonts.MEDIUM.getWidth(option.getName());
|
int nameLen = Fonts.MEDIUM.getWidth(option.name);
|
||||||
Fonts.MEDIUM.drawString(optionStartX, y + optionTextOffsetY, option.getName(), COL_WHITE);
|
Fonts.MEDIUM.drawString(optionStartX, y + optionTextOffsetY, option.name, COL_WHITE);
|
||||||
int sliderLen = optionWidth - nameLen - padding;
|
int sliderLen = optionWidth - nameLen - padding;
|
||||||
if (sliderLen <= 1) {
|
if (sliderLen <= 1) {
|
||||||
return;
|
return;
|
||||||
|
@ -453,7 +452,7 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float sliderValue = (float) (option.getIntegerValue() - option.getMinValue()) / (option.getMaxValue() - option.getMinValue());
|
float sliderValue = (float) (option.val - option.min) / (option.max - option.min);
|
||||||
float sliderBallPos = sliderStartX + (int) ((sliderLen - controlImageSize) * sliderValue);
|
float sliderBallPos = sliderStartX + (int) ((sliderLen - controlImageSize) * sliderValue);
|
||||||
|
|
||||||
g.setLineWidth(3f);
|
g.setLineWidth(3f);
|
||||||
|
@ -471,10 +470,10 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderGenericOption(GameOption option, int y) {
|
private void renderGenericOption(GenericOption option, int y) {
|
||||||
String value = option.getValueString();
|
String value = option.getValueString();
|
||||||
int valueLen = Fonts.MEDIUM.getWidth(value);
|
int valueLen = Fonts.MEDIUM.getWidth(value);
|
||||||
Fonts.MEDIUM.drawString(optionStartX, y + optionTextOffsetY, option.getName(), COL_WHITE);
|
Fonts.MEDIUM.drawString(optionStartX, y + optionTextOffsetY, option.name, COL_WHITE);
|
||||||
Fonts.MEDIUM.drawString(optionStartX + optionWidth - valueLen, y + optionTextOffsetY, value, COL_BLUE);
|
Fonts.MEDIUM.drawString(optionStartX + optionWidth - valueLen, y + optionTextOffsetY, value, COL_BLUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -556,9 +555,9 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||||
updateIndicatorAlpha();
|
updateIndicatorAlpha();
|
||||||
UI.getBackButton().hoverUpdate(delta, mouseX, mouseY);
|
UI.getBackButton().hoverUpdate(delta, mouseX, mouseY);
|
||||||
if (isAdjustingSlider) {
|
if (isAdjustingSlider) {
|
||||||
int sliderValue = hoverOption.getIntegerValue();
|
int sliderValue = ((NumericOption) hoverOption).val;
|
||||||
updateSliderOption();
|
updateSliderOption();
|
||||||
if (hoverOption.getIntegerValue() - sliderValue != 0 && sliderSoundDelay <= 0) {
|
if (((NumericOption) hoverOption).val - sliderValue != 0 && sliderSoundDelay <= 0) {
|
||||||
sliderSoundDelay = 90;
|
sliderSoundDelay = 90;
|
||||||
SoundController.playSound(SoundEffect.MENUHIT);
|
SoundController.playSound(SoundEffect.MENUHIT);
|
||||||
}
|
}
|
||||||
|
@ -634,7 +633,7 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||||
mousePressY = y;
|
mousePressY = y;
|
||||||
selectedOption = hoverOption;
|
selectedOption = hoverOption;
|
||||||
|
|
||||||
if (hoverOption != null && hoverOption.getType() == OptionType.NUMERIC) {
|
if (hoverOption != null && hoverOption instanceof NumericOption) {
|
||||||
isAdjustingSlider = sliderOptionStartX <= x && x < sliderOptionStartX + sliderOptionLength;
|
isAdjustingSlider = sliderOptionStartX <= x && x < sliderOptionStartX + sliderOptionLength;
|
||||||
if (isAdjustingSlider) {
|
if (isAdjustingSlider) {
|
||||||
updateSliderOption();
|
updateSliderOption();
|
||||||
|
@ -678,16 +677,16 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hoverOption != null) {
|
if (hoverOption != null) {
|
||||||
if (hoverOption.getType() == OptionType.BOOLEAN) {
|
if (hoverOption instanceof ToggleOption) {
|
||||||
hoverOption.click();
|
((ToggleOption) hoverOption).toggle();
|
||||||
if (listener != null) {
|
if (listener != null) {
|
||||||
listener.onSaveOption(hoverOption);
|
listener.onSaveOption(hoverOption);
|
||||||
}
|
}
|
||||||
SoundController.playSound(SoundEffect.MENUHIT);
|
SoundController.playSound(SoundEffect.MENUHIT);
|
||||||
return true;
|
return true;
|
||||||
} else if (hoverOption == GameOption.KEY_LEFT) {
|
} else if (hoverOption == OPTION_KEY_LEFT) {
|
||||||
keyEntryLeft = true;
|
keyEntryLeft = true;
|
||||||
} else if (hoverOption == GameOption.KEY_RIGHT) {
|
} else if (hoverOption == OPTION_KEY_RIGHT) {
|
||||||
keyEntryLeft = true;
|
keyEntryLeft = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -724,13 +723,17 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||||
@Override
|
@Override
|
||||||
public boolean onKeyPressed(int key, char c) {
|
public boolean onKeyPressed(int key, char c) {
|
||||||
if (keyEntryRight) {
|
if (keyEntryRight) {
|
||||||
Options.setGameKeyRight(key);
|
if (Utils.isValidGameKey(key)) {
|
||||||
|
OPTION_KEY_RIGHT.intval = key;
|
||||||
|
}
|
||||||
keyEntryRight = false;
|
keyEntryRight = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keyEntryLeft) {
|
if (keyEntryLeft) {
|
||||||
Options.setGameKeyLeft(key);
|
if (Utils.isValidGameKey(key)) {
|
||||||
|
OPTION_KEY_LEFT.intval = key;
|
||||||
|
}
|
||||||
keyEntryLeft = false;
|
keyEntryLeft = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -767,10 +770,9 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateSliderOption() {
|
private void updateSliderOption() {
|
||||||
int min = hoverOption.getMinValue();
|
NumericOption o = (NumericOption) hoverOption;
|
||||||
int max = hoverOption.getMaxValue();
|
int value = o.min + Math.round((float) (o.max - o.min) * (displayContainer.mouseX - sliderOptionStartX) / (sliderOptionLength));
|
||||||
int value = min + Math.round((float) (max - min) * (displayContainer.mouseX - sliderOptionStartX) / (sliderOptionLength));
|
o.setValue(Utils.clamp(value, o.min, o.max));
|
||||||
hoverOption.setValue(Utils.clamp(value, min, max));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateHoverOption(int mouseX, int mouseY) {
|
private void updateHoverOption(int mouseX, int mouseY) {
|
||||||
|
@ -797,7 +799,7 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (int optionIndex = 0; optionIndex < section.options.length; optionIndex++) {
|
for (int optionIndex = 0; optionIndex < section.options.length; optionIndex++) {
|
||||||
GameOption option = section.options[optionIndex];
|
Option option = section.options[optionIndex];
|
||||||
if (option.isFiltered() || !option.showCondition()) {
|
if (option.isFiltered() || !option.showCondition()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -824,7 +826,7 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||||
if (section.options == null) {
|
if (section.options == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (GameOption opt : section.options) {
|
for (Option opt : section.options) {
|
||||||
opt.filter(null);
|
opt.filter(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -844,7 +846,7 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
section.filtered = true;
|
section.filtered = true;
|
||||||
for (GameOption option : section.options) {
|
for (Option option : section.options) {
|
||||||
if (lastBigSectionMatches || sectionMatches) {
|
if (lastBigSectionMatches || sectionMatches) {
|
||||||
section.filtered = false;
|
section.filtered = false;
|
||||||
option.filter(null);
|
option.filter(null);
|
||||||
|
@ -859,24 +861,9 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||||
updateHoverOption(prevMouseX, prevMouseY);
|
updateHoverOption(prevMouseX, prevMouseY);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class OptionTab {
|
|
||||||
|
|
||||||
public final String name;
|
|
||||||
public final GameOption[] options;
|
|
||||||
private boolean filtered;
|
|
||||||
|
|
||||||
public OptionTab(String name, GameOption[] options) {
|
|
||||||
this.name = name;
|
|
||||||
this.options = options;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface Listener {
|
public interface Listener {
|
||||||
|
|
||||||
void onLeaveOptionsMenu();
|
void onLeaveOptionsMenu();
|
||||||
void onSaveOption(GameOption option);
|
void onSaveOption(Option option);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,12 +17,11 @@
|
||||||
*/
|
*/
|
||||||
package yugecin.opsudance.ui;
|
package yugecin.opsudance.ui;
|
||||||
|
|
||||||
import itdelatrisu.opsu.Options;
|
|
||||||
import itdelatrisu.opsu.Options.GameOption;
|
|
||||||
import itdelatrisu.opsu.audio.MusicController;
|
import itdelatrisu.opsu.audio.MusicController;
|
||||||
import itdelatrisu.opsu.objects.GameObject;
|
import itdelatrisu.opsu.objects.GameObject;
|
||||||
import itdelatrisu.opsu.states.Game;
|
import itdelatrisu.opsu.states.Game;
|
||||||
import itdelatrisu.opsu.states.OptionsMenu;
|
import yugecin.opsudance.options.Option;
|
||||||
|
import yugecin.opsudance.options.OptionGroups;
|
||||||
import itdelatrisu.opsu.ui.Fonts;
|
import itdelatrisu.opsu.ui.Fonts;
|
||||||
import org.newdawn.slick.Color;
|
import org.newdawn.slick.Color;
|
||||||
import org.newdawn.slick.Graphics;
|
import org.newdawn.slick.Graphics;
|
||||||
|
@ -30,15 +29,17 @@ import org.newdawn.slick.Input;
|
||||||
import yugecin.opsudance.ObjectColorOverrides;
|
import yugecin.opsudance.ObjectColorOverrides;
|
||||||
import yugecin.opsudance.core.DisplayContainer;
|
import yugecin.opsudance.core.DisplayContainer;
|
||||||
import yugecin.opsudance.core.state.OverlayOpsuState;
|
import yugecin.opsudance.core.state.OverlayOpsuState;
|
||||||
|
import yugecin.opsudance.options.OptionTab;
|
||||||
import yugecin.opsudance.sbv2.MoveStoryboard;
|
import yugecin.opsudance.sbv2.MoveStoryboard;
|
||||||
import yugecin.opsudance.ui.OptionsOverlay.OptionTab;
|
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
import static yugecin.opsudance.options.Options.*;
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public class StoryboardOverlay extends OverlayOpsuState implements OptionsOverlay.Listener {
|
public class StoryboardOverlay extends OverlayOpsuState implements OptionsOverlay.Listener {
|
||||||
|
|
||||||
private final static List<GameOption> optionList = new ArrayList<>();
|
private final static List<Option> optionList = new ArrayList<>();
|
||||||
|
|
||||||
private final DisplayContainer displayContainer;
|
private final DisplayContainer displayContainer;
|
||||||
|
|
||||||
|
@ -47,7 +48,7 @@ public class StoryboardOverlay extends OverlayOpsuState implements OptionsOverla
|
||||||
private int speed;
|
private int speed;
|
||||||
private GameObject[] gameObjects;
|
private GameObject[] gameObjects;
|
||||||
private HashMap[] optionsMap;
|
private HashMap[] optionsMap;
|
||||||
private HashMap<Options.GameOption, String> initialOptions;
|
private HashMap<Option, String> initialOptions;
|
||||||
|
|
||||||
private int index;
|
private int index;
|
||||||
|
|
||||||
|
@ -56,7 +57,7 @@ public class StoryboardOverlay extends OverlayOpsuState implements OptionsOverla
|
||||||
private final OptionsOverlay optionsOverlay;
|
private final OptionsOverlay optionsOverlay;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
for (OptionTab tab : OptionsMenu.storyboardOptions) {
|
for (OptionTab tab : OptionGroups.storyboardOptions) {
|
||||||
optionList.addAll(Arrays.asList(tab.options));
|
optionList.addAll(Arrays.asList(tab.options));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,7 +74,7 @@ public class StoryboardOverlay extends OverlayOpsuState implements OptionsOverla
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRender(Graphics g) {
|
public void onRender(Graphics g) {
|
||||||
if (!Options.isEnableSB() || hide) {
|
if (!OPTION_DANCE_ENABLE_SB.state || hide) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int lh = Fonts.SMALL.getLineHeight();
|
int lh = Fonts.SMALL.getLineHeight();
|
||||||
|
@ -86,8 +87,8 @@ public class StoryboardOverlay extends OverlayOpsuState implements OptionsOverla
|
||||||
if (index < optionsMap.length && optionsMap[index] != null) {
|
if (index < optionsMap.length && optionsMap[index] != null) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (Object o : optionsMap[index].entrySet()) {
|
for (Object o : optionsMap[index].entrySet()) {
|
||||||
Map.Entry<Options.GameOption, String> option = (Map.Entry<Options.GameOption, String>) o;
|
Map.Entry<Option, String> option = (Map.Entry<Option, String>) o;
|
||||||
Fonts.SMALL.drawString(10, 50 + i * lh, option.getKey().getName(), Color.cyan);
|
Fonts.SMALL.drawString(10, 50 + i * lh, option.getKey().name, Color.cyan);
|
||||||
Fonts.SMALL.drawString(displayContainer.width / 5, 50 + i * lh, option.getKey().getValueString(), Color.cyan);
|
Fonts.SMALL.drawString(displayContainer.width / 5, 50 + i * lh, option.getKey().getValueString(), Color.cyan);
|
||||||
g.fillRect(0, 50 + i * lh + lh / 4, 10, 10);
|
g.fillRect(0, 50 + i * lh + lh / 4, 10, 10);
|
||||||
i++;
|
i++;
|
||||||
|
@ -177,7 +178,7 @@ public class StoryboardOverlay extends OverlayOpsuState implements OptionsOverla
|
||||||
if (optionsMap.length > 0) {
|
if (optionsMap.length > 0) {
|
||||||
// copy all current settings in first obj map
|
// copy all current settings in first obj map
|
||||||
optionsMap[0] = new HashMap<>();
|
optionsMap[0] = new HashMap<>();
|
||||||
for (Options.GameOption o : optionList) {
|
for (Option o : optionList) {
|
||||||
optionsMap[0].put(o, o.write());
|
optionsMap[0].put(o, o.write());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -210,7 +211,7 @@ public class StoryboardOverlay extends OverlayOpsuState implements OptionsOverla
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (Object o : options.entrySet()) {
|
for (Object o : options.entrySet()) {
|
||||||
Map.Entry<Options.GameOption, String> next = (Map.Entry<Options.GameOption, String>) o;
|
Map.Entry<Option, String> next = (Map.Entry<Option, String>) o;
|
||||||
next.getKey().read(next.getValue());
|
next.getKey().read(next.getValue());
|
||||||
readOption(next.getKey());
|
readOption(next.getKey());
|
||||||
}
|
}
|
||||||
|
@ -227,7 +228,7 @@ public class StoryboardOverlay extends OverlayOpsuState implements OptionsOverla
|
||||||
int ypos = 50 + lh / 4;
|
int ypos = 50 + lh / 4;
|
||||||
for (Object o : optionsMap[index].entrySet()) {
|
for (Object o : optionsMap[index].entrySet()) {
|
||||||
if (y >= ypos && y <= ypos + 10) {
|
if (y >= ypos && y <= ypos + 10) {
|
||||||
optionsMap[index].remove(((Map.Entry<Options.GameOption, String>) o).getKey());
|
optionsMap[index].remove(((Map.Entry<Option, String>) o).getKey());
|
||||||
if (optionsMap[index].size() == 0) {
|
if (optionsMap[index].size() == 0) {
|
||||||
optionsMap[index] = null;
|
optionsMap[index] = null;
|
||||||
}
|
}
|
||||||
|
@ -246,7 +247,7 @@ public class StoryboardOverlay extends OverlayOpsuState implements OptionsOverla
|
||||||
|
|
||||||
public void onEnter() {
|
public void onEnter() {
|
||||||
// enter, save current settings
|
// enter, save current settings
|
||||||
for (Options.GameOption o : optionList) {
|
for (Option o : optionList) {
|
||||||
initialOptions.put(o, o.write());
|
initialOptions.put(o, o.write());
|
||||||
}
|
}
|
||||||
speed = 10;
|
speed = 10;
|
||||||
|
@ -254,7 +255,7 @@ public class StoryboardOverlay extends OverlayOpsuState implements OptionsOverla
|
||||||
|
|
||||||
public void onLeave() {
|
public void onLeave() {
|
||||||
// leave, revert the settings saved before entering
|
// leave, revert the settings saved before entering
|
||||||
for (Options.GameOption o : optionList) {
|
for (Option o : optionList) {
|
||||||
if (initialOptions.containsKey(o)) {
|
if (initialOptions.containsKey(o)) {
|
||||||
o.read(initialOptions.get(o));
|
o.read(initialOptions.get(o));
|
||||||
readOption(o);
|
readOption(o);
|
||||||
|
@ -263,10 +264,10 @@ public class StoryboardOverlay extends OverlayOpsuState implements OptionsOverla
|
||||||
}
|
}
|
||||||
|
|
||||||
// needed for object color overrides...
|
// needed for object color overrides...
|
||||||
private void readOption(Options.GameOption o) {
|
private void readOption(Option o) {
|
||||||
if (o == Options.GameOption.DANCE_OBJECT_COLOR_OVERRIDE
|
if (o == OPTION_DANCE_OBJECT_COLOR_OVERRIDE
|
||||||
|| o == Options.GameOption.DANCE_OBJECT_COLOR_OVERRIDE_MIRRORED
|
|| o == OPTION_DANCE_OBJECT_COLOR_OVERRIDE_MIRRORED
|
||||||
|| o == Options.GameOption.DANCE_RGB_OBJECT_INC) {
|
|| o == OPTION_DANCE_RGB_OBJECT_INC) {
|
||||||
if (index < gameObjects.length) {
|
if (index < gameObjects.length) {
|
||||||
ObjectColorOverrides.hue = gameObjects[index].getHue();
|
ObjectColorOverrides.hue = gameObjects[index].getHue();
|
||||||
}
|
}
|
||||||
|
@ -284,7 +285,7 @@ public class StoryboardOverlay extends OverlayOpsuState implements OptionsOverla
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSaveOption(GameOption option) {
|
public void onSaveOption(Option option) {
|
||||||
if (optionsMap[index] == null) {
|
if (optionsMap[index] == null) {
|
||||||
optionsMap[index] = new HashMap<>();
|
optionsMap[index] = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user