diff --git a/CREDITS.md b/CREDITS.md
index d528d86e..a3b0d880 100644
--- a/CREDITS.md
+++ b/CREDITS.md
@@ -21,6 +21,7 @@ The images included in opsu! belong to their respective authors.
* kouyang
* teinecthel
* Font Awesome by Dave Gandy - http://fontawesome.io
+* Chaaoos/C0N - the opsu!dance logo
Projects
--------
@@ -32,5 +33,4 @@ The following projects were referenced in creating opsu!:
Theme Song
----------
-The theme song is "On the Bach" by Jingle Punks, from the [YouTube Audio Library]
-(https://www.youtube.com/audiolibrary/music).
+The theme song is "On the Bach" by Jingle Punks, from the [YouTube Audio Library](https://www.youtube.com/audiolibrary/music).
diff --git a/README.md b/README.md
index b16118d5..a6df6f85 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
**Table of contents**
-* [What](#What) - [Why](#why) - [Downloads](#downloads) - [Running](#running) - [Building a JAR](#building-a-jar) - [Credits](#credits) - [License](#license)
+* [What](#what) - [Why](#why) - [Downloads](#downloads) - [Running](#running) - [Building a JAR](#building-a-jar) - [Credits](#credits) - [License](#license)
What
----
@@ -38,10 +38,7 @@ You should know how to do this. It's recommended to use a working directory like
### Using apache ant
-Resolve dependencies first, use either:
-
-* `ant ivyresolve` to download dependencies using apache ivy
-* `ant mvnresolve` to download dependencies using apache mvn
+Resolve dependencies first by doing `ant mvnresolve` or `mvn initialize`
Then do `ant run`
diff --git a/build.xml b/build.xml
index b24b89de..938decb3 100644
--- a/build.xml
+++ b/build.xml
@@ -1,9 +1,8 @@
-
+
-
@@ -21,14 +20,12 @@
ant clean --> clean the ant working dir
ant cleanlib --> clean the lib folder
-ant ivyresolve --> resolve dependencies using ivy
ant mvnresolve --> resolve dependencies using mvn
ant compile --> compile the code
ant run --> prepare to run and run
ant jar --> package a jar
-resolve dependencies first
-(using either mvnresolve or ivyresolve),
+resolve dependencies first (mvnresolve)
then run (code is compiled automatically when you run)
@@ -40,12 +37,6 @@ then run (code is compiled automatically when you run)
-
-
-
-
-
-
@@ -119,9 +110,6 @@ then run (code is compiled automatically when you run)
-
-
-
diff --git a/ivy.xml b/ivy.xml
deleted file mode 100644
index 1573a486..00000000
--- a/ivy.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 9a19f00a..8ddbaf43 100644
--- a/pom.xml
+++ b/pom.xml
@@ -8,12 +8,12 @@
opsu-dance
0.5.0-SNAPSHOT
+ target/Natives
UTF-8
${project.version}
${maven.build.timestamp}
yyyy-MM-dd HH:mm
yugecin.opsudance.core.Entrypoint
- false
src
@@ -147,10 +147,6 @@
${mainClassName}
- ${XDG}
- OpenAL32.dll,OpenAL64.dll,lwjgl.dll,lwjgl64.dll
- liblwjgl.so,liblwjgl64.so,libopenal.so,libopenal64.so
- liblwjgl.dylib,openal.dylib
@@ -236,11 +232,6 @@
jna-platform
4.1.0
-
- org.apache.maven
- maven-artifact
- 3.3.3
-
org.apache.commons
commons-compress
@@ -263,4 +254,4 @@
-
\ No newline at end of file
+
diff --git a/res/epiwarning.pdn b/res/epiwarning.pdn
new file mode 100644
index 00000000..07b2daa7
Binary files /dev/null and b/res/epiwarning.pdn differ
diff --git a/res/icon16.png b/res/icon16.png
index c6e71e06..39db77a7 100644
Binary files a/res/icon16.png and b/res/icon16.png differ
diff --git a/res/icon32.png b/res/icon32.png
index 412f623d..12176ee0 100644
Binary files a/res/icon32.png and b/res/icon32.png differ
diff --git a/res/icon48dp.png b/res/icon48dp.png
deleted file mode 100644
index 60c770cb..00000000
Binary files a/res/icon48dp.png and /dev/null differ
diff --git a/res/logo.png b/res/logo.png
deleted file mode 100644
index 3f59daec..00000000
Binary files a/res/logo.png and /dev/null differ
diff --git a/res/logo2piece.png b/res/logo2piece.png
new file mode 100644
index 00000000..1fae6bdd
Binary files /dev/null and b/res/logo2piece.png differ
diff --git a/res/logo2piece2.png b/res/logo2piece2.png
deleted file mode 100644
index 35484e97..00000000
Binary files a/res/logo2piece2.png and /dev/null differ
diff --git a/res/logo2pulse.png b/res/logo2pulse.png
new file mode 100644
index 00000000..e37d38ec
Binary files /dev/null and b/res/logo2pulse.png differ
diff --git a/res/menu-back.png b/res/menu-back.png
index e3678753..34f690b7 100644
Binary files a/res/menu-back.png and b/res/menu-back.png differ
diff --git a/res/menu-background.jpg b/res/menu-background.jpg
deleted file mode 100644
index 92bcd310..00000000
Binary files a/res/menu-background.jpg and /dev/null differ
diff --git a/res/menu-background.pdn b/res/menu-background.pdn
new file mode 100644
index 00000000..3dddfaec
Binary files /dev/null and b/res/menu-background.pdn differ
diff --git a/res/menu-background.png b/res/menu-background.png
new file mode 100644
index 00000000..da2dccd9
Binary files /dev/null and b/res/menu-background.png differ
diff --git a/res/menu-exit.png b/res/menu-exit.png
index 79a484b7..8faf6a19 100644
Binary files a/res/menu-exit.png and b/res/menu-exit.png differ
diff --git a/res/menu-exit2.png b/res/menu-exit2.png
deleted file mode 100644
index 7acd9900..00000000
Binary files a/res/menu-exit2.png and /dev/null differ
diff --git a/res/menu-options-1.pdn b/res/menu-options-1.pdn
new file mode 100644
index 00000000..25d63320
Binary files /dev/null and b/res/menu-options-1.pdn differ
diff --git a/res/menu-options-2.pdn b/res/menu-options-2.pdn
new file mode 100644
index 00000000..edeeb5c8
Binary files /dev/null and b/res/menu-options-2.pdn differ
diff --git a/res/menu-options-3.pdn b/res/menu-options-3.pdn
new file mode 100644
index 00000000..457260e7
Binary files /dev/null and b/res/menu-options-3.pdn differ
diff --git a/res/menu-options-background.pdn b/res/menu-options-background.pdn
new file mode 100644
index 00000000..e51aa575
Binary files /dev/null and b/res/menu-options-background.pdn differ
diff --git a/res/menu-options.pdn b/res/menu-options.pdn
new file mode 100644
index 00000000..3e611d88
Binary files /dev/null and b/res/menu-options.pdn differ
diff --git a/res/menu-options.png b/res/menu-options.png
new file mode 100644
index 00000000..90ce46e6
Binary files /dev/null and b/res/menu-options.png differ
diff --git a/res/menu-play.png b/res/menu-play.png
index 4ecd2c72..6bab54c4 100644
Binary files a/res/menu-play.png and b/res/menu-play.png differ
diff --git a/res/menu-play2.png b/res/menu-play2.png
deleted file mode 100644
index 0ba86471..00000000
Binary files a/res/menu-play2.png and /dev/null differ
diff --git a/res/music-next.png b/res/music-next.png
index f600ef30..5838b17d 100644
Binary files a/res/music-next.png and b/res/music-next.png differ
diff --git a/res/music-np-bg-black.png b/res/music-np-bg-black.png
new file mode 100644
index 00000000..5c83f2d0
Binary files /dev/null and b/res/music-np-bg-black.png differ
diff --git a/res/music-np-bg-white.png b/res/music-np-bg-white.png
new file mode 100644
index 00000000..fd1f7005
Binary files /dev/null and b/res/music-np-bg-white.png differ
diff --git a/res/music-np.pdn b/res/music-np.pdn
new file mode 100644
index 00000000..ffacaef9
Binary files /dev/null and b/res/music-np.pdn differ
diff --git a/res/music-np.png b/res/music-np.png
new file mode 100644
index 00000000..a1b406cf
Binary files /dev/null and b/res/music-np.png differ
diff --git a/res/music-pause.png b/res/music-pause.png
index 1df82839..f61d58bd 100644
Binary files a/res/music-pause.png and b/res/music-pause.png differ
diff --git a/res/music-play.png b/res/music-play.png
index 5cf7d9c4..7ff5ed28 100644
Binary files a/res/music-play.png and b/res/music-play.png differ
diff --git a/res/music-previous.png b/res/music-previous.png
index 799f405c..1e0cec9c 100644
Binary files a/res/music-previous.png and b/res/music-previous.png differ
diff --git a/res/music-stop.png b/res/music-stop.png
new file mode 100644
index 00000000..988a4271
Binary files /dev/null and b/res/music-stop.png differ
diff --git a/res/options-background.png b/res/options-background.png
deleted file mode 100644
index 10612e32..00000000
Binary files a/res/options-background.png and /dev/null differ
diff --git a/res/playfield.png b/res/playfield.png
index e7f45899..34f690b7 100644
Binary files a/res/playfield.png and b/res/playfield.png differ
diff --git a/res/selection-mode-over.png b/res/selection-mode-over.png
new file mode 100644
index 00000000..1833f567
Binary files /dev/null and b/res/selection-mode-over.png differ
diff --git a/res/selection-mode.png b/res/selection-mode.png
new file mode 100644
index 00000000..cd2a9c1f
Binary files /dev/null and b/res/selection-mode.png differ
diff --git a/res/selection-mods-over.png b/res/selection-mods-over.png
index 890daa54..37fd4d2a 100644
Binary files a/res/selection-mods-over.png and b/res/selection-mods-over.png differ
diff --git a/res/selection-mods.png b/res/selection-mods.png
index 53078a2e..743bd47b 100644
Binary files a/res/selection-mods.png and b/res/selection-mods.png differ
diff --git a/res/selection-options-over.png b/res/selection-options-over.png
index ab5f95e5..b252e5a9 100644
Binary files a/res/selection-options-over.png and b/res/selection-options-over.png differ
diff --git a/res/selection-options.png b/res/selection-options.png
index f94051fe..cc9e730d 100644
Binary files a/res/selection-options.png and b/res/selection-options.png differ
diff --git a/res/selection-random-over.png b/res/selection-random-over.png
index 9daf6072..adc6a1e8 100644
Binary files a/res/selection-random-over.png and b/res/selection-random-over.png differ
diff --git a/res/selection-random.png b/res/selection-random.png
index 8afd55d3..11d7698c 100644
Binary files a/res/selection-random.png and b/res/selection-random.png differ
diff --git a/res/selection-selectoptions-over.png b/res/selection-selectoptions-over.png
deleted file mode 100644
index 27af71de..00000000
Binary files a/res/selection-selectoptions-over.png and /dev/null differ
diff --git a/res/selection-selectoptions.png b/res/selection-selectoptions.png
deleted file mode 100644
index ab60811f..00000000
Binary files a/res/selection-selectoptions.png and /dev/null differ
diff --git a/src/awlex/ospu/FakeGameObject.java b/src/awlex/ospu/FakeGameObject.java
index 0ce5c963..b474acc2 100644
--- a/src/awlex/ospu/FakeGameObject.java
+++ b/src/awlex/ospu/FakeGameObject.java
@@ -10,7 +10,7 @@ import itdelatrisu.opsu.objects.curves.Vec2f;
import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
-import static yugecin.opsudance.core.InstanceContainer.displayContainer;
+import static yugecin.opsudance.core.InstanceContainer.*;
/**
* This class is just a dummy {@link GameObject} to place in the middle of 2 GameObjects.
@@ -24,8 +24,8 @@ public class FakeGameObject extends GameObject {
public FakeGameObject() {
this.start = new Vec2f();
this.end = new Vec2f();
- this.start.x = this.end.x = displayContainer.width / 2;
- this.start.y = this.end.y = displayContainer.height / 2;
+ this.start.x = this.end.x = width2;
+ this.start.y = this.end.y = height2;
}
public FakeGameObject(GameObject start, GameObject end) {
diff --git a/src/awlex/ospu/movers/CombinedSpiralMover.java b/src/awlex/ospu/movers/CombinedSpiralMover.java
index 04729047..b44dd178 100644
--- a/src/awlex/ospu/movers/CombinedSpiralMover.java
+++ b/src/awlex/ospu/movers/CombinedSpiralMover.java
@@ -131,6 +131,6 @@ public class CombinedSpiralMover extends Mover {
}
private boolean checkBounds(double[] pos) {
- return 0 < pos[0] && pos[0] < displayContainer.width && 0 < pos[1] && pos[1] < displayContainer.height;
+ return 0 < pos[0] && pos[0] < width && 0 < pos[1] && pos[1] < height;
}
}
diff --git a/src/awlex/ospu/movers/factories/SpiralMoverFactory.java b/src/awlex/ospu/movers/factories/SpiralMoverFactory.java
index f24a527c..f7e142c7 100644
--- a/src/awlex/ospu/movers/factories/SpiralMoverFactory.java
+++ b/src/awlex/ospu/movers/factories/SpiralMoverFactory.java
@@ -8,7 +8,7 @@ import yugecin.opsudance.movers.Mover;
import awlex.ospu.movers.SpiralToMover;
import yugecin.opsudance.movers.factories.MoverFactory;
-import static yugecin.opsudance.core.InstanceContainer.displayContainer;
+import static yugecin.opsudance.core.InstanceContainer.*;
/**
* Created by Alex Wieser on 09.10.2016.
@@ -88,7 +88,7 @@ public class SpiralMoverFactory implements MoverFactory {
* @return
*/
private boolean checkBounds(double[] pos) {
- return 0 < pos[0] && pos[0] < displayContainer.width && 0 < pos[1] && pos[1] < displayContainer.height;
+ return 0 < pos[0] && pos[0] < width && 0 < pos[1] && pos[1] < height;
}
@Override
diff --git a/src/awlex/ospu/spinners/SpiralSpinner.java b/src/awlex/ospu/spinners/SpiralSpinner.java
index 50fa9295..20104fd9 100644
--- a/src/awlex/ospu/spinners/SpiralSpinner.java
+++ b/src/awlex/ospu/spinners/SpiralSpinner.java
@@ -43,18 +43,16 @@ public class SpiralSpinner extends Spinner {
double ang;
double rad;
for (int i = 0; i < SIZE / 2; i++) {
- MAX_RAD = (int) (displayContainer.height * .35);
+ MAX_RAD = (int) (height * .35);
ang = (DENSITY * (Math.PI / SIZE) * i);
rad = (MAX_RAD / (SIZE / 2)) * i;
- int offsetX = displayContainer.width / 2;
- int offsetY = displayContainer.height / 2;
points[SIZE / 2 - 1 - i] = new double[]{
- offsetX + rad * Math.cos(ang),
- offsetY + rad * Math.sin(ang)
+ width2 + rad * Math.cos(ang),
+ height2 + rad * Math.sin(ang)
};
points[SIZE / 2 + i] = new double[]{
- offsetX + rad * (Math.cos(ang) * Math.cos(Math.PI) - Math.sin(ang) * Math.sin(Math.PI)),
- offsetY + rad * -Math.sin(ang)
+ width2 + rad * (Math.cos(ang) * Math.cos(Math.PI) - Math.sin(ang) * Math.sin(Math.PI)),
+ height2 + rad * -Math.sin(ang)
};
}
}
@@ -84,12 +82,12 @@ public class SpiralSpinner extends Spinner {
}
private void rotatePointAroundCenter(double[] point, double beta) {
- double angle = Math.atan2(point[1] - displayContainer.height / 2, point[0] - displayContainer.width / 2);
- double rad = Utils.distance(point[0], point[1], displayContainer.width / 2, displayContainer.height / 2);
+ double angle = Math.atan2(point[1] - height2, point[0] - width2);
+ double rad = Utils.distance(point[0], point[1], width2, height2);
//rotationMatrix
- point[0] = displayContainer.width / 2 + rad * (Math.cos(angle) * Math.cos(beta) - Math.sin(angle) * Math.sin(beta));
- point[1] = displayContainer.height / 2 + rad * (Math.cos(angle) * Math.sin(beta) + Math.sin(angle) * Math.cos(beta));
+ point[0] = width2 + rad * (Math.cos(angle) * Math.cos(beta) - Math.sin(angle) * Math.sin(beta));
+ point[1] = height2 + rad * (Math.cos(angle) * Math.sin(beta) + Math.sin(angle) * Math.cos(beta));
}
diff --git a/src/itdelatrisu/opsu/GameData.java b/src/itdelatrisu/opsu/GameData.java
index c45c8945..be9fe557 100644
--- a/src/itdelatrisu/opsu/GameData.java
+++ b/src/itdelatrisu/opsu/GameData.java
@@ -603,8 +603,6 @@ public class GameData {
*/
@SuppressWarnings("deprecation")
public void drawGameElements(Graphics g, boolean breakPeriod, boolean firstObject, float alpha) {
- int width = displayContainer.width;
- int height = displayContainer.height;
boolean relaxAutoPilot = (GameMod.RELAX.isActive() || GameMod.AUTOPILOT.isActive());
int margin = (int) (width * 0.008f);
float uiScale = GameImage.getUIscale();
@@ -796,9 +794,6 @@ public class GameData {
* @param beatmap the beatmap
*/
public void drawRankingElements(Graphics g, Beatmap beatmap) {
- int width = displayContainer.width;
- int height = displayContainer.height;
-
// TODO Version 2 skins
float rankingHeight = 75;
float scoreTextScale = 1.0f;
@@ -863,7 +858,7 @@ public class GameData {
if (comboMax == fullObjectCount) {
GameImage.RANKING_PERFECT.getImage().draw(
width * 0.08f,
- (height * 0.99f) - GameImage.RANKING_PERFECT.getImage().getHeight()
+ (height * 0.99f) - GameImage.RANKING_PERFECT.getHeight()
);
}
@@ -911,7 +906,7 @@ public class GameData {
if (hitResult.hitResultType == HitObjectType.SPINNER && hitResult.result != HIT_MISS) {
Image spinnerOsu = GameImage.SPINNER_OSU.getImage();
spinnerOsu.setAlpha(hitResult.alpha);
- spinnerOsu.drawCentered(displayContainer.width / 2, displayContainer.height / 4);
+ spinnerOsu.drawCentered(width2, height / 4);
spinnerOsu.setAlpha(1f);
} else if (OPTION_SHOW_HIT_LIGHTING.state && !hitResult.hideResult && hitResult.result != HIT_MISS &&
// hit lighting
@@ -1185,7 +1180,7 @@ public class GameData {
// combo burst
if (comboBurstIndex > -1 && OPTION_SHOW_COMBO_BURSTS.state) {
int leftX = 0;
- int rightX = displayContainer.width - comboBurstImages[comboBurstIndex].getWidth();
+ int rightX = width - comboBurstImages[comboBurstIndex].getWidth();
if (comboBurstX < leftX) {
comboBurstX += (delta / 2f) * GameImage.getUIscale();
if (comboBurstX > leftX)
@@ -1246,7 +1241,7 @@ public class GameData {
}
comboBurstAlpha = 0.8f;
if ((comboBurstIndex % 2) == 0) {
- comboBurstX = displayContainer.width;
+ comboBurstX = width;
} else {
comboBurstX = comboBurstImages[0].getWidth() * -1;
}
diff --git a/src/itdelatrisu/opsu/GameImage.java b/src/itdelatrisu/opsu/GameImage.java
index 68002fc5..183335ab 100644
--- a/src/itdelatrisu/opsu/GameImage.java
+++ b/src/itdelatrisu/opsu/GameImage.java
@@ -18,7 +18,6 @@
package itdelatrisu.opsu;
-import itdelatrisu.opsu.ui.Colors;
import itdelatrisu.opsu.ui.Fonts;
import java.io.File;
@@ -31,10 +30,11 @@ import org.newdawn.slick.SlickException;
import org.newdawn.slick.util.Log;
import org.newdawn.slick.util.ResourceLoader;
import yugecin.opsudance.core.errorhandling.ErrorHandler;
-import yugecin.opsudance.events.BubNotifListener;
import yugecin.opsudance.skinning.SkinService;
import yugecin.opsudance.utils.SlickUtil;
+import static itdelatrisu.opsu.ui.Colors.*;
+import static yugecin.opsudance.core.InstanceContainer.*;
import static yugecin.opsudance.options.Options.*;
/**
@@ -90,7 +90,9 @@ public enum GameImage {
PLAYFIELD ("playfield", "png|jpg", false, false) {
@Override
protected Image process_sub(Image img, int w, int h) {
- img.setAlpha(0.7f);
+ if (img.getWidth() == 1 && img.getHeight() == 1) {
+ img = MENU_BG.getImage().getFlippedCopy(/*h*/ false, /*v*/ true);
+ }
return img.getScaledCopy(w, h);
}
},
@@ -230,14 +232,14 @@ public enum GameImage {
MOD_AUTOPILOT ("selection-mod-relax2", "png", false, false),
// Selection Buttons
+ SELECTION_MODE ("selection-mode", "png", false, false),
+ SELECTION_MODE_OVERLAY ("selection-mode-over", "png", false, false),
SELECTION_MODS ("selection-mods", "png", false, false),
SELECTION_MODS_OVERLAY ("selection-mods-over", "png", false, false),
SELECTION_RANDOM ("selection-random", "png", false, false),
SELECTION_RANDOM_OVERLAY ("selection-random-over", "png", false, false),
SELECTION_OPTIONS ("selection-options", "png", false, false),
SELECTION_OPTIONS_OVERLAY ("selection-options-over", "png", false, false),
- SELECTION_OTHER_OPTIONS ("selection-selectoptions", "png", false, false),
- SELECTION_OTHER_OPTIONS_OVERLAY ("selection-selectoptions-over", "png", false, false),
// Replay Speed Buttons
REPLAY_PLAYBACK_NORMAL ("playback-normal", "png", false, false),
@@ -299,25 +301,37 @@ public enum GameImage {
MENU_LOGO ("logo2", "png", false, true) {
@Override
protected Image process_sub(Image img, int w, int h) {
- return img.getScaledCopy(0.8f);
+ return img.getScaledCopy(0.75f);
}
},
- MENU_LOGO_PIECE ("logo2piece2", "png", false, true) {
+ MENU_LOGO_PIECE ("logo2piece", "png", false, true) {
@Override
protected Image process_sub(Image img, int w, int h) {
- return img.getScaledCopy(0.8f);
+ return img.getScaledCopy(0.75f);
}
},
- MENU_PLAY ("menu-play2", "png", false, false) {
+ MENU_LOGO_PULSE ("logo2pulse", "png", false, true) {
@Override
protected Image process_sub(Image img, int w, int h) {
- return img.getScaledCopy(0.8f);
+ return img.getScaledCopy(0.75f);
}
},
- MENU_EXIT ("menu-exit2", "png", false, false) {
+ MENU_PLAY ("menu-play", "png", false, false) {
@Override
protected Image process_sub(Image img, int w, int h) {
- return img.getScaledCopy(0.8f);
+ return img.getScaledCopy(0.75f);
+ }
+ },
+ MENU_EXIT ("menu-exit", "png", false, false) {
+ @Override
+ protected Image process_sub(Image img, int w, int h) {
+ return img.getScaledCopy(0.75f);
+ }
+ },
+ MENU_OPTIONS ("menu-options", "png", false, false) {
+ @Override
+ protected Image process_sub(Image img, int w, int h) {
+ return img.getScaledCopy(0.75f);
}
},
MENU_BUTTON_MID ("button-middle", "png", false, false),
@@ -326,21 +340,25 @@ public enum GameImage {
STAR ("star", "png", false, false) {
@Override
protected Image process_sub(Image img, int w, int h) {
- return img.getScaledCopy((MENU_BUTTON_BG.getImage().getHeight() * 0.16f) / img.getHeight());
+ return img.getScaledCopy((MENU_BUTTON_BG.getHeight() * 0.16f) / img.getHeight());
}
},
STAR2 ("star2", "png", false, false) {
@Override
protected Image process_sub(Image img, int w, int h) {
- return img.getScaledCopy((MENU_BUTTON_BG.getImage().getHeight() * 0.33f) / img.getHeight());
+ return img.getScaledCopy((MENU_BUTTON_BG.getHeight() * 0.33f) / img.getHeight());
}
},
// Music Player Buttons
MUSIC_PLAY ("music-play", "png", false, false),
MUSIC_PAUSE ("music-pause", "png", false, false),
+ MUSIC_STOP ("music-stop", "png", false, false),
MUSIC_NEXT ("music-next", "png", false, false),
MUSIC_PREVIOUS ("music-previous", "png", false, false),
+ MUSIC_NOWPLAYING ("music-np", "png", false, false),
+ MUSIC_NOWPLAYING_BG_BLACK ("music-np-bg-black", "png", false, false),
+ MUSIC_NOWPLAYING_BG_WHITE ("music-np-bg-white", "png", false, false),
DOWNLOADS ("downloads", "png", false, false) {
@Override
@@ -386,13 +404,6 @@ public enum GameImage {
return img.getScaledCopy((h / 14f) / img.getHeight());
}
},
- OPTIONS_BG ("options-background", "png|jpg", false, true) {
- @Override
- protected Image process_sub(Image img, int w, int h) {
- img.setAlpha(0.7f);
- return img.getScaledCopy(w, h);
- }
- },
CHEVRON_DOWN ("chevron-down", "png", false, false),
CHEVRON_RIGHT ("chevron-right", "png", false, false),
@@ -646,6 +657,30 @@ public enum GameImage {
return (skinImage != null) ? skinImage : defaultImage;
}
+ public int getHeight() {
+ return getImage().getHeight();
+ }
+
+ public int getWidth() {
+ return getImage().getWidth();
+ }
+
+ /**
+ * Returns the image associated with this resource, with a scale applied.
+ * The beatmap skin image takes priority over the default image.
+ */
+ public Image getScaledImage(float scale) {
+ return this.getImage().getScaledCopy(scale);
+ }
+
+ /**
+ * Returns the image associated with this resource, with a scale applied.
+ * The beatmap skin image takes priority over the default image.
+ */
+ public Image getScaledImage(int width, int height) {
+ return this.getImage().getScaledCopy(width, height);
+ }
+
/**
* Returns an Animation based on the image array.
* If no image array exists, returns the single image as an animation.
@@ -743,7 +778,7 @@ public enum GameImage {
String err = String.format("Could not find default image '%s'.", filename);
Log.warn(err);
- BubNotifListener.EVENT.make().onBubNotif(err, Colors.BUB_RED);
+ bubNotifs.send(BUB_RED, err);
}
/**
@@ -806,8 +841,7 @@ public enum GameImage {
img = img.getScaledCopy(0.5f);
list.add(img);
} catch (SlickException e) {
- BubNotifListener.EVENT.make().onBubNotif(
- String.format("Failed to set image '%s'.", name), Colors.BUB_RED);
+ bubNotifs.sendf(BUB_RED, "Failed to set image '%s'.", name);
break;
}
}
@@ -834,8 +868,7 @@ public enum GameImage {
img = img.getScaledCopy(0.5f);
return img;
} catch (SlickException e) {
- BubNotifListener.EVENT.make().onBubNotif(
- String.format("Failed to set image '%s'.", filename), Colors.BUB_RED);
+ bubNotifs.sendf(BUB_RED, "Failed to set image '%s'.", filename);
}
}
return null;
diff --git a/src/itdelatrisu/opsu/GameMod.java b/src/itdelatrisu/opsu/GameMod.java
index 8449db60..7a0ed8e5 100644
--- a/src/itdelatrisu/opsu/GameMod.java
+++ b/src/itdelatrisu/opsu/GameMod.java
@@ -100,7 +100,7 @@ public enum GameMod {
*/
public void init(int width, int height) {
float multY = Fonts.LARGE.getLineHeight() * 2 + height * 0.06f;
- float offsetY = GameImage.MOD_EASY.getImage().getHeight() * 1.5f;
+ float offsetY = GameImage.MOD_EASY.getHeight() * 1.5f;
this.x = width / 30f;
this.y = multY + Fonts.LARGE.getLineHeight() * 3f + offsetY * index;
}
@@ -193,7 +193,7 @@ public enum GameMod {
// create buttons
float baseX = Category.EASY.getX() + Fonts.LARGE.getWidth(Category.EASY.getName()) * 1.25f;
- float offsetX = GameImage.MOD_EASY.getImage().getWidth() * 2.1f;
+ float offsetX = GameImage.MOD_EASY.getWidth() * 2.1f;
for (GameMod mod : GameMod.values()) {
Image img = mod.image.getImage();
mod.button = new MenuButton(img,
diff --git a/src/itdelatrisu/opsu/NativeLoader.java b/src/itdelatrisu/opsu/NativeLoader.java
index 840fc9b5..c6338619 100644
--- a/src/itdelatrisu/opsu/NativeLoader.java
+++ b/src/itdelatrisu/opsu/NativeLoader.java
@@ -19,7 +19,6 @@
package itdelatrisu.opsu;
import org.newdawn.slick.util.Log;
-import yugecin.opsudance.utils.ManifestWrapper;
import java.io.File;
import java.io.IOException;
@@ -50,42 +49,32 @@ public class NativeLoader {
* Unpacks natives for the current operating system to the natives directory.
* @throws IOException if an I/O exception occurs
*/
- public static void loadNatives(JarFile jarfile, ManifestWrapper manifest) throws IOException {
+ public static void loadNatives(JarFile jarfile) throws IOException {
if (!config.NATIVE_DIR.exists() && !config.NATIVE_DIR.mkdir()) {
String msg = String.format("Could not create folder '%s'",
config.NATIVE_DIR.getAbsolutePath());
throw new RuntimeException(msg);
}
- String osName = System.getProperty("os.name");
- String nativekey = null;
+ final String osName = System.getProperty("os.name");
+ final String[] files;
if (osName.startsWith("Win")) {
- nativekey = "WinNatives";
+ files = new String[] { "OpenAL32.dll", "OpenAL64.dll", "lwjgl.dll", "lwjgl64.dll" };
} else if (osName.startsWith("Linux")) {
- nativekey = "NixNatives";
+ files = new String[] { "liblwjgl.so", "liblwjgl64.so", "libopenal.so", "libopenal64.so" };
} else if (osName.startsWith("Mac") || osName.startsWith("Darwin")) {
- nativekey = "MacNatives";
- }
-
- if (nativekey == null) {
+ files = new String[] { "liblwjgl.dylib", "openal.dylib" };
+ } else {
Log.warn("Cannot determine natives for os " + osName);
return;
}
- String natives = manifest.valueOrDefault(null, nativekey, null);
- if (natives == null) {
- String msg = String.format("No entry for '%s' in manifest, jar is badly packed or damaged",
- nativekey);
- throw new RuntimeException(msg);
- }
-
- String[] nativefiles = natives.split(",");
- for (String nativefile : nativefiles) {
- File unpackedFile = new File(config.NATIVE_DIR, nativefile);
+ for (String file : files) {
+ File unpackedFile = new File(config.NATIVE_DIR, file);
if (unpackedFile.exists()) {
continue;
}
- Utils.unpackFromJar(jarfile, unpackedFile, nativefile);
+ Utils.unpackFromJar(jarfile, unpackedFile, file);
}
}
diff --git a/src/itdelatrisu/opsu/ScoreData.java b/src/itdelatrisu/opsu/ScoreData.java
index b873672f..28ed044e 100644
--- a/src/itdelatrisu/opsu/ScoreData.java
+++ b/src/itdelatrisu/opsu/ScoreData.java
@@ -101,7 +101,7 @@ public class ScoreData implements Comparable {
baseX = containerWidth * 0.01f;
baseY = topY;
buttonWidth = containerWidth * 0.4f;
- float gradeHeight = GameImage.MENU_BUTTON_BG.getImage().getHeight() * 0.45f;
+ float gradeHeight = GameImage.MENU_BUTTON_BG.getHeight() * 0.45f;
buttonHeight = Math.max(gradeHeight, Fonts.DEFAULT.getLineHeight() * 3.03f);
buttonOffset = buttonHeight + gradeHeight / 10f;
buttonAreaHeight = (SongMenu.MAX_SCORE_BUTTONS - 1) * buttonOffset + buttonHeight;
diff --git a/src/itdelatrisu/opsu/Utils.java b/src/itdelatrisu/opsu/Utils.java
index cbebead9..c3a49687 100644
--- a/src/itdelatrisu/opsu/Utils.java
+++ b/src/itdelatrisu/opsu/Utils.java
@@ -464,8 +464,8 @@ public class Utils {
*/
public static int getRegion(double x, double y) {
int q = 0;
- if (y < displayContainer.height / 2d) q = 2;
- if (x < displayContainer.width / 2d) q |= 1;
+ if (y < height2) q = 2;
+ if (x < width2) q |= 1;
return q;
}
@@ -483,24 +483,24 @@ public class Utils {
*/
public static float[] mirrorPoint(float x, float y) {
- double dx = x - displayContainer.width / 2d;
- double dy = y - displayContainer.height / 2d;
+ double dx = x - width2;
+ double dy = y - height2;
double ang = Math.atan2(dy, dx);
double d = -Math.sqrt(dx * dx + dy * dy);
return new float[]{
- (float) (displayContainer.width / 2d + Math.cos(ang) * d),
- (float) (displayContainer.height / 2d + Math.sin(ang) * d)
+ (float) (width2 + Math.cos(ang) * d),
+ (float) (height2 + Math.sin(ang) * d)
};
}
public static float[] mirrorPoint(float x, float y, float degrees) {
- double dx = x - displayContainer.width / 2d;
- double dy = y - displayContainer.height / 2d;
+ double dx = x - width2;
+ double dy = y - height2;
double ang = Math.atan2(dy, dx) + (degrees * Math.PI / 180d);
double d = Math.sqrt(dx * dx + dy * dy);
return new float[]{
- (float) (displayContainer.width / 2d + Math.cos(ang) * d),
- (float) (displayContainer.height / 2d + Math.sin(ang) * d)
+ (float) (width2 + Math.cos(ang) * d),
+ (float) (height2 + Math.sin(ang) * d)
};
}
diff --git a/src/itdelatrisu/opsu/audio/MusicController.java b/src/itdelatrisu/opsu/audio/MusicController.java
index eee4135a..8d957ed8 100644
--- a/src/itdelatrisu/opsu/audio/MusicController.java
+++ b/src/itdelatrisu/opsu/audio/MusicController.java
@@ -22,6 +22,7 @@ import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.beatmap.Beatmap;
import itdelatrisu.opsu.beatmap.TimingPoint;
import itdelatrisu.opsu.states.Game;
+import yugecin.opsudance.options.Options;
import java.io.File;
import java.io.IOException;
@@ -33,7 +34,6 @@ import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;
-import itdelatrisu.opsu.ui.Colors;
import org.lwjgl.BufferUtils;
import org.lwjgl.openal.AL;
import org.lwjgl.openal.AL10;
@@ -45,10 +45,10 @@ import org.newdawn.slick.openal.SoundStore;
import org.newdawn.slick.util.Log;
import org.newdawn.slick.util.ResourceLoader;
import org.tritonus.share.sampled.file.TAudioFileFormat;
-import yugecin.opsudance.events.BarNotifListener;
-import yugecin.opsudance.events.BubNotifListener;
+import static itdelatrisu.opsu.ui.Colors.*;
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
+import static yugecin.opsudance.core.InstanceContainer.*;
import static yugecin.opsudance.options.Options.*;
/**
@@ -103,8 +103,7 @@ public class MusicController {
if (lastBeatmap == null || !beatmap.audioFilename.equals(lastBeatmap.audioFilename)) {
final File audioFile = beatmap.audioFilename;
if (!audioFile.isFile() && !ResourceLoader.resourceExists(audioFile.getPath())) {
- BarNotifListener.EVENT.make().onBarNotif(String.format("Could not find track '%s'.",
- audioFile.getName()));
+ barNotifs.sendf("Could not find track '%s'.", audioFile.getName());
return;
}
@@ -159,7 +158,7 @@ public class MusicController {
} catch (Exception e) {
String err = String.format("Could not play track '%s'.", file.getName());
Log.error(err, e);
- BubNotifListener.EVENT.make().onBubNotif(err, Colors.BUB_RED);
+ bubNotifs.send(BUB_RED, err);
}
}
@@ -219,6 +218,17 @@ public class MusicController {
return (float) ((((trackPosition - beatTime) * 100.0) % beatLength) / beatLength);
}
+ /**
+ * gets the current beat length
+ * @return
+ */
+ public static Float getBeatLength() {
+ if (!updateTimingPoint())
+ return null;
+
+ return lastTimingPoint.getBeatLength();
+ }
+
/**
* Gets the progress of the current measure.
* @return a measure progress value [0,1) where 0 marks the start of the measure and
@@ -349,10 +359,14 @@ public class MusicController {
* If no track is loaded, 0 will be returned.
*/
public static int getPosition() {
+ int offset = OPTION_MUSIC_OFFSET.val;
+ if (lastBeatmap != null)
+ offset += lastBeatmap.localMusicOffset;
+
if (isPlaying())
- return (int) (player.getPosition() * 1000 + OPTION_MUSIC_OFFSET.val + Game.currentMapMusicOffset);
+ return (int) (player.getPosition() * 1000 + offset);
else if (isPaused())
- return Math.max((int) (pauseTime * 1000 + OPTION_MUSIC_OFFSET.val + Game.currentMapMusicOffset), 0);
+ return Math.max((int) (pauseTime * 1000 + offset), 0);
else
return 0;
}
diff --git a/src/itdelatrisu/opsu/audio/SoundController.java b/src/itdelatrisu/opsu/audio/SoundController.java
index 659b9fbb..2f62d3d2 100644
--- a/src/itdelatrisu/opsu/audio/SoundController.java
+++ b/src/itdelatrisu/opsu/audio/SoundController.java
@@ -36,15 +36,14 @@ import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineListener;
import javax.sound.sampled.LineUnavailableException;
-import itdelatrisu.opsu.ui.Colors;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.util.ResourceLoader;
-import yugecin.opsudance.events.BarNotifListener;
-import yugecin.opsudance.events.BubNotifListener;
import yugecin.opsudance.options.Configuration;
import yugecin.opsudance.skinning.SkinService;
+import static itdelatrisu.opsu.ui.Colors.*;
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
+import static yugecin.opsudance.core.InstanceContainer.*;
import static yugecin.opsudance.options.Options.*;
/**
@@ -220,8 +219,8 @@ public class SoundController {
// menu and game sounds
for (SoundEffect s : SoundEffect.values()) {
if ((currentFileName = getSoundFileName(s.getFileName())) == null) {
- BubNotifListener.EVENT.make().onBubNotif(
- "Could not find sound file " + s.getFileName(), Colors.BUB_ORANGE);
+ final String name = s.getFileName();
+ bubNotifs.send(BUB_ORANGE, "Could not find sound file " + name);
continue;
}
MultiClip newClip = loadClip(currentFileName, currentFileName.endsWith(".mp3"));
@@ -240,8 +239,10 @@ public class SoundController {
for (HitSound s : HitSound.values()) {
String filename = String.format("%s-%s", ss.getName(), s.getFileName());
if ((currentFileName = getSoundFileName(filename)) == null) {
- BubNotifListener.EVENT.make().onBubNotif(
- "Could not find hit sound file " + filename, Colors.BUB_ORANGE);
+ bubNotifs.send(
+ BUB_ORANGE,
+ "Could not find hit sound file " + filename
+ );
continue;
}
MultiClip newClip = loadClip(currentFileName, false);
@@ -398,8 +399,7 @@ public class SoundController {
@Override
public void error() {
- BarNotifListener.EVENT.make().onBarNotif(
- "Failed to download track preview");
+ barNotifs.send("Failed to download track preview");
}
});
try {
diff --git a/src/itdelatrisu/opsu/beatmap/Beatmap.java b/src/itdelatrisu/opsu/beatmap/Beatmap.java
index acb24feb..dac22ad1 100644
--- a/src/itdelatrisu/opsu/beatmap/Beatmap.java
+++ b/src/itdelatrisu/opsu/beatmap/Beatmap.java
@@ -89,6 +89,9 @@ public class Beatmap implements Comparable {
/** The last time this beatmap was played (timestamp). */
public long lastPlayed = 0;
+ /** The local music offset. */
+ public int localMusicOffset = 0;
+
/**
* [General]
*/
diff --git a/src/itdelatrisu/opsu/beatmap/BeatmapParser.java b/src/itdelatrisu/opsu/beatmap/BeatmapParser.java
index 7550d0af..1e31d024 100644
--- a/src/itdelatrisu/opsu/beatmap/BeatmapParser.java
+++ b/src/itdelatrisu/opsu/beatmap/BeatmapParser.java
@@ -31,13 +31,12 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import itdelatrisu.opsu.ui.Colors;
import org.newdawn.slick.Color;
import org.newdawn.slick.util.Log;
import yugecin.opsudance.core.Nullable;
-import yugecin.opsudance.events.BubNotifListener;
import yugecin.opsudance.skinning.SkinService;
+import static itdelatrisu.opsu.ui.Colors.*;
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
import static yugecin.opsudance.core.InstanceContainer.*;
import static yugecin.opsudance.options.Options.*;
@@ -890,7 +889,7 @@ public class BeatmapParser {
private static void logAndShowErrorNotification(Exception e, String message, Object... formatArgs) {
message = String.format(message, formatArgs);
Log.error(message, e);
- BubNotifListener.EVENT.make().onBubNotif(message, Colors.BUB_RED);
+ bubNotifs.send(BUB_RED, message);
}
}
\ No newline at end of file
diff --git a/src/itdelatrisu/opsu/beatmap/BeatmapSetList.java b/src/itdelatrisu/opsu/beatmap/BeatmapSetList.java
index 1cb1d72c..2e6ea9db 100644
--- a/src/itdelatrisu/opsu/beatmap/BeatmapSetList.java
+++ b/src/itdelatrisu/opsu/beatmap/BeatmapSetList.java
@@ -21,8 +21,6 @@ package itdelatrisu.opsu.beatmap;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.audio.MusicController;
import itdelatrisu.opsu.db.BeatmapDB;
-import itdelatrisu.opsu.ui.Colors;
-import yugecin.opsudance.events.BubNotifListener;
import java.io.File;
import java.io.IOException;
@@ -36,6 +34,9 @@ import java.util.LinkedList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import static itdelatrisu.opsu.ui.Colors.*;
+import static yugecin.opsudance.core.InstanceContainer.*;
+
/**
* Indexed, expanding, doubly-linked list data type for song groups.
*/
@@ -215,7 +216,7 @@ public class BeatmapSetList {
try {
Utils.deleteToTrash(dir);
} catch (IOException e) {
- BubNotifListener.EVENT.make().onBubNotif("Could not delete song group", Colors.BUB_ORANGE);
+ bubNotifs.send(BUB_ORANGE, "Could not delete song group");
}
if (ws != null)
ws.resume();
@@ -271,7 +272,7 @@ public class BeatmapSetList {
try {
Utils.deleteToTrash(file);
} catch (IOException e) {
- BubNotifListener.EVENT.make().onBubNotif("Could not delete song", Colors.BUB_ORANGE);
+ bubNotifs.send(BUB_ORANGE, "Could not delete song");
}
if (ws != null)
ws.resume();
diff --git a/src/itdelatrisu/opsu/beatmap/BeatmapWatchService.java b/src/itdelatrisu/opsu/beatmap/BeatmapWatchService.java
index b49acd37..8b36f570 100644
--- a/src/itdelatrisu/opsu/beatmap/BeatmapWatchService.java
+++ b/src/itdelatrisu/opsu/beatmap/BeatmapWatchService.java
@@ -38,11 +38,9 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
-import itdelatrisu.opsu.ui.Colors;
import org.newdawn.slick.util.Log;
-import yugecin.opsudance.events.BarNotifListener;
-import yugecin.opsudance.events.BubNotifListener;
+import static itdelatrisu.opsu.ui.Colors.*;
import static yugecin.opsudance.core.InstanceContainer.*;
import static yugecin.opsudance.options.Options.*;
@@ -101,7 +99,7 @@ public class BeatmapWatchService {
ws.register(config.beatmapDir.toPath());
} catch (IOException e) {
Log.error("Could not create watch service", e);
- BubNotifListener.EVENT.make().onBubNotif("Could not create watch service", Colors.BUB_RED);
+ bubNotifs.send(BUB_RED, "Could not create watch service");
return;
}
@@ -124,7 +122,7 @@ public class BeatmapWatchService {
} catch (IOException e) {
String msg = "An I/O exception occurred while closing the previous watch service.";
Log.error(msg, e);
- BarNotifListener.EVENT.make().onBarNotif(msg);
+ barNotifs.send(msg);
ws = null;
}
}
diff --git a/src/itdelatrisu/opsu/beatmap/HitObject.java b/src/itdelatrisu/opsu/beatmap/HitObject.java
index 0503a85a..be30b7bc 100644
--- a/src/itdelatrisu/opsu/beatmap/HitObject.java
+++ b/src/itdelatrisu/opsu/beatmap/HitObject.java
@@ -240,7 +240,7 @@ public class HitObject {
String[] edgeHitSoundTokens = tokens[8].split("\\|");
this.edgeHitSound = new byte[edgeHitSoundTokens.length];
for (int j = 0; j < edgeHitSoundTokens.length; j++)
- edgeHitSound[j] = Byte.parseByte(edgeHitSoundTokens[j]);
+ edgeHitSound[j] = (byte) Short.parseShort(edgeHitSoundTokens[j]);
}
if (tokens.length > 9) {
String[] edgeAdditionTokens = tokens[9].split("\\|");
diff --git a/src/itdelatrisu/opsu/beatmap/OszUnpacker.java b/src/itdelatrisu/opsu/beatmap/OszUnpacker.java
index 05e7182a..a31ed064 100644
--- a/src/itdelatrisu/opsu/beatmap/OszUnpacker.java
+++ b/src/itdelatrisu/opsu/beatmap/OszUnpacker.java
@@ -23,12 +23,11 @@ import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.List;
-import itdelatrisu.opsu.ui.Colors;
import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import org.newdawn.slick.util.Log;
-import yugecin.opsudance.events.BubNotifListener;
+import static itdelatrisu.opsu.ui.Colors.*;
import static yugecin.opsudance.core.InstanceContainer.*;
/**
@@ -97,7 +96,7 @@ public class OszUnpacker {
} catch (ZipException e) {
String err = String.format("Failed to unzip file %s to dest %s.", file.getAbsolutePath(), dest.getAbsolutePath());
Log.error(err, e);
- BubNotifListener.EVENT.make().onBubNotif(err, Colors.BUB_RED);
+ bubNotifs.send(BUB_RED, err);
}
}
diff --git a/src/itdelatrisu/opsu/db/BeatmapDB.java b/src/itdelatrisu/opsu/db/BeatmapDB.java
index 745271db..e0d4ca8e 100644
--- a/src/itdelatrisu/opsu/db/BeatmapDB.java
+++ b/src/itdelatrisu/opsu/db/BeatmapDB.java
@@ -20,6 +20,7 @@ package itdelatrisu.opsu.db;
import itdelatrisu.opsu.beatmap.Beatmap;
import itdelatrisu.opsu.beatmap.BeatmapParser;
+import yugecin.opsudance.core.errorhandling.ErrorHandler;
import java.io.File;
import java.sql.Connection;
@@ -47,7 +48,7 @@ public class BeatmapDB {
* This value should be changed whenever the database format changes.
* Add any update queries to the {@link #getUpdateQueries(int)} method.
*/
- private static final int DATABASE_VERSION = 20161222;
+ private static final int DATABASE_VERSION = 20161225;
/**
* Returns a list of SQL queries to apply, in order, to update from
@@ -64,6 +65,10 @@ public class BeatmapDB {
list.add("ALTER TABLE beatmaps ADD COLUMN lastPlayed INTEGER");
list.add("UPDATE beatmaps SET dateAdded = 0, favorite = 0, playCount = 0, lastPlayed = 0");
}
+ if (version < 20161225) {
+ list.add("ALTER TABLE beatmaps ADD COLUMN localOffset INTEGER");
+ list.add("UPDATE beatmaps SET localOffset = 0");
+ }
/* add future updates here */
@@ -85,7 +90,7 @@ public class BeatmapDB {
/** Query statements. */
private static PreparedStatement
insertStmt, selectStmt, deleteMapStmt, deleteGroupStmt,
- setStarsStmt, updatePlayStatsStmt, setFavoriteStmt, updateSizeStmt;
+ setStarsStmt, updatePlayStatsStmt, setFavoriteStmt, setLocalOffsetStmt, updateSizeStmt;
/** Current size of beatmap cache table. */
private static int cacheSize = -1;
@@ -121,7 +126,7 @@ public class BeatmapDB {
"INSERT INTO beatmaps VALUES (" +
"?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?," +
"?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?," +
- "?, ?, ?, ?, ?, ?" +
+ "?, ?, ?, ?, ?, ?, ?" +
")"
);
selectStmt = connection.prepareStatement("SELECT * FROM beatmaps WHERE dir = ? AND file = ?");
@@ -130,6 +135,7 @@ public class BeatmapDB {
setStarsStmt = connection.prepareStatement("UPDATE beatmaps SET stars = ? WHERE dir = ? AND file = ?");
updatePlayStatsStmt = connection.prepareStatement("UPDATE beatmaps SET playCount = ?, lastPlayed = ? WHERE dir = ? AND file = ?");
setFavoriteStmt = connection.prepareStatement("UPDATE beatmaps SET favorite = ? WHERE dir = ? AND file = ?");
+ setLocalOffsetStmt = connection.prepareStatement("UPDATE beatmaps SET localOffset = ? WHERE dir = ? AND file = ?");
} catch (SQLException e) {
explode("Failed to prepare beatmap statements.", e, DEFAULT_OPTIONS);
}
@@ -153,7 +159,7 @@ public class BeatmapDB {
"mode INTEGER, letterboxInBreaks BOOLEAN, widescreenStoryboard BOOLEAN, epilepsyWarning BOOLEAN, " +
"bg TEXT, sliderBorder TEXT, timingPoints TEXT, breaks TEXT, combo TEXT, " +
"md5hash TEXT, stars REAL, " +
- "dateAdded INTEGER, favorite BOOLEAN, playCount INTEGER, lastPlayed INTEGER" +
+ "dateAdded INTEGER, favorite BOOLEAN, playCount INTEGER, lastPlayed INTEGER, localOffset INTEGER" +
"); " +
"CREATE TABLE IF NOT EXISTS info (" +
"key TEXT NOT NULL UNIQUE, value TEXT" +
@@ -402,6 +408,7 @@ public class BeatmapDB {
stmt.setBoolean(44, beatmap.favorite);
stmt.setInt(45, beatmap.playCount);
stmt.setLong(46, beatmap.lastPlayed);
+ stmt.setInt(47, beatmap.localMusicOffset);
} catch (SQLException e) {
throw e;
} catch (Exception e) {
@@ -549,6 +556,7 @@ public class BeatmapDB {
beatmap.favorite = rs.getBoolean(44);
beatmap.playCount = rs.getInt(45);
beatmap.lastPlayed = rs.getLong(46);
+ beatmap.localMusicOffset = rs.getInt(47);
} catch (SQLException e) {
throw e;
} catch (Exception e) {
@@ -694,6 +702,24 @@ public class BeatmapDB {
}
}
+ /**
+ * Updates the local music offset for a beatmap in the database.
+ * @param beatmap the beatmap
+ */
+ public static void updateLocalOffset(Beatmap beatmap) {
+ if (connection == null)
+ return;
+ try {
+ setLocalOffsetStmt.setInt(1, beatmap.localMusicOffset);
+ setLocalOffsetStmt.setString(2, beatmap.getFile().getParentFile().getName());
+ setLocalOffsetStmt.setString(3, beatmap.getFile().getName());
+ setLocalOffsetStmt.executeUpdate();
+ } catch (SQLException e) {
+ ErrorHandler.explode(String.format("Failed to update local music offset for beatmap '%s' in database.",
+ beatmap.toString()), e, ErrorHandler.DEFAULT_OPTIONS);
+ }
+ }
+
/**
* Closes the connection to the database.
*/
diff --git a/src/itdelatrisu/opsu/downloads/Download.java b/src/itdelatrisu/opsu/downloads/Download.java
index 1b65d5d3..35f59134 100644
--- a/src/itdelatrisu/opsu/downloads/Download.java
+++ b/src/itdelatrisu/opsu/downloads/Download.java
@@ -33,10 +33,10 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
-import itdelatrisu.opsu.ui.Colors;
import org.newdawn.slick.util.Log;
-import yugecin.opsudance.events.BubNotifListener;
+import static itdelatrisu.opsu.ui.Colors.*;
+import static yugecin.opsudance.core.InstanceContainer.*;
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
/**
@@ -220,7 +220,7 @@ public class Download {
else if (redirectCount > MAX_REDIRECTS)
error = String.format("Download for URL '%s' is attempting too many redirects (over %d).", base.toString(), MAX_REDIRECTS);
if (error != null) {
- BubNotifListener.EVENT.make().onBubNotif(error, Colors.BUB_ORANGE);
+ bubNotifs.send(BUB_ORANGE, error);
throw new IOException();
}
diff --git a/src/itdelatrisu/opsu/downloads/DownloadNode.java b/src/itdelatrisu/opsu/downloads/DownloadNode.java
index e5625306..e5899642 100644
--- a/src/itdelatrisu/opsu/downloads/DownloadNode.java
+++ b/src/itdelatrisu/opsu/downloads/DownloadNode.java
@@ -33,9 +33,8 @@ import java.io.File;
import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
-import yugecin.opsudance.events.BarNotifListener;
-import yugecin.opsudance.events.BubNotifListener;
+import static itdelatrisu.opsu.ui.Colors.*;
import static yugecin.opsudance.core.InstanceContainer.*;
import static yugecin.opsudance.options.Options.*;
@@ -132,7 +131,7 @@ public class DownloadNode {
* @param index the index (to offset the button from the topmost button)
*/
public static boolean resultIconContains(float cx, float cy, int index) {
- int iconWidth = GameImage.MUSIC_PLAY.getImage().getWidth();
+ int iconWidth = GameImage.MUSIC_PLAY.getWidth();
float x = buttonBaseX + buttonWidth * 0.001f;
float y = buttonBaseY + (index * buttonOffset) + buttonHeight / 2f;
return ((cx > x && cx < x + iconWidth) &&
@@ -187,7 +186,7 @@ public class DownloadNode {
* @param index the index (to offset the button from the topmost button)
*/
public static boolean downloadIconContains(float cx, float cy, int index) {
- int iconWidth = GameImage.DELETE.getImage().getWidth();
+ int iconWidth = GameImage.DELETE.getWidth();
float edgeX = infoBaseX + infoWidth * 0.985f;
float y = infoBaseY + (index * infoHeight);
float marginY = infoHeight * 0.04f;
@@ -280,14 +279,12 @@ public class DownloadNode {
download.setListener(new DownloadListener() {
@Override
public void completed() {
- BarNotifListener.EVENT.make().onBarNotif(
- String.format("Download complete: %s", getTitle()));
+ barNotifs.sendf("Download complete: %s", getTitle());
}
@Override
public void error() {
- BarNotifListener.EVENT.make().onBarNotif(
- "Download failed due to a connection error.");
+ barNotifs.send("Download failed due to a connection error.");
}
});
this.download = download;
@@ -409,9 +406,10 @@ public class DownloadNode {
public void drawDownload(Graphics g, float position, int id, boolean hover) {
Download download = this.download; // in case clearDownload() is called asynchronously
if (download == null) {
- BubNotifListener.EVENT.make().onBubNotif(
- "Trying to draw download information for button without Download object",
- Colors.BUB_ORANGE);
+ bubNotifs.send(
+ BUB_ORANGE,
+ "Trying to draw download information for button without Download object"
+ );
return;
}
diff --git a/src/itdelatrisu/opsu/downloads/Updater.java b/src/itdelatrisu/opsu/downloads/Updater.java
index f0d95efd..5a199f82 100644
--- a/src/itdelatrisu/opsu/downloads/Updater.java
+++ b/src/itdelatrisu/opsu/downloads/Updater.java
@@ -32,11 +32,10 @@ import java.util.Date;
import java.util.Locale;
import java.util.Properties;
-import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.newdawn.slick.util.Log;
import org.newdawn.slick.util.ResourceLoader;
import yugecin.opsudance.core.Constants;
-import yugecin.opsudance.events.BarNotifListener;
+import yugecin.opsudance.utils.SimpleVersion;
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
import static yugecin.opsudance.core.InstanceContainer.*;
@@ -92,7 +91,7 @@ public class Updater {
private Status status;
/** The current and latest versions. */
- private DefaultArtifactVersion currentVersion, latestVersion;
+ private SimpleVersion currentVersion, latestVersion;
/** The version information if the program was just updated. */
private String updatedFromVersion, updatedToVersion;
@@ -107,7 +106,7 @@ public class Updater {
if (currentVersion == null) {
return "unknown version";
}
- return currentVersion.getMajorVersion() + "." + currentVersion.getMinorVersion() + "." + currentVersion.getIncrementalVersion();
+ return currentVersion.toString();
}
public Updater() {
@@ -182,13 +181,13 @@ public class Updater {
* @param props the set of properties
* @return the version, or null if not found
*/
- private DefaultArtifactVersion getVersion(Properties props) {
- String version = props.getProperty("version");
- if (version == null || version.equals("${pom.version}")) {
- status = Status.INTERNAL_ERROR;
- return null;
- } else
- return new DefaultArtifactVersion(version);
+ private SimpleVersion getVersion(Properties props) {
+ final String version = props.getProperty("version");
+ if (version != null && !version.equals("${pom.version}")) {
+ return SimpleVersion.parse(version);
+ }
+ this.status = Status.INTERNAL_ERROR;
+ return null;
}
/**
@@ -196,7 +195,7 @@ public class Updater {
* @throws IOException if an I/O exception occurs
*/
public void checkForUpdates() throws IOException {
- if (status != Status.INITIAL || config.USE_XDG)
+ if (status != Status.INITIAL)
return;
status = Status.CHECKING;
@@ -241,14 +240,13 @@ public class Updater {
@Override
public void completed() {
status = Status.UPDATE_DOWNLOADED;
- BarNotifListener.EVENT.make().onBarNotif("Update has finished downloading");
+ barNotifs.send("Update has finished downloading");
}
@Override
public void error() {
status = Status.CONNECTION_ERROR;
- BarNotifListener.EVENT.make().onBarNotif(
- "Update failed due to a connection error.");
+ barNotifs.send("Update failed due to a connection error.");
}
});
}
diff --git a/src/itdelatrisu/opsu/objects/Slider.java b/src/itdelatrisu/opsu/objects/Slider.java
index c2c5f6d3..621ee757 100644
--- a/src/itdelatrisu/opsu/objects/Slider.java
+++ b/src/itdelatrisu/opsu/objects/Slider.java
@@ -370,13 +370,13 @@ public class Slider extends GameObject {
float followCircleScale = 1f + (tickExpandTime / (float) TICK_EXPAND_TIME) * 0.1f;
float followAlpha = 1f;
if (followCircleActive && followExpandTime < FOLLOW_EXPAND_TIME) {
- followExpandTime += displayContainer.renderDelta;
+ followExpandTime += renderDelta;
followCircleScale *= 0.5f;
float progress = AnimationEquation.OUT_QUAD.calc((float) followExpandTime / FOLLOW_EXPAND_TIME);
followCircleScale = followCircleScale + followCircleScale * progress;
followAlpha = progress;
} else if (!followCircleActive) {
- followExpandTime -= displayContainer.renderDelta;
+ followExpandTime -= renderDelta;
if (followExpandTime > FOLLOW_SHRINK_TIME) {
followExpandTime = FOLLOW_SHRINK_TIME;
}
@@ -391,7 +391,7 @@ public class Slider extends GameObject {
float oldAlphaBlack = Colors.BLACK_ALPHA.a;
Colors.BLACK_ALPHA.a = 0.75f;
g.setColor(Colors.BLACK_ALPHA);
- g.fillRect(0, 0, displayContainer.width, displayContainer.height);
+ g.fillRect(0, 0, width, height);
Colors.BLACK_ALPHA.a = oldAlphaBlack;
}
}
diff --git a/src/itdelatrisu/opsu/objects/Spinner.java b/src/itdelatrisu/opsu/objects/Spinner.java
index 0e868ab5..7b8a5ccd 100644
--- a/src/itdelatrisu/opsu/objects/Spinner.java
+++ b/src/itdelatrisu/opsu/objects/Spinner.java
@@ -34,15 +34,14 @@ import itdelatrisu.opsu.ui.Colors;
import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
-import yugecin.opsudance.core.DisplayContainer;
import yugecin.opsudance.skinning.SkinService;
+import static yugecin.opsudance.core.InstanceContainer.*;
+
/**
* Data type representing a spinner object.
*/
public class Spinner extends GameObject {
- /** Container dimensions. */
- private static int width, height;
/** The map's overall difficulty value. */
private static float overallDifficulty = 5f;
@@ -112,9 +111,7 @@ public class Spinner extends GameObject {
* Initializes the Spinner data type with images and dimensions.
* @param difficulty the map's overall difficulty value
*/
- public static void init(DisplayContainer displayContainer, float difficulty) {
- width = displayContainer.width;
- height = displayContainer.height;
+ public static void init(float difficulty) {
overallDifficulty = difficulty;
}
@@ -207,7 +204,7 @@ public class Spinner extends GameObject {
// rpm
Image rpmImg = GameImage.SPINNER_RPM.getImage();
rpmImg.setAlpha(alpha);
- rpmImg.drawCentered(width / 2f, height - rpmImg.getHeight() / 2f);
+ rpmImg.drawCentered(width2, height - rpmImg.getHeight() / 2f);
if (timeDiff < 0)
data.drawSymbolString(Integer.toString(drawnRPM), (width + rpmImg.getWidth() * 0.95f) / 2f,
height - data.getScoreSymbolImage('0').getHeight() * 1.025f, 1f, 1f, true);
@@ -225,21 +222,21 @@ public class Spinner extends GameObject {
// main spinner elements
GameImage.SPINNER_CIRCLE.getImage().setAlpha(alpha);
GameImage.SPINNER_CIRCLE.getImage().setRotation(drawRotation * 360f);
- GameImage.SPINNER_CIRCLE.getImage().drawCentered(width / 2, height / 2);
+ GameImage.SPINNER_CIRCLE.getImage().drawCentered(width2, height2);
if (!GameMod.HIDDEN.isActive()) {
float approachScale = 1 - Utils.clamp(((float) timeDiff / (hitObject.getTime() - hitObject.getEndTime())), 0f, 1f);
Image approachCircleScaled = GameImage.SPINNER_APPROACHCIRCLE.getImage().getScaledCopy(approachScale);
approachCircleScaled.setAlpha(alpha);
- approachCircleScaled.drawCentered(width / 2, height / 2);
+ approachCircleScaled.drawCentered(width2, height2);
}
GameImage.SPINNER_SPIN.getImage().setAlpha(alpha);
- GameImage.SPINNER_SPIN.getImage().drawCentered(width / 2, height * 3 / 4);
+ GameImage.SPINNER_SPIN.getImage().drawCentered(width2, height * 3 / 4);
if (spinnerComplete) {
- GameImage.SPINNER_CLEAR.getImage().drawCentered(width / 2, height / 4);
+ GameImage.SPINNER_CLEAR.getImage().drawCentered(width2, height / 4);
int extraRotations = (int) (rotations - rotationsNeeded);
if (extraRotations > 0)
- data.drawSymbolNumber(extraRotations * 1000, width / 2, height * 2 / 3, 1f, 1f);
+ data.drawSymbolNumber(extraRotations * 1000, width2, height * 2 / 3, 1f, 1f);
}
}
@@ -261,14 +258,14 @@ public class Spinner extends GameObject {
else
result = GameData.HIT_MISS;
- data.sendHitResult(hitObject.getEndTime(), result, width / 2, height / 2,
+ data.sendHitResult(hitObject.getEndTime(), result, width2, height2,
Color.transparent, true, hitObject, HitObjectType.SPINNER, true, 0, null, false);
return result;
}
@Override
public boolean mousePressed(int x, int y, int trackPosition) {
- lastAngle = (float) Math.atan2(x - (height / 2), y - (width / 2));
+ lastAngle = (float) Math.atan2(x - height2, y - width2);
return false;
}
@@ -297,7 +294,7 @@ public class Spinner extends GameObject {
angleDiff = delta * SPUN_OUT_MULTIPLIER;
isSpinning = true;
} else {
- float angle = (float) Math.atan2(mouseY - (height / 2), mouseX - (width / 2));
+ float angle = (float) Math.atan2(mouseY - height2, mouseX - width2);
// set initial angle to current mouse position to skip first click
if (!isSpinning && (keyPressed || GameMod.RELAX.isActive())) {
diff --git a/src/itdelatrisu/opsu/objects/curves/Curve.java b/src/itdelatrisu/opsu/objects/curves/Curve.java
index cd21a525..bf1f5353 100644
--- a/src/itdelatrisu/opsu/objects/curves/Curve.java
+++ b/src/itdelatrisu/opsu/objects/curves/Curve.java
@@ -98,13 +98,13 @@ public abstract class Curve {
* @param circleDiameter the circle diameter
* @param borderColor the curve border color
*/
- public static void init(int width, int height, float circleDiameter, Color borderColor) {
+ public static void init(float circleDiameter, Color borderColor) {
Curve.borderColor = borderColor;
ContextCapabilities capabilities = GLContext.getCapabilities();
mmsliderSupported = capabilities.OpenGL30;
if (mmsliderSupported) {
- CurveRenderState.init(width, height, circleDiameter);
+ CurveRenderState.init(circleDiameter);
} else if (SkinService.skin.getSliderStyle() != Skin.STYLE_PEPPYSLIDER) {
Log.warn("New slider style requires OpenGL 3.0.");
}
diff --git a/src/itdelatrisu/opsu/render/CurveRenderState.java b/src/itdelatrisu/opsu/render/CurveRenderState.java
index ebf365e3..c69aa034 100644
--- a/src/itdelatrisu/opsu/render/CurveRenderState.java
+++ b/src/itdelatrisu/opsu/render/CurveRenderState.java
@@ -48,8 +48,6 @@ import static yugecin.opsudance.options.Options.*;
* @author Bigpet {@literal }
*/
public class CurveRenderState {
- /** The width and height of the display container this curve gets drawn into. */
- protected static int containerWidth, containerHeight;
/** Thickness of the curve. */
protected static int scale;
@@ -79,14 +77,9 @@ public class CurveRenderState {
/**
* Set the width and height of the container that Curves get drawn into.
* Should be called before any curves are drawn.
- * @param width the container width
- * @param height the container height
* @param circleDiameter the circle diameter
*/
- public static void init(int width, int height, float circleDiameter) {
- containerWidth = width;
- containerHeight = height;
-
+ public static void init(float circleDiameter) {
// equivalent to what happens in Slider.init()
scale = (int) (circleDiameter * HitObject.getXMultiplier()); // convert from Osupixels (640x480)
//scale = scale * 118 / 128; //for curves exactly as big as the sliderball
@@ -410,8 +403,6 @@ public class CurveRenderState {
x1 = m[0];
y1 = m[1];
}
- float divx = containerWidth / 2.0f;
- float divy = containerHeight / 2.0f;
float offx = -1.0f;
float offy = 1.0f;
float radius = scale / 2;
@@ -419,8 +410,8 @@ public class CurveRenderState {
for (int i = 0; i < NewCurveStyleState.unitCone.length / 6; ++i) {
buff.put(NewCurveStyleState.unitCone[i * 6 + 0]);
buff.put(NewCurveStyleState.unitCone[i * 6 + 1]);
- buff.put(offx + (x1 + radius * NewCurveStyleState.unitCone[i * 6 + 2]) / divx);
- buff.put(offy - (y1 + radius * NewCurveStyleState.unitCone[i * 6 + 3]) / divy);
+ buff.put(offx + (x1 + radius * NewCurveStyleState.unitCone[i * 6 + 2]) / width2);
+ buff.put(offy - (y1 + radius * NewCurveStyleState.unitCone[i * 6 + 3]) / height2);
buff.put(NewCurveStyleState.unitCone[i * 6 + 4]);
buff.put(NewCurveStyleState.unitCone[i * 6 + 5]);
}
diff --git a/src/itdelatrisu/opsu/replay/Replay.java b/src/itdelatrisu/opsu/replay/Replay.java
index 9296f55e..6550e96e 100644
--- a/src/itdelatrisu/opsu/replay/Replay.java
+++ b/src/itdelatrisu/opsu/replay/Replay.java
@@ -39,13 +39,12 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
-import itdelatrisu.opsu.ui.Colors;
import org.apache.commons.compress.compressors.lzma.LZMACompressorInputStream;
import org.newdawn.slick.util.Log;
import lzma.streams.LzmaOutputStream;
-import yugecin.opsudance.events.BubNotifListener;
+import static itdelatrisu.opsu.ui.Colors.*;
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
import static yugecin.opsudance.core.InstanceContainer.*;
@@ -275,7 +274,7 @@ public class Replay {
public void save() {
// create replay directory
if (!config.replayDir.isDirectory() && !config.replayDir.mkdir()) {
- BubNotifListener.EVENT.make().onBubNotif("Failed to create replay directory", Colors.BUB_RED);
+ bubNotifs.send(BUB_RED, "Failed to create replay directory");
return;
}
diff --git a/src/itdelatrisu/opsu/replay/ReplayImporter.java b/src/itdelatrisu/opsu/replay/ReplayImporter.java
index 84b0a44e..3d002bf1 100644
--- a/src/itdelatrisu/opsu/replay/ReplayImporter.java
+++ b/src/itdelatrisu/opsu/replay/ReplayImporter.java
@@ -28,10 +28,9 @@ import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
-import itdelatrisu.opsu.ui.Colors;
import org.newdawn.slick.util.Log;
-import yugecin.opsudance.events.BubNotifListener;
+import static itdelatrisu.opsu.ui.Colors.*;
import static yugecin.opsudance.core.InstanceContainer.*;
/**
@@ -69,7 +68,7 @@ public class ReplayImporter {
if (!config.replayDir.isDirectory() && !config.replayDir.mkdir()) {
String err = String.format("Failed to create replay directory '%s'.", config.replayDir.getAbsolutePath());
Log.error(err);
- BubNotifListener.EVENT.make().onBubNotif(err, Colors.BUB_RED);
+ bubNotifs.send(BUB_RED, err);
return;
}
@@ -83,7 +82,7 @@ public class ReplayImporter {
moveToFailedDirectory(file);
String err = String.format("Failed to import replay '%s'. The replay file could not be parsed.", file.getName());
Log.error(err, e);
- BubNotifListener.EVENT.make().onBubNotif(err, Colors.BUB_RED);
+ bubNotifs.send(BUB_RED, err);
continue;
}
Beatmap beatmap = BeatmapSetList.get().getBeatmapFromHash(r.beatmapHash);
@@ -102,7 +101,7 @@ public class ReplayImporter {
moveToFailedDirectory(file);
String err = String.format("Failed to import replay '%s'. The associated beatmap could not be found.", file.getName());
Log.error(err);
- BubNotifListener.EVENT.make().onBubNotif(err, Colors.BUB_RED);
+ bubNotifs.send(BUB_RED, err);
}
}
diff --git a/src/itdelatrisu/opsu/skins/SkinLoader.java b/src/itdelatrisu/opsu/skins/SkinLoader.java
index 799a2da2..6c45e747 100644
--- a/src/itdelatrisu/opsu/skins/SkinLoader.java
+++ b/src/itdelatrisu/opsu/skins/SkinLoader.java
@@ -29,10 +29,11 @@ import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedList;
-import itdelatrisu.opsu.ui.Colors;
import org.newdawn.slick.Color;
import org.newdawn.slick.util.Log;
-import yugecin.opsudance.events.BubNotifListener;
+
+import static itdelatrisu.opsu.ui.Colors.*;
+import static yugecin.opsudance.core.InstanceContainer.*;
/**
* Loads skin configuration files.
@@ -293,7 +294,7 @@ public class SkinLoader {
} catch (IOException e) {
String err = String.format("Failed to read file '%s'.", skinFile.getAbsolutePath());
Log.error(err, e);
- BubNotifListener.EVENT.make().onBubNotif(err, Colors.BUB_RED);
+ bubNotifs.send(BUB_RED, err);
}
return skin;
diff --git a/src/itdelatrisu/opsu/states/ButtonMenu.java b/src/itdelatrisu/opsu/states/ButtonMenu.java
index acc66611..57e3b9f0 100644
--- a/src/itdelatrisu/opsu/states/ButtonMenu.java
+++ b/src/itdelatrisu/opsu/states/ButtonMenu.java
@@ -181,7 +181,7 @@ public class ButtonMenu extends BaseOpsuState {
@Override
protected float getBaseY() {
- return displayContainer.height * 2f / 3;
+ return height * 2f / 3;
}
@Override
@@ -203,10 +203,9 @@ public class ButtonMenu extends BaseOpsuState {
float mult = GameMod.getScoreMultiplier();
String multString = String.format("Score Multiplier: %.2fx", mult);
Color multColor = (mult == 1f) ? Color.white : (mult > 1f) ? Color.green : Color.red;
- float multY = Fonts.LARGE.getLineHeight() * 2 + displayContainer.height * 0.06f;
- Fonts.LARGE.drawString(
- (displayContainer.width - Fonts.LARGE.getWidth(multString)) / 2f,
- multY, multString, multColor);
+ float multY = Fonts.LARGE.getLineHeight() * 2 + height * 0.06f;
+ final float multX = width2 - Fonts.LARGE.getWidth(multString) / 2f;
+ Fonts.LARGE.drawString(multX, multY, multString, multColor);
// category text
for (GameMod.Category category : GameMod.Category.values()) {
@@ -227,14 +226,14 @@ public class ButtonMenu extends BaseOpsuState {
super.preRenderUpdate();
GameMod hoverMod = null;
for (GameMod mod : GameMod.values()) {
- mod.hoverUpdate(displayContainer.renderDelta, mod.isActive());
- if (hoverMod == null && mod.contains(displayContainer.mouseX, displayContainer.mouseY))
+ mod.hoverUpdate(renderDelta, mod.isActive());
+ if (hoverMod == null && mod.contains(mouseX, mouseY))
hoverMod = mod;
}
// tooltips
if (hoverMod != null) {
- UI.updateTooltip(displayContainer.renderDelta, hoverMod.getDescription(), true);
+ UI.updateTooltip(renderDelta, hoverMod.getDescription(), true);
}
}
@@ -296,13 +295,12 @@ public class ButtonMenu extends BaseOpsuState {
* Initializes the menu state.
*/
public void revalidate(Image button, Image buttonL, Image buttonR) {
- float center = displayContainer.width / 2;
float baseY = getBaseY();
float offsetY = button.getHeight() * 1.25f;
menuButtons = new MenuButton[buttons.length];
for (int i = 0; i < buttons.length; i++) {
- MenuButton b = new MenuButton(button, buttonL, buttonR, center, baseY + (i * offsetY));
+ MenuButton b = new MenuButton(button, buttonL, buttonR, width2, baseY + (i * offsetY));
b.setText(String.format("%d. %s", i + 1, buttons[i].getText()), Fonts.XLARGE, Color.white);
b.setHoverFade();
menuButtons[i] = b;
@@ -313,7 +311,7 @@ public class ButtonMenu extends BaseOpsuState {
* Returns the base Y coordinate for the buttons.
*/
protected float getBaseY() {
- float baseY = displayContainer.height * 0.2f;
+ float baseY = height * 0.2f;
baseY += ((getTitle().length - 1) * Fonts.LARGE.getLineHeight());
return baseY;
}
@@ -325,7 +323,7 @@ public class ButtonMenu extends BaseOpsuState {
public void render(Graphics g) {
// draw title
if (actualTitle != null) {
- float marginX = displayContainer.width * 0.015f, marginY = displayContainer.height * 0.01f;
+ float marginX = width * 0.015f, marginY = height * 0.01f;
int lineHeight = Fonts.LARGE.getLineHeight();
for (int i = 0, size = actualTitle.size(); i < size; i++)
Fonts.LARGE.drawString(marginX, marginY + (i * lineHeight), actualTitle.get(i), Color.white);
@@ -342,15 +340,16 @@ public class ButtonMenu extends BaseOpsuState {
* Updates the menu state.
*/
public void preRenderUpdate() {
- float center = displayContainer.width / 2f;
- boolean centerOffsetUpdated = centerOffset.update(displayContainer.renderDelta);
+ boolean centerOffsetUpdated = centerOffset.update(renderDelta);
float centerOffsetX = centerOffset.getValue();
+ final float[] offsets = { centerOffsetX, - centerOffsetX };
for (int i = 0; i < buttons.length; i++) {
- menuButtons[i].hoverUpdate(displayContainer.renderDelta, displayContainer.mouseX, displayContainer.mouseY);
+ menuButtons[i].hoverUpdate(renderDelta, mouseX, mouseY);
// move button to center
- if (centerOffsetUpdated)
- menuButtons[i].setX((i % 2 == 0) ? center + centerOffsetX : center - centerOffsetX);
+ if (centerOffsetUpdated) {
+ menuButtons[i].setX(width2 + offsets[i & 1]);
+ }
}
}
@@ -394,18 +393,17 @@ public class ButtonMenu extends BaseOpsuState {
* Processes a state enter request.
*/
public void enter() {
- float center = displayContainer.width / 2f;
- float centerOffsetX = displayContainer.width * OFFSET_WIDTH_RATIO;
+ float centerOffsetX = width * OFFSET_WIDTH_RATIO;
centerOffset = new AnimatedValue(700, centerOffsetX, 0, AnimationEquation.OUT_BOUNCE);
for (int i = 0; i < buttons.length; i++) {
- menuButtons[i].setX(center + ((i % 2 == 0) ? centerOffsetX : centerOffsetX * -1));
+ menuButtons[i].setX(width2 + ((i % 2 == 0) ? centerOffsetX : centerOffsetX * -1));
menuButtons[i].resetHover();
}
// create title string list
actualTitle = new ArrayList<>();
String[] title = getTitle();
- int maxLineWidth = (int) (displayContainer.width * 0.96f);
+ int maxLineWidth = (int) (width * 0.96f);
for (String aTitle : title) {
// wrap text if too long
if (Fonts.LARGE.getWidth(aTitle) > maxLineWidth) {
@@ -601,7 +599,7 @@ public class ButtonMenu extends BaseOpsuState {
// initialize buttons
Image button = GameImage.MENU_BUTTON_MID.getImage();
- button = button.getScaledCopy(displayContainer.width / 2, button.getHeight());
+ button = button.getScaledCopy(width2, button.getHeight());
Image buttonL = GameImage.MENU_BUTTON_LEFT.getImage();
Image buttonR = GameImage.MENU_BUTTON_RIGHT.getImage();
for (MenuState ms : MenuState.values()) {
@@ -624,7 +622,7 @@ public class ButtonMenu extends BaseOpsuState {
public void preRenderUpdate() {
super.preRenderUpdate();
- UI.update(displayContainer.renderDelta);
+ UI.update(renderDelta);
MusicController.loopTrackIfEnded(false);
menuState.preRenderUpdate();
}
diff --git a/src/itdelatrisu/opsu/states/DownloadsMenu.java b/src/itdelatrisu/opsu/states/DownloadsMenu.java
index 23fe14b8..b783b300 100644
--- a/src/itdelatrisu/opsu/states/DownloadsMenu.java
+++ b/src/itdelatrisu/opsu/states/DownloadsMenu.java
@@ -53,7 +53,6 @@ import org.newdawn.slick.SlickException;
import org.newdawn.slick.gui.TextField;
import org.newdawn.slick.util.Log;
import yugecin.opsudance.core.state.ComplexOpsuState;
-import yugecin.opsudance.events.BarNotifListener;
import static org.lwjgl.input.Keyboard.*;
import static yugecin.opsudance.core.InstanceContainer.*;
@@ -150,9 +149,6 @@ public class DownloadsMenu extends ComplexOpsuState {
/** Beatmap set ID of the current beatmap being previewed, or -1 if none. */
private int previewID = -1;
- /** The bar notification to send upon entering the state. */
- private String barNotificationOnLoad;
-
/** Search query, executed in {@code queryThread}. */
private SearchQuery searchQuery;
@@ -273,13 +269,12 @@ public class DownloadsMenu extends ComplexOpsuState {
if (this.importedNode == null) {
return;
}
- String msg;
+
if (dirs.length == 1) {
- msg = "Imported 1 new song.";
- } else {
- msg = String.format("Imported %d new songs.", dirs.length);
+ barNotifs.send("Imported 1 new song.");
+ return;
}
- BarNotifListener.EVENT.make().onBarNotif(msg);
+ barNotifs.sendf("Imported %d new songs.", dirs.length);
}
}
@@ -298,8 +293,6 @@ public class DownloadsMenu extends ComplexOpsuState {
components.clear();
- int width = displayContainer.width;
- int height = displayContainer.height;
int baseX = (int) (width * 0.024f);
int searchY = (int) (height * 0.04f + Fonts.LARGE.getLineHeight());
int searchWidth = (int) (width * 0.3f);
@@ -371,7 +364,7 @@ public class DownloadsMenu extends ComplexOpsuState {
// dropdown menu
int serverWidth = (int) (width * 0.12f);
int x = baseX + searchWidth + buttonMarginX * 3 + resetButtonWidth + rankedButtonWidth;
- serverMenu = new DropdownMenu(displayContainer, SERVERS, x, searchY, serverWidth) {
+ serverMenu = new DropdownMenu(SERVERS, x, searchY, serverWidth) {
@Override
public void itemSelected(int index, DownloadServer item) {
resultList = null;
@@ -414,7 +407,7 @@ public class DownloadsMenu extends ComplexOpsuState {
GameImage.SEARCH_BG.getImage().draw();
// title
- Fonts.LARGE.drawString(displayContainer.width * 0.024f, displayContainer.height * 0.03f, "Download Beatmaps!", Color.white);
+ Fonts.LARGE.drawString(width * 0.024f, height * 0.03f, "Download Beatmaps!", Color.white);
// search
g.setColor(Color.white);
@@ -440,7 +433,7 @@ public class DownloadsMenu extends ComplexOpsuState {
if (index >= nodes.length)
break;
nodes[index].drawResult(g, offset + i * DownloadNode.getButtonOffset(),
- DownloadNode.resultContains(displayContainer.mouseX, displayContainer.mouseY - offset, i) && !serverMenu.isHovered(),
+ DownloadNode.resultContains(mouseX, mouseY - offset, i) && !serverMenu.isHovered(),
(index == focusResult), (previewID == nodes[index].getID()));
}
g.clearClip();
@@ -451,9 +444,9 @@ public class DownloadsMenu extends ComplexOpsuState {
// pages
if (nodes.length > 0) {
- float baseX = displayContainer.width * 0.024f;
- float buttonY = displayContainer.height * 0.2f;
- float buttonWidth = displayContainer.width * 0.7f;
+ float baseX = width * 0.024f;
+ float buttonY = height * 0.2f;
+ float buttonWidth = width * 0.7f;
Fonts.BOLD.drawString(
baseX + (buttonWidth - Fonts.BOLD.getWidth("Page 1")) / 2f,
buttonY - Fonts.BOLD.getLineHeight() * 1.3f,
@@ -467,11 +460,10 @@ public class DownloadsMenu extends ComplexOpsuState {
}
// downloads
- float downloadsX = displayContainer.width * 0.75f, downloadsY = search.y;
+ float downloadsX = width * 0.75f, downloadsY = search.y;
g.setColor(Colors.BLACK_BG_NORMAL);
- g.fillRect(downloadsX, downloadsY,
- displayContainer.width * 0.25f, displayContainer.height - downloadsY * 2f);
- Fonts.LARGE.drawString(downloadsX + displayContainer.width * 0.015f, downloadsY + displayContainer.height * 0.015f, "Downloads", Color.white);
+ g.fillRect(downloadsX, downloadsY, width * 0.25f, height - downloadsY * 2f);
+ Fonts.LARGE.drawString(downloadsX + width * 0.015f, downloadsY + height * 0.015f, "Downloads", Color.white);
int downloadsSize = DownloadList.get().size();
if (downloadsSize > 0) {
int maxDownloadsShown = DownloadNode.maxDownloadsShown();
@@ -487,7 +479,7 @@ public class DownloadsMenu extends ComplexOpsuState {
if (node == null)
break;
node.drawDownload(g, i * DownloadNode.getInfoHeight() + offset, index,
- DownloadNode.downloadContains(displayContainer.mouseX, displayContainer.mouseY - offset, i));
+ DownloadNode.downloadContains(mouseX, mouseY - offset, i));
}
g.clearClip();
@@ -510,15 +502,13 @@ public class DownloadsMenu extends ComplexOpsuState {
if (importThread != null) {
// darken the screen
g.setColor(Colors.BLACK_ALPHA);
- g.fillRect(0, 0, displayContainer.width, displayContainer.height);
+ g.fillRect(0, 0, width, height);
UI.drawLoadingProgress(g);
+ } else {
+ backButton.draw(g);
}
- // back button
- else
- UI.getBackButton().draw(g);
-
UI.draw(g);
}
@@ -526,7 +516,7 @@ public class DownloadsMenu extends ComplexOpsuState {
public void preRenderUpdate() {
super.preRenderUpdate();
- int delta = displayContainer.renderDelta;
+ int delta = renderDelta;
UI.update(delta);
if (importThread == null)
MusicController.loopTrackIfEnded(false);
@@ -547,9 +537,7 @@ public class DownloadsMenu extends ComplexOpsuState {
}
importThread = null;
}
- int mouseX = displayContainer.mouseX;
- int mouseY = displayContainer.mouseY;
- UI.getBackButton().hoverUpdate(delta, mouseX, mouseY);
+ backButton.hoverUpdate();
prevPage.hoverUpdate(delta, mouseX, mouseY);
nextPage.hoverUpdate(delta, mouseX, mouseY);
clearButton.hoverUpdate(delta, mouseX, mouseY);
@@ -619,7 +607,7 @@ public class DownloadsMenu extends ComplexOpsuState {
}
// back
- if (UI.getBackButton().contains(x, y)) {
+ if (backButton.contains(x, y)) {
SoundController.playSound(SoundEffect.MENUBACK);
displayContainer.switchState(mainmenuState);
return true;
@@ -686,7 +674,7 @@ public class DownloadsMenu extends ComplexOpsuState {
if (playing)
previewID = node.getID();
} catch (SlickException e) {
- BarNotifListener.EVENT.make().onBarNotif("Failed to load track preview. See log for details.");
+ barNotifs.send("Failed to load track preview. See log for details.");
Log.error(e);
}
}
@@ -709,7 +697,7 @@ public class DownloadsMenu extends ComplexOpsuState {
if (!DownloadList.get().contains(node.getID())) {
node.createDownload(serverMenu.getSelectedItem());
if (node.getDownload() == null) {
- BarNotifListener.EVENT.make().onBarNotif("The download could not be started");
+ barNotifs.send("The download could not be started");
} else {
DownloadList.get().addNode(node);
node.getDownload().start();
@@ -856,7 +844,7 @@ public class DownloadsMenu extends ComplexOpsuState {
}
int shift = (newValue < 0) ? 1 : -1;
- scrollLists(displayContainer.mouseX, displayContainer.mouseY, shift);
+ scrollLists(mouseX, mouseY, shift);
return true;
}
@@ -950,10 +938,6 @@ public class DownloadsMenu extends ComplexOpsuState {
startDownloadIndexPos.setPosition(0);
pageDir = Page.RESET;
previewID = -1;
- if (barNotificationOnLoad != null) {
- BarNotifListener.EVENT.make().onBarNotif(barNotificationOnLoad);
- barNotificationOnLoad = null;
- }
}
@Override
@@ -994,10 +978,4 @@ public class DownloadsMenu extends ComplexOpsuState {
else if (DownloadNode.downloadAreaContains(cx, cy))
startDownloadIndexPos.scrollOffset(shift * DownloadNode.getInfoHeight());
}
-
- /**
- * Sends a bar notification upon entering the state.
- * @param s the notification string
- */
- public void notifyOnLoad(String s) { barNotificationOnLoad = s; }
}
diff --git a/src/itdelatrisu/opsu/states/Game.java b/src/itdelatrisu/opsu/states/Game.java
index ca6697c6..e71fa0ad 100644
--- a/src/itdelatrisu/opsu/states/Game.java
+++ b/src/itdelatrisu/opsu/states/Game.java
@@ -24,6 +24,7 @@ import itdelatrisu.opsu.audio.MusicController;
import itdelatrisu.opsu.audio.SoundController;
import itdelatrisu.opsu.audio.SoundEffect;
import itdelatrisu.opsu.beatmap.Beatmap;
+import itdelatrisu.opsu.beatmap.BeatmapParser;
import itdelatrisu.opsu.beatmap.HitObject;
import itdelatrisu.opsu.beatmap.TimingPoint;
import itdelatrisu.opsu.db.BeatmapDB;
@@ -60,9 +61,6 @@ import org.newdawn.slick.SlickException;
import org.newdawn.slick.util.Log;
import yugecin.opsudance.*;
import yugecin.opsudance.core.state.ComplexOpsuState;
-import yugecin.opsudance.core.state.specialstates.BubNotifState;
-import yugecin.opsudance.events.BarNotifListener;
-import yugecin.opsudance.events.BubNotifListener;
import yugecin.opsudance.objects.curves.FakeCombinedCurve;
import yugecin.opsudance.options.OptionGroups;
import yugecin.opsudance.sbv2.MoveStoryboard;
@@ -71,6 +69,8 @@ import yugecin.opsudance.ui.OptionsOverlay;
import yugecin.opsudance.ui.StoryboardOverlay;
import yugecin.opsudance.utils.GLHelper;
+import static itdelatrisu.opsu.GameImage.*;
+import static itdelatrisu.opsu.ui.Colors.*;
import static org.lwjgl.input.Keyboard.*;
import static yugecin.opsudance.options.Options.*;
import static yugecin.opsudance.core.InstanceContainer.*;
@@ -268,8 +268,6 @@ public class Game extends ComplexOpsuState {
/** Music position bar coordinates and dimensions (for replay seeking). */
private float musicBarX, musicBarY, musicBarWidth, musicBarHeight;
- public static int currentMapMusicOffset;
-
private int mirrorFrom;
private int mirrorTo;
@@ -320,9 +318,9 @@ public class Game extends ComplexOpsuState {
public Game() {
super();
mirrorCursor = new Cursor(true);
- this.moveStoryboardOverlay = new MoveStoryboard(displayContainer);
- this.optionsOverlay = new OptionsOverlay(displayContainer, OptionGroups.storyboardOptions);
- this.storyboardOverlay = new StoryboardOverlay(displayContainer, moveStoryboardOverlay, optionsOverlay, this);
+ this.moveStoryboardOverlay = new MoveStoryboard();
+ this.optionsOverlay = new OptionsOverlay(OptionGroups.storyboardOptions);
+ this.storyboardOverlay = new StoryboardOverlay(moveStoryboardOverlay, optionsOverlay, this);
storyboardOverlay.show();
moveStoryboardOverlay.show();
optionsOverlay.setListener(storyboardOverlay);
@@ -334,25 +332,26 @@ public class Game extends ComplexOpsuState {
// create offscreen graphics
try {
- offscreen = new Image(displayContainer.width, displayContainer.height);
+ offscreen = new Image(width, height);
gOffscreen = offscreen.getGraphics();
gOffscreen.setBackground(Color.black);
} catch (SlickException e) {
Log.error("could not create offscreen graphics", e);
- BubNotifListener.EVENT.make().onBubNotif(
- "Exception while creating offscreen graphics. See logfile for details.",
- Colors.BUB_RED);
+ bubNotifs.send(
+ BUB_RED,
+ "Exception while creating offscreen graphics. See logfile for details."
+ );
}
// initialize music position bar location
- musicBarX = displayContainer.width * 0.01f;
- musicBarY = displayContainer.height * 0.05f;
- musicBarWidth = Math.max(displayContainer.width * 0.005f, 7);
- musicBarHeight = displayContainer.height * 0.9f;
+ musicBarX = width * 0.01f;
+ musicBarY = height * 0.05f;
+ musicBarWidth = Math.max(width * 0.005f, 7);
+ musicBarHeight = height * 0.9f;
// initialize scoreboard star stream
- scoreboardStarStream = new StarStream(0, displayContainer.height * 2f / 3f, displayContainer.width / 4, 0, 0);
- scoreboardStarStream.setPositionSpread(displayContainer.height / 20f);
+ scoreboardStarStream = new StarStream(0, height * 2f / 3f, width / 4, 0, 0);
+ scoreboardStarStream.setPositionSpread(height / 20f);
scoreboardStarStream.setDirectionSpread(10f);
scoreboardStarStream.setDurationSpread(700, 100);
@@ -386,12 +385,9 @@ public class Game extends ComplexOpsuState {
@Override
public void render(Graphics g) {
- int width = displayContainer.width;
- int height = displayContainer.height;
-
int trackPosition = MusicController.getPosition();
if (isLeadIn()) {
- trackPosition -= leadInTime - currentMapMusicOffset - OPTION_MUSIC_OFFSET.val;
+ trackPosition -= leadInTime - OPTION_MUSIC_OFFSET.val - beatmap.localMusicOffset;
}
if (pauseTime > -1) // returning from pause screen
trackPosition = pauseTime;
@@ -444,7 +440,7 @@ public class Game extends ComplexOpsuState {
if (GameMod.FLASHLIGHT.isActive()) {
// render hit objects offscreen
Graphics.setCurrent(gOffscreen);
- int trackPos = (isLeadIn()) ? (leadInTime - OPTION_MUSIC_OFFSET.val) * -1 : trackPosition;
+ int trackPos = (isLeadIn()) ? (leadInTime - OPTION_MUSIC_OFFSET.val - beatmap.localMusicOffset) * -1 : trackPosition;
drawHitObjects(gOffscreen, trackPos);
// restore original graphics context
@@ -454,23 +450,23 @@ public class Game extends ComplexOpsuState {
// draw alpha map around cursor
g.setDrawMode(Graphics.MODE_ALPHA_MAP);
g.clearAlphaMap();
- int mouseX, mouseY;
+ int mx, my;
if (pauseTime > -1 && pausedMousePosition != null) {
- mouseX = (int) pausedMousePosition.x;
- mouseY = (int) pausedMousePosition.y;
+ mx = (int) pausedMousePosition.x;
+ my = (int) pausedMousePosition.y;
} else if (GameMod.AUTO.isActive() || GameMod.AUTOPILOT.isActive()) {
- mouseX = (int) autoMousePosition.x;
- mouseY = (int) autoMousePosition.y;
+ mx = (int) autoMousePosition.x;
+ my = (int) autoMousePosition.y;
} else if (isReplay) {
- mouseX = replayX;
- mouseY = replayY;
+ mx = replayX;
+ my = replayY;
} else {
- mouseX = displayContainer.mouseX;
- mouseY = displayContainer.mouseY;
+ mx = mouseX;
+ my = mouseY;
}
int alphaRadius = flashlightRadius * 256 / 215;
- int alphaX = mouseX - alphaRadius / 2;
- int alphaY = mouseY - alphaRadius / 2;
+ int alphaX = mx - alphaRadius / 2;
+ int alphaY = my - alphaRadius / 2;
GameImage.ALPHA_MAP.getImage().draw(alphaX, alphaY, alphaRadius, alphaRadius);
// blend offscreen image
@@ -557,8 +553,8 @@ public class Game extends ComplexOpsuState {
// show retries
if (retries >= 2 && timeDiff >= -1000) {
int retryHeight = Math.max(
- GameImage.SCOREBAR_BG.getImage().getHeight(),
- GameImage.SCOREBAR_KI.getImage().getHeight()
+ GameImage.SCOREBAR_BG.getHeight(),
+ GameImage.SCOREBAR_KI.getHeight()
);
float oldAlpha = Colors.WHITE_FADE.a;
if (timeDiff < -500)
@@ -571,8 +567,8 @@ public class Game extends ComplexOpsuState {
Colors.WHITE_FADE.a = oldAlpha;
}
- if (isLeadIn())
- trackPosition = (leadInTime - OPTION_MUSIC_OFFSET.val) * -1; // render approach circles during song lead-in
+ if (isLeadIn()) // render approach circles during song lead-in
+ trackPosition = (leadInTime - OPTION_MUSIC_OFFSET.val - beatmap.localMusicOffset) * -1;
// countdown
if (beatmap.countdown > 0) {
@@ -594,7 +590,7 @@ public class Game extends ComplexOpsuState {
}
}
if (timeDiff < 1500 * speedModifier) {
- GameImage.COUNTDOWN_2.getImage().draw(width - GameImage.COUNTDOWN_2.getImage().getWidth(), 0);
+ COUNTDOWN_2.getImage().draw(width - COUNTDOWN_2.getWidth(), 0);
if (!countdown2Sound) {
SoundController.playSound(SoundEffect.COUNT2);
countdown2Sound = true;
@@ -641,7 +637,7 @@ public class Game extends ComplexOpsuState {
float animation = AnimationEquation.IN_OUT_QUAD.calc(
Utils.clamp((trackPosition - lastRankUpdateTime) / SCOREBOARD_ANIMATION_TIME, 0f, 1f)
);
- int scoreboardPosition = 2 * displayContainer.height / 3;
+ int scoreboardPosition = 2 * height / 3;
// draw star stream behind the scores
scoreboardStarStream.draw();
@@ -682,7 +678,7 @@ public class Game extends ComplexOpsuState {
// draw music position bar (for replay seeking)
if (isReplay && OPTION_REPLAY_SEEKING.state) {
- g.setColor((musicPositionBarContains(displayContainer.mouseX, displayContainer.mouseY)) ? MUSICBAR_HOVER : MUSICBAR_NORMAL);
+ g.setColor((musicPositionBarContains(mouseX, mouseY)) ? MUSICBAR_HOVER : MUSICBAR_NORMAL);
g.fillRoundRect(musicBarX, musicBarY, musicBarWidth, musicBarHeight, 4);
if (!isLeadIn()) {
g.setColor(MUSICBAR_FILL);
@@ -698,8 +694,8 @@ public class Game extends ComplexOpsuState {
g.fillRect(0, 0, width, height);
// draw glowing hit select circle and pulse effect
- int circleDiameter = GameImage.HITCIRCLE.getImage().getWidth();
- Image cursorCircle = GameImage.HITCIRCLE_SELECT.getImage().getScaledCopy(circleDiameter, circleDiameter);
+ int circleDiameter = HITCIRCLE.getWidth();
+ Image cursorCircle = HITCIRCLE_SELECT.getScaledImage(circleDiameter, circleDiameter);
cursorCircle.setAlpha(1.0f);
cursorCircle.drawCentered(pausedMousePosition.x, pausedMousePosition.y);
Image cursorCirclePulse = cursorCircle.getScaledCopy(1f + pausePulse);
@@ -718,6 +714,15 @@ public class Game extends ComplexOpsuState {
displayContainer.cursor.draw(Utils.isGameKeyPressed());
}
+ super.render(g);
+
+ if (OPTION_DANCE_ENABLE_SB.state) {
+ optionsOverlay.render(g);
+ if (optionsOverlay.isActive()) {
+ backButton.draw(g);
+ }
+ }
+
UI.draw(g);
//g.setColor(new Color(0.2f, 0.2f, 0.2f));
@@ -736,15 +741,20 @@ public class Game extends ComplexOpsuState {
replayPlayback.render(displayContainer.renderDelta, g, ypos, trackPosition);
//}
}
-
- super.render(g);
}
@Override
public void preRenderUpdate() {
super.preRenderUpdate();
- int delta = displayContainer.renderDelta;
+ if (OPTION_DANCE_ENABLE_SB.state) {
+ optionsOverlay.preRenderUpdate();
+ if (optionsOverlay.isActive()) {
+ backButton.hoverUpdate();
+ }
+ }
+
+ int delta = renderDelta;
UI.update(delta);
Pippi.update(delta);
@@ -752,8 +762,6 @@ public class Game extends ComplexOpsuState {
epiImgTime -= delta;
}
yugecin.opsudance.spinners.Spinner.update(delta);
- int mouseX = displayContainer.mouseX;
- int mouseY = displayContainer.mouseY;
skipButton.hoverUpdate(delta, mouseX, mouseY);
if (isReplay || GameMod.AUTO.isActive())
playbackSpeed.getButton().hoverUpdate(delta, mouseX, mouseY);
@@ -929,16 +937,16 @@ public class Game extends ComplexOpsuState {
} else if (GameMod.AUTO.isActive()) {
displayContainer.cursor.setCursorPosition(displayContainer.delta, (int) autoMousePosition.x, (int) autoMousePosition.y);
if (OPTION_DANCE_MIRROR.state && GameMod.AUTO.isActive()) {
- double dx = autoMousePosition.x - displayContainer.width / 2d;
- double dy = autoMousePosition.y - displayContainer.height / 2d;
+ double dx = autoMousePosition.x - width2;
+ double dy = autoMousePosition.y - height2;
double d = Math.sqrt(dx * dx + dy * dy);
double a = Math.atan2(dy, dx) + Math.PI;
- mirrorCursor.setCursorPosition(displayContainer.delta, (int) (Math.cos(a) * d + displayContainer.width / 2), (int) (Math.sin(a) * d + displayContainer.height / 2));
+ mirrorCursor.setCursorPosition(displayContainer.delta, (int) (Math.cos(a) * d + width2), (int) (Math.sin(a) * d + height2));
}
} else if (GameMod.AUTOPILOT.isActive()) {
displayContainer.cursor.setCursorPosition(displayContainer.delta, (int) autoMousePosition.x, (int) autoMousePosition.y);
} else {
- displayContainer.cursor.setCursorPosition(displayContainer.delta, displayContainer.mouseX, displayContainer.mouseY);
+ displayContainer.cursor.setCursorPosition(displayContainer.delta, mouseX, mouseY);
}
}
@@ -1088,7 +1096,6 @@ public class Game extends ComplexOpsuState {
if (restart != Restart.LOSE) {
// update objects (loop in unlikely event of any skipped indexes)
boolean keyPressed = keys != ReplayFrame.KEY_NONE;
- boolean skippedObject = false;
while (objectIndex < gameObjects.length && trackPosition > beatmap.objects[objectIndex].getTime()) {
// check if we've already passed the next object's start time
boolean overlap = (objectIndex + 1 < gameObjects.length &&
@@ -1096,7 +1103,6 @@ public class Game extends ComplexOpsuState {
// update hit object and check completion status
if (gameObjects[objectIndex].update(overlap, delta, mouseX, mouseY, keyPressed, trackPosition)) {
- skippedObject = true;
objectIndex++; // done, so increment object index
storyboardOverlay.updateIndex(objectIndex);
if (objectIndex >= mirrorTo) {
@@ -1119,6 +1125,10 @@ public class Game extends ComplexOpsuState {
@Override
public boolean keyPressed(int key, char c) {
+ if (OPTION_DANCE_ENABLE_SB.state && optionsOverlay.keyPressed(key, c)) {
+ return true;
+ }
+
if (super.keyPressed(key, c)) {
return true;
}
@@ -1128,8 +1138,6 @@ public class Game extends ComplexOpsuState {
}
int trackPosition = MusicController.getPosition();
- int mouseX = displayContainer.mouseX;
- int mouseY = displayContainer.mouseY;
// game keys
if (!Keyboard.isRepeatEvent()) {
@@ -1189,7 +1197,7 @@ public class Game extends ComplexOpsuState {
if (0 <= time && time < 3600) {
OPTION_CHECKPOINT.setValue(time);
SoundController.playSound(SoundEffect.MENUCLICK);
- BarNotifListener.EVENT.make().onBarNotif("Checkpoint saved.");
+ barNotifs.send("Checkpoint saved.");
}
}
break;
@@ -1201,7 +1209,7 @@ public class Game extends ComplexOpsuState {
break; // invalid checkpoint
loadCheckpoint(checkpoint);
SoundController.playSound(SoundEffect.MENUHIT);
- BarNotifListener.EVENT.make().onBarNotif("Checkpoint loaded.");
+ barNotifs.send("Checkpoint loaded.");
}
break;
case KEY_F:
@@ -1242,14 +1250,13 @@ public class Game extends ComplexOpsuState {
}
OPTION_DANCE_MIRROR.toggle();
break;
+ case KEY_SUBTRACT:
case KEY_MINUS:
- currentMapMusicOffset += 5;
- BarNotifListener.EVENT.make().onBarNotif("Current map offset: " + currentMapMusicOffset);
+ adjustLocalMusicOffset(-5);
break;
}
- if (key == KEY_ADD || c == '+') {
- currentMapMusicOffset -= 5;
- BarNotifListener.EVENT.make().onBarNotif("Current map offset: " + currentMapMusicOffset);
+ if (key == KEY_EQUALS || key == KEY_ADD || c == '+') {
+ adjustLocalMusicOffset(5);
}
return true;
@@ -1257,14 +1264,21 @@ public class Game extends ComplexOpsuState {
@Override
public boolean mouseDragged(int oldx, int oldy, int newx, int newy) {
- if (super.mouseDragged(oldx, oldy, newx, newy)) {
+ if (OPTION_DANCE_ENABLE_SB.state &&
+ optionsOverlay.mouseDragged(oldx, oldy, newx, newy))
+ {
return true;
}
- return true;
+
+ return super.mouseDragged(oldx, oldy, newx, newy);
}
@Override
public boolean mousePressed(int button, int x, int y) {
+ if (OPTION_DANCE_ENABLE_SB.state && optionsOverlay.mousePressed(button, x, y)) {
+ return true;
+ }
+
if (super.mousePressed(button, x, y)) {
return true;
}
@@ -1340,7 +1354,7 @@ public class Game extends ComplexOpsuState {
// returning from pause screen
if (pauseTime > -1) {
double distance = Math.hypot(pausedMousePosition.x - x, pausedMousePosition.y - y);
- int circleRadius = GameImage.HITCIRCLE.getImage().getWidth() / 2;
+ int circleRadius = GameImage.HITCIRCLE.getWidth() / 2;
if (distance < circleRadius) {
// unpause the game
pauseTime = -1;
@@ -1370,6 +1384,10 @@ public class Game extends ComplexOpsuState {
@Override
public boolean mouseReleased(int button, int x, int y) {
+ if (OPTION_DANCE_ENABLE_SB.state && optionsOverlay.mouseReleased(button, x, y)) {
+ return true;
+ }
+
if (super.mouseReleased(button, x, y)) {
return true;
}
@@ -1399,6 +1417,10 @@ public class Game extends ComplexOpsuState {
@Override
public boolean keyReleased(int key, char c) {
+ if (OPTION_DANCE_ENABLE_SB.state && optionsOverlay.keyReleased(key, c)) {
+ return true;
+ }
+
if (super.keyReleased(key, c)) {
return true;
}
@@ -1436,6 +1458,10 @@ public class Game extends ComplexOpsuState {
@Override
public boolean mouseWheelMoved(int newValue) {
+ if (OPTION_DANCE_ENABLE_SB.state && optionsOverlay.mouseWheelMoved(newValue)) {
+ return true;
+ }
+
if (super.mouseWheelMoved(newValue)) {
return true;
}
@@ -1453,11 +1479,9 @@ public class Game extends ComplexOpsuState {
public void enter() {
overlays.clear();
if (OPTION_DANCE_ENABLE_SB.state) {
- overlays.add(optionsOverlay);
overlays.add(moveStoryboardOverlay);
overlays.add(storyboardOverlay);
storyboardOverlay.onEnter();
- optionsOverlay.revalidate();
}
super.enter();
@@ -1523,8 +1547,9 @@ public class Game extends ComplexOpsuState {
}
if (beatmap == null || beatmap.objects == null) {
- BubNotifListener.EVENT.make().onBubNotif("Game was running without a beatmap", Colors.BUB_RED);
+ bubNotifs.send(BUB_RED, "Game was running without a beatmap");
displayContainer.switchStateInstantly(songMenuState);
+ return;
}
Dancer.instance.reset();
@@ -1552,10 +1577,9 @@ public class Game extends ComplexOpsuState {
epiImgTime = OPTION_EPILEPSY_WARNING.val * 100;
if (epiImgTime > 0) {
epiImg = GameImage.EPILEPSY_WARNING.getImage();
- float desWidth = displayContainer.width / 2;
- epiImg = epiImg.getScaledCopy(desWidth / epiImg.getWidth());
- epiImgX = (displayContainer.width - epiImg.getWidth()) / 2;
- epiImgY = (displayContainer.height - epiImg.getHeight()) / 2;
+ epiImg = epiImg.getScaledCopy(width2 / epiImg.getWidth());
+ epiImgX = width2 - epiImg.getWidth() / 2;
+ epiImgY = height2 - epiImg.getHeight() / 2;
}
// load mods
@@ -1630,7 +1654,7 @@ public class Game extends ComplexOpsuState {
} catch (Exception e) {
String message = String.format("Failed to create %s at index %d:\n%s", hitObject.getTypeName(), i, hitObject.toString());
Log.error(message, e);
- BubNotifListener.EVENT.make().onBubNotif(message, Colors.BUB_RED);
+ bubNotifs.send(BUB_RED, message);
gameObjects[i] = new DummyObject(hitObject);
}
}
@@ -1657,8 +1681,8 @@ public class Game extends ComplexOpsuState {
// load replay frames
if (isReplay) {
// load initial data
- replayX = displayContainer.width / 2;
- replayY = displayContainer.height / 2;
+ replayX = width2;
+ replayY = height2;
replayKeyPressed = false;
replaySkipTime = -1;
for (replayIndex = 0; replayIndex < replay.frames.length; replayIndex++) {
@@ -1680,7 +1704,7 @@ public class Game extends ComplexOpsuState {
lastKeysPressed = ReplayFrame.KEY_NONE;
replaySkipTime = -1;
replayFrames = new LinkedList<>();
- replayFrames.add(new ReplayFrame(0, 0, displayContainer.mouseX, displayContainer.mouseY, 0));
+ replayFrames.add(new ReplayFrame(0, 0, mouseX, mouseY, 0));
}
for (int i = 0; i < gameObjects.length; i++) {
@@ -1698,6 +1722,10 @@ public class Game extends ComplexOpsuState {
scoreboardVisible = true;
currentScoreboardAlpha = 0f;
+ // using local offset?
+ if (beatmap.localMusicOffset != 0)
+ barNotifs.send(String.format("Using local beatmap offset (%dms)", beatmap.localMusicOffset));
+
// needs to play before setting position to resume without lag later
MusicController.play(false);
MusicController.setPosition(0);
@@ -1773,6 +1801,8 @@ public class Game extends ComplexOpsuState {
storyboardOverlay.onLeave();
}
+ optionsOverlay.hide();
+
isInGame = false;
// container.setMouseGrabbed(false);
skippedToCheckpoint = false;
@@ -1796,6 +1826,18 @@ public class Game extends ComplexOpsuState {
GameMod.loadModState(previousMods);
}
+ /**
+ * Adjusts the beatmap's local music offset.
+ * @param sign the sign (multiplier)
+ */
+ public void adjustLocalMusicOffset(int amount) {
+ int newOffset = beatmap.localMusicOffset + amount;
+ barNotifs.send(String.format("Local beatmap offset set to %dms", newOffset));
+ if (beatmap.localMusicOffset != newOffset) {
+ beatmap.localMusicOffset = newOffset;
+ BeatmapDB.updateLocalOffset(beatmap);
+ }
+ }
public void addMergedSliderPointsToRender(int from, int to) {
knorkesliders.addRange(from, to);
}
@@ -1850,7 +1892,7 @@ public class Game extends ComplexOpsuState {
}
if (lastObjectIndex != -1 && !beatmap.objects[index].isNewCombo()) {
// calculate points
- final int followPointInterval = displayContainer.height / 14;
+ final int followPointInterval = height / 14;
int lastObjectEndTime = gameObjects[lastObjectIndex].getEndTime() + 1;
int objectStartTime = beatmap.objects[index].getTime();
Vec2f startPoint = gameObjects[lastObjectIndex].getPointAt(lastObjectEndTime);
@@ -1858,7 +1900,7 @@ public class Game extends ComplexOpsuState {
float xDiff = endPoint.x - startPoint.x;
float yDiff = endPoint.y - startPoint.y;
float dist = (float) Math.hypot(xDiff, yDiff);
- int numPoints = (int) ((dist - GameImage.HITCIRCLE.getImage().getWidth()) / followPointInterval);
+ int numPoints = (int) ((dist - GameImage.HITCIRCLE.getWidth()) / followPointInterval);
if (numPoints > 0) {
// set the image angle
Image followPoint = GameImage.FOLLOWPOINT.getImage();
@@ -1911,7 +1953,7 @@ public class Game extends ComplexOpsuState {
gameObj.draw(g, trackPosition, false);
if (OPTION_DANCE_MIRROR.state && GameMod.AUTO.isActive() && idx < mirrorTo && idx >= mirrorFrom) {
g.pushTransform();
- g.rotate(displayContainer.width / 2f, displayContainer.height / 2f, 180f);
+ g.rotate(width2, height2, 180f);
gameObj.draw(g, trackPosition, true);
g.popTransform();
}
@@ -1939,7 +1981,7 @@ public class Game extends ComplexOpsuState {
g.pushTransform();
// translate and rotate the object
- g.translate(0, dt * dt * displayContainer.height);
+ g.translate(0, dt * dt * height);
Vec2f rotationCenter = gameObj.getPointAt((beatmap.objects[idx].getTime() + beatmap.objects[idx].getEndTime()) / 2);
g.rotate(rotationCenter.x, rotationCenter.y, rotSpeed * dt);
gameObj.draw(g, trackPosition, false);
@@ -1954,15 +1996,12 @@ public class Game extends ComplexOpsuState {
* @param beatmap the beatmap to load
*/
public void loadBeatmap(Beatmap beatmap) {
- if (this.beatmap == null || this.beatmap.beatmapID != beatmap.beatmapID) {
- currentMapMusicOffset = 0;
- }
this.beatmap = beatmap;
Display.setTitle(String.format("opsu!dance - %s", beatmap.toString()));
if (beatmap.breaks == null) {
BeatmapDB.load(beatmap, BeatmapDB.LOAD_ARRAY);
}
- beatmapParser.parseHitObjects(beatmap);
+ BeatmapParser.parseHitObjects(beatmap);
HitSound.setDefaultSampleSet(beatmap.sampleSet);
}
@@ -1993,7 +2032,7 @@ public class Game extends ComplexOpsuState {
lastReplayTime = 0;
autoMousePosition = new Vec2f();
autoMousePressed = false;
- flashlightRadius = displayContainer.height * 2 / 3;
+ flashlightRadius = height * 2 / 3;
if (scoreboardStarStream != null) {
scoreboardStarStream.clear();
}
@@ -2045,10 +2084,10 @@ public class Game extends ComplexOpsuState {
// skip button
if (GameImage.SKIP.getImages() != null) {
Animation skip = GameImage.SKIP.getAnimation(120);
- skipButton = new MenuButton(skip, displayContainer.width - skip.getWidth() / 2f, displayContainer.height - (skip.getHeight() / 2f));
+ skipButton = new MenuButton(skip, width - skip.getWidth() / 2f, height - (skip.getHeight() / 2f));
} else {
Image skip = GameImage.SKIP.getImage();
- skipButton = new MenuButton(skip, displayContainer.width - skip.getWidth() / 2f, displayContainer.height - (skip.getHeight() / 2f));
+ skipButton = new MenuButton(skip, width - skip.getWidth() / 2f, height - (skip.getHeight() / 2f));
}
skipButton.setHoverAnimationDuration(350);
skipButton.setHoverAnimationEquation(AnimationEquation.IN_OUT_BACK);
@@ -2093,12 +2132,12 @@ public class Game extends ComplexOpsuState {
// initialize objects
gameObjectRenderer.initForGame(data, diameter);
Slider.init(gameObjectRenderer.circleDiameter, beatmap);
- Spinner.init(displayContainer, overallDifficulty);
+ Spinner.init(overallDifficulty);
Color sliderBorderColor = SkinService.skin.getSliderBorderColor();
if (!OPTION_IGNORE_BEATMAP_SKINS.state && beatmap.getSliderBorderColor() != null) {
sliderBorderColor = beatmap.getSliderBorderColor();
}
- Curve.init(displayContainer.width, displayContainer.height, diameter, sliderBorderColor);
+ Curve.init(diameter, sliderBorderColor);
// approachRate (hit object approach time)
if (approachRate < 5)
@@ -2214,15 +2253,16 @@ public class Game extends ComplexOpsuState {
if (replay == null) {
this.isReplay = false;
this.replay = null;
- } else {
- if (replay.frames == null) {
- BubNotifListener.EVENT.make().onBubNotif("Attempting to set a replay with no frames.",
- Colors.BUB_ORANGE);
- return;
- }
- this.isReplay = true;
- this.replay = replay;
+ return;
}
+
+ if (replay.frames == null) {
+ bubNotifs.send(BUB_ORANGE, "Attempting to set a replay with no frames.");
+ return;
+ }
+
+ this.isReplay = true;
+ this.replay = replay;
}
/**
@@ -2316,25 +2356,25 @@ public class Game extends ComplexOpsuState {
if (isLeadIn()) {
// lead-in: expand area
float progress = Math.max((float) (leadInTime - beatmap.audioLeadIn) / approachTime, 0f);
- flashlightRadius = displayContainer.width - (int) ((displayContainer.width - (displayContainer.height * 2 / 3)) * progress);
+ flashlightRadius = width - (int) ((width - (height * 2 / 3)) * progress);
} else if (firstObject) {
// before first object: shrink area
int timeDiff = beatmap.objects[0].getTime() - trackPosition;
- flashlightRadius = displayContainer.width;
+ flashlightRadius = width;
if (timeDiff < approachTime) {
float progress = (float) timeDiff / approachTime;
- flashlightRadius -= (displayContainer.width - (displayContainer.height * 2 / 3)) * (1 - progress);
+ flashlightRadius -= (width - (height * 2 / 3)) * (1 - progress);
}
} else {
// gameplay: size based on combo
int targetRadius;
int combo = data.getComboStreak();
if (combo < 100)
- targetRadius = displayContainer.height * 2 / 3;
+ targetRadius = height * 2 / 3;
else if (combo < 200)
- targetRadius = displayContainer.height / 2;
+ targetRadius = height2;
else
- targetRadius = displayContainer.height / 3;
+ targetRadius = height / 3;
if (beatmap.breaks != null && breakIndex < beatmap.breaks.size() && breakTime > 0) {
// breaks: expand at beginning, shrink at end
flashlightRadius = targetRadius;
@@ -2346,11 +2386,11 @@ public class Game extends ComplexOpsuState {
progress = (float) (trackPosition - breakTime) / approachTime;
else if (endTime - trackPosition < approachTime)
progress = (float) (endTime - trackPosition) / approachTime;
- flashlightRadius += (displayContainer.width - flashlightRadius) * progress;
+ flashlightRadius += (width - flashlightRadius) * progress;
}
} else if (flashlightRadius != targetRadius) {
// radius size change
- float radiusDiff = displayContainer.height * delta / 2000f;
+ float radiusDiff = height * delta / 2000f;
if (flashlightRadius > targetRadius) {
flashlightRadius -= radiusDiff;
if (flashlightRadius < targetRadius)
diff --git a/src/itdelatrisu/opsu/states/GamePauseMenu.java b/src/itdelatrisu/opsu/states/GamePauseMenu.java
index dc92a060..a320f3ca 100644
--- a/src/itdelatrisu/opsu/states/GamePauseMenu.java
+++ b/src/itdelatrisu/opsu/states/GamePauseMenu.java
@@ -32,6 +32,7 @@ import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import yugecin.opsudance.core.state.BaseOpsuState;
+import static itdelatrisu.opsu.GameImage.*;
import static org.lwjgl.input.Keyboard.*;
import static yugecin.opsudance.core.InstanceContainer.*;
import static yugecin.opsudance.options.Options.*;
@@ -73,11 +74,11 @@ public class GamePauseMenu extends BaseOpsuState {
@Override
public void preRenderUpdate() {
- int delta = displayContainer.renderDelta;
+ int delta = renderDelta;
UI.update(delta);
- continueButton.hoverUpdate(delta, displayContainer.mouseX, displayContainer.mouseY);
- retryButton.hoverUpdate(delta, displayContainer.mouseX, displayContainer.mouseY);
- backButton.hoverUpdate(delta, displayContainer.mouseX, displayContainer.mouseY);
+ continueButton.hoverUpdate(delta, mouseX, mouseY);
+ retryButton.hoverUpdate(delta, mouseX, mouseY);
+ backButton.hoverUpdate(delta, mouseX, mouseY);
}
@Override
@@ -89,9 +90,9 @@ public class GamePauseMenu extends BaseOpsuState {
// game keys
if (!Keyboard.isRepeatEvent()) {
if (key == OPTION_KEY_LEFT.intval) {
- mousePressed(Input.MOUSE_LEFT_BUTTON, displayContainer.mouseX, displayContainer.mouseY);
+ mousePressed(Input.MOUSE_LEFT_BUTTON, mouseX, mouseY);
} else if (key == OPTION_KEY_RIGHT.intval) {
- mousePressed(Input.MOUSE_RIGHT_BUTTON, displayContainer.mouseX, displayContainer.mouseY);
+ mousePressed(Input.MOUSE_RIGHT_BUTTON, mouseX, mouseY);
}
}
@@ -116,6 +117,15 @@ public class GamePauseMenu extends BaseOpsuState {
return true;
}
+ if (key == KEY_SUBTRACT || key == KEY_MINUS) {
+ gameState.adjustLocalMusicOffset(-5);
+ return true;
+ }
+ if (key == KEY_EQUALS || key == KEY_ADD || c == '+') {
+ gameState.adjustLocalMusicOffset(5);
+ return true;
+ }
+
return false;
}
@@ -193,9 +203,9 @@ public class GamePauseMenu extends BaseOpsuState {
*/
public void loadImages() {
// initialize buttons
- continueButton = new MenuButton(GameImage.PAUSE_CONTINUE.getImage(), displayContainer.width / 2f, displayContainer.height * 0.25f);
- retryButton = new MenuButton(GameImage.PAUSE_RETRY.getImage(), displayContainer.width / 2f, displayContainer.height * 0.5f);
- backButton = new MenuButton(GameImage.PAUSE_BACK.getImage(), displayContainer.width / 2f, displayContainer.height * 0.75f);
+ continueButton = new MenuButton(PAUSE_CONTINUE.getImage(), width2, height * 0.25f);
+ retryButton = new MenuButton(PAUSE_RETRY.getImage(), width2, height2);
+ backButton = new MenuButton(PAUSE_BACK.getImage(), width2, height * 0.75f);
final int buttonAnimationDuration = 300;
continueButton.setHoverAnimationDuration(buttonAnimationDuration);
retryButton.setHoverAnimationDuration(buttonAnimationDuration);
diff --git a/src/itdelatrisu/opsu/states/GameRanking.java b/src/itdelatrisu/opsu/states/GameRanking.java
index eb069a0e..29bd9d3e 100644
--- a/src/itdelatrisu/opsu/states/GameRanking.java
+++ b/src/itdelatrisu/opsu/states/GameRanking.java
@@ -38,7 +38,6 @@ import org.newdawn.slick.Image;
import org.newdawn.slick.Input;
import org.newdawn.slick.util.Log;
import yugecin.opsudance.core.state.BaseOpsuState;
-import yugecin.opsudance.events.BarNotifListener;
import static yugecin.opsudance.core.InstanceContainer.*;
@@ -67,10 +66,10 @@ public class GameRanking extends BaseOpsuState {
// buttons
Image retry = GameImage.PAUSE_RETRY.getImage();
Image replay = GameImage.PAUSE_REPLAY.getImage();
- replayY = (displayContainer.height * 0.985f) - replay.getHeight() / 2f;
+ replayY = height * 0.985f - replay.getHeight() / 2f;
retryY = replayY - (replay.getHeight() / 2f) - (retry.getHeight() / 1.975f);
- retryButton = new MenuButton(retry, displayContainer.width - (retry.getWidth() / 2f), retryY);
- replayButton = new MenuButton(replay, displayContainer.width - (replay.getWidth() / 2f), replayY);
+ retryButton = new MenuButton(retry, width - (retry.getWidth() / 2f), retryY);
+ replayButton = new MenuButton(replay, width - (replay.getWidth() / 2f), replayY);
retryButton.setHoverFade();
replayButton.setHoverFade();
}
@@ -80,7 +79,7 @@ public class GameRanking extends BaseOpsuState {
Beatmap beatmap = MusicController.getBeatmap();
// background
- if (!beatmap.drawBackground(displayContainer.width, displayContainer.height, 0.7f, true)) {
+ if (!beatmap.drawBackground(width, height, 0.7f, true)) {
GameImage.PLAYFIELD.getImage().draw(0, 0);
}
@@ -91,7 +90,7 @@ public class GameRanking extends BaseOpsuState {
replayButton.draw();
if (data.isGameplay() && !GameMod.AUTO.isActive())
retryButton.draw();
- UI.getBackButton().draw(g);
+ backButton.draw(g);
UI.draw(g);
@@ -100,15 +99,15 @@ public class GameRanking extends BaseOpsuState {
@Override
public void preRenderUpdate() {
- int delta = displayContainer.renderDelta;
+ int delta = renderDelta;
UI.update(delta);
- replayButton.hoverUpdate(delta, displayContainer.mouseX, displayContainer.mouseY);
+ replayButton.hoverUpdate(delta, mouseX, mouseY);
if (data.isGameplay()) {
- retryButton.hoverUpdate(delta, displayContainer.mouseX, displayContainer.mouseY);
+ retryButton.hoverUpdate(delta, mouseX, mouseY);
} else {
MusicController.loopTrackIfEnded(true);
}
- UI.getBackButton().hoverUpdate(delta, displayContainer.mouseX, displayContainer.mouseY);
+ backButton.hoverUpdate();
}
@Override
@@ -140,7 +139,7 @@ public class GameRanking extends BaseOpsuState {
}
// back to menu
- if (UI.getBackButton().contains(x, y)) {
+ if (backButton.contains(x, y)) {
returnToSongMenu();
return true;
}
@@ -157,14 +156,14 @@ public class GameRanking extends BaseOpsuState {
gameState.setRestart((data.isGameplay()) ? Game.Restart.REPLAY : Game.Restart.NEW);
returnToGame = true;
} catch (FileNotFoundException e) {
- BarNotifListener.EVENT.make().onBarNotif("Replay file not found.");
+ barNotifs.send("Replay file not found.");
} catch (IOException e) {
Log.error("Failed to load replay data.", e);
- BarNotifListener.EVENT.make().onBarNotif(
- "Failed to load replay data. See log for details.");
+ barNotifs.send("Failed to load replay data. See log for details.");
}
- } else
- BarNotifListener.EVENT.make().onBarNotif("Replay file not found.");
+ } else {
+ barNotifs.send("Replay file not found.");
+ }
}
// retry
diff --git a/src/itdelatrisu/opsu/states/MainMenu.java b/src/itdelatrisu/opsu/states/MainMenu.java
index c711e05b..96fc42c7 100644
--- a/src/itdelatrisu/opsu/states/MainMenu.java
+++ b/src/itdelatrisu/opsu/states/MainMenu.java
@@ -37,20 +37,31 @@ import java.awt.Desktop;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
+import java.util.Iterator;
+import java.util.LinkedList;
import java.util.Stack;
import org.lwjgl.opengl.Display;
+import org.lwjgl.opengl.GL11;
import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.Input;
+import org.newdawn.slick.opengl.Texture;
+import org.newdawn.slick.opengl.renderer.SGL;
import org.newdawn.slick.util.Log;
import yugecin.opsudance.core.Constants;
+import yugecin.opsudance.core.Entrypoint;
+import yugecin.opsudance.core.InstanceContainer;
import yugecin.opsudance.core.state.BaseOpsuState;
import yugecin.opsudance.core.state.OpsuState;
-import yugecin.opsudance.events.BarNotifListener;
-import yugecin.opsudance.events.BubNotifListener;
+import yugecin.opsudance.ui.ImagePosition;
+import static itdelatrisu.opsu.GameImage.*;
+import static itdelatrisu.opsu.ui.Colors.*;
+import static itdelatrisu.opsu.ui.animations.AnimationEquation.*;
+import static java.awt.Desktop.Action.*;
+import static java.lang.Math.*;
import static org.lwjgl.input.Keyboard.*;
import static yugecin.opsudance.core.InstanceContainer.*;
import static yugecin.opsudance.options.Options.*;
@@ -63,13 +74,15 @@ import static yugecin.opsudance.options.Options.*;
public class MainMenu extends BaseOpsuState {
/** 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 = 6000;
/** Max alpha level of the menu background. */
private static final float BG_MAX_ALPHA = 0.9f;
+
+ private float barHeight;
- /** Logo button that reveals other buttons on click. */
- private MenuButton logo;
+ private ImagePosition logo;
+ private AnimatedValue logoHover;
/** Logo states. */
private enum LogoState { DEFAULT, OPENING, OPEN, CLOSING }
@@ -81,16 +94,27 @@ public class MainMenu extends BaseOpsuState {
private int logoTimer = 0;
/** Logo horizontal offset for opening and closing actions. */
- private AnimatedValue logoOpen, logoClose;
+ private AnimatedValue logoPosition;
+ private float logoPositionOffsetX;
+
+ private int lastMouseX;
+ private int lastMouseY;
+
+ private AnimatedValue logoClickScale;
+ private AnimatedValue buttonAnimation;
+ private int buttonsX;
+ private AnimatedValue[] buttonAnimations;
+ private ImagePosition[] buttonPositions;
/** Logo button alpha levels. */
private AnimatedValue logoButtonAlpha;
-
- /** Main "Play" and "Exit" buttons. */
- private MenuButton playButton, exitButton;
+
+ /** Now playing position vlaue. */
+ private final AnimatedValue nowPlayingPosition;
/** Music control buttons. */
- private MenuButton musicPlay, musicPause, musicNext, musicPrevious;
+ private MenuButton musicPlay, musicPause, musicStop, musicNext, musicPrev;
+ private MenuButton[] musicButtons = new MenuButton[5];
/** Button linking to Downloads menu. */
private MenuButton downloadsButton;
@@ -104,8 +128,9 @@ public class MainMenu extends BaseOpsuState {
/** Buttons for installing updates. */
private MenuButton updateButton, restartButton;
- /** Application start time, for drawing the total running time. */
- private long programStartTime;
+ private int textMarginX;
+ private int textTopMarginY;
+ private int textLineHeight;
/** Indexes of previous songs. */
private Stack previous;
@@ -117,117 +142,131 @@ public class MainMenu extends BaseOpsuState {
private boolean enterNotification = false;
/** Music position bar coordinates and dimensions. */
- private float musicBarX, musicBarY, musicBarWidth, musicBarHeight;
+ private int musicBarX, musicBarY, musicBarWidth, musicBarHeight;
/** Last measure progress value. */
private float lastMeasureProgress = 0f;
/** The star fountain. */
private StarFountain starFountain;
+
+ /** Time format used to show running time. */
+ private final SimpleDateFormat timeFormat;
+
+ private LinkedList pulseData = new LinkedList<>();
+ private float lastPulseProgress;
+
+ public MainMenu() {
+ this.nowPlayingPosition = new AnimatedValue(1000, 0, 0, OUT_QUART);
+ this.logoClickScale = new AnimatedValue(300, .9f, 1f, OUT_QUAD);
+ this.logoHover = new AnimatedValue(350, 1f, 1.096f, IN_OUT_EXPO);
+ this.logoPosition = new AnimatedValue(1, 0, 1, AnimationEquation.OUT_QUAD);
+ this.logoButtonAlpha = new AnimatedValue(200, 0f, 1f, AnimationEquation.LINEAR);
+ this.buttonAnimation = new AnimatedValue(1, 0f, 1f, OUT_QUAD);
+ this.buttonAnimations = new AnimatedValue[3];
+ for (int i = 0; i < 3; i++) {
+ this.buttonAnimations[i] = new AnimatedValue(1, 0f, 1f, LINEAR);
+ }
+ this.buttonPositions = new ImagePosition[3];
+ this.timeFormat = new SimpleDateFormat("HH:mm");
+ this.previous = new Stack<>();
+ }
@Override
protected void revalidate() {
- programStartTime = System.currentTimeMillis();
- previous = new Stack<>();
- // initialize menu buttons
- Image logoImg = GameImage.MENU_LOGO.getImage();
- Image playImg = GameImage.MENU_PLAY.getImage();
- Image exitImg = GameImage.MENU_EXIT.getImage();
- float exitOffset = (playImg.getWidth() - exitImg.getWidth()) / 3f;
- logo = new MenuButton(logoImg, displayContainer.width / 2f, displayContainer.height / 2f);
- playButton = new MenuButton(playImg,
- displayContainer.width * 0.75f, (displayContainer.height / 2) - (logoImg.getHeight() / 5f)
- );
- exitButton = new MenuButton(exitImg,
- displayContainer.width * 0.75f - exitOffset, (displayContainer.height / 2) + (exitImg.getHeight() / 2f)
- );
- final int logoAnimationDuration = 350;
- logo.setHoverAnimationDuration(logoAnimationDuration);
- playButton.setHoverAnimationDuration(logoAnimationDuration);
- exitButton.setHoverAnimationDuration(logoAnimationDuration);
- final AnimationEquation logoAnimationEquation = AnimationEquation.IN_OUT_BACK;
- logo.setHoverAnimationEquation(logoAnimationEquation);
- playButton.setHoverAnimationEquation(logoAnimationEquation);
- exitButton.setHoverAnimationEquation(logoAnimationEquation);
- final float logoHoverScale = 1.08f;
- logo.setHoverExpand(logoHoverScale);
- playButton.setHoverExpand(logoHoverScale);
- exitButton.setHoverExpand(logoHoverScale);
+ this.barHeight = height * 0.1125f;
+
+ this.textMarginX = (int) (width * 0.015f);
+ this.textTopMarginY = (int) (height * 0.01f);
+ this.textLineHeight = (int) (Fonts.MEDIUM.getLineHeight() * 0.925f);
// initialize music buttons
- int musicWidth = GameImage.MUSIC_PLAY.getImage().getWidth();
- int musicHeight = GameImage.MUSIC_PLAY.getImage().getHeight();
- musicPlay = new MenuButton(GameImage.MUSIC_PLAY.getImage(), displayContainer.width - (2 * musicWidth), musicHeight / 1.5f);
- musicPause = new MenuButton(GameImage.MUSIC_PAUSE.getImage(), displayContainer.width - (2 * musicWidth), musicHeight / 1.5f);
- musicNext = new MenuButton(GameImage.MUSIC_NEXT.getImage(), displayContainer.width - musicWidth, musicHeight / 1.5f);
- musicPrevious = new MenuButton(GameImage.MUSIC_PREVIOUS.getImage(), displayContainer.width - (3 * musicWidth), musicHeight / 1.5f);
- musicPlay.setHoverExpand(1.5f);
- musicPause.setHoverExpand(1.5f);
- musicNext.setHoverExpand(1.5f);
- musicPrevious.setHoverExpand(1.5f);
+ final int musicSize = (int) (this.textLineHeight * 0.8f);
+ final float musicScale = (float) musicSize / MUSIC_STOP.getWidth();
+ final int musicSpacing = (int) (musicSize * 0.8f) + musicSize; // (center to center)
+ int x = width - this.textMarginX - musicSize / 2;
+ int y = this.textLineHeight * 2 + this.textLineHeight / 2;
+ this.musicNext = new MenuButton(MUSIC_NEXT.getScaledImage(musicScale), x, y);
+ x -= musicSpacing;
+ this.musicStop = new MenuButton(MUSIC_STOP.getScaledImage(musicScale), x, y);
+ x -= musicSpacing;
+ this.musicPause = new MenuButton(MUSIC_PAUSE.getScaledImage(musicScale), x, y);
+ x -= musicSpacing;
+ this.musicPlay = new MenuButton(MUSIC_PLAY.getScaledImage(musicScale), x, y);
+ x -= musicSpacing;
+ this.musicPrev = new MenuButton(MUSIC_PREVIOUS.getScaledImage(musicScale), x, y);
+ this.musicButtons[0] = this.musicPrev;
+ this.musicButtons[1] = this.musicPlay;
+ this.musicButtons[2] = this.musicPause;
+ this.musicButtons[3] = this.musicStop;
+ this.musicButtons[4] = this.musicNext;
+ for (MenuButton b : this.musicButtons) {
+ b.setHoverExpand(1.15f);
+ }
// initialize music position bar location
- musicBarX = displayContainer.width - musicWidth * 3.5f;
- musicBarY = musicHeight * 1.25f;
- musicBarWidth = musicWidth * 3f;
- musicBarHeight = musicHeight * 0.11f;
+ this.musicBarX = x - musicSize / 2;
+ this.musicBarY = y + musicSize;
+ this.musicBarWidth = musicSize + musicSpacing * 4;
+ this.musicBarHeight = (int) (musicSize * 0.3f);
// initialize downloads button
Image dlImg = GameImage.DOWNLOADS.getImage();
- downloadsButton = new MenuButton(dlImg, displayContainer.width - dlImg.getWidth() / 2f, displayContainer.height / 2f);
+ downloadsButton = new MenuButton(dlImg, width - dlImg.getWidth() / 2f, height2);
downloadsButton.setHoverAnimationDuration(350);
downloadsButton.setHoverAnimationEquation(AnimationEquation.IN_OUT_BACK);
downloadsButton.setHoverExpand(1.03f, Expand.LEFT);
- // initialize repository button
- float startX = displayContainer.width * 0.997f, startY = displayContainer.height * 0.997f;
- if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) { // only if a webpage can be opened
- Image repoImg;
- repoImg = GameImage.REPOSITORY.getImage();
- repoButton = new MenuButton(repoImg,
- startX - repoImg.getWidth() * 2.5f, startY - repoImg.getHeight()
- );
- repoButton.setHoverAnimationDuration(350);
- repoButton.setHoverAnimationEquation(AnimationEquation.IN_OUT_BACK);
- repoButton.setHoverExpand();
- repoImg = GameImage.REPOSITORY.getImage();
- danceRepoButton = new MenuButton(repoImg,
- startX - repoImg.getWidth(), startY - repoImg.getHeight()
- );
- danceRepoButton.setHoverAnimationDuration(350);
- danceRepoButton.setHoverAnimationEquation(AnimationEquation.IN_OUT_BACK);
- danceRepoButton.setHoverExpand();
+ // initialize repository button (only if a webpage can be opened)
+ if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(BROWSE)) {
+ final Image repoImg = GameImage.REPOSITORY.getImage();
+ float repoX = this.textMarginX + repoImg.getWidth() / 2;
+ final float repoY = height - this.barHeight / 2;
+ repoButton = new MenuButton(repoImg, repoX, repoY);
+ repoButton.setHoverAnimationDuration(100);
+ repoButton.setHoverExpand(1.1f);
+ repoX += repoImg.getWidth() * 1.5f;
+ danceRepoButton = new MenuButton(repoImg, repoX, repoY);
+ danceRepoButton.setHoverAnimationDuration(100);
+ danceRepoButton.setHoverExpand(1.1f);
}
// initialize update buttons
- float updateX = displayContainer.width / 2f, updateY = displayContainer.height * 17 / 18f;
- Image downloadImg = GameImage.DOWNLOAD.getImage();
- updateButton = new MenuButton(downloadImg, updateX, updateY);
+ final float updateY = height * 17 / 18f;
+ final Image downloadImg = GameImage.DOWNLOAD.getImage();
+ updateButton = new MenuButton(downloadImg, width2, updateY);
updateButton.setHoverAnimationDuration(400);
updateButton.setHoverAnimationEquation(AnimationEquation.IN_OUT_QUAD);
updateButton.setHoverExpand(1.1f);
- Image updateImg = GameImage.UPDATE.getImage();
- restartButton = new MenuButton(updateImg, updateX, updateY);
+ final Image updateImg = GameImage.UPDATE.getImage();
+ restartButton = new MenuButton(updateImg, width2, updateY);
restartButton.setHoverAnimationDuration(2000);
restartButton.setHoverAnimationEquation(AnimationEquation.LINEAR);
restartButton.setHoverRotate(360);
// initialize star fountain
- starFountain = new StarFountain(displayContainer.width, displayContainer.height);
+ starFountain = new StarFountain(width, height);
- // logo animations
- float centerOffsetX = displayContainer.width / 6.5f;
- logoOpen = new AnimatedValue(100, 0, centerOffsetX, AnimationEquation.OUT_QUAD);
- logoClose = new AnimatedValue(2200, centerOffsetX, 0, AnimationEquation.OUT_QUAD);
- logoButtonAlpha = new AnimatedValue(200, 0f, 1f, AnimationEquation.LINEAR);
+ // logo & buttons
+ this.logo = new ImagePosition(MENU_LOGO.getImage());
+ this.logoPositionOffsetX = 0.35f * MENU_LOGO.getHeight();
+ this.logoPosition.setValues(0, logoPositionOffsetX);
+ this.buttonsX = width2 - MENU_OPTIONS.getWidth() / 2;
+ this.buttonPositions[0] = new ImagePosition(MENU_PLAY.getImage());
+ this.buttonPositions[1] = new ImagePosition(MENU_OPTIONS.getImage());
+ this.buttonPositions[2] = new ImagePosition(MENU_EXIT.getImage());
+ final int basey = height2 - MENU_OPTIONS.getHeight() / 2;
+ final float yoffset = MENU_LOGO.getHeight() * 0.196378f;
+ for (int i = 0; i < 3; i++) {
+ this.buttonPositions[i].width = MENU_OPTIONS.getWidth();
+ this.buttonPositions[i].y = (int) (basey + (i - 1f) * yoffset);
+ this.buttonPositions[i].height = MENU_OPTIONS.getHeight();
+ }
}
@Override
public void render(Graphics g) {
- int width = displayContainer.width;
- int height = displayContainer.height;
-
// draw background
Beatmap beatmap = MusicController.getBeatmap();
if (OPTION_DYNAMIC_BACKGROUND.state &&
@@ -241,75 +280,167 @@ public class MainMenu extends BaseOpsuState {
// top/bottom horizontal bars
float oldAlpha = Colors.BLACK_ALPHA.a;
- Colors.BLACK_ALPHA.a = 0.2f;
+ Colors.BLACK_ALPHA.a = 0.4f;
g.setColor(Colors.BLACK_ALPHA);
- g.fillRect(0, 0, width, height / 9f);
- g.fillRect(0, height * 8 / 9f, width, height / 9f);
+ g.fillRect(0, 0, width, this.barHeight);
+ g.fillRect(0, height - this.barHeight, width, this.barHeight);
Colors.BLACK_ALPHA.a = oldAlpha;
// draw star fountain
- starFountain.draw();
+ if (OPTION_STARFOUNTAINS.state) {
+ starFountain.draw();
+ }
// draw downloads button
downloadsButton.draw();
+
+ // calculate scale stuff for logo
+ final float clickScale = this.logoClickScale.getValue();
+ Float beatPosition = MusicController.getBeatProgress();
+ Float beatLength = MusicController.getBeatLength();
+ final boolean renderPiece = beatPosition != null;
+ if (beatPosition == null || beatLength == null) {
+ beatPosition = System.currentTimeMillis() % 1000 / 1000f;
+ beatLength = 1000f;
+ }
+ final float hoverScale = this.logoHover.getValue();
+ if (beatPosition < this.lastPulseProgress) {
+ this.pulseData.add(new PulseData((int) (beatPosition*beatLength), hoverScale));
+ }
+ this.lastPulseProgress = beatPosition;
+ final float smoothExpandProgress;
+ if (beatPosition < 0.05f) {
+ smoothExpandProgress = 1f - IN_CUBIC.calc(beatPosition / 0.05f);
+ } else {
+ smoothExpandProgress = (beatPosition - 0.05f) / 0.95f;
+ }
+ final float logoScale = (0.9726f + smoothExpandProgress * 0.0274f) * clickScale;
+ final float totalLogoScale = hoverScale * logoScale;
+
+ // pulse ripples
+ final Color logoColor;
+ if (OPTION_COLOR_MAIN_MENU_LOGO.state) {
+ logoColor = Cursor.lastCursorColor;
+ } else {
+ logoColor = Color.white;
+ }
+ for (PulseData pd : this.pulseData) {
+ final float progress = OUT_CUBIC.calc(pd.position / 1000f);
+ final float scale = (pd.initialScale + (0.432f * progress)) * clickScale;
+ final Image p = MENU_LOGO_PULSE.getScaledImage(scale);
+ p.setAlpha(0.15f * (1f - IN_QUAD.calc(progress)));
+ p.drawCentered(this.logo.middleX(), this.logo.middleY(), logoColor);
+ }
// draw buttons
- if (logoState == LogoState.OPEN || logoState == LogoState.CLOSING) {
- playButton.draw();
- exitButton.draw();
+ final float buttonProgress = this.buttonAnimation.getValue();
+ if (this.logoState != LogoState.DEFAULT && buttonProgress > 0f) {
+ final int btnwidth = MENU_OPTIONS.getWidth();
+ final float btnhalfheight = MENU_OPTIONS.getHeight() / 2f;
+ final int basey = height2;
+ final int x = (int) (this.buttonsX + btnwidth * 0.375f * buttonProgress);
+ final Color col = new Color(logoColor);
+ final Image[] imgs = {
+ MENU_PLAY.getImage(),
+ MENU_OPTIONS.getImage(),
+ MENU_EXIT.getImage()
+ };
+ final float circleradius = MENU_LOGO.getHeight() * 0.44498f;
+ final float yoffset = MENU_LOGO.getHeight() * 0.196378f;
+ final float cr = circleradius * totalLogoScale;
+ for (int i = 0; i < 3; i++) {
+ final float hoverprogress = this.buttonAnimations[i].getValue();
+ final int bx = x + (int) (btnwidth * 0.075f * hoverprogress);
+ this.buttonPositions[i].x = bx;
+ final float yoff = (i - 1f) * yoffset;
+ final double cliptop = cr * cos(asin((yoff - btnhalfheight) / cr));
+ final double clipbot = cr * cos(asin((yoff + btnhalfheight) / cr));
+ final float clipxstart = bx - this.logo.middleX();
+ final int ct = (int) (cliptop - clipxstart);
+ final int cb = (int) (clipbot - clipxstart);
+ final int y = (int) (basey + yoff);
+ col.a = buttonProgress * 0.85f + hoverprogress * 0.15f;
+ this.drawMenuButton(imgs[i], bx, y, ct, cb, col);
+ }
}
- // draw logo (pulsing)
- Color color = OPTION_COLOR_MAIN_MENU_LOGO.state ? Cursor.lastCursorColor : Color.white;
- Float position = MusicController.getBeatProgress();
- boolean renderPiece = position != null;
- if (position == null) {
- position = System.currentTimeMillis() % 1000 / 1000f;
- }
- float scale = 1f + position * 0.05f;
- logo.draw(color, scale);
+ // draw logo
+ this.logo.scale(logoScale);
+ this.logo.draw(logoColor);
if (renderPiece) {
- Image piece = GameImage.MENU_LOGO_PIECE.getImage().getScaledCopy(logo.getLastScale());
- piece.rotate(position * 360);
- piece.drawCentered(logo.getX(), logo.getY(), color);
+ final Image piece = MENU_LOGO_PIECE.getScaledImage(hoverScale * logoScale);
+ piece.rotate(beatPosition * 360f);
+ piece.drawCentered(this.logo.middleX(), this.logo.middleY(), logoColor);
}
- float ghostScale = logo.getLastScale() / scale * 1.05f;
- Image ghostLogo = GameImage.MENU_LOGO.getImage().getScaledCopy(ghostScale);
- ghostLogo.drawCentered(logo.getX(), logo.getY(), Colors.GHOST_LOGO);
+ final float ghostScale = hoverScale * 1.0186f - smoothExpandProgress * 0.0186f;
+ Image ghostLogo = MENU_LOGO.getScaledImage(ghostScale * clickScale);
+ ghostLogo.setAlpha(0.25f);
+ ghostLogo.drawCentered(this.logo.middleX(), this.logo.middleY(), logoColor);
+
+ // now playing
+ final Image np = GameImage.MUSIC_NOWPLAYING.getImage();
+ final String trackText;
+ if (beatmap != null) {
+ if (OPTION_SHOW_UNICODE.state) {
+ Fonts.loadGlyphs(Fonts.MEDIUM, beatmap.titleUnicode);
+ Fonts.loadGlyphs(Fonts.MEDIUM, beatmap.artistUnicode);
+ }
+ trackText = beatmap.getArtist() + ": " + beatmap.getTitle();
+ } else {
+ trackText = "Loading...";
+ }
+ final float textWidth = Fonts.MEDIUM.getWidth(trackText);
+ final float npheight = Fonts.MEDIUM.getLineHeight() * 1.15f;
+ final float npscale = npheight / np.getHeight();
+ final float npwidth = np.getWidth() * npscale;
+ float totalWidth = textMarginX + textWidth + npwidth;
+ if (this.nowPlayingPosition.getMax() != totalWidth) {
+ final float current = this.nowPlayingPosition.getValue();
+ this.nowPlayingPosition.setValues(current, totalWidth);
+ this.nowPlayingPosition.setTime(0);
+ }
+ final float npimgx = width - this.nowPlayingPosition.getValue();
+ final float npx = npimgx + npwidth;
+ MUSIC_NOWPLAYING_BG_BLACK.getImage().draw(npx, 0, width - npx, npheight);
+ MUSIC_NOWPLAYING_BG_WHITE.getImage().draw(npimgx, npheight, width - npimgx, 2);
+ np.draw(npimgx, 0, npscale);
+ Fonts.MEDIUM.drawString(npx, 0, trackText);
// draw music buttons
- if (MusicController.isPlaying())
- musicPause.draw();
- else
- musicPlay.draw();
- musicNext.draw();
- musicPrevious.draw();
+ for (MenuButton b : this.musicButtons) {
+ b.draw();
+ }
// draw music position bar
- int mouseX = displayContainer.mouseX;
- int mouseY = displayContainer.mouseY;
g.setColor((musicPositionBarContains(mouseX, mouseY)) ? Colors.BLACK_BG_HOVER : Colors.BLACK_BG_NORMAL);
- g.fillRoundRect(musicBarX, musicBarY, musicBarWidth, musicBarHeight, 4);
- g.setColor(Color.white);
+ g.fillRect(this.musicBarX, this.musicBarY, this.musicBarWidth, this.musicBarHeight);
+ g.setColor(Colors.WHITE_ALPHA_75);
if (!MusicController.isTrackLoading() && beatmap != null) {
- float musicBarPosition = Math.min((float) MusicController.getPosition() / MusicController.getDuration(), 1f);
- g.fillRoundRect(musicBarX, musicBarY, musicBarWidth * musicBarPosition, musicBarHeight, 4);
+ final float trackpos = MusicController.getPosition();
+ final float tracklen = MusicController.getDuration();
+ final float barwidth = musicBarWidth * Math.min(trackpos / tracklen, 1f);
+ g.fillRect(this.musicBarX, this.musicBarY, barwidth, this.musicBarHeight);
}
// draw repository buttons
if (repoButton != null) {
String text;
int fheight, fwidth;
+ float x, y;
repoButton.draw();
text = "opsu!";
fheight = Fonts.SMALL.getLineHeight();
fwidth = Fonts.SMALL.getWidth(text);
- Fonts.SMALL.drawString(repoButton.getX() - fwidth / 2, repoButton.getY() - repoButton.getImage().getHeight() / 2 - fheight, text, Color.white);
+ x = repoButton.getX() - fwidth / 2;
+ y = repoButton.getY() - repoButton.getImage().getHeight() / 2 - fheight;
+ Fonts.SMALL.drawString(x, y, text, Color.white);
danceRepoButton.draw();
text = "opsu!dance";
fheight = Fonts.SMALL.getLineHeight();
fwidth = Fonts.SMALL.getWidth(text);
- Fonts.SMALL.drawString(danceRepoButton.getX() - fwidth / 2, repoButton.getY() - repoButton.getImage().getHeight() / 2 - fheight, text, Color.white);
+ x = danceRepoButton.getX() - fwidth / 2;
+ y = danceRepoButton.getY() - repoButton.getImage().getHeight() / 2 - fheight;
+ Fonts.SMALL.drawString(x, y, text, Color.white);
}
// draw update button
@@ -323,43 +454,63 @@ public class MainMenu extends BaseOpsuState {
}
// draw text
- float marginX = width * 0.015f, topMarginY = height * 0.01f, bottomMarginY = height * 0.015f;
g.setFont(Fonts.MEDIUM);
- float lineHeight = Fonts.MEDIUM.getLineHeight() * 0.925f;
- g.drawString(String.format("Loaded %d songs and %d beatmaps.",
- BeatmapSetList.get().getMapSetCount(), BeatmapSetList.get().getMapCount()), marginX, topMarginY);
- if (MusicController.isTrackLoading()) {
- g.drawString("Track loading...", marginX, topMarginY + lineHeight);
- } else if (MusicController.trackExists()) {
- if (OPTION_SHOW_UNICODE.state) {
- Fonts.loadGlyphs(Fonts.MEDIUM, beatmap.titleUnicode);
- Fonts.loadGlyphs(Fonts.MEDIUM, beatmap.artistUnicode);
- }
- g.drawString((MusicController.isPlaying()) ? "Now Playing:" : "Paused:", marginX, topMarginY + lineHeight);
- g.drawString(String.format("%s: %s", beatmap.getArtist(), beatmap.getTitle()), marginX + 25, topMarginY + (lineHeight * 2));
+ g.setColor(Color.white);
+ String txt = String.format(
+ "You have %d beatmaps (%d songs) available!",
+ BeatmapSetList.get().getMapCount(),
+ BeatmapSetList.get().getMapSetCount()
+ );
+ g.drawString(txt, textMarginX, textTopMarginY);
+ txt = String.format(
+ "%s has been running for %s.",
+ Constants.PROJECT_NAME,
+ Utils.getTimeString((int) (Entrypoint.runtime() / 1000L))
+ );
+ g.drawString(txt, textMarginX, textTopMarginY + textLineHeight);
+ txt = String.format(
+ "It is currently %s.",
+ this.timeFormat.format(new Date())
+ );
+ g.drawString(txt, textMarginX, textTopMarginY + textLineHeight * 2);
+
+ optionsOverlay.render(g);
+ if (optionsOverlay.isActive()) {
+ backButton.draw(g);
}
- g.drawString(String.format("opsu! has been running for %s.",
- Utils.getTimeString((int) (System.currentTimeMillis() - programStartTime) / 1000)),
- marginX, height - bottomMarginY - (lineHeight * 2));
- g.drawString(String.format("It is currently %s.",
- new SimpleDateFormat("h:mm a").format(new Date())),
- marginX, height - bottomMarginY - lineHeight);
UI.draw(g);
}
@Override
public void preRenderUpdate() {
- int delta = displayContainer.renderDelta;
+ optionsOverlay.preRenderUpdate();
+ if (optionsOverlay.isActive()) {
+ backButton.hoverUpdate();
+ }
+
+ int delta = renderDelta;
+
+ int mouseX = InstanceContainer.mouseX;
+ int mouseY = InstanceContainer.mouseY;
+ if (optionsOverlay.containsMouse()) {
+ // dirty hack to not show elements underneath options overlay as hovered
+ mouseX = -mouseX;
+ mouseY = -mouseY;
+ }
+
+ final Iterator pulseDataIter = this.pulseData.iterator();
+ while (pulseDataIter.hasNext()) {
+ final PulseData pd = pulseDataIter.next();
+ pd.position += delta;
+ if (pd.position > 1000) {
+ pulseDataIter.remove();
+ }
+ }
UI.update(delta);
if (MusicController.trackEnded())
nextTrack(false); // end of track: go to next track
- int mouseX = displayContainer.mouseX;
- int mouseY = displayContainer.mouseY;
- logo.hoverUpdate(delta, mouseX, mouseY, 0.25f);
- playButton.hoverUpdate(delta, mouseX, mouseY, 0.25f);
- exitButton.hoverUpdate(delta, mouseX, mouseY, 0.25f);
if (repoButton != null) {
repoButton.hoverUpdate(delta, mouseX, mouseY);
danceRepoButton.hoverUpdate(delta, mouseX, mouseY);
@@ -369,15 +520,12 @@ public class MainMenu extends BaseOpsuState {
restartButton.autoHoverUpdate(delta, false);
}
downloadsButton.hoverUpdate(delta, mouseX, mouseY);
- // ensure only one button is in hover state at once
- boolean noHoverUpdate = musicPositionBarContains(mouseX, mouseY);
- boolean contains = musicPlay.contains(mouseX, mouseY);
- musicPlay.hoverUpdate(delta, !noHoverUpdate && contains);
- musicPause.hoverUpdate(delta, !noHoverUpdate && contains);
- noHoverUpdate |= contains;
- musicNext.hoverUpdate(delta, !noHoverUpdate && musicNext.contains(mouseX, mouseY));
- musicPrevious.hoverUpdate(delta, !noHoverUpdate && musicPrevious.contains(mouseX, mouseY));
- starFountain.update(delta);
+ for (MenuButton b : this.musicButtons) {
+ b.hoverUpdate(delta, b.contains(mouseX, mouseY));
+ }
+ if (OPTION_STARFOUNTAINS.state) {
+ starFountain.update(delta);
+ }
// window focus change: increase/decrease theme song volume
if (MusicController.isThemePlaying() &&
@@ -392,83 +540,125 @@ public class MainMenu extends BaseOpsuState {
// check measure progress
Float measureProgress = MusicController.getMeasureProgress(2);
if (measureProgress != null) {
- if (measureProgress < lastMeasureProgress)
+ if (OPTION_STARFOUNTAINS.state && measureProgress < lastMeasureProgress)
starFountain.burst(true);
lastMeasureProgress = measureProgress;
}
// buttons
- int centerX = displayContainer.width / 2;
- float currentLogoButtonAlpha;
+ this.logo.width = MENU_LOGO.getWidth();
+ this.logo.height = MENU_LOGO.getHeight();
+ this.logo.x = width2 - this.logo.width / 2;
+ this.logo.y = height2 - this.logo.height / 2;
+ if (this.logoState != LogoState.DEFAULT) {
+ this.logo.x -= (int) this.logoPosition.getValue();
+ }
switch (logoState) {
case DEFAULT:
break;
case OPENING:
- if (logoOpen.update(delta)) // shifting to left
- logo.setX(centerX - logoOpen.getValue());
- else {
+ if (logoPosition.update(delta)) {
+ this.buttonAnimation.update(delta);
+ } else {
+ this.buttonAnimation.setTime(this.buttonAnimation.getDuration());
logoState = LogoState.OPEN;
logoTimer = 0;
logoButtonAlpha.setTime(0);
}
break;
case OPEN:
- if (logoButtonAlpha.update(delta)) { // fade in buttons
- currentLogoButtonAlpha = logoButtonAlpha.getValue();
- playButton.getImage().setAlpha(currentLogoButtonAlpha);
- exitButton.getImage().setAlpha(currentLogoButtonAlpha);
- } else if (logoTimer >= LOGO_IDLE_DELAY) { // timer over: shift back to center
- logoState = LogoState.CLOSING;
- logoClose.setTime(0);
- logoTimer = 0;
- } else // increment timer
- logoTimer += delta;
+ logoButtonAlpha.update(delta);
+ if (this.lastMouseX != mouseX || this.lastMouseY != mouseY) {
+ this.logoTimer = 0;
+ this.lastMouseX = mouseX;
+ this.lastMouseY = mouseY;
+ } else {
+ this.logoTimer += delta;
+ if (this.logoTimer >= LOGO_IDLE_DELAY) {
+ this.closeLogo();
+ }
+ }
break;
case CLOSING:
- if (logoButtonAlpha.update(-delta)) { // fade out buttons
- currentLogoButtonAlpha = logoButtonAlpha.getValue();
- playButton.getImage().setAlpha(currentLogoButtonAlpha);
- exitButton.getImage().setAlpha(currentLogoButtonAlpha);
+ logoButtonAlpha.update(-delta);
+ if (logoPosition.update(-delta)) {
+ this.buttonAnimation.update(-delta);
+ } else {
+ this.logoState = LogoState.DEFAULT;
+ this.buttonAnimation.setTime(0);
}
- if (logoClose.update(delta)) // shifting to right
- logo.setX(centerX - logoClose.getValue());
break;
}
+ this.logoClickScale.update(delta);
+ final boolean logoHovered = this.logo.contains(mouseX, mouseY, 0.25f);
+ if (logoHovered) {
+ this.logoHover.update(delta);
+ } else {
+ this.logoHover.update(-delta);
+ }
+ final float hoverScale = this.logoHover.getValue();
+ if (hoverScale != 1f) {
+ this.logo.scale(hoverScale);
+ }
+ for (int i = 0; i < 3; i++) {
+ final ImagePosition pos = this.buttonPositions[i];
+ final AnimatedValue anim = this.buttonAnimations[i];
+ if (!logoHovered && pos.contains(mouseX, mouseY, 0.25f)) {
+ if (anim.getDuration() != 500) {
+ anim.change(500, 0f, 1f, OUT_ELASTIC);
+ continue;
+ }
+ anim.update(delta);
+ continue;
+ }
+
+ if (anim.getDuration() != 350) {
+ anim.change(350, 0f, 1f, IN_QUAD);
+ continue;
+ }
+ anim.update(-delta);
+ }
// tooltips
if (musicPositionBarContains(mouseX, mouseY))
UI.updateTooltip(delta, "Click to seek to a specific point in the song.", false);
+ else if (musicPrev.contains(mouseX, mouseY))
+ UI.updateTooltip(delta, "Previous track", false);
else if (musicPlay.contains(mouseX, mouseY))
- UI.updateTooltip(delta, (MusicController.isPlaying()) ? "Pause" : "Play", false);
+ UI.updateTooltip(delta, "Play", false);
+ else if (musicPause.contains(mouseX, mouseY))
+ UI.updateTooltip(delta, "Pause", false);
+ else if (musicStop.contains(mouseX, mouseY))
+ UI.updateTooltip(delta, "Stop", false);
else if (musicNext.contains(mouseX, mouseY))
UI.updateTooltip(delta, "Next track", false);
- else if (musicPrevious.contains(mouseX, mouseY))
- UI.updateTooltip(delta, "Previous track", false);
else if (updater.showButton()) {
Updater.Status status = updater.getStatus();
if (((status == Updater.Status.UPDATE_AVAILABLE || status == Updater.Status.UPDATE_DOWNLOADING) && updateButton.contains(mouseX, mouseY)) ||
(status == Updater.Status.UPDATE_DOWNLOADED && restartButton.contains(mouseX, mouseY)))
UI.updateTooltip(delta, status.getDescription(), true);
}
+
+ nowPlayingPosition.update(delta);
}
@Override
public void enter() {
super.enter();
- logo.setX(displayContainer.width / 2);
- logoOpen.setTime(0);
- logoClose.setTime(0);
+ logoPosition.setTime(0);
logoButtonAlpha.setTime(0);
- logoTimer = 0;
+ nowPlayingPosition.setTime(0);
logoState = LogoState.DEFAULT;
+ this.logoClickScale.setTime(this.logoClickScale.getDuration());
+ this.buttonAnimation.setTime(0);
UI.enter();
if (!enterNotification) {
if (updater.getStatus() == Updater.Status.UPDATE_AVAILABLE) {
- BarNotifListener.EVENT.make().onBarNotif("An opsu! update is available.");
+ barNotifs.send("An opsu! update is available.");
} else if (updater.justUpdated()) {
- BarNotifListener.EVENT.make().onBarNotif("opsu! is now up to date!");
+ barNotifs.send("opsu! is now up to date!");
}
enterNotification = true;
}
@@ -478,22 +668,11 @@ public class MainMenu extends BaseOpsuState {
starFountain.clear();
// reset button hover states if mouse is not currently hovering over the button
- int mouseX = displayContainer.mouseX;
- int mouseY = displayContainer.mouseY;
- if (!logo.contains(mouseX, mouseY, 0.25f))
- logo.resetHover();
- if (!playButton.contains(mouseX, mouseY, 0.25f))
- playButton.resetHover();
- if (!exitButton.contains(mouseX, mouseY, 0.25f))
- exitButton.resetHover();
- if (!musicPlay.contains(mouseX, mouseY))
- musicPlay.resetHover();
- if (!musicPause.contains(mouseX, mouseY))
- musicPause.resetHover();
- if (!musicNext.contains(mouseX, mouseY))
- musicNext.resetHover();
- if (!musicPrevious.contains(mouseX, mouseY))
- musicPrevious.resetHover();
+ for (MenuButton b : this.musicButtons) {
+ if (!b.contains(mouseX, mouseY)) {
+ b.resetHover();
+ }
+ }
if (repoButton != null && !repoButton.contains(mouseX, mouseY))
repoButton.resetHover();
if (danceRepoButton != null && !danceRepoButton.contains(mouseX, mouseY))
@@ -513,35 +692,24 @@ public class MainMenu extends BaseOpsuState {
@Override
public boolean mousePressed(int button, int x, int y) {
+ if (optionsOverlay.mousePressed(button, x, y)) {
+ return true;
+ }
+
// check mouse button
if (button == Input.MOUSE_MIDDLE_BUTTON)
return false;
// music position bar
- if (MusicController.isPlaying()) {
- if (musicPositionBarContains(x, y)) {
- lastMeasureProgress = 0f;
- float pos = (x - musicBarX) / musicBarWidth;
- MusicController.setPosition((int) (pos * MusicController.getDuration()));
- return true;
- }
+ if (MusicController.isPlaying() && musicPositionBarContains(x, y)) {
+ this.lastMeasureProgress = 0f;
+ float pos = (float) (x - this.musicBarX) / this.musicBarWidth;
+ MusicController.setPosition((int) (pos * MusicController.getDuration()));
+ return true;
}
// music button actions
- if (musicPlay.contains(x, y)) {
- if (MusicController.isPlaying()) {
- MusicController.pause();
- BarNotifListener.EVENT.make().onBarNotif("Pause");
- } else if (!MusicController.isTrackLoading()) {
- MusicController.resume();
- BarNotifListener.EVENT.make().onBarNotif("Play");
- }
- return true;
- } else if (musicNext.contains(x, y)) {
- nextTrack(true);
- BarNotifListener.EVENT.make().onBarNotif(">> Next");
- return true;
- } else if (musicPrevious.contains(x, y)) {
+ if (musicPrev.contains(x, y)) {
lastMeasureProgress = 0f;
if (!previous.isEmpty()) {
songMenuState.setFocus(BeatmapSetList.get().getBaseNode(previous.pop()), -1, true, false);
@@ -551,7 +719,34 @@ public class MainMenu extends BaseOpsuState {
} else {
MusicController.setPosition(0);
}
- BarNotifListener.EVENT.make().onBarNotif("<< Previous");
+ barNotifs.send("<< Previous");
+ return true;
+ } else if (musicPlay.contains(x, y)) {
+ if (MusicController.isPlaying()) {
+ lastMeasureProgress = 0f;
+ MusicController.setPosition(0);
+ } else if (!MusicController.isTrackLoading()) {
+ MusicController.resume();
+ }
+ barNotifs.send("Play");
+ return true;
+ } else if (musicPause.contains(x, y)) {
+ if (MusicController.isPlaying()) {
+ MusicController.pause();
+ barNotifs.send("Pause");
+ } else if (!MusicController.isTrackLoading()) {
+ MusicController.resume();
+ barNotifs.send("Unpause");
+ }
+ } else if (musicStop.contains(x, y)) {
+ if (MusicController.isPlaying()) {
+ MusicController.setPosition(0);
+ MusicController.pause();
+ }
+ barNotifs.send("Stop Playing");
+ } else if (musicNext.contains(x, y)) {
+ nextTrack(true);
+ barNotifs.send(">> Next");
return true;
}
@@ -567,11 +762,10 @@ public class MainMenu extends BaseOpsuState {
try {
Desktop.getDesktop().browse(Constants.REPOSITORY_URI);
} catch (UnsupportedOperationException e) {
- BarNotifListener.EVENT.make().onBarNotif(
- "The repository web page could not be opened.");
+ barNotifs.send("The repository web page could not be opened.");
} catch (IOException e) {
Log.error("could not browse to repo", e);
- BubNotifListener.EVENT.make().onBubNotif("Could not browse to repo", Colors.BUB_ORANGE);
+ bubNotifs.send(BUB_ORANGE, "Could not browse to repo");
}
return true;
}
@@ -580,11 +774,10 @@ public class MainMenu extends BaseOpsuState {
try {
Desktop.getDesktop().browse(Constants.DANCE_REPOSITORY_URI);
} catch (UnsupportedOperationException e) {
- BarNotifListener.EVENT.make().onBarNotif(
- "The repository web page could not be opened.");
+ barNotifs.send("The repository web page could not be opened.");
} catch (IOException e) {
Log.error("could not browse to repo", e);
- BubNotifListener.EVENT.make().onBubNotif("Could not browse to repo", Colors.BUB_ORANGE);
+ bubNotifs.send(BUB_ORANGE, "Could not browse to repo");
}
return true;
}
@@ -608,36 +801,42 @@ public class MainMenu extends BaseOpsuState {
}
}
- // start moving logo (if clicked)
+ final boolean logoHovered = this.logo.contains(x, y, 0.25f);
if (logoState == LogoState.DEFAULT || logoState == LogoState.CLOSING) {
- if (logo.contains(x, y, 0.25f)) {
- logoState = LogoState.OPENING;
- logoOpen.setTime(0);
- logoTimer = 0;
- playButton.getImage().setAlpha(0f);
- exitButton.getImage().setAlpha(0f);
+ if (logoHovered) {
+ this.openLogo();
SoundController.playSound(SoundEffect.MENUHIT);
+ this.logoClickScale.setTime(0);
return true;
}
- }
-
- // other button actions (if visible)
- else if (logoState == LogoState.OPEN || logoState == LogoState.OPENING) {
- if (logo.contains(x, y, 0.25f) || playButton.contains(x, y, 0.25f)) {
+ } else {
+ if (logoHovered || this.buttonPositions[0].contains(x, y, 0.25f)) {
+ this.logoClickScale.setTime(0);
SoundController.playSound(SoundEffect.MENUHIT);
enterSongMenu();
return true;
- } else if (exitButton.contains(x, y, 0.25f)) {
+ }
+
+ if (this.buttonPositions[1].contains(x, y, 0.25f)) {
+ if (!optionsOverlay.isActive()) {
+ SoundController.playSound(SoundEffect.MENUHIT);
+ optionsOverlay.show();
+ }
+ return true;
+ }
+
+ if (this.buttonPositions[2].contains(x, y, 0.25f)) {
displayContainer.exitRequested = true;
return true;
}
}
+
return false;
}
@Override
public boolean mouseWheelMoved(int newValue) {
- if (super.mouseWheelMoved(newValue)) {
+ if (optionsOverlay.mouseWheelMoved(newValue)) {
return true;
}
@@ -647,17 +846,15 @@ public class MainMenu extends BaseOpsuState {
@Override
public boolean keyPressed(int key, char c) {
- if (super.keyPressed(key, c)) {
+ if (optionsOverlay.keyPressed(key, c)) {
return true;
}
switch (key) {
case KEY_ESCAPE:
case KEY_Q:
- if (logoTimer > 0) {
- logoState = LogoState.CLOSING;
- logoClose.setTime(0);
- logoTimer = 0;
+ if (logoState == LogoState.OPEN || logoState == LogoState.OPENING) {
+ this.closeLogo();
break;
}
buttonState.setMenuState(MenuState.EXIT);
@@ -666,13 +863,10 @@ public class MainMenu extends BaseOpsuState {
case KEY_P:
SoundController.playSound(SoundEffect.MENUHIT);
if (logoState == LogoState.DEFAULT || logoState == LogoState.CLOSING) {
- logoState = LogoState.OPENING;
- logoOpen.setTime(0);
- logoTimer = 0;
- playButton.getImage().setAlpha(0f);
- exitButton.getImage().setAlpha(0f);
- } else
+ this.openLogo();
+ } else {
enterSongMenu();
+ }
return true;
case KEY_D:
SoundController.playSound(SoundEffect.MENUHIT);
@@ -687,9 +881,28 @@ public class MainMenu extends BaseOpsuState {
case KEY_DOWN:
UI.changeVolume(-1);
return true;
+ case KEY_O:
+ if (input.isControlDown()) {
+ optionsOverlay.show();
+ }
}
return false;
}
+
+ @Override
+ public boolean keyReleased(int key, char c) {
+ return optionsOverlay.keyReleased(key, c);
+ }
+
+ @Override
+ public boolean mouseReleased(int button, int x, int y) {
+ return optionsOverlay.mouseReleased(button, x, y);
+ }
+
+ @Override
+ public boolean mouseDragged(int oldx, int oldy, int newx, int newy) {
+ return optionsOverlay.mouseDragged(oldx, oldy, newx, newy);
+ }
/**
* Returns true if the coordinates are within the music position bar bounds.
@@ -730,11 +943,69 @@ public class MainMenu extends BaseOpsuState {
* Enters the song menu, or the downloads menu if no beatmaps are loaded.
*/
private void enterSongMenu() {
+ if (optionsOverlay.isActive()) {
+ optionsOverlay.hide();
+ }
OpsuState state = songMenuState;
if (BeatmapSetList.get().getMapSetCount() == 0) {
- downloadState.notifyOnLoad("Download some beatmaps to get started!");
+ barNotifs.send("Download some beatmaps to get started!");
state = downloadState;
}
displayContainer.switchState(state);
}
+
+ private void openLogo() {
+ buttonAnimation.change(300, 0f, 1f, OUT_QUAD);
+ logoPosition.change(300, 0, logoPositionOffsetX, OUT_CUBIC);
+ logoState = LogoState.OPENING;
+ }
+
+ private void closeLogo() {
+ buttonAnimation.change(500, 0f, 1f, OUT_QUAD);
+ logoPosition.change(1800, 0, logoPositionOffsetX, IN_QUAD);
+ logoState = LogoState.CLOSING;
+ }
+
+ private void drawMenuButton(
+ Image img,
+ int x,
+ int y,
+ int clipxtop,
+ int clipxbot,
+ Color col)
+ {
+ col.bind();
+ final Texture t = img.getTexture();
+ t.bind();
+
+ final int width = img.getWidth();
+ final int height = img.getHeight();
+ final float twidth = t.getWidth();
+ final float theight = t.getHeight();
+ y -= height / 2;
+
+ final float texXtop = clipxtop > 0 ? (float) clipxtop / width * twidth : 0f;
+ final float texXbot = clipxbot > 0 ? (float) clipxbot / width * twidth : 0f;
+
+ GL11.glBegin(SGL.GL_QUADS);
+ GL11.glTexCoord2f(texXtop, 0);
+ GL11.glVertex3i(x + clipxtop, y, 0);
+ GL11.glTexCoord2f(twidth, 0);
+ GL11.glVertex3i(x + width, y, 0);
+ GL11.glTexCoord2f(twidth, theight);
+ GL11.glVertex3i(x + width, y + height, 0);
+ GL11.glTexCoord2f(texXbot, theight);
+ GL11.glVertex3i(x + clipxbot, y + height, 0);
+ GL11.glEnd();
+ }
+
+ private static class PulseData {
+ private int position;
+ private float initialScale;
+
+ private PulseData(int position, float initialScale) {
+ this.position = position;
+ this.initialScale = initialScale;
+ }
+ }
}
diff --git a/src/itdelatrisu/opsu/states/SongMenu.java b/src/itdelatrisu/opsu/states/SongMenu.java
index 3bb48625..70bf2129 100644
--- a/src/itdelatrisu/opsu/states/SongMenu.java
+++ b/src/itdelatrisu/opsu/states/SongMenu.java
@@ -48,6 +48,7 @@ import itdelatrisu.opsu.ui.UI;
import itdelatrisu.opsu.ui.animations.AnimatedValue;
import itdelatrisu.opsu.ui.animations.AnimationEquation;
+import java.awt.Point;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.StandardWatchEventKinds;
@@ -63,11 +64,11 @@ import org.newdawn.slick.Image;
import org.newdawn.slick.Input;
import org.newdawn.slick.SpriteSheet;
import org.newdawn.slick.gui.TextField;
-import yugecin.opsudance.core.state.ComplexOpsuState;
-import yugecin.opsudance.events.BarNotifListener;
-import yugecin.opsudance.options.OptionGroups;
-import yugecin.opsudance.ui.OptionsOverlay;
+import yugecin.opsudance.core.InstanceContainer;
+import yugecin.opsudance.core.state.ComplexOpsuState;
+
+import static itdelatrisu.opsu.GameImage.*;
import static org.lwjgl.input.Keyboard.*;
import static yugecin.opsudance.core.InstanceContainer.*;
import static yugecin.opsudance.options.Options.*;
@@ -99,7 +100,7 @@ public class SongMenu extends ComplexOpsuState {
private static final int SEARCH_TRANSITION_TIME = 250;
/** Line width of the header/footer divider. */
- private static final int DIVIDER_LINE_WIDTH = 4;
+ private static final int DIVIDER_LINE_WIDTH = 3;
/** Song node class representing an BeatmapSetNode and file index. */
private static class SongNode {
@@ -161,7 +162,7 @@ public class SongMenu extends ComplexOpsuState {
private BeatmapSetNode hoverIndex = null;
/** The selection buttons. */
- private MenuButton selectModsButton, selectRandomButton, selectMapOptionsButton, selectOptionsButton;
+ private MenuButton selectModeButton, selectModsButton, selectRandomButton, selectMapOptionsButton;
/** The search textfield. */
private TextField searchTextField;
@@ -311,12 +312,8 @@ public class SongMenu extends ComplexOpsuState {
/** Sort order dropdown menu. */
private DropdownMenu sortMenu;
- private final OptionsOverlay optionsOverlay;
-
public SongMenu() {
super();
- optionsOverlay = new OptionsOverlay(displayContainer, OptionGroups.normalOptions);
- overlays.add(optionsOverlay);
}
@Override
@@ -325,26 +322,27 @@ public class SongMenu extends ComplexOpsuState {
components.clear();
+ final float footerHeight = height * 0.116666666666f;
+
// header/footer coordinates
- headerY = displayContainer.height * 0.0075f + GameImage.MENU_MUSICNOTE.getImage().getHeight() +
+ headerY = height * 0.0075f + GameImage.MENU_MUSICNOTE.getHeight() +
Fonts.BOLD.getLineHeight() + Fonts.DEFAULT.getLineHeight() +
Fonts.SMALL.getLineHeight();
- footerY = displayContainer.height - GameImage.SELECTION_MODS.getImage().getHeight();
+ footerY = height - footerHeight;
// footer logo coordinates
- float footerHeight = displayContainer.height - footerY;
footerLogoSize = footerHeight * 3.25f;
Image logo = GameImage.MENU_LOGO.getImage();
logo = logo.getScaledCopy(footerLogoSize / logo.getWidth());
- footerLogoButton = new MenuButton(logo, displayContainer.width - footerHeight * 0.8f, displayContainer.height - footerHeight * 0.65f);
+ footerLogoButton = new MenuButton(logo, width - footerHeight * 0.8f, height - footerHeight * 0.65f);
footerLogoButton.setHoverAnimationDuration(1);
footerLogoButton.setHoverExpand(1.2f);
// initialize sorts
- int sortWidth = (int) (displayContainer.width * 0.12f);
- int posX = (int) (displayContainer.width * 0.87f);
- int posY = (int) (headerY - GameImage.MENU_TAB.getImage().getHeight() * 2.25f);
- sortMenu = new DropdownMenu(displayContainer, BeatmapSortOrder.values(), posX, posY, sortWidth) {
+ int sortWidth = (int) (width * 0.12f);
+ int posX = (int) (width * 0.87f);
+ int posY = (int) (headerY - GameImage.MENU_TAB.getHeight() * 2.25f);
+ sortMenu = new DropdownMenu(BeatmapSortOrder.values(), posX, posY, sortWidth) {
@Override
public void itemSelected(int index, BeatmapSortOrder item) {
BeatmapSortOrder.set(item);
@@ -373,25 +371,25 @@ public class SongMenu extends ComplexOpsuState {
// initialize group tabs
for (BeatmapGroup group : BeatmapGroup.values())
- group.init(displayContainer.width, headerY - DIVIDER_LINE_WIDTH / 2);
+ group.init(width, headerY - DIVIDER_LINE_WIDTH / 2);
// initialize score data buttons
- ScoreData.init(displayContainer.width, headerY + displayContainer.height * 0.01f);
+ ScoreData.init(width, headerY + height * 0.01f);
// song button background & graphics context
Image menuBackground = GameImage.MENU_BUTTON_BG.getImage();
// song button coordinates
- buttonX = displayContainer.width * 0.6f;
+ buttonX = width * 0.6f;
//buttonY = headerY;
buttonWidth = menuBackground.getWidth();
buttonHeight = menuBackground.getHeight();
buttonOffset = (footerY - headerY - DIVIDER_LINE_WIDTH) / MAX_SONG_BUTTONS;
// search
- int textFieldX = (int) (displayContainer.width * 0.7125f + Fonts.BOLD.getWidth("Search: "));
+ int textFieldX = (int) (width * 0.7125f + Fonts.BOLD.getWidth("Search: "));
int textFieldY = (int) (headerY + Fonts.BOLD.getLineHeight() / 2);
- searchTextField = new TextField(Fonts.BOLD, textFieldX, textFieldY, (int) (displayContainer.width * 0.99f) - textFieldX, Fonts.BOLD.getLineHeight()) {
+ searchTextField = new TextField(Fonts.BOLD, textFieldX, textFieldY, (int) (width * 0.99f) - textFieldX, Fonts.BOLD.getLineHeight()) {
@Override
public boolean isFocusable() {
return false;
@@ -405,33 +403,23 @@ public class SongMenu extends ComplexOpsuState {
components.add(searchTextField);
// selection buttons
- Image selectionMods = GameImage.SELECTION_MODS.getImage();
- int selectButtonsWidth = selectionMods.getWidth();
- int selectButtonsHeight = selectionMods.getHeight();
- if (selectButtonsHeight < 20) {
- selectButtonsHeight = 100;
- }
- if (selectButtonsWidth < 20) {
- selectButtonsWidth = 100;
- }
- float selectX = displayContainer.width * 0.183f + selectButtonsWidth / 2f;
- float selectY = displayContainer.height - selectButtonsHeight / 2f;
- float selectOffset = selectButtonsWidth * 1.05f;
- selectModsButton = new MenuButton(GameImage.SELECTION_MODS_OVERLAY.getImage(),
- selectX, selectY);
- selectRandomButton = new MenuButton(GameImage.SELECTION_RANDOM_OVERLAY.getImage(),
- selectX + selectOffset, selectY);
- selectMapOptionsButton = new MenuButton(GameImage.SELECTION_OPTIONS_OVERLAY.getImage(),
- selectX + selectOffset * 2f, selectY);
- selectOptionsButton = new MenuButton(GameImage.SELECTION_OTHER_OPTIONS_OVERLAY.getImage(),
- selectX + selectOffset * 3f, selectY);
+ // TODO: the origin should be bottomleft or something
+ float selectX = width * (isWidescreen ? 0.164f : 0.1875f);
+ final float footerButtonWidth = footerHeight * 0.84f;
+ selectModeButton = new MenuButton(SELECTION_MODE_OVERLAY, selectX, footerY);
+ selectX += footerHeight + 2;
+ selectModsButton = new MenuButton(SELECTION_MODS_OVERLAY, selectX, footerY);
+ selectX += footerButtonWidth;
+ selectRandomButton = new MenuButton(SELECTION_RANDOM_OVERLAY, selectX, footerY);
+ selectX += footerButtonWidth;
+ selectMapOptionsButton = new MenuButton(SELECTION_OPTIONS_OVERLAY, selectX, footerY);
+ selectModeButton.setHoverFade(0f);
selectModsButton.setHoverFade(0f);
selectRandomButton.setHoverFade(0f);
selectMapOptionsButton.setHoverFade(0f);
- selectOptionsButton.setHoverFade(0f);
// loader
- int loaderDim = GameImage.MENU_MUSICNOTE.getImage().getWidth();
+ int loaderDim = GameImage.MENU_MUSICNOTE.getWidth();
SpriteSheet spr = new SpriteSheet(GameImage.MENU_LOADER.getImage(), loaderDim, loaderDim);
loader = new Animation(spr, 50);
@@ -446,14 +434,13 @@ public class SongMenu extends ComplexOpsuState {
if (!displayContainer.isInState(SongMenu.class)) {
return;
}
- BarNotifListener.EVENT.make().onBarNotif(
- "Changed is Songs folder detected. Hit F5 to refresh.");
+ barNotifs.send("Changes in Songs folder detected. Hit F5 to refresh.");
}
});
// star stream
- starStream = new StarStream(displayContainer.width, (displayContainer.height - GameImage.STAR.getImage().getHeight()) / 2, -displayContainer.width, 0, MAX_STREAM_STARS);
- starStream.setPositionSpread(displayContainer.height / 20f);
+ starStream = new StarStream(width, height2 - GameImage.STAR.getImage().getHeight() / 2, -width, 0, MAX_STREAM_STARS);
+ starStream.setPositionSpread(height / 20f);
starStream.setDirectionSpread(10f);
}
@@ -461,11 +448,6 @@ public class SongMenu extends ComplexOpsuState {
public void render(Graphics g) {
g.setBackground(Color.black);
- int width = displayContainer.width;
- int height = displayContainer.height;
- int mouseX = displayContainer.mouseX;
- int mouseY = displayContainer.mouseY;
-
// background
if (focusNode != null) {
Beatmap focusNodeBeatmap = focusNode.getSelectedBeatmap();
@@ -542,14 +524,12 @@ public class SongMenu extends ComplexOpsuState {
}
// top/bottom bars
- g.setColor(Colors.BLACK_ALPHA);
+ g.setColor(Color.black);
g.fillRect(0, 0, width, headerY);
g.fillRect(0, footerY, width, height - footerY);
g.setColor(Colors.BLUE_DIVIDER);
- g.setLineWidth(DIVIDER_LINE_WIDTH);
- g.drawLine(0, headerY, width, headerY);
- g.drawLine(0, footerY, width, footerY);
- g.resetLineWidth();
+ g.fillRect(0, headerY, width, DIVIDER_LINE_WIDTH);
+ g.fillRect(0, footerY, width, DIVIDER_LINE_WIDTH);
// footer logo (pulsing)
Float position = MusicController.getBeatProgress();
@@ -563,10 +543,8 @@ public class SongMenu extends ComplexOpsuState {
footerLogoButton.draw(Color.white, 1f - expand);
Image ghostLogo = GameImage.MENU_LOGO.getImage();
ghostLogo = ghostLogo.getScaledCopy((1f + expand) * footerLogoSize / ghostLogo.getWidth());
- float oldGhostAlpha = Colors.GHOST_LOGO.a;
- Colors.GHOST_LOGO.a *= (1f - position);
- ghostLogo.drawCentered(footerLogoButton.getX(), footerLogoButton.getY(), Colors.GHOST_LOGO);
- Colors.GHOST_LOGO.a = oldGhostAlpha;
+ ghostLogo.setAlpha(0.25f * (1f - position));
+ ghostLogo.drawCentered(footerLogoButton.getX(), footerLogoButton.getY());
}
// header
@@ -636,14 +614,19 @@ public class SongMenu extends ComplexOpsuState {
}
// selection buttons
- GameImage.SELECTION_MODS.getImage().drawCentered(selectModsButton.getX(), selectModsButton.getY());
+ Point c;
+ c = selectModeButton.bottomLeft();
+ SELECTION_MODE.getImage().draw(c.x, c.y - SELECTION_MODE.getHeight());
+ selectModeButton.draw();
+ c = selectModsButton.bottomLeft();
+ SELECTION_MODS.getImage().draw(c.x, c.y - SELECTION_MODS.getHeight());
selectModsButton.draw();
- GameImage.SELECTION_RANDOM.getImage().drawCentered(selectRandomButton.getX(), selectRandomButton.getY());
+ c = selectRandomButton.bottomLeft();
+ SELECTION_RANDOM.getImage().draw(c.x, c.y - SELECTION_RANDOM.getHeight());
selectRandomButton.draw();
- GameImage.SELECTION_OPTIONS.getImage().drawCentered(selectMapOptionsButton.getX(), selectMapOptionsButton.getY());
+ c = selectMapOptionsButton.bottomLeft();
+ SELECTION_OPTIONS.getImage().draw(c.x, c.y - SELECTION_OPTIONS.getHeight());
selectMapOptionsButton.draw();
- GameImage.SELECTION_OTHER_OPTIONS.getImage().drawCentered(selectOptionsButton.getX(), selectOptionsButton.getY());
- selectOptionsButton.draw();
// group tabs
BeatmapGroup currentGroup = BeatmapGroup.current();
@@ -701,11 +684,11 @@ public class SongMenu extends ComplexOpsuState {
g.fillRect(0, 0, width, height);
UI.drawLoadingProgress(g);
+ } else {
+ optionsOverlay.render(g);
+ backButton.draw(g);
}
- // back button
- else
- UI.getBackButton().draw(g);
UI.draw(g);
@@ -715,8 +698,18 @@ public class SongMenu extends ComplexOpsuState {
@Override
public void preRenderUpdate() {
super.preRenderUpdate();
+
+ optionsOverlay.preRenderUpdate();
- int delta = displayContainer.renderDelta;
+ int mouseX = InstanceContainer.mouseX;
+ int mouseY = InstanceContainer.mouseY;
+ if (optionsOverlay.containsMouse()) {
+ // dirty hack to not show elements underneath options overlay as hovered
+ mouseX = -mouseX;
+ mouseY = -mouseY;
+ }
+
+ int delta = renderDelta;
UI.update(delta);
if (reloadThread == null)
MusicController.loopTrackIfEnded(true);
@@ -732,13 +725,11 @@ public class SongMenu extends ComplexOpsuState {
MusicController.playThemeSong(config.themeBeatmap);
reloadThread = null;
}
- int mouseX = displayContainer.mouseX;
- int mouseY = displayContainer.mouseY;
- UI.getBackButton().hoverUpdate(delta, mouseX, mouseY);
+ backButton.hoverUpdate();
+ selectModeButton.hoverUpdate(delta, mouseX, mouseY);
selectModsButton.hoverUpdate(delta, mouseX, mouseY);
selectRandomButton.hoverUpdate(delta, mouseX, mouseY);
selectMapOptionsButton.hoverUpdate(delta, mouseX, mouseY);
- selectOptionsButton.hoverUpdate(delta, mouseX, mouseY);
footerLogoButton.hoverUpdate(delta, mouseX, mouseY, 0.25f);
// beatmap menu timer
@@ -873,6 +864,10 @@ public class SongMenu extends ComplexOpsuState {
if (super.mousePressed(button, x, y)) {
return true;
}
+
+ if (optionsOverlay.mousePressed(button, x, y)) {
+ return true;
+ }
if (button == Input.MOUSE_MIDDLE_BUTTON) {
return false;
@@ -892,6 +887,10 @@ public class SongMenu extends ComplexOpsuState {
if (super.mouseReleased(button, x, y)) {
return true;
}
+
+ if (optionsOverlay.mouseReleased(button, x, y)) {
+ return true;
+ }
if (button == Input.MOUSE_MIDDLE_BUTTON) {
return false;
@@ -908,14 +907,17 @@ public class SongMenu extends ComplexOpsuState {
return true;
}
- if (UI.getBackButton().contains(x, y)) {
+ if (backButton.contains(x, y)) {
SoundController.playSound(SoundEffect.MENUBACK);
displayContainer.switchState(mainmenuState);
return true;
}
// selection buttons
- if (selectModsButton.contains(x, y)) {
+ if (selectModeButton.contains(x, y)) {
+ barNotifs.send("There are no other modes available.");
+ return true;
+ } else if (selectModsButton.contains(x, y)) {
this.keyPressed(KEY_F1, '\0');
return true;
} else if (selectRandomButton.contains(x, y)) {
@@ -924,10 +926,6 @@ public class SongMenu extends ComplexOpsuState {
} else if (selectMapOptionsButton.contains(x, y)) {
this.keyPressed(KEY_F3, '\0');
return true;
- } else if (selectOptionsButton.contains(x, y)) {
- SoundController.playSound(SoundEffect.MENUHIT);
- optionsOverlay.show();
- return true;
}
// group tabs
@@ -955,7 +953,7 @@ public class SongMenu extends ComplexOpsuState {
setFocus(BeatmapSetList.get().getRandomNode(), -1, true, true);
if (BeatmapSetList.get().size() < 1 && group.getEmptyMessage() != null) {
- BarNotifListener.EVENT.make().onBarNotif(group.getEmptyMessage());
+ barNotifs.send(group.getEmptyMessage());
}
return true;
}
@@ -1038,6 +1036,10 @@ public class SongMenu extends ComplexOpsuState {
if (super.keyPressed(key, c)) {
return true;
}
+
+ if (optionsOverlay.keyPressed(key, c)) {
+ return true;
+ }
// block input
if ((reloadThread != null && key != KEY_ESCAPE) || beatmapMenuTimer > -1 || isScrollingToFocusNode) {
@@ -1192,6 +1194,10 @@ public class SongMenu extends ComplexOpsuState {
if (super.mouseDragged(oldx, oldy, newx, newy)) {
return true;
}
+
+ if (optionsOverlay.mouseDragged(oldx, oldy, newx, newy)) {
+ return true;
+ }
if (isInputBlocked()) {
return true;
@@ -1225,6 +1231,10 @@ public class SongMenu extends ComplexOpsuState {
if (super.mouseWheelMoved(newValue)) {
return true;
}
+
+ if (optionsOverlay.mouseWheelMoved(newValue)) {
+ return true;
+ }
if (isInputBlocked()) {
return true;
@@ -1242,16 +1252,25 @@ public class SongMenu extends ComplexOpsuState {
changeIndex(shift);
return false;
}
+
+ @Override
+ public boolean keyReleased(int key, char c) {
+ if (super.keyReleased(key, c)) {
+ return true;
+ }
+
+ return optionsOverlay.keyReleased(key, c);
+ }
@Override
public void enter() {
super.enter();
UI.enter();
+ selectModeButton.resetHover();
selectModsButton.resetHover();
selectRandomButton.resetHover();
selectMapOptionsButton.resetHover();
- selectOptionsButton.resetHover();
hoverOffset.setTime(0);
hoverIndex = null;
isScrollingToFocusNode = false;
@@ -1761,7 +1780,7 @@ public class SongMenu extends ComplexOpsuState {
Beatmap beatmap = MusicController.getBeatmap();
if (focusNode == null || beatmap != focusNode.getSelectedBeatmap()) {
- BarNotifListener.EVENT.make().onBarNotif("Unable to load the beatmap audio.");
+ barNotifs.send("Unable to load the beatmap audio.");
return;
}
diff --git a/src/itdelatrisu/opsu/states/Splash.java b/src/itdelatrisu/opsu/states/Splash.java
index eba0f109..44800dda 100644
--- a/src/itdelatrisu/opsu/states/Splash.java
+++ b/src/itdelatrisu/opsu/states/Splash.java
@@ -22,13 +22,12 @@ import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.audio.MusicController;
import itdelatrisu.opsu.audio.SoundController;
import itdelatrisu.opsu.beatmap.BeatmapSetList;
+import itdelatrisu.opsu.ui.Cursor;
import itdelatrisu.opsu.ui.UI;
import org.lwjgl.input.Keyboard;
import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
-import org.newdawn.slick.Input;
-import org.newdawn.slick.opengl.renderer.Renderer;
import org.newdawn.slick.util.Log;
import yugecin.opsudance.core.state.BaseOpsuState;
@@ -65,9 +64,6 @@ public class Splash extends BaseOpsuState {
return;
}
- System.out.println(
- Renderer.get().getClass()
- );
inited = true;
thread = new Thread() {
@Override
@@ -111,7 +107,13 @@ public class Splash extends BaseOpsuState {
@Override
public void render(Graphics g) {
g.setBackground(Color.black);
- GameImage.MENU_LOGO.getImage().drawCentered(displayContainer.width / 2, displayContainer.height / 2);
+ final Color col;
+ if (OPTION_COLOR_MAIN_MENU_LOGO.state) {
+ col = Cursor.lastCursorColor;
+ } else {
+ col = Color.white;
+ }
+ GameImage.MENU_LOGO.getImage().drawCentered(width2, height2, col);
UI.drawLoadingProgress(g);
}
diff --git a/src/itdelatrisu/opsu/ui/Colors.java b/src/itdelatrisu/opsu/ui/Colors.java
index cd17f0fd..51477fc9 100644
--- a/src/itdelatrisu/opsu/ui/Colors.java
+++ b/src/itdelatrisu/opsu/ui/Colors.java
@@ -28,6 +28,7 @@ public class Colors {
BLACK_ALPHA = new Color(0, 0, 0, 0.5f),
BLACK_ALPHA_75 = new Color(0, 0, 0, 0.75f),
BLACK_ALPHA_85 = new Color(0, 0, 0, 0.85f),
+ WHITE_ALPHA_75 = new Color(1, 1, 1, 0.75f),
WHITE_ALPHA = new Color(255, 255, 255, 0.5f),
BLUE_DIVIDER = new Color(49, 94, 237),
BLUE_BACKGROUND = new Color(74, 130, 255),
@@ -53,8 +54,7 @@ public class Colors {
BUB_WHITE = new Color(220, 220, 220),
BUB_PURPLE = new Color(94, 46, 149),
BUB_RED = new Color(141, 49, 16),
- BUB_ORANGE = new Color(138, 72, 51),
- GHOST_LOGO = new Color(1.0f, 1.0f, 1.0f, 0.25f);
+ BUB_ORANGE = new Color(138, 72, 51);
// This class should not be instantiated.
private Colors() {}
diff --git a/src/itdelatrisu/opsu/ui/Cursor.java b/src/itdelatrisu/opsu/ui/Cursor.java
index 0cc0dc02..44e8e30f 100644
--- a/src/itdelatrisu/opsu/ui/Cursor.java
+++ b/src/itdelatrisu/opsu/ui/Cursor.java
@@ -30,6 +30,7 @@ import yugecin.opsudance.Dancer;
import yugecin.opsudance.skinning.SkinService;
import static yugecin.opsudance.options.Options.*;
+import static yugecin.opsudance.core.InstanceContainer.*;
/**
* Updates and draws the cursor.
@@ -263,8 +264,8 @@ public class Cursor {
* If the old style cursor is being used, this will do nothing.
* @param delta the delta interval since the last call
*/
- public void updateAngle(int delta) {
- cursorAngle += delta / 40f;
+ public void updateAngle() {
+ cursorAngle += renderDelta / 40f;
cursorAngle %= 360;
}
diff --git a/src/itdelatrisu/opsu/ui/DropdownMenu.java b/src/itdelatrisu/opsu/ui/DropdownMenu.java
index ec56dfd4..317aded0 100644
--- a/src/itdelatrisu/opsu/ui/DropdownMenu.java
+++ b/src/itdelatrisu/opsu/ui/DropdownMenu.java
@@ -29,15 +29,14 @@ import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.Input;
import org.newdawn.slick.UnicodeFont;
-import yugecin.opsudance.core.DisplayContainer;
import yugecin.opsudance.core.components.Component;
+import static yugecin.opsudance.core.InstanceContainer.*;
+
public class DropdownMenu extends Component {
private static final float PADDING_Y = 0.1f, CHEVRON_X = 0.03f;
- private final DisplayContainer displayContainer;
-
private E[] items;
private String[] itemNames;
private int selectedItemIndex;
@@ -61,8 +60,7 @@ public class DropdownMenu extends Component {
private Image chevronDown;
private Image chevronRight;
- public DropdownMenu(DisplayContainer displayContainer, E[] items, int x, int y, int width) {
- this.displayContainer = displayContainer;
+ public DropdownMenu(E[] items, int x, int y, int width) {
init(items, x, y, width);
}
@@ -143,13 +141,13 @@ public class DropdownMenu extends Component {
@Override
public void render(Graphics g) {
- int delta = displayContainer.renderDelta;
+ int delta = renderDelta;
// update animation
expandProgress.update((expanded) ? delta : -delta * 2);
// get parameters
- int idx = getIndexAt(displayContainer.mouseY);
+ int idx = getIndexAt(mouseY);
float t = expandProgress.getValue();
if (expanded) {
t = AnimationEquation.OUT_CUBIC.calc(t);
@@ -245,7 +243,7 @@ public class DropdownMenu extends Component {
return;
}
- int idx = getIndexAt(displayContainer.mouseY);
+ int idx = getIndexAt(mouseY);
if (idx == -2) {
this.expanded = false;
return;
diff --git a/src/itdelatrisu/opsu/ui/MenuButton.java b/src/itdelatrisu/opsu/ui/MenuButton.java
index a155d270..bc26188c 100644
--- a/src/itdelatrisu/opsu/ui/MenuButton.java
+++ b/src/itdelatrisu/opsu/ui/MenuButton.java
@@ -18,10 +18,13 @@
package itdelatrisu.opsu.ui;
+import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.ui.animations.AnimatedValue;
import itdelatrisu.opsu.ui.animations.AnimationEquation;
+import java.awt.Point;
+
import org.newdawn.slick.Animation;
import org.newdawn.slick.Color;
import org.newdawn.slick.Font;
@@ -98,9 +101,6 @@ public class MenuButton {
/** The default max rotation angle of the button. */
private static final float DEFAULT_ANGLE_MAX = 30f;
- /** The last scale at which the button was drawn. */
- private float lastScale = 1f;
-
/**
* Creates a new button from an Image.
* @param img the image
@@ -115,6 +115,14 @@ public class MenuButton {
this.yRadius = img.getHeight() / 2f;
}
+ public MenuButton(GameImage img, float topleftX, float topleftY) {
+ this.img = img.getImage();
+ this.xRadius = img.getWidth() / 2f;
+ this.yRadius = img.getHeight() / 2f;
+ this.x = topleftX + this.xRadius;
+ this.y = topleftY + this.yRadius;
+ }
+
/**
* Creates a new button from a 3-part Image.
* @param imgCenter the center image
@@ -168,11 +176,20 @@ public class MenuButton {
* Returns the center y coordinate.
*/
public float getY() { return y; }
+
+ public Point bottomLeft() {
+ return new Point((int) (x - xRadius), (int) (y + yRadius));
+ }
/**
- * Returns the last scale at which the button was drawn.
+ * Returns the scale multiplier, from the hover effect, used to draw the button.
*/
- public float getLastScale() { return lastScale; }
+ public float getCurrentHoverExpandValue() {
+ if ((hoverEffect & EFFECT_EXPAND) == 0) {
+ return 1f;
+ }
+ return scale.getValue();
+ }
/**
* Sets text to draw in the middle of the button.
@@ -229,7 +246,6 @@ public class MenuButton {
xScaleOffset = image.getWidth() / 2f - xRadius;
yScaleOffset = image.getHeight() / 2f - yRadius;
}
- lastScale = scaleOverride;
if (hoverEffect == 0)
image.draw(x - xRadius, y - yRadius, filter);
else {
@@ -243,7 +259,6 @@ public class MenuButton {
xScaleOffset = image.getWidth() / 2f - xRadius;
yScaleOffset = image.getHeight() / 2f - yRadius;
}
- lastScale *= scale.getValue();
}
}
if ((hoverEffect & EFFECT_FADE) > 0)
diff --git a/src/itdelatrisu/opsu/ui/UI.java b/src/itdelatrisu/opsu/ui/UI.java
index 8acfb1cf..df4c5e55 100644
--- a/src/itdelatrisu/opsu/ui/UI.java
+++ b/src/itdelatrisu/opsu/ui/UI.java
@@ -22,27 +22,21 @@ import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.audio.SoundController;
import itdelatrisu.opsu.beatmap.BeatmapParser;
-import itdelatrisu.opsu.beatmap.OszUnpacker;
-import itdelatrisu.opsu.replay.ReplayImporter;
import itdelatrisu.opsu.ui.animations.AnimatedValue;
import itdelatrisu.opsu.ui.animations.AnimationEquation;
import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
-import yugecin.opsudance.core.DisplayContainer;
-import yugecin.opsudance.ui.BackButton;
import static yugecin.opsudance.options.Options.*;
+import static yugecin.opsudance.core.InstanceContainer.*;
/**
* Draws common UI components.
*/
public class UI {
- /** Back button. */
- private static BackButton backButton;
-
/** Time to show volume image, in milliseconds. */
private static final int VOLUME_DISPLAY_TIME = 1500;
@@ -58,20 +52,9 @@ public class UI {
/** The alpha level of the current tooltip (if any). */
private static AnimatedValue tooltipAlpha = new AnimatedValue(200, 0f, 1f, AnimationEquation.LINEAR);
- // game-related variables
- private static DisplayContainer displayContainer;
-
// This class should not be instantiated.
private UI() {}
- /**
- * Initializes UI data.
- */
- public static void init(DisplayContainer displayContainer) {
- UI.displayContainer = displayContainer;
- backButton = new BackButton(displayContainer);
- }
-
/**
* Updates all UI components by a delta interval.
* @param delta the delta interval since the last call.
@@ -93,15 +76,9 @@ public class UI {
* Resets the necessary UI components upon entering a state.
*/
public static void enter() {
- backButton.resetHover();
resetTooltip();
}
- /**
- * Returns the 'menu-back' MenuButton.
- */
- public static BackButton getBackButton() { return backButton; }
-
/**
* Draws a tab image and text centered at a location.
* @param x the center x coordinate
@@ -145,13 +122,13 @@ public class UI {
else if (ratio >= 0.9f)
xOffset = img.getWidth() * (1 - ((1 - ratio) * 10f));
- img.drawCentered(displayContainer.width - img.getWidth() / 2f + xOffset, displayContainer.height / 2f);
+ img.drawCentered(width - img.getWidth() / 2f + xOffset, height2);
float barHeight = img.getHeight() * 0.9f;
float volume = OPTION_MASTER_VOLUME.val / 100f;
g.setColor(Color.white);
g.fillRoundRect(
- displayContainer.width - (img.getWidth() * 0.368f) + xOffset,
- (displayContainer.height / 2f) - (img.getHeight() * 0.47f) + (barHeight * (1 - volume)),
+ width - (img.getWidth() * 0.368f) + xOffset,
+ height2 - (img.getHeight() * 0.47f) + (barHeight * (1 - volume)),
img.getWidth() * 0.15f, barHeight * volume, 3
);
}
@@ -193,33 +170,25 @@ public class UI {
int progress;
// determine current action
- //
- /*
- TODO
- if ((file = OszUnpacker.getCurrentFileName()) != null) {
+ if ((file = oszunpacker.getCurrentFileName()) != null) {
text = "Unpacking new beatmaps...";
- progress = OszUnpacker.getUnpackerProgress();
- } else if ((file = BeatmapParser.getCurrentFileName()) != null) {
- text = (BeatmapParser.getStatus() == BeatmapParser.Status.INSERTING) ?
+ progress = oszunpacker.getUnpackerProgress();
+ } else if ((file = beatmapParser.getCurrentFileName()) != null) {
+ text = (beatmapParser.getStatus() == BeatmapParser.Status.INSERTING) ?
"Updating database..." : "Loading beatmaps...";
- progress = BeatmapParser.getParserProgress();
- } else if ((file = ReplayImporter.getCurrentFileName()) != null) {
+ progress = beatmapParser.getParserProgress();
+ } else if ((file = replayImporter.getCurrentFileName()) != null) {
text = "Importing replays...";
- progress = ReplayImporter.getLoadingProgress();
+ progress = replayImporter.getLoadingProgress();
} else if ((file = SoundController.getCurrentFileName()) != null) {
text = "Loading sounds...";
progress = SoundController.getLoadingProgress();
} else
return;
- */
-
- if (true) {
- return; // TODO
- }
// draw loading info
- float marginX = displayContainer.width * 0.02f, marginY = displayContainer.height * 0.02f;
- float lineY = displayContainer.height - marginY;
+ float marginX = width * 0.02f, marginY = height * 0.02f;
+ float lineY = height - marginY;
int lineOffsetY = Fonts.MEDIUM.getLineHeight();
if (OPTION_LOAD_VERBOSE.state) {
// verbose: display percentages and file names
@@ -232,7 +201,7 @@ public class UI {
Fonts.MEDIUM.drawString(marginX, lineY - (lineOffsetY * 2), text, Color.white);
g.setColor(Color.white);
g.fillRoundRect(marginX, lineY - (lineOffsetY / 2f),
- (displayContainer.width - (marginX * 2f)) * progress / 100f, lineOffsetY / 4f, 4
+ (width - (marginX * 2f)) * progress / 100f, lineOffsetY / 4f, 4
);
}
}
@@ -256,7 +225,7 @@ public class UI {
float unitBaseX, float unitBaseY, float unitWidth, float scrollAreaHeight,
Color bgColor, Color scrollbarColor, boolean right
) {
- float scrollbarWidth = displayContainer.width * 0.00347f;
+ float scrollbarWidth = width * 0.00347f;
float scrollbarHeight = scrollAreaHeight * lengthShown / totalLength;
float offsetY = (scrollAreaHeight - scrollbarHeight) * (position / (totalLength - lengthShown));
float scrollbarX = unitBaseX + unitWidth - ((right) ? scrollbarWidth : 0);
@@ -292,8 +261,8 @@ public class UI {
if (tooltipAlpha.getTime() == 0 || tooltip == null)
return;
- int margin = displayContainer.width / 100, textMarginX = 2;
- int offset = GameImage.CURSOR_MIDDLE.getImage().getWidth() / 2;
+ int margin = width / 100, textMarginX = 2;
+ int offset = GameImage.CURSOR_MIDDLE.getWidth() / 2;
int lineHeight = Fonts.SMALL.getLineHeight();
int textWidth = textMarginX * 2, textHeight = lineHeight;
if (tooltipNewlines) {
@@ -310,14 +279,14 @@ public class UI {
textWidth += Fonts.SMALL.getWidth(tooltip);
// get drawing coordinates
- int x = displayContainer.mouseX + offset;
- int y = displayContainer.mouseY + offset;
- if (x + textWidth > displayContainer.width - margin)
- x = displayContainer.width - margin - textWidth;
+ int x = mouseX + offset;
+ int y = mouseY + offset;
+ if (x + textWidth > width - margin)
+ x = width - margin - textWidth;
else if (x < margin)
x = margin;
- if (y + textHeight > displayContainer.height - margin)
- y = displayContainer.height - margin - textHeight;
+ if (y + textHeight > height - margin)
+ y = height - margin - textHeight;
else if (y < margin)
y = margin;
diff --git a/src/itdelatrisu/opsu/ui/animations/AnimatedValue.java b/src/itdelatrisu/opsu/ui/animations/AnimatedValue.java
index da8bd8d5..3b385ded 100644
--- a/src/itdelatrisu/opsu/ui/animations/AnimatedValue.java
+++ b/src/itdelatrisu/opsu/ui/animations/AnimatedValue.java
@@ -57,6 +57,41 @@ public class AnimatedValue {
this.diff = max - min;
this.eqn = eqn;
}
+
+ public void change(int duration, float min, float max, AnimationEquation eqn) {
+ float progress = (float) this.time / this.duration;
+ if (this.eqn != eqn) {
+ if (this.time != 0 && this.time != this.duration) {
+ progress = eqn.uncalc(this.eqn.calc(progress));
+ }
+ this.eqn = eqn;
+ }
+ this.duration = duration;
+ this.time = (int) (this.duration * progress);
+ this.base = min;
+ this.diff = max - min;
+ this.updateValue();
+ }
+
+ /**
+ * Change the from and to values
+ * @param min start value
+ * @param max end value
+ */
+ public void setValues(float min, float max) {
+ this.base = min;
+ this.value = min;
+ this.diff = max - min;
+ this.updateValue();
+ }
+
+ /**
+ * Gets the max (end) value
+ * @return the max (end) value
+ */
+ public float getMax() {
+ return this.base + this.diff;
+ }
/**
* Returns the current value.
diff --git a/src/itdelatrisu/opsu/ui/animations/AnimationEquation.java b/src/itdelatrisu/opsu/ui/animations/AnimationEquation.java
index 146be941..db78fd1e 100644
--- a/src/itdelatrisu/opsu/ui/animations/AnimationEquation.java
+++ b/src/itdelatrisu/opsu/ui/animations/AnimationEquation.java
@@ -312,4 +312,19 @@ public enum AnimationEquation {
* @return the new {@code t} value [0,1]
*/
public abstract float calc(float t);
+
+ public float uncalc(float x) {
+ float min = 0f;
+ float max = 1f;
+ // 7 iterations is already decent, do we need 8?
+ for (int i = 0; i < 8; i++) {
+ float pos = (min + max) / 2f;
+ if (this.calc(pos) > x) {
+ max = pos;
+ } else {
+ min = pos;
+ }
+ }
+ return (min + max) / 2f;
+ }
}
diff --git a/src/org/newdawn/slick/Input.java b/src/org/newdawn/slick/Input.java
index b340588b..673ca2cd 100644
--- a/src/org/newdawn/slick/Input.java
+++ b/src/org/newdawn/slick/Input.java
@@ -43,7 +43,7 @@ import static org.lwjgl.input.Keyboard.*;
*
* @author kevin
*/
-@SuppressWarnings({"rawtypes", "unchecked", "unused"})
+@SuppressWarnings({"unused"})
public class Input {
/** A helper for left ALT */
@@ -98,8 +98,6 @@ public class Input {
protected char[] keys = new char[1024];
/** True if the key has been pressed since last queries */
protected boolean[] pressed = new boolean[1024];
- /** The time since the next key repeat to be fired for the key */
- protected long[] nextRepeat = new long[1024];
/** The listeners to notify of key events */
protected ArrayList keyListeners = new ArrayList<>();
@@ -113,13 +111,6 @@ public class Input {
/** True if the display is active */
private boolean displayActive = true;
- /** True if key repeat is enabled */
- private boolean keyRepeat;
- /** The initial delay for key repeat starts */
- private int keyRepeatInitial;
- /** The interval of key repeat */
- private int keyRepeatInterval;
-
/** The clicked button */
private int clickButton;
@@ -344,7 +335,6 @@ public class Input {
keys[eventKey] = Keyboard.getEventCharacter();
pressed[eventKey] = true;
- nextRepeat[eventKey] = System.currentTimeMillis() + keyRepeatInitial;
for (KeyListener listener : keyListeners) {
if (listener.keyPressed(eventKey, Keyboard.getEventCharacter())) {
@@ -353,7 +343,6 @@ public class Input {
}
} else {
int eventKey = Keyboard.getEventKey();
- nextRepeat[eventKey] = 0;
for (KeyListener listener : keyListeners) {
if (listener.keyReleased(eventKey, keys[eventKey])) {
@@ -424,21 +413,6 @@ public class Input {
lastMouseY = getMouseY();
}
}
-
- if (keyRepeat) {
- for (int i=0;i<1024;i++) {
- if (pressed[i] && (nextRepeat[i] != 0)) {
- if (System.currentTimeMillis() > nextRepeat[i]) {
- nextRepeat[i] = System.currentTimeMillis() + keyRepeatInterval;
- for (KeyListener listener : keyListeners) {
- if (listener.keyPressed(i, keys[i])) {
- break;
- }
- }
- }
- }
- }
- }
if (Display.isCreated()) {
displayActive = Display.isActive();
diff --git a/src/yugecin/opsudance/Dancer.java b/src/yugecin/opsudance/Dancer.java
index 944df3d1..4f5ddeb2 100644
--- a/src/yugecin/opsudance/Dancer.java
+++ b/src/yugecin/opsudance/Dancer.java
@@ -1,6 +1,6 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
- * Copyright (C) 2016 yugecin
+ * Copyright (C) 2016-2018 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
@@ -35,7 +35,6 @@ import yugecin.opsudance.movers.factories.*;
import yugecin.opsudance.movers.slidermovers.DefaultSliderMoverController;
import yugecin.opsudance.movers.slidermovers.InheritedSliderMoverController;
import yugecin.opsudance.movers.slidermovers.SliderMoverController;
-import yugecin.opsudance.render.GameObjectRenderer;
import yugecin.opsudance.spinners.*;
import java.awt.*;
@@ -252,8 +251,8 @@ public class Dancer {
}
}
Pippi.dance(time, c, isCurrentLazySlider);
- x = Utils.clamp(x, 10, displayContainer.width - 10);
- y = Utils.clamp(y, 10, displayContainer.height - 10);
+ x = Utils.clamp(x, 10, width - 10);
+ y = Utils.clamp(y, 10, height - 10);
}
private void createNewMover() {
diff --git a/src/yugecin/opsudance/core/DisplayContainer.java b/src/yugecin/opsudance/core/DisplayContainer.java
index f9ee69a4..2fed84d0 100644
--- a/src/yugecin/opsudance/core/DisplayContainer.java
+++ b/src/yugecin/opsudance/core/DisplayContainer.java
@@ -1,6 +1,6 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
- * Copyright (C) 2017 yugecin
+ * Copyright (C) 2017-2018 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
@@ -25,8 +25,8 @@ import itdelatrisu.opsu.downloads.DownloadList;
import itdelatrisu.opsu.downloads.DownloadNode;
import itdelatrisu.opsu.downloads.Updater;
import itdelatrisu.opsu.render.CurveRenderState;
+import itdelatrisu.opsu.render.FrameBufferCache;
import itdelatrisu.opsu.replay.PlaybackSpeed;
-import itdelatrisu.opsu.ui.Colors;
import itdelatrisu.opsu.ui.Cursor;
import itdelatrisu.opsu.ui.Fonts;
import itdelatrisu.opsu.ui.UI;
@@ -43,16 +43,16 @@ import org.newdawn.slick.opengl.renderer.SGL;
import org.newdawn.slick.util.Log;
import yugecin.opsudance.core.errorhandling.ErrorDumpable;
import yugecin.opsudance.core.state.OpsuState;
-import yugecin.opsudance.core.state.specialstates.BarNotificationState;
-import yugecin.opsudance.core.state.specialstates.BubNotifState;
-import yugecin.opsudance.core.state.specialstates.FpsRenderState;
-import yugecin.opsudance.events.BubNotifListener;
import yugecin.opsudance.events.ResolutionChangedListener;
import yugecin.opsudance.events.SkinChangedListener;
+import yugecin.opsudance.ui.BackButton;
import yugecin.opsudance.utils.GLHelper;
import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.List;
+import static itdelatrisu.opsu.ui.Colors.*;
import static yugecin.opsudance.core.Entrypoint.sout;
import static yugecin.opsudance.core.InstanceContainer.*;
import static yugecin.opsudance.options.Options.*;
@@ -60,33 +60,23 @@ import static yugecin.opsudance.options.Options.*;
/**
* based on org.newdawn.slick.AppGameContainer
*/
-public class DisplayContainer implements ErrorDumpable, ResolutionChangedListener, SkinChangedListener {
+public class DisplayContainer implements ErrorDumpable, SkinChangedListener {
private static SGL GL = Renderer.get();
- private FpsRenderState fpsState;
- private BarNotificationState barNotifState;
- private BubNotifState bubNotifState;
-
private OpsuState state;
public final DisplayMode nativeDisplayMode;
private Graphics graphics;
- public int width;
- public int height;
-
- public int mouseX;
- public int mouseY;
-
private int targetUpdatesPerSecond;
public int targetUpdateInterval;
private int targetRendersPerSecond;
public int targetRenderInterval;
public int targetBackgroundRenderInterval;
- public int renderDelta;
+ private boolean rendering;
public int delta;
public boolean exitRequested;
@@ -104,53 +94,22 @@ public class DisplayContainer implements ErrorDumpable, ResolutionChangedListene
public final Cursor cursor;
public boolean drawCursor;
+
+ private final List resolutionChangedListeners;
- class Transition {
- int in;
- int out;
- int total;
- int progress = -1;
- OpsuState nextstate;
- Color OVERLAY = new Color(Color.black);
+ private int tIn;
+ private int tOut;
+ private int tProgress = -1;
+ private OpsuState tNextState;
+ private final Color tOVERLAY = new Color(Color.black);
- public void update() {
- if (progress == -1) {
- return;
- }
- progress += delta;
- if (progress > out && nextstate != null) {
- switchStateInstantly(nextstate);
- nextstate = null;
- }
- if (progress > total) {
- progress = -1;
- }
- }
-
- public void render(Graphics graphics) {
- if (progress == -1) {
- return;
- }
- int relprogress = progress;
- int reltotal = out;
- if (progress > out) {
- reltotal = in;
- relprogress = total - progress;
- }
- OVERLAY.a = (float) relprogress / reltotal;
- graphics.setColor(OVERLAY);
- graphics.fillRect(0, 0, width, height);
- }
- }
-
- private final Transition transition = new Transition();
-
- public DisplayContainer() {
+ public DisplayContainer()
+ {
+ this.resolutionChangedListeners = new ArrayList<>();
this.cursor = new Cursor();
drawCursor = true;
- ResolutionChangedListener.EVENT.addListener(this);
- SkinChangedListener.EVENT.addListener(this);
+ skinservice.addSkinChangedListener(this);
this.nativeDisplayMode = Display.getDisplayMode();
targetBackgroundRenderInterval = 41; // ~24 fps
@@ -159,10 +118,9 @@ public class DisplayContainer implements ErrorDumpable, ResolutionChangedListene
renderDelta = 1;
}
- @Override
- public void onResolutionChanged(int w, int h) {
- destroyImages();
- reinit();
+ public void addResolutionChangedListener(ResolutionChangedListener l)
+ {
+ this.resolutionChangedListeners.add(l);
}
@Override
@@ -186,12 +144,13 @@ public class DisplayContainer implements ErrorDumpable, ResolutionChangedListene
}
}
+ backButton = new BackButton();
+
// 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) {
@@ -205,13 +164,9 @@ public class DisplayContainer implements ErrorDumpable, ResolutionChangedListene
}
public void init(OpsuState startingState) {
- setUPS(OPTION_TARGET_UPS.val);
+ setUPS(targetUPS[OPTION_TARGET_UPS.val]);
setFPS(targetFPS[targetFPSIndex]);
- fpsState = new FpsRenderState();
- bubNotifState = new BubNotifState();
- barNotifState = new BarNotificationState();
-
state = startingState;
state.enter();
}
@@ -228,8 +183,18 @@ public class DisplayContainer implements ErrorDumpable, ResolutionChangedListene
mouseX = input.getMouseX();
mouseY = input.getMouseY();
- transition.update();
- fpsState.update();
+ // state transition
+ if (tProgress != -1) {
+ tProgress += delta;
+ if (tProgress > tOut && tNextState != null) {
+ switchStateInstantly(tNextState);
+ tNextState = null;
+ }
+ if (tProgress > tIn + tOut) {
+ tProgress = -1;
+ }
+ }
+ fpsDisplay.update();
state.update();
if (drawCursor) {
@@ -244,6 +209,7 @@ public class DisplayContainer implements ErrorDumpable, ResolutionChangedListene
}
if (timeSinceLastRender >= maxRenderInterval) {
+ rendering = true;
GL.glClear(SGL.GL_COLOR_BUFFER_BIT);
/*
@@ -257,32 +223,44 @@ public class DisplayContainer implements ErrorDumpable, ResolutionChangedListene
state.preRenderUpdate();
state.render(graphics);
- fpsState.render(graphics);
- bubNotifState.render(graphics);
- barNotifState.render(graphics);
+ fpsDisplay.render(graphics);
+ bubNotifs.render(graphics);
+ barNotifs.render(graphics);
- cursor.updateAngle(renderDelta);
+ cursor.updateAngle();
if (drawCursor) {
cursor.draw(Mouse.isButtonDown(Input.MOUSE_LEFT_BUTTON) ||
Mouse.isButtonDown(Input.MOUSE_RIGHT_BUTTON));
}
UI.drawTooltip(graphics);
- transition.render(graphics);
+ // transition
+ if (tProgress != -1) {
+ if (tProgress > tOut) {
+ tOVERLAY.a = 1f - (tProgress - tOut) / (float) tIn;
+ } else {
+ tOVERLAY.a = tProgress / (float) tOut;
+ }
+ graphics.setColor(tOVERLAY);
+ graphics.fillRect(0, 0, width, height);
+ }
timeSinceLastRender = 0;
Display.update(false);
GL11.glFlush();
+ rendering = false;
}
Display.processMessages();
- Display.sync(targetUpdatesPerSecond);
+ if (targetUpdatesPerSecond >= 60) {
+ Display.sync(targetUpdatesPerSecond);
+ }
}
}
public void setup() throws Exception {
- width = height = -1;
+ width = height = width2 = height2 = -1;
Display.setTitle("opsu!dance");
setupResolutionOptionlist(nativeDisplayMode.getWidth(), nativeDisplayMode.getHeight());
updateDisplayMode(OPTION_SCREEN_RESOLUTION.getValueString());
@@ -318,6 +296,7 @@ public class DisplayContainer implements ErrorDumpable, ResolutionChangedListene
GameImage.destroyImages();
GameData.Grade.destroyImages();
Beatmap.destroyBackgroundImageCache();
+ FrameBufferCache.shutdown();
}
public void teardownAL() {
@@ -342,13 +321,13 @@ public class DisplayContainer implements ErrorDumpable, ResolutionChangedListene
return true;
}
if (DownloadList.get().hasActiveDownloads()) {
- BubNotifListener.EVENT.make().onBubNotif(DownloadList.EXIT_CONFIRMATION, Colors.BUB_RED);
+ bubNotifs.send(BUB_RED, DownloadList.EXIT_CONFIRMATION);
exitRequested = false;
exitconfirmation = System.currentTimeMillis();
return false;
}
if (updater.getStatus() == Updater.Status.UPDATE_DOWNLOADING) {
- BubNotifListener.EVENT.make().onBubNotif(Updater.EXIT_CONFIRMATION, Colors.BUB_PURPLE);
+ bubNotifs.send(BUB_PURPLE, Updater.EXIT_CONFIRMATION);
exitRequested = false;
exitconfirmation = System.currentTimeMillis();
return false;
@@ -372,6 +351,13 @@ public class DisplayContainer implements ErrorDumpable, ResolutionChangedListene
width = Integer.parseInt(res[0]);
height = Integer.parseInt(res[1]);
}
+
+ updateDisplayMode(width, height);
+ }
+
+ public void updateDisplayMode(int width, int height) {
+ int screenWidth = nativeDisplayMode.getWidth();
+ int screenHeight = nativeDisplayMode.getHeight();
// check for larger-than-screen dimensions
if (!OPTION_ALLOW_LARGER_RESOLUTIONS.state && (screenWidth < width || screenHeight < height)) {
@@ -387,34 +373,35 @@ public class DisplayContainer implements ErrorDumpable, ResolutionChangedListene
try {
setDisplayMode(width, height, OPTION_FULLSCREEN.state);
} catch (Exception e) {
- BubNotifListener.EVENT.make().onBubNotif("Failed to change resolution", Colors.BUB_RED);
+ bubNotifs.send(BUB_RED, "Failed to change display mode");
Log.error("Failed to set display mode.", e);
}
}
- public void setDisplayMode(int width, int height, boolean fullscreen) throws Exception {
- if (this.width == width && this.height == height) {
- Display.setFullscreen(fullscreen);
- return;
- }
-
+ public void setDisplayMode(int w, int h, boolean fullscreen) throws Exception {
DisplayMode displayMode = null;
if (fullscreen) {
- displayMode = GLHelper.findFullscreenDisplayMode(nativeDisplayMode.getBitsPerPixel(), nativeDisplayMode.getFrequency(), width, height);
+ final int bpp = this.nativeDisplayMode.getBitsPerPixel();
+ final int freq = this.nativeDisplayMode.getFrequency();
+ displayMode = GLHelper.findFullscreenDisplayMode(bpp, freq, w, h);
}
if (displayMode == null) {
- displayMode = new DisplayMode(width, height);
+ displayMode = new DisplayMode(w, h);
if (fullscreen) {
fullscreen = false;
- String msg = String.format("Fullscreen mode is not supported for %sx%s", width, height);
+ String msg = "Fullscreen mode is not supported for %sx%s";
+ msg = String.format(msg, w, h);
Log.warn(msg);
- BubNotifListener.EVENT.make().onBubNotif(msg, Colors.BUB_ORANGE);
+ bubNotifs.send(BUB_ORANGE, msg);
}
}
- this.width = displayMode.getWidth();
- this.height = displayMode.getHeight();
+ width = displayMode.getWidth();
+ height = displayMode.getHeight();
+ width2 = width / 2;
+ height2 = height / 2;
+ isWidescreen = width * 1000 / height > 1500; // 1777 = 16:9, 1333 = 4:3
Display.setDisplayMode(displayMode);
Display.setFullscreen(fullscreen);
@@ -439,7 +426,7 @@ public class DisplayContainer implements ErrorDumpable, ResolutionChangedListene
input = new Input(height);
input.enableKeyRepeat();
input.addListener(new GlobalInputListener());
- input.addMouseListener(bubNotifState);
+ input.addMouseListener(bubNotifs);
}
input.addListener(state);
@@ -448,7 +435,15 @@ public class DisplayContainer implements ErrorDumpable, ResolutionChangedListene
GameImage.init(width, height);
Fonts.init();
- ResolutionChangedListener.EVENT.make().onResolutionChanged(width, height);
+ destroyImages();
+ reinit();
+
+ barNotifs.onResolutionChanged(width, height);
+ bubNotifs.onResolutionChanged(width, height);
+ fpsDisplay.onResolutionChanged(width, height);
+ for (ResolutionChangedListener l : this.resolutionChangedListeners) {
+ l.onResolutionChanged(width, height);
+ }
}
public void resetCursor() {
@@ -466,10 +461,6 @@ public class DisplayContainer implements ErrorDumpable, ResolutionChangedListene
return (Sys.getTime() * 1000) / Sys.getTimerResolution();
}
- public boolean isWidescreen() {
- return width * 1000 / height > 1500; // 1777 = 16:9, 1333 = 4:3
- }
-
@Override
public void writeErrorDump(StringWriter dump) {
dump.append("> DisplayContainer dump\n");
@@ -487,22 +478,32 @@ public class DisplayContainer implements ErrorDumpable, ResolutionChangedListene
}
public void switchState(OpsuState state) {
- switchState(state, 200, 300);
+ switchState(state, 150, 250);
}
public void switchState(OpsuState newstate, int outtime, int intime) {
- if (transition.progress != -1) {
+ if (tProgress != -1 && tProgress <= tOut) {
return;
}
+
if (outtime == 0) {
switchStateInstantly(newstate);
newstate = null;
+ } else {
+ input.removeListener(this.state);
}
- transition.nextstate = newstate;
- transition.total = transition.in = intime;
- transition.out = outtime;
- transition.total += outtime;
- transition.progress = 0;
+
+ if (tProgress == -1) {
+ tProgress = 0;
+ } else {
+ // we were in a transition (out state), so start from the time
+ // that was already spent transitioning in
+ tProgress = (int) (((1f - (tProgress - tOut) / (float) tIn)) * outtime);
+ }
+
+ tNextState = newstate;
+ tIn = intime;
+ tOut = outtime;
}
public void switchStateInstantly(OpsuState state) {
@@ -511,6 +512,13 @@ public class DisplayContainer implements ErrorDumpable, ResolutionChangedListene
this.state = state;
this.state.enter();
input.addListener(this.state);
+ backButton.resetHover();
+ if (this.rendering) {
+ // state might be changed in preRenderUpdate,
+ // in that case the new state will be rendered without having
+ // preRenderUpdate being called first, so do that now
+ this.state.preRenderUpdate();
+ }
}
}
diff --git a/src/yugecin/opsudance/core/GlobalInputListener.java b/src/yugecin/opsudance/core/GlobalInputListener.java
index 4e57f1b2..7a15bde0 100644
--- a/src/yugecin/opsudance/core/GlobalInputListener.java
+++ b/src/yugecin/opsudance/core/GlobalInputListener.java
@@ -1,6 +1,6 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
- * Copyright (C) 2017 yugecin
+ * Copyright (C) 2017-2018 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
@@ -21,7 +21,6 @@ import itdelatrisu.opsu.states.Game;
import itdelatrisu.opsu.ui.UI;
import org.newdawn.slick.Input;
import org.newdawn.slick.InputListener;
-import yugecin.opsudance.events.BarNotifListener;
import static org.lwjgl.input.Keyboard.*;
import static yugecin.opsudance.core.InstanceContainer.*;
@@ -38,8 +37,8 @@ public class GlobalInputListener implements InputListener {
public boolean keyReleased(int key, char c) {
if (key == KEY_F7) {
OPTION_TARGET_FPS.clickListItem((targetFPSIndex + 1) % targetFPS.length);
- BarNotifListener.EVENT.make().onBarNotif(String.format("Frame limiter: %s",
- OPTION_TARGET_FPS.getValueString()));
+ final String value = OPTION_TARGET_FPS.getValueString();
+ barNotifs.sendf("Frame limiter: %s", value);
return true;
}
if (key == KEY_F10) {
diff --git a/src/yugecin/opsudance/core/InstanceContainer.java b/src/yugecin/opsudance/core/InstanceContainer.java
index a2cb6c75..ea53fd90 100644
--- a/src/yugecin/opsudance/core/InstanceContainer.java
+++ b/src/yugecin/opsudance/core/InstanceContainer.java
@@ -1,6 +1,6 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
- * Copyright (C) 2017 yugecin
+ * Copyright (C) 2017-2018 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
@@ -26,11 +26,17 @@ import itdelatrisu.opsu.states.*;
import org.newdawn.slick.Input;
import org.newdawn.slick.util.FileSystemLocation;
import org.newdawn.slick.util.ResourceLoader;
+
+import yugecin.opsudance.core.state.specialstates.BarNotificationState;
+import yugecin.opsudance.core.state.specialstates.BubNotifState;
+import yugecin.opsudance.core.state.specialstates.FpsRenderState;
import yugecin.opsudance.options.Configuration;
+import yugecin.opsudance.options.OptionGroups;
import yugecin.opsudance.options.OptionsService;
import yugecin.opsudance.render.GameObjectRenderer;
import yugecin.opsudance.skinning.SkinService;
-import yugecin.opsudance.utils.ManifestWrapper;
+import yugecin.opsudance.ui.BackButton;
+import yugecin.opsudance.ui.OptionsOverlay;
import java.io.File;
import java.io.IOException;
@@ -51,10 +57,17 @@ public class InstanceContainer {
public static BeatmapParser beatmapParser;
public static Updater updater;
+ public static BackButton backButton;
public static DisplayContainer displayContainer;
public static Input input;
public static GameObjectRenderer gameObjectRenderer;
+
+ public static BarNotificationState barNotifs;
+ public static BubNotifState bubNotifs;
+ public static FpsRenderState fpsDisplay;
+
+ public static OptionsOverlay optionsOverlay;
public static Splash splashState;
public static MainMenu mainmenuState;
@@ -64,17 +77,21 @@ public class InstanceContainer {
public static Game gameState;
public static GameRanking gameRankingState;
public static GamePauseMenu pauseState;
+
+ public static int width, width2, height, height2;
+ public static boolean isWidescreen;
+ public static int mouseX, mouseY;
+ public static int renderDelta;
public static void kickstart() {
updater = new Updater();
env = new Environment();
JarFile jarfile = getJarfile();
- ManifestWrapper manifest = new ManifestWrapper(getJarManifest(jarfile));
- config = new Configuration(manifest);
+ config = new Configuration();
if (jarfile != null) {
try {
- NativeLoader.loadNatives(jarfile, manifest);
+ NativeLoader.loadNatives(jarfile);
} catch (IOException e) {
String msg = String.format("Could not unpack native(s): %s", e.getMessage());
throw new RuntimeException(msg, e);
@@ -94,9 +111,15 @@ public class InstanceContainer {
updater = new Updater();
displayContainer = new DisplayContainer();
+
+ barNotifs = new BarNotificationState();
+ bubNotifs = new BubNotifState();
+ fpsDisplay = new FpsRenderState();
gameObjectRenderer = new GameObjectRenderer();
+ optionsOverlay = new OptionsOverlay(OptionGroups.normalOptions);
+
splashState = new Splash();
mainmenuState = new MainMenu();
buttonState = new ButtonMenu();
diff --git a/src/yugecin/opsudance/core/errorhandling/ErrorHandler.java b/src/yugecin/opsudance/core/errorhandling/ErrorHandler.java
index 2a3ef34f..d8627635 100644
--- a/src/yugecin/opsudance/core/errorhandling/ErrorHandler.java
+++ b/src/yugecin/opsudance/core/errorhandling/ErrorHandler.java
@@ -24,6 +24,11 @@ import yugecin.opsudance.utils.MiscUtils;
import javax.swing.*;
import java.awt.Desktop;
+import java.awt.Dialog.ModalityType;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.Window;
import java.awt.Cursor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
@@ -94,30 +99,15 @@ public class ErrorHandler {
}
JLabel message = new JLabel(messageText);
- JTextArea textArea = new JTextArea(15, 100);
- textArea.setEditable(false);
- textArea.setBackground(UIManager.getColor("Panel.background"));
- textArea.setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
- textArea.setTabSize(2);
- textArea.setLineWrap(false);
- textArea.setWrapStyleWord(true);
- textArea.setText(messageBody);
-
ActionListener reportAction = new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
- try {
- URI url = createGithubIssueUrl(customMessage, cause, errorDump);
- Desktop.getDesktop().browse(url);
- } catch (IOException e) {
- Log.warn("Could not open browser to report issue", e);
- JOptionPane.showMessageDialog(null, "whoops could not launch a browser",
- "errorception", JOptionPane.ERROR_MESSAGE);
- }
+ Window parent = SwingUtilities.getWindowAncestor(message);
+ showCreateIssueDialog(parent, errorDump, customMessage, cause);
}
};
- Object[] messageComponents = new Object[] { message, new JScrollPane(textArea), createViewLogButton(),
+ Object[] messageComponents = new Object[] { message, readonlyTextarea(messageBody), createViewLogButton(),
createReportButton(flags, reportAction) };
String[] buttons;
@@ -181,8 +171,71 @@ public class ErrorHandler {
button.setEnabled(false);
return button;
}
+
+ private static void showCreateIssueDialog(
+ Window parent,
+ String errorDump,
+ String customMessage,
+ Throwable cause)
+ {
+ final String dump = createIssueDump(customMessage, cause, errorDump);
- private static URI createGithubIssueUrl(String customMessage, Throwable cause, String errorDump) {
+ final String title = "report error";
+ JDialog d = new JDialog(parent, title, ModalityType.APPLICATION_MODAL);
+ d.setLayout(new GridBagLayout());
+ final GridBagConstraints c = new GridBagConstraints();
+ c.gridx = 1;
+ c.gridy = 1;
+ c.weightx = 1d;
+ c.weighty = 0d;
+ c.fill = GridBagConstraints.BOTH;
+ c.insets = new Insets(4, 8, 4, 8);
+
+ d.add(new JLabel(
+ "Copy the text in the box below.
"
+ + "Then click the button below.
"
+ + "Your browser should open a page where you can report the issue.
"
+ + "Please paste the dump below in the issue box."
+ ), c);
+
+ c.gridy++;
+ c.weighty = 1d;
+ d.add(readonlyTextarea(dump), c);
+ c.gridy++;
+ c.weighty = c.weightx = 0d;
+ c.fill = GridBagConstraints.NONE;
+ JButton btn = new JButton("Report");
+ btn.addActionListener(e -> {
+ try {
+ URI url = createGithubIssueUrl(customMessage, cause);
+ Desktop.getDesktop().browse(url);
+ d.dispose();
+ } catch (IOException t) {
+ Log.warn("Could not open browser to report issue", t);
+ JOptionPane.showMessageDialog(null, "whoops could not launch a browser",
+ "errorception", JOptionPane.ERROR_MESSAGE);
+ }
+ });
+ d.add(btn, c);
+ d.pack();
+ d.setLocationRelativeTo(parent);
+ d.setVisible(true);
+ }
+
+ private static URI createGithubIssueUrl(String customMessage, Throwable cause) {
+ String issueTitle = "";
+ String issueBody = "";
+ try {
+ issueTitle = URLEncoder.encode("*** Unhandled " + cause.getClass().getSimpleName() + ": " +
+ customMessage, "UTF-8");
+ issueBody = URLEncoder.encode("PASTE THE DUMP HERE", "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ Log.warn("URLEncoder failed to encode the auto-filled issue report URL.", e);
+ }
+ return URI.create(String.format(Constants.ISSUES_URL, issueTitle, issueBody));
+ }
+
+ private static String createIssueDump(String customMessage, Throwable cause, String errorDump) {
StringWriter dump = new StringWriter();
dump.append(customMessage).append("\n");
@@ -203,25 +256,19 @@ public class ErrorHandler {
dump.append("**info dump**").append('\n');
dump.append("```\n").append(errorDump).append("\n```\n\n");
-
- String issueTitle = "";
- String issueBody = "";
- try {
- issueTitle = URLEncoder.encode("*** Unhandled " + cause.getClass().getSimpleName() + " " +
- customMessage, "UTF-8");
- issueBody = URLEncoder.encode(truncateGithubIssueBody(dump.toString()), "UTF-8");
- } catch (UnsupportedEncodingException e) {
- Log.warn("URLEncoder failed to encode the auto-filled issue report URL.", e);
- }
- return URI.create(String.format(Constants.ISSUES_URL, issueTitle, issueBody));
+ return dump.toString();
}
- private static String truncateGithubIssueBody(String body) {
- if (body.replaceAll("[^a-zA-Z+-]", "").length() < 1750) {
- return body;
- }
- Log.warn("error dump too long to fit into github issue url, truncating");
- return body.substring(0, 1640) + "** TRUNCATED **\n```";
+ private static JComponent readonlyTextarea(String contents) {
+ JTextArea textArea = new JTextArea(15, 100);
+ textArea.setEditable(false);
+ textArea.setBackground(UIManager.getColor("Panel.background"));
+ textArea.setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
+ textArea.setTabSize(2);
+ textArea.setLineWrap(false);
+ textArea.setWrapStyleWord(true);
+ textArea.setFont(new JLabel().getFont());
+ textArea.setText(contents);
+ return new JScrollPane(textArea);
}
-
}
diff --git a/src/yugecin/opsudance/core/events/Event.java b/src/yugecin/opsudance/core/events/Event.java
deleted file mode 100644
index 63160e02..00000000
--- a/src/yugecin/opsudance/core/events/Event.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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 .
- */
-package yugecin.opsudance.core.events;
-
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-import java.util.LinkedList;
-
-@SuppressWarnings("unchecked")
-public class Event {
-
- private final Class type;
- private final LinkedList listeners;
-
- public Event(Class type) {
- this.type = type;
- this.listeners = new LinkedList<>();
- }
-
- public void addListener(T listener) {
- this.listeners.add(listener);
- }
-
- public T make() {
- return (T) Proxy.newProxyInstance(type.getClassLoader(), new Class[]{type},
- new InvocationHandler() {
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- for (T listener : listeners) {
- method.invoke(listener, args);
- }
- return null;
- }
- });
- }
-
-}
diff --git a/src/yugecin/opsudance/core/inject/Binder.java b/src/yugecin/opsudance/core/inject/Binder.java
deleted file mode 100644
index 16f33180..00000000
--- a/src/yugecin/opsudance/core/inject/Binder.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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 .
- */
-package yugecin.opsudance.core.inject;
-
-public interface Binder {
-
- void asEagerSingleton();
- void asLazySingleton();
- void to(Class extends T> type);
-}
diff --git a/src/yugecin/opsudance/core/inject/Inject.java b/src/yugecin/opsudance/core/inject/Inject.java
deleted file mode 100644
index 04fc897a..00000000
--- a/src/yugecin/opsudance/core/inject/Inject.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * 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 .
- */
-package yugecin.opsudance.core.inject;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-@Retention(RetentionPolicy.RUNTIME) public @interface Inject {
-}
diff --git a/src/yugecin/opsudance/core/inject/Injector.java b/src/yugecin/opsudance/core/inject/Injector.java
deleted file mode 100644
index 9ddee01d..00000000
--- a/src/yugecin/opsudance/core/inject/Injector.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * 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 .
- */
-package yugecin.opsudance.core.inject;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.ListIterator;
-
-@SuppressWarnings("unchecked")
-public abstract class Injector implements InstanceContainer, Binder {
-
- private final HashMap, Object> instances;
- private final LinkedList> lazyInstances;
-
- private Class> lastType;
-
- public Injector() {
- instances = new HashMap<>();
- lazyInstances = new LinkedList<>();
- instances.put(InstanceContainer.class, this);
- configure();
- }
-
- protected abstract void configure();
-
- public final T provide(Class type) {
- Object instance = instances.get(type);
- if (instance != null) {
- return (T) instance;
- }
- ListIterator> iter = lazyInstances.listIterator();
- while (iter.hasNext()) {
- Class> l = iter.next();
- if (l == type) {
- iter.remove();
- instance = createInstance(type);
- instances.put(type, instance);
- return (T) instance;
- }
- }
- return createInstance(type);
- }
-
- private T createInstance(Class type) {
- Constructor>[] constructors = type.getDeclaredConstructors();
- if (constructors.length == 0) {
- throw new RuntimeException("Cannot provide " + type.getSimpleName());
- }
- Constructor constructor = constructors[0];
- Class>[] parameterTypes = constructor.getParameterTypes();
- Object[] params = new Object[parameterTypes.length];
- for (int i = parameterTypes.length - 1; i >= 0; i--) {
- params[i] = provide(parameterTypes[i]);
- }
- try {
- return injectFields((T) constructor.newInstance(params), type);
- } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
- throw new RuntimeException(e);
- }
- }
-
- private T injectFields(T object, Class> type) {
- do {
- for (Field f : type.getDeclaredFields()) {
- if (f.getDeclaredAnnotation(Inject.class) == null) {
- continue;
- }
- boolean accessible = f.isAccessible();
- if (!accessible) {
- f.setAccessible(true);
- }
- try {
- f.set(object, provide(f.getType()));
- } catch (IllegalAccessException e) {
- throw new RuntimeException(e);
- }
- if (!accessible) {
- f.setAccessible(false);
- }
- }
- type = type.getSuperclass();
- } while (type != null);
- return object;
- }
-
- @Override
- public T injectFields(T obj) {
- return injectFields(obj, obj.getClass());
- }
-
- public final Binder bind(Class type) {
- lastType = type;
- return this;
- }
-
- @Override
- public final void asEagerSingleton() {
- instances.put(lastType, createInstance(lastType));
- }
-
- @Override
- public final void asLazySingleton() {
- lazyInstances.add(lastType);
- }
-
- @Override
- public final void to(Class type) {
- instances.put(lastType, createInstance(type));
- }
-
-}
diff --git a/src/yugecin/opsudance/core/inject/InstanceContainer.java b/src/yugecin/opsudance/core/inject/InstanceContainer.java
deleted file mode 100644
index 77ba1be7..00000000
--- a/src/yugecin/opsudance/core/inject/InstanceContainer.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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 .
- */
-package yugecin.opsudance.core.inject;
-
-public interface InstanceContainer {
-
- T provide(Class type);
- T injectFields(T instance);
-
-}
diff --git a/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java b/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java
deleted file mode 100644
index ba100f31..00000000
--- a/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * 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 .
- */
-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 yugecin.opsudance.core.DisplayContainer;
-import yugecin.opsudance.core.state.specialstates.BarNotificationState;
-import yugecin.opsudance.core.state.specialstates.BubNotifState;
-import yugecin.opsudance.core.state.specialstates.FpsRenderState;
-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 {
-
- 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(DisplayContainer.class).asEagerSingleton();
-
- bind(ErrorHandler.class).asEagerSingleton();
-
- bind(FpsRenderState.class).asEagerSingleton();
- bind(BarNotificationState.class).asEagerSingleton();
- bind(BubNotifState.class).asEagerSingleton();
-
- bind(GameObjectRenderer.class).asEagerSingleton();
-
- bind(Splash.class).asEagerSingleton();
- bind(MainMenu.class).asEagerSingleton();
- bind(ButtonMenu.class).asEagerSingleton();
- bind(SongMenu.class).asEagerSingleton();
- bind(DownloadsMenu.class).asEagerSingleton();
- bind(Game.class).asEagerSingleton();
- bind(GameRanking.class).asEagerSingleton();
- bind(GamePauseMenu.class).asEagerSingleton();
- }
-
-}
diff --git a/src/yugecin/opsudance/core/state/BaseOpsuState.java b/src/yugecin/opsudance/core/state/BaseOpsuState.java
index 893a4853..01ed84d2 100644
--- a/src/yugecin/opsudance/core/state/BaseOpsuState.java
+++ b/src/yugecin/opsudance/core/state/BaseOpsuState.java
@@ -1,6 +1,6 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
- * Copyright (C) 2017 yugecin
+ * Copyright (C) 2017-2018 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
@@ -19,11 +19,15 @@ package yugecin.opsudance.core.state;
import org.newdawn.slick.Graphics;
import yugecin.opsudance.events.ResolutionChangedListener;
+import yugecin.opsudance.events.SkinChangedListener;
import java.io.StringWriter;
-public abstract class BaseOpsuState implements OpsuState, ResolutionChangedListener {
+import static yugecin.opsudance.core.InstanceContainer.*;
+public abstract class BaseOpsuState implements OpsuState, ResolutionChangedListener,
+ SkinChangedListener
+{
/**
* state is dirty when resolution or skin changed but hasn't rendered yet
*/
@@ -31,7 +35,8 @@ public abstract class BaseOpsuState implements OpsuState, ResolutionChangedListe
private boolean isCurrentState;
public BaseOpsuState() {
- ResolutionChangedListener.EVENT.addListener(this);
+ displayContainer.addResolutionChangedListener(this);
+ skinservice.addSkinChangedListener(this);
}
protected void revalidate() {
@@ -48,9 +53,18 @@ public abstract class BaseOpsuState implements OpsuState, ResolutionChangedListe
@Override
public void render(Graphics g) {
}
+
+ @Override
+ public void onSkinChanged(String name) {
+ makeDirty();
+ }
@Override
public void onResolutionChanged(int w, int h) {
+ makeDirty();
+ }
+
+ private void makeDirty() {
if (isCurrentState) {
revalidate();
return;
diff --git a/src/yugecin/opsudance/core/state/ComplexOpsuState.java b/src/yugecin/opsudance/core/state/ComplexOpsuState.java
index 888c6938..d7a70e27 100644
--- a/src/yugecin/opsudance/core/state/ComplexOpsuState.java
+++ b/src/yugecin/opsudance/core/state/ComplexOpsuState.java
@@ -130,7 +130,7 @@ public abstract class ComplexOpsuState extends BaseOpsuState {
public void preRenderUpdate() {
super.preRenderUpdate();
for (Component component : components) {
- component.updateHover(displayContainer.mouseX, displayContainer.mouseY);
+ component.updateHover(mouseX, mouseY);
component.preRenderUpdate();
}
for (OverlayOpsuState overlay : overlays) {
diff --git a/src/yugecin/opsudance/core/state/OverlayOpsuState.java b/src/yugecin/opsudance/core/state/OverlayOpsuState.java
index 849b4567..c81d2f79 100644
--- a/src/yugecin/opsudance/core/state/OverlayOpsuState.java
+++ b/src/yugecin/opsudance/core/state/OverlayOpsuState.java
@@ -1,6 +1,6 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
- * Copyright (C) 2017 yugecin
+ * Copyright (C) 2017-2018 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
@@ -33,6 +33,10 @@ public abstract class OverlayOpsuState implements OpsuState {
public void show() {
acceptInput = active = true;
}
+
+ public boolean isActive() {
+ return this.active;
+ }
@Override
public final void update() {
diff --git a/src/yugecin/opsudance/core/state/specialstates/BarNotificationState.java b/src/yugecin/opsudance/core/state/specialstates/BarNotificationState.java
index dfb24d2c..0aeeb4ed 100644
--- a/src/yugecin/opsudance/core/state/specialstates/BarNotificationState.java
+++ b/src/yugecin/opsudance/core/state/specialstates/BarNotificationState.java
@@ -1,6 +1,6 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
- * Copyright (C) 2017 yugecin
+ * Copyright (C) 2017-2018 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
@@ -21,17 +21,17 @@ import itdelatrisu.opsu.ui.Fonts;
import itdelatrisu.opsu.ui.animations.AnimationEquation;
import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
-import yugecin.opsudance.events.BarNotifListener;
import yugecin.opsudance.events.ResolutionChangedListener;
+import java.util.Formatter;
import java.util.List;
-import static yugecin.opsudance.core.InstanceContainer.displayContainer;
+import static yugecin.opsudance.core.InstanceContainer.*;
-public class BarNotificationState implements BarNotifListener, ResolutionChangedListener {
+public class BarNotificationState implements ResolutionChangedListener {
private final int IN_TIME = 200;
- private final int DISPLAY_TIME = 5700 + IN_TIME;
+ private final int DISPLAY_TIME = 2700 + IN_TIME;
private final int OUT_TIME = 200;
private final int TOTAL_TIME = DISPLAY_TIME + OUT_TIME;
@@ -51,21 +51,19 @@ public class BarNotificationState implements BarNotifListener, ResolutionChanged
this.bgcol = new Color(Color.black);
this.textCol = new Color(Color.white);
this.timeShown = TOTAL_TIME;
- BarNotifListener.EVENT.addListener(this);
- ResolutionChangedListener.EVENT.addListener(this);
}
public void render(Graphics g) {
if (timeShown >= TOTAL_TIME) {
return;
}
- timeShown += displayContainer.renderDelta;
+ timeShown += renderDelta;
processAnimations();
g.setColor(bgcol);
- g.fillRect(0, displayContainer.height / 2 - barHalfHeight, displayContainer.width, barHalfHeight * 2);
+ g.fillRect(0, height2 - barHalfHeight, width, barHalfHeight * 2);
int y = textY;
for (String line : lines) {
- Fonts.LARGE.drawString((displayContainer.width - Fonts.LARGE.getWidth(line)) / 2, y, line, textCol);
+ Fonts.LARGE.drawString((width - Fonts.LARGE.getWidth(line)) / 2, y, line, textCol);
y += Fonts.LARGE.getLineHeight();
}
}
@@ -90,14 +88,18 @@ public class BarNotificationState implements BarNotifListener, ResolutionChanged
}
private void calculatePosition() {
- this.lines = Fonts.wrap(Fonts.LARGE, message, (int) (displayContainer.width * 0.96f), true);
+ this.lines = Fonts.wrap(Fonts.LARGE, message, (int) (width * 0.96f), true);
int textHeight = (int) (Fonts.LARGE.getLineHeight() * (lines.size() + 0.5f));
- textY = (displayContainer.height - textHeight) / 2 + (int) (Fonts.LARGE.getLineHeight() / 5f);
+ textY = (height - textHeight) / 2 + (int) (Fonts.LARGE.getLineHeight() / 5f);
barHalfTargetHeight = textHeight / 2;
}
+
+ @SuppressWarnings("resource")
+ public void sendf(String format, Object... args) {
+ this.send(new Formatter().format(format, args).toString());
+ }
- @Override
- public void onBarNotif(String message) {
+ public void send(String message) {
this.message = message;
calculatePosition();
timeShown = 0;
diff --git a/src/yugecin/opsudance/core/state/specialstates/BubNotifState.java b/src/yugecin/opsudance/core/state/specialstates/BubNotifState.java
index 34cefd0f..1e427cec 100644
--- a/src/yugecin/opsudance/core/state/specialstates/BubNotifState.java
+++ b/src/yugecin/opsudance/core/state/specialstates/BubNotifState.java
@@ -1,6 +1,6 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
- * Copyright (C) 2017 yugecin
+ * Copyright (C) 2017-2018 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
@@ -22,16 +22,16 @@ import itdelatrisu.opsu.ui.animations.AnimationEquation;
import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.MouseListener;
-import yugecin.opsudance.events.BubNotifListener;
import yugecin.opsudance.events.ResolutionChangedListener;
+import java.util.Formatter;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import static yugecin.opsudance.core.InstanceContainer.*;
-public class BubNotifState implements MouseListener, BubNotifListener, ResolutionChangedListener {
+public class BubNotifState implements MouseListener, ResolutionChangedListener {
public static final int IN_TIME = 633;
public static final int DISPLAY_TIME = 7000 + IN_TIME;
@@ -46,8 +46,6 @@ public class BubNotifState implements MouseListener, BubNotifListener, Resolutio
public BubNotifState() {
this.bubbles = new LinkedList<>();
this.addAnimationTime = IN_TIME;
- BubNotifListener.EVENT.addListener(this);
- ResolutionChangedListener.EVENT.addListener(this);
}
public void render(Graphics g) {
@@ -55,7 +53,7 @@ public class BubNotifState implements MouseListener, BubNotifListener, Resolutio
if (!iter.hasNext()) {
return;
}
- addAnimationTime += displayContainer.renderDelta;
+ addAnimationTime += renderDelta;
if (addAnimationTime > IN_TIME) {
finishAddAnimation();
}
@@ -65,7 +63,7 @@ public class BubNotifState implements MouseListener, BubNotifListener, Resolutio
if (animateUp && addAnimationTime < IN_TIME) {
next.y = next.baseY - (int) (addAnimationHeight * AnimationEquation.OUT_QUINT.calc((float) addAnimationTime / IN_TIME));
}
- if (next.render(g, displayContainer.mouseX, displayContainer.mouseY, displayContainer.renderDelta)) {
+ if (next.render(g, mouseX, mouseY, renderDelta)) {
iter.remove();
}
animateUp = true;
@@ -74,10 +72,10 @@ public class BubNotifState implements MouseListener, BubNotifListener, Resolutio
private void calculatePositions() {
// if width is 0, attempting to wrap it will result in infinite loop
- Notification.width = Math.max(50, (int) (displayContainer.width * 0.1703125f));
- Notification.baseLine = (int) (displayContainer.height * 0.9645f);
- Notification.paddingY = (int) (displayContainer.height * 0.0144f);
- Notification.finalX = displayContainer.width - Notification.width - (int) (displayContainer.width * 0.01);
+ Notification.width = Math.max(50, (int) (width * 0.1703125f));
+ Notification.baseLine = (int) (height * 0.9645f);
+ Notification.paddingY = (int) (height * 0.0144f);
+ Notification.finalX = width - Notification.width - (int) (width * 0.01);
Notification.fontPaddingX = (int) (Notification.width * 0.02f);
Notification.fontPaddingY = (int) (Fonts.SMALLBOLD.getLineHeight() / 4f);
Notification.lineHeight = Fonts.SMALLBOLD.getLineHeight();
@@ -111,8 +109,12 @@ public class BubNotifState implements MouseListener, BubNotifListener, Resolutio
addAnimationTime = IN_TIME;
}
- @Override
- public void onBubNotif(String message, Color borderColor) {
+ @SuppressWarnings("resource")
+ public void sendf(Color borderColor, String format, Object... args) {
+ this.send(borderColor, new Formatter().format(format, args).toString());
+ }
+
+ public void send(Color borderColor, String message) {
finishAddAnimation();
Notification newBubble = new Notification(message, borderColor);
bubbles.add(0, newBubble);
diff --git a/src/yugecin/opsudance/core/state/specialstates/FpsRenderState.java b/src/yugecin/opsudance/core/state/specialstates/FpsRenderState.java
index 5d41a5b5..9186db35 100644
--- a/src/yugecin/opsudance/core/state/specialstates/FpsRenderState.java
+++ b/src/yugecin/opsudance/core/state/specialstates/FpsRenderState.java
@@ -1,6 +1,6 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
- * Copyright (C) 2017 yugecin
+ * Copyright (C) 2017-2018 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
@@ -24,7 +24,7 @@ import yugecin.opsudance.events.ResolutionChangedListener;
import yugecin.opsudance.utils.FPSMeter;
import static yugecin.opsudance.options.Options.*;
-import static yugecin.opsudance.core.InstanceContainer.displayContainer;
+import static yugecin.opsudance.core.InstanceContainer.*;
public class FpsRenderState implements ResolutionChangedListener {
@@ -42,7 +42,6 @@ public class FpsRenderState implements ResolutionChangedListener {
public FpsRenderState() {
fpsMeter = new FPSMeter(10);
upsMeter = new FPSMeter(10);
- ResolutionChangedListener.EVENT.addListener(this);
}
public void update() {
@@ -50,7 +49,7 @@ public class FpsRenderState implements ResolutionChangedListener {
}
public void render(Graphics g) {
- fpsMeter.update(displayContainer.renderDelta);
+ fpsMeter.update(renderDelta);
if (!OPTION_SHOW_FPS.state) {
return;
}
@@ -61,7 +60,7 @@ public class FpsRenderState implements ResolutionChangedListener {
}
private String getText(int value, String unit) {
- if (OPTION_USE_FPS_DELTAS.state) {
+ if (OPTION_USE_FPS_DELTAS.state || value > 1000) {
return String.format("%.2fms", 1000f / value);
}
return value + " " + unit;
@@ -91,8 +90,8 @@ public class FpsRenderState implements ResolutionChangedListener {
@Override
public void onResolutionChanged(int w, int h) {
singleHeight = Fonts.SMALL.getLineHeight();
- x = displayContainer.width - 3;
- y = displayContainer.height - 3 - singleHeight - 10;
+ x = width - 3;
+ y = height - 3 - singleHeight - 10;
}
}
diff --git a/src/yugecin/opsudance/events/BarNotifListener.java b/src/yugecin/opsudance/events/BarNotifListener.java
deleted file mode 100644
index ed798e32..00000000
--- a/src/yugecin/opsudance/events/BarNotifListener.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * 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 .
- */
-package yugecin.opsudance.events;
-
-import yugecin.opsudance.core.events.Event;
-
-public interface BarNotifListener {
-
- Event EVENT = new Event<>(BarNotifListener.class);
-
- void onBarNotif(String message);
-
-}
diff --git a/src/yugecin/opsudance/events/BubNotifListener.java b/src/yugecin/opsudance/events/BubNotifListener.java
deleted file mode 100644
index 2990d676..00000000
--- a/src/yugecin/opsudance/events/BubNotifListener.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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 .
- */
-package yugecin.opsudance.events;
-
-import org.newdawn.slick.Color;
-import yugecin.opsudance.core.events.Event;
-
-@SuppressWarnings({"UnnecessaryInterfaceModifier", "unused"})
-public interface BubNotifListener {
-
- Event EVENT = new Event<>(BubNotifListener.class);
-
- void onBubNotif(String message, Color borderColor);
-
-}
diff --git a/src/yugecin/opsudance/events/ResolutionChangedListener.java b/src/yugecin/opsudance/events/ResolutionChangedListener.java
index c0311f0d..f00c9e4f 100644
--- a/src/yugecin/opsudance/events/ResolutionChangedListener.java
+++ b/src/yugecin/opsudance/events/ResolutionChangedListener.java
@@ -1,6 +1,6 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
- * Copyright (C) 2017 yugecin
+ * Copyright (C) 2017-2018 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
@@ -17,12 +17,7 @@
*/
package yugecin.opsudance.events;
-import yugecin.opsudance.core.events.Event;
-
-public interface ResolutionChangedListener {
-
- Event EVENT = new Event<>(ResolutionChangedListener.class);
-
+public interface ResolutionChangedListener
+{
void onResolutionChanged(int w, int h);
-
}
diff --git a/src/yugecin/opsudance/events/SkinChangedListener.java b/src/yugecin/opsudance/events/SkinChangedListener.java
index 273fa1b6..76eb7e99 100644
--- a/src/yugecin/opsudance/events/SkinChangedListener.java
+++ b/src/yugecin/opsudance/events/SkinChangedListener.java
@@ -1,6 +1,6 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
- * Copyright (C) 2017 yugecin
+ * Copyright (C) 2017-2018 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
@@ -17,12 +17,7 @@
*/
package yugecin.opsudance.events;
-import yugecin.opsudance.core.events.Event;
-
-public interface SkinChangedListener {
-
- Event EVENT = new Event<>(SkinChangedListener.class);
-
- void onSkinChanged(String stringName);
-
+public interface SkinChangedListener
+{
+ void onSkinChanged(String name);
}
diff --git a/src/yugecin/opsudance/movers/CircleMover.java b/src/yugecin/opsudance/movers/CircleMover.java
index e9e3bda4..4e76c4c2 100644
--- a/src/yugecin/opsudance/movers/CircleMover.java
+++ b/src/yugecin/opsudance/movers/CircleMover.java
@@ -1,6 +1,6 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
- * Copyright (C) 2016 yugecin
+ * Copyright (C) 2016-2018 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
@@ -64,7 +64,7 @@ public class CircleMover extends Mover {
double a = ang + SOME_CONSTANT * t;
pos[0] = (startX + (endX - startX) * t) - middlexoffset - Math.cos(a) * radius;
pos[1] = (startY + (endY - startY) * t) - middleyoffset - Math.sin(a) * radius;
- if (pos[0] < 0 || displayContainer.width < pos[0] || pos[1] < 0 || displayContainer.height < pos[1]) {
+ if (pos[0] < 0 || width < pos[0] || pos[1] < 0 || height < pos[1]) {
pass = false;
break;
}
diff --git a/src/yugecin/opsudance/movers/ExgonMover.java b/src/yugecin/opsudance/movers/ExgonMover.java
index 6c7f200b..1eb3e57d 100644
--- a/src/yugecin/opsudance/movers/ExgonMover.java
+++ b/src/yugecin/opsudance/movers/ExgonMover.java
@@ -1,6 +1,6 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
- * Copyright (C) 2016 yugecin
+ * Copyright (C) 2016-2018 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
@@ -44,8 +44,8 @@ public class ExgonMover extends Mover {
pos[0] = endX;
pos[1] = endY;
} else {
- pos[0] = randgen.nextInt(displayContainer.width);
- pos[1] = randgen.nextInt(displayContainer.height);
+ pos[0] = randgen.nextInt(width);
+ pos[1] = randgen.nextInt(height);
}
}
return pos;
diff --git a/src/yugecin/opsudance/movers/factories/AutoMoverFactory.java b/src/yugecin/opsudance/movers/factories/AutoMoverFactory.java
index 333a894a..b9dce873 100644
--- a/src/yugecin/opsudance/movers/factories/AutoMoverFactory.java
+++ b/src/yugecin/opsudance/movers/factories/AutoMoverFactory.java
@@ -1,6 +1,6 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
- * Copyright (C) 2016 yugecin
+ * Copyright (C) 2016-2018 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
@@ -102,8 +102,8 @@ public class AutoMoverFactory implements MoverFactory {
}
private boolean checkBounds( double[] pos ) {
- return 0 < pos[0] && pos[0] < displayContainer.width - displayContainer.width / 8 &&
- 0 < pos[1] && pos[1] < displayContainer.height - displayContainer.height / 8;
+ return 0 < pos[0] && pos[0] < width - width / 8 &&
+ 0 < pos[1] && pos[1] < height - height / 8;
}
@Override
diff --git a/src/yugecin/opsudance/options/Configuration.java b/src/yugecin/opsudance/options/Configuration.java
index 989d99fc..c0c33a35 100644
--- a/src/yugecin/opsudance/options/Configuration.java
+++ b/src/yugecin/opsudance/options/Configuration.java
@@ -1,6 +1,6 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
- * Copyright (C) 2017 yugecin
+ * Copyright (C) 2017-2018 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
@@ -24,13 +24,10 @@ import itdelatrisu.opsu.audio.SoundController;
import itdelatrisu.opsu.audio.SoundEffect;
import itdelatrisu.opsu.beatmap.Beatmap;
import itdelatrisu.opsu.beatmap.TimingPoint;
-import itdelatrisu.opsu.ui.Colors;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.GL11;
import org.newdawn.slick.util.Log;
-import yugecin.opsudance.events.BubNotifListener;
-import yugecin.opsudance.utils.ManifestWrapper;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
@@ -42,13 +39,12 @@ import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
+import static itdelatrisu.opsu.ui.Colors.*;
import static yugecin.opsudance.options.Options.*;
import static yugecin.opsudance.core.InstanceContainer.*;
public class Configuration {
- public final boolean USE_XDG;
public final File CONFIG_DIR;
public final File DATA_DIR;
public final File CACHE_DIR;
@@ -73,12 +69,10 @@ public class Configuration {
public File replayImportDir;
public File skinRootDir;
- public Configuration(ManifestWrapper jarmanifest) {
- USE_XDG = jarmanifest.valueOrDefault(null, "Use-XDG", "").equalsIgnoreCase("true");
-
- CONFIG_DIR = getXDGBaseDir("XDG_CONFIG_HOME", ".config");
- DATA_DIR = getXDGBaseDir("XDG_DATA_HOME", ".local/share");
- CACHE_DIR = getXDGBaseDir("XDG_CACHE_HOME", ".cache");
+ public Configuration() {
+ CONFIG_DIR = env.workingdir;
+ DATA_DIR = env.workingdir;
+ CACHE_DIR = env.workingdir;
BEATMAP_DIR = new File(DATA_DIR, "Songs/");
SKIN_ROOT_DIR = new File(DATA_DIR, "Skins/");
@@ -155,7 +149,7 @@ public class Configuration {
}
if (!defaultDir.isDirectory() && !defaultDir.mkdir()) {
String msg = String.format("Failed to create %s directory at '%s'.", kind, defaultDir.getAbsolutePath());
- BubNotifListener.EVENT.make().onBubNotif(msg, Colors.BUB_RED);
+ bubNotifs.send(BUB_RED, msg);
}
return defaultDir;
}
@@ -175,39 +169,6 @@ public class Configuration {
return loadDirectory(dir, defaultDir, kind);
}
- /**
- * Returns the directory based on the XDG base directory specification for
- * Unix-like operating systems, only if the "XDG" flag is enabled.
- * @param envvar 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 envvar, String fallback) {
- if (!USE_XDG) {
- return env.workingdir;
- }
-
- String OS = System.getProperty("os.name").toLowerCase();
- if (OS.indexOf("nix") == -1 && OS.indexOf("nux") == -1 && OS.indexOf("aix") == -1){
- return env.workingdir;
- }
-
- String rootPath = System.getenv(envvar);
- 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()) {
- explode(String.format("Failed to create configuration folder at '%s/opsu'.", rootPath),
- new Exception("empty"), PREVENT_REPORT);
- }
- return dir;
- }
-
/**
* @author http://wiki.lwjgl.org/index.php?title=Taking_Screen_Shots
*/
@@ -215,9 +176,11 @@ public class Configuration {
// TODO: get a decent place for this
// create the screenshot directory
if (!screenshotDir.isDirectory() && !screenshotDir.mkdir()) {
- BubNotifListener.EVENT.make().onBubNotif(
- String.format( "Failed to create screenshot directory at '%s'.",
- screenshotDir.getAbsolutePath()), Colors.BUB_RED);
+ bubNotifs.sendf(
+ BUB_RED,
+ "Failed to create screenshot directory at '%s'.",
+ screenshotDir.getAbsolutePath()
+ );
return;
}
@@ -251,13 +214,13 @@ public class Configuration {
}
}
ImageIO.write(image, OPTION_SCREENSHOT_FORMAT.getValueString().toLowerCase(), file);
- BubNotifListener.EVENT.make().onBubNotif("Created " + fileName,
- Colors.BUB_PURPLE);
+ bubNotifs.send(BUB_PURPLE, "Created " + fileName);
} catch (Exception e) {
Log.error("Could not take screenshot", e);
- BubNotifListener.EVENT.make().onBubNotif(
- "Failed to take a screenshot. See log file for details",
- Colors.BUB_PURPLE);
+ bubNotifs.send(
+ BUB_PURPLE,
+ "Failed to take a screenshot. See log file for details"
+ );
}
}
}.start();
diff --git a/src/yugecin/opsudance/options/ListOption.java b/src/yugecin/opsudance/options/ListOption.java
index 5c0c5808..52c9f1bc 100644
--- a/src/yugecin/opsudance/options/ListOption.java
+++ b/src/yugecin/opsudance/options/ListOption.java
@@ -19,6 +19,8 @@ package yugecin.opsudance.options;
public abstract class ListOption extends Option {
+ public Runnable observer;
+
public ListOption(String name, String configurationName, String description) {
super(name, configurationName, description);
}
@@ -30,4 +32,8 @@ public abstract class ListOption extends Option {
public abstract Object[] getListItems();
public abstract void clickListItem(int index);
+ protected final void onChange() {
+ observer.run();
+ }
+
}
diff --git a/src/yugecin/opsudance/options/NumericOption.java b/src/yugecin/opsudance/options/NumericOption.java
index 84a83dc2..7bf4fc71 100644
--- a/src/yugecin/opsudance/options/NumericOption.java
+++ b/src/yugecin/opsudance/options/NumericOption.java
@@ -1,6 +1,6 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
- * Copyright (C) 2017 yugecin
+ * Copyright (C) 2017-2018 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
@@ -18,8 +18,9 @@
package yugecin.opsudance.options;
import itdelatrisu.opsu.Utils;
-import itdelatrisu.opsu.ui.Colors;
-import yugecin.opsudance.events.BubNotifListener;
+
+import static itdelatrisu.opsu.ui.Colors.*;
+import static yugecin.opsudance.core.InstanceContainer.*;
public class NumericOption extends Option {
@@ -53,8 +54,7 @@ public class NumericOption extends Option {
try {
val = Utils.clamp(Integer.parseInt(s), min, max);
} catch (Exception ignored) {
- BubNotifListener.EVENT.make().onBubNotif("Failed to parse " + configurationName + " option",
- Colors.BUB_RED);
+ bubNotifs.send(BUB_RED, "Failed to parse '" + configurationName + "' option");
}
}
diff --git a/src/yugecin/opsudance/options/Option.java b/src/yugecin/opsudance/options/Option.java
index 76acf4f0..7f31a142 100644
--- a/src/yugecin/opsudance/options/Option.java
+++ b/src/yugecin/opsudance/options/Option.java
@@ -75,6 +75,14 @@ public class Option {
return false;
}
filtered = !name.toLowerCase().contains(searchString) && !description.toLowerCase().contains(searchString);
+ if (this instanceof ListOption) {
+ for (Object itm : ((ListOption) this).getListItems()) {
+ if (itm != null && itm.toString().toLowerCase().contains(searchString)) {
+ filtered = false;
+ return false;
+ }
+ }
+ }
return filtered;
}
diff --git a/src/yugecin/opsudance/options/OptionGroups.java b/src/yugecin/opsudance/options/OptionGroups.java
index 0df29f34..de2ff0c2 100644
--- a/src/yugecin/opsudance/options/OptionGroups.java
+++ b/src/yugecin/opsudance/options/OptionGroups.java
@@ -42,6 +42,7 @@ public class OptionGroups {
OPTION_TARGET_FPS,
OPTION_SHOW_FPS,
OPTION_USE_FPS_DELTAS,
+ OPTION_STARFOUNTAINS,
OPTION_SCREENSHOT_FORMAT,
}),
new OptionTab("SLIDER OPTIONS", new Option[]{
@@ -181,7 +182,8 @@ public class OptionGroups {
};
public static final OptionTab[] storyboardOptions = new OptionTab[] {
- new OptionTab("Gameplay", new Option[] {
+ new OptionTab("Gameplay", GameImage.MENU_NAV_GAMEPLAY),
+ new OptionTab("GENERAL", new Option[] {
OPTION_BACKGROUND_DIM,
OPTION_DANCE_REMOVE_BG,
OPTION_SNAKING_SLIDERS,
@@ -192,12 +194,14 @@ public class OptionGroups {
OPTION_SHOW_PERFECT_HIT,
OPTION_SHOW_FOLLOW_POINTS,
}),
- new OptionTab("Input", new Option[] {
+ new OptionTab("Input", GameImage.MENU_NAV_INPUT),
+ new OptionTab("INPUT", new Option[] {
OPTION_CURSOR_SIZE,
OPTION_NEW_CURSOR,
OPTION_DISABLE_CURSOR
}),
- new OptionTab("Dance", new Option[] {
+ new OptionTab("Dance", GameImage.MENU_NAV_DANCE),
+ new OptionTab("MOVER", new Option[]{
OPTION_DANCE_MOVER,
OPTION_DANCE_EXGON_DELAY,
OPTION_DANCE_QUAD_BEZ_AGGRESSIVENESS,
@@ -206,36 +210,56 @@ public class OptionGroups {
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_CIRCLE_STREAMS,
- OPTION_DANCE_ONLY_CIRCLE_STACKS,
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("Dance display", new Option[] {
+ new OptionTab("Advanced Display", GameImage.MENU_NAV_ADVANCED),
+ 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,
- OPTION_DANCE_HIDE_OBJECTS,
- OPTION_DANCE_HIDE_UI,
}),
- new OptionTab ("Pippi", new Option[] {
+ new OptionTab("MISC", new Option[] {
+ OPTION_DANCE_HIDE_UI,
+ OPTION_DANCE_REMOVE_BG,
+ OPTION_DANCE_ENABLE_SB,
+ }),
+ new OptionTab ("Pippi", GameImage.MENU_NAV_PIPPI),
+ 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,
- })
+ }),
};
}
diff --git a/src/yugecin/opsudance/options/Options.java b/src/yugecin/opsudance/options/Options.java
index 17f3cf92..3806c671 100644
--- a/src/yugecin/opsudance/options/Options.java
+++ b/src/yugecin/opsudance/options/Options.java
@@ -1,6 +1,6 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
- * Copyright (C) 2017 yugecin
+ * Copyright (C) 2017-2018 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
@@ -27,7 +27,6 @@ import org.newdawn.slick.SlickException;
import org.newdawn.slick.openal.SoundStore;
import org.newdawn.slick.util.Log;
import yugecin.opsudance.*;
-import yugecin.opsudance.events.BarNotifListener;
import yugecin.opsudance.movers.factories.ExgonMoverFactory;
import yugecin.opsudance.movers.factories.QuadraticBezierMoverFactory;
import yugecin.opsudance.movers.slidermovers.DefaultSliderMoverController;
@@ -128,6 +127,8 @@ public class Options {
public static final ToggleOption OPTION_NOSINGLEINSTANCE = new ToggleOption("-", "NoSingleInstance", "-", false);
+ public static final ToggleOption OPTION_STARFOUNTAINS = new ToggleOption("Star fountains in main menu", "StarFountains", "Show star bursts in main menu", true);
+
// in-game options
public static final ListOption OPTION_SCREEN_RESOLUTION = new ListOption("Screen Resolution", "ScreenResolution", "Change the size of the game.") {
private final String[] resolutions = {
@@ -167,6 +168,7 @@ public class Options {
public void clickListItem(int index){
idx = index;
displayContainer.updateDisplayMode(resolutions[idx]);
+ this.onChange();
}
@Override
@@ -185,7 +187,14 @@ public class Options {
};
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 ToggleOption OPTION_FULLSCREEN = new ToggleOption("Fullscreen Mode", "Fullscreen", "Fullscreen mode", false) {
+ @Override
+ public void toggle()
+ {
+ super.toggle();
+ displayContainer.updateDisplayMode(width, height);
+ }
+ };
public static final ListOption OPTION_SKIN = new ListOption("Skin", "Skin", "Change how the game looks.") {
@Override
@@ -202,6 +211,7 @@ public class Options {
public void clickListItem(int index){
skinservice.usedSkinName = skinservice.availableSkinDirectories[index];
skinservice.reloadSkin();
+ this.onChange();
}
@Override
@@ -215,16 +225,34 @@ public class Options {
}
};
- 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) {
+ public static final int[] targetUPS = { 60, 120, 240, 480, 960, 1000, -1 };
+
+ 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.", 2, 0, targetUPS.length - 1) {
@Override
public String getValueString () {
- return String.format("%dups", val);
+ if (targetUPS[val] == -1) {
+ return "unlimited";
+ }
+ return String.valueOf(targetUPS[val]);
}
@Override
- public void setValue ( int value){
+ public void setValue(int value) {
+ if (value < 0 || targetUPS.length <= value) {
+ return;
+ }
+ final int ups = targetUPS[value];
+ final int fps = targetFPS[targetFPSIndex];
super.setValue(value);
- displayContainer.setUPS(value);
+ displayContainer.setUPS(ups);
+ if (ups != -1 && fps > ups) {
+ for (int i = targetFPSIndex - 1; i >= 0; i--) {
+ if (targetFPS[i] >= ups) {
+ OPTION_TARGET_FPS.clickListItem(i);
+ break;
+ }
+ }
+ }
}
};
@@ -256,7 +284,17 @@ public class Options {
@Override
public void clickListItem(int index){
targetFPSIndex = index;
- displayContainer.setFPS(targetFPS[targetFPSIndex]);
+ int fps = targetFPS[targetFPSIndex];
+ displayContainer.setFPS(fps);
+ if (targetUPS[OPTION_TARGET_UPS.val] < fps) {
+ for (int i = 0; i < targetUPS.length; i++) {
+ if (targetUPS[i] >= fps) {
+ OPTION_TARGET_UPS.setValue(i);
+ break;
+ }
+ }
+ }
+ this.onChange();
}
@Override
@@ -318,6 +356,7 @@ public class Options {
@Override
public void clickListItem(int index){
this.index = index;
+ this.onChange();
}
@Override
@@ -386,7 +425,7 @@ public class Options {
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) {
+ public static final NumericOption OPTION_MUSIC_OFFSET = new NumericOption("Global 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);
@@ -439,7 +478,7 @@ public class Options {
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() {
- BarNotifListener.EVENT.make().onBarNotif(state ?
+ barNotifs.send(state ?
"Mouse buttons are disabled." : "Mouse buttons are enabled.");
}
};
@@ -608,10 +647,11 @@ public class Options {
public void clickListItem(int index){
if (Game.isInGame && Dancer.moverFactories[index] instanceof PolyMoverFactory) {
// TODO remove this when #79 is fixed
- BarNotifListener.EVENT.make().onBarNotif("This mover is disabled in the storyboard right now");
+ barNotifs.send("This mover is disabled in the storyboard right now");
return;
}
Dancer.instance.setMoverFactoryIndex(index);
+ this.onChange();
}
@Override
@@ -701,6 +741,7 @@ public class Options {
@Override
public void clickListItem(int index){
Dancer.moverDirection = MoverDirection.values()[index];
+ this.onChange();
}
@Override
@@ -731,6 +772,7 @@ public class Options {
public void clickListItem(int index){
val = index;
Dancer.sliderMoverController = Dancer.sliderMovers[index];
+ this.onChange();
}
@Override
@@ -753,6 +795,7 @@ public class Options {
@Override
public void clickListItem(int index){
Dancer.instance.setSpinnerIndex(index);
+ this.onChange();
}
@Override
@@ -797,6 +840,7 @@ public class Options {
@Override
public void clickListItem(int index){
Dancer.colorOverride = ObjectColorOverrides.values()[index];
+ this.onChange();
}
@Override
@@ -824,6 +868,7 @@ public class Options {
@Override
public void clickListItem(int index){
Dancer.colorMirrorOverride = ObjectColorOverrides.values()[index];
+ this.onChange();
}
@Override
@@ -858,6 +903,7 @@ public class Options {
@Override
public void clickListItem(int index){
Dancer.cursorColorOverride = CursorColorOverrides.values()[index];
+ this.onChange();
}
@Override
@@ -885,6 +931,7 @@ public class Options {
@Override
public void clickListItem(int index){
Dancer.cursorColorMirrorOverride = CursorColorOverrides.values()[index];
+ this.onChange();
}
@Override
diff --git a/src/yugecin/opsudance/options/OptionsService.java b/src/yugecin/opsudance/options/OptionsService.java
index b4fe3ee9..d0d972a0 100644
--- a/src/yugecin/opsudance/options/OptionsService.java
+++ b/src/yugecin/opsudance/options/OptionsService.java
@@ -1,6 +1,6 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
- * Copyright (C) 2017 yugecin
+ * Copyright (C) 2017-2018 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
@@ -17,15 +17,14 @@
*/
package yugecin.opsudance.options;
-import itdelatrisu.opsu.ui.Colors;
import org.newdawn.slick.util.Log;
-import yugecin.opsudance.events.BubNotifListener;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
+import static itdelatrisu.opsu.ui.Colors.*;
import static yugecin.opsudance.core.InstanceContainer.*;
/**
@@ -80,7 +79,7 @@ public class OptionsService {
} catch (IOException e) {
String err = String.format("Failed to read option file '%s'.", config.OPTIONS_FILE.getAbsolutePath());
Log.error(err, e);
- BubNotifListener.EVENT.make().onBubNotif(err, Colors.BUB_RED);
+ bubNotifs.send(BUB_RED, err);
}
config.loadDirectories();
}
@@ -109,7 +108,7 @@ public class OptionsService {
} catch (IOException e) {
String err = String.format("Failed to write to file '%s'.", config.OPTIONS_FILE.getAbsolutePath());
Log.error(err, e);
- BubNotifListener.EVENT.make().onBubNotif(err, Colors.BUB_RED);
+ bubNotifs.send(BUB_RED, err);
}
}
diff --git a/src/yugecin/opsudance/render/GameObjectRenderer.java b/src/yugecin/opsudance/render/GameObjectRenderer.java
index 04edeaa1..d07361bd 100644
--- a/src/yugecin/opsudance/render/GameObjectRenderer.java
+++ b/src/yugecin/opsudance/render/GameObjectRenderer.java
@@ -28,6 +28,7 @@ import org.newdawn.slick.Color;
import org.newdawn.slick.Image;
import yugecin.opsudance.skinning.SkinService;
+import static itdelatrisu.opsu.GameImage.*;
import static yugecin.opsudance.options.Options.*;
public class GameObjectRenderer {
@@ -88,7 +89,8 @@ public class GameObjectRenderer {
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);
+ float scale = HITCIRCLE.getWidth() * 0.40f / gameData.getDefaultSymbolImage(0).getHeight();
+ gameData.drawSymbolNumber(number, x, y, scale, alpha);
}
}
diff --git a/src/yugecin/opsudance/sbv2/MoveStoryboard.java b/src/yugecin/opsudance/sbv2/MoveStoryboard.java
index d7fd084e..73093277 100644
--- a/src/yugecin/opsudance/sbv2/MoveStoryboard.java
+++ b/src/yugecin/opsudance/sbv2/MoveStoryboard.java
@@ -1,6 +1,6 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
- * Copyright (C) 2016 yugecin
+ * Copyright (C) 2016-2018 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
@@ -23,9 +23,7 @@ import itdelatrisu.opsu.ui.Fonts;
import itdelatrisu.opsu.ui.animations.AnimationEquation;
import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
-import yugecin.opsudance.core.DisplayContainer;
import yugecin.opsudance.core.state.OverlayOpsuState;
-import yugecin.opsudance.events.BarNotifListener;
import yugecin.opsudance.sbv2.movers.CubicStoryboardMover;
import yugecin.opsudance.sbv2.movers.LinearStoryboardMover;
import yugecin.opsudance.sbv2.movers.QuadraticStoryboardMover;
@@ -35,9 +33,9 @@ import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
-public class MoveStoryboard extends OverlayOpsuState{
+import static yugecin.opsudance.core.InstanceContainer.*;
- private final DisplayContainer displayContainer;
+public class MoveStoryboard extends OverlayOpsuState{
private SimpleButton btnAddLinear;
private SimpleButton btnAddQuadratic;
@@ -56,8 +54,7 @@ public class MoveStoryboard extends OverlayOpsuState{
private int trackPosition;
- public MoveStoryboard(DisplayContainer displayContainer) {
- this.displayContainer = displayContainer;
+ public MoveStoryboard() {
dummyMove = (StoryboardMove) Proxy.newProxyInstance(StoryboardMove.class.getClassLoader(), new Class>[]{StoryboardMove.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
@@ -70,12 +67,12 @@ public class MoveStoryboard extends OverlayOpsuState{
public void revalidate() {
super.revalidate();
- btnAddLinear = new SimpleButton(displayContainer.width - 205, 50, 200, 25, Fonts.SMALL, "add linear", Colors.BLUE_BUTTON, Colors.WHITE_FADE, Colors.WHITE_FADE, Colors.ORANGE_BUTTON);
- btnAddQuadratic = new SimpleButton(displayContainer.width - 205, 80, 200, 25, Fonts.SMALL, "add quadratic", Colors.BLUE_BUTTON, Colors.WHITE_FADE, Colors.WHITE_FADE, Colors.ORANGE_BUTTON);
- btnAddCubic = new SimpleButton(displayContainer.width - 205, 110, 200, 25, Fonts.SMALL, "add cubic", Colors.BLUE_BUTTON, Colors.WHITE_FADE, Colors.WHITE_FADE, Colors.ORANGE_BUTTON);
- btnAnimLin = new SimpleButton(displayContainer.width - 250, 50, 40, 25, Fonts.SMALL, "lin", Color.blue, Color.white, Color.white, Color.orange);
- btnAnimMid = new SimpleButton(displayContainer.width - 250, 80, 40, 25, Fonts.SMALL, "mid", Color.blue, Color.white, Color.white, Color.orange);
- btnAnimCub = new SimpleButton(displayContainer.width - 250, 110, 40, 25, Fonts.SMALL, "cub", Color.blue, Color.white, Color.white, Color.orange);
+ btnAddLinear = new SimpleButton(width - 205, 50, 200, 25, Fonts.SMALL, "add linear", Colors.BLUE_BUTTON, Colors.WHITE_FADE, Colors.WHITE_FADE, Colors.ORANGE_BUTTON);
+ btnAddQuadratic = new SimpleButton(width - 205, 80, 200, 25, Fonts.SMALL, "add quadratic", Colors.BLUE_BUTTON, Colors.WHITE_FADE, Colors.WHITE_FADE, Colors.ORANGE_BUTTON);
+ btnAddCubic = new SimpleButton(width - 205, 110, 200, 25, Fonts.SMALL, "add cubic", Colors.BLUE_BUTTON, Colors.WHITE_FADE, Colors.WHITE_FADE, Colors.ORANGE_BUTTON);
+ btnAnimLin = new SimpleButton(width - 250, 50, 40, 25, Fonts.SMALL, "lin", Color.blue, Color.white, Color.white, Color.orange);
+ btnAnimMid = new SimpleButton(width - 250, 80, 40, 25, Fonts.SMALL, "mid", Color.blue, Color.white, Color.white, Color.orange);
+ btnAnimCub = new SimpleButton(width - 250, 110, 40, 25, Fonts.SMALL, "cub", Color.blue, Color.white, Color.white, Color.orange);
}
/**
@@ -97,8 +94,8 @@ public class MoveStoryboard extends OverlayOpsuState{
@Override
protected void onPreRenderUpdate() {
- int x = displayContainer.mouseX;
- int y = displayContainer.mouseY;
+ int x = mouseX;
+ int y = mouseY;
btnAddLinear.update(x, y);
btnAddQuadratic.update(x, y);
btnAddCubic.update(x, y);
@@ -106,7 +103,7 @@ public class MoveStoryboard extends OverlayOpsuState{
btnAnimMid.update(x, y);
btnAnimCub.update(x, y);
if (moves[objectIndex] != null) {
- moves[objectIndex].update(displayContainer.renderDelta, x, y);
+ moves[objectIndex].update(renderDelta, x, y);
}
}
@@ -185,11 +182,11 @@ public class MoveStoryboard extends OverlayOpsuState{
private StoryboardMove getCurrentMoveOrCreateNew() {
if (gameObjects[objectIndex].isSlider() && trackPosition > gameObjects[objectIndex].getTime() && trackPosition < gameObjects[objectIndex].getEndTime()) {
- BarNotifListener.EVENT.make().onBarNotif("Wait until the slider ended");
+ barNotifs.send("Wait until the slider ended");
return dummyMove;
}
if (moves[objectIndex] == null) {
- return moves[objectIndex] = new StoryboardMoveImpl(gameObjects[objectIndex - 1].end, gameObjects[objectIndex].start, displayContainer.width);
+ return moves[objectIndex] = new StoryboardMoveImpl(gameObjects[objectIndex - 1].end, gameObjects[objectIndex].start, width);
}
return moves[objectIndex];
}
diff --git a/src/yugecin/opsudance/skinning/SkinService.java b/src/yugecin/opsudance/skinning/SkinService.java
index 814f736d..a2541e35 100644
--- a/src/yugecin/opsudance/skinning/SkinService.java
+++ b/src/yugecin/opsudance/skinning/SkinService.java
@@ -1,6 +1,6 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
- * Copyright (C) 2017 yugecin
+ * Copyright (C) 2017-2018 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
@@ -26,21 +26,39 @@ import org.newdawn.slick.util.ResourceLoader;
import yugecin.opsudance.events.SkinChangedListener;
import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
import static yugecin.opsudance.core.InstanceContainer.*;
+
/**
* @author itdelatrisu (https://github.com/itdelatrisu) most functions are copied from itdelatrisu.opsu.Options.java
*/
-public class SkinService {
+public class SkinService
+{
+ private final List skinChangedListeners;
public String[] availableSkinDirectories;
public String usedSkinName = "Default";
public static Skin skin;
+
+ public SkinService()
+ {
+ this.skinChangedListeners = new ArrayList<>();
+ }
+
+ public void addSkinChangedListener(SkinChangedListener l)
+ {
+ this.skinChangedListeners.add(l);
+ }
- public void reloadSkin() {
+ public void reloadSkin()
+ {
loadSkin();
SoundController.init();
- SkinChangedListener.EVENT.make().onSkinChanged(usedSkinName);
+ for (SkinChangedListener l : this.skinChangedListeners) {
+ l.onSkinChanged(this.usedSkinName);
+ }
}
/**
diff --git a/src/yugecin/opsudance/spinners/ApproachCircleSpinner.java b/src/yugecin/opsudance/spinners/ApproachCircleSpinner.java
index f25e5d4b..b4a46d5a 100644
--- a/src/yugecin/opsudance/spinners/ApproachCircleSpinner.java
+++ b/src/yugecin/opsudance/spinners/ApproachCircleSpinner.java
@@ -1,6 +1,6 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
- * Copyright (C) 2016 yugecin
+ * Copyright (C) 2016-2018 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
@@ -38,10 +38,10 @@ public class ApproachCircleSpinner extends Spinner {
ang += 15;
}
- double rad = displayContainer.width / 4.0f * (1d - Spinner.PROGRESS);
+ double rad = width / 4.0f * (1d - Spinner.PROGRESS);
- point[0] = displayContainer.width / 2.0f + rad * Math.sin(ang / 180d * Math.PI);
- point[1] = displayContainer.height / 2.0f - rad * Math.cos(ang / 180d * Math.PI);
+ point[0] = width2 + rad * Math.sin(ang / 180d * Math.PI);
+ point[1] = height2 - rad * Math.cos(ang / 180d * Math.PI);
return point;
}
diff --git a/src/yugecin/opsudance/spinners/BeamSpinner.java b/src/yugecin/opsudance/spinners/BeamSpinner.java
index d0908bae..bbf8bb29 100644
--- a/src/yugecin/opsudance/spinners/BeamSpinner.java
+++ b/src/yugecin/opsudance/spinners/BeamSpinner.java
@@ -1,6 +1,6 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
- * Copyright (C) 2016 yugecin
+ * Copyright (C) 2016-2018 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
@@ -41,30 +41,30 @@ public class BeamSpinner extends Spinner {
index = ++index % 4;
final int MOD = 60;
- point[0] = displayContainer.width / 2d;
- point[1] = displayContainer.height / 2d;
+ point[0] = width2;
+ point[1] = height2;
- if( index == 0 ) {
- add( MOD, 90 );
- add( MOD, 180 );
- } else if( index == 1 ) {
- add( MOD, 90 );
- add( displayContainer.height / 2 * 0.8d, 0 );
- } else if( index == 2 ) {
- add( MOD, -90 );
- add( displayContainer.height / 2 * 0.8d, 0 );
- } else if( index == 3 ) {
- add( MOD, -90 );
- add( MOD, 180 );
+ if (index == 0) {
+ add(MOD, 90);
+ add(MOD, 180);
+ } else if (index == 1) {
+ add(MOD, 90);
+ add(height2 * 0.8d, 0);
+ } else if (index == 2) {
+ add(MOD, -90);
+ add(height2 * 0.8d, 0);
+ } else if (index == 3) {
+ add(MOD, -90);
+ add(MOD, 180);
ang += 0.3;
}
return point;
}
- private void add( double rad, double ang ) {
- point[0] += rad * Math.cos( (this.ang + ang) / 180d * Math.PI);
- point[1] -= rad * Math.sin( (this.ang + ang) / 180d * Math.PI);
+ private void add (double rad, double ang ) {
+ point[0] += rad * Math.cos((this.ang + ang) / 180d * Math.PI);
+ point[1] -= rad * Math.sin((this.ang + ang) / 180d * Math.PI);
}
@Override
diff --git a/src/yugecin/opsudance/spinners/CircleSpinner.java b/src/yugecin/opsudance/spinners/CircleSpinner.java
index b014d406..ba519d63 100644
--- a/src/yugecin/opsudance/spinners/CircleSpinner.java
+++ b/src/yugecin/opsudance/spinners/CircleSpinner.java
@@ -1,6 +1,6 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
- * Copyright (C) 2016 yugecin
+ * Copyright (C) 2016-2018 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
@@ -36,10 +36,10 @@ public class CircleSpinner extends Spinner {
ang += 15;
}
- double rad = displayContainer.width / 4.0f;
+ double rad = width / 4.0f;
- point[0] = displayContainer.width / 2.0f + rad * Math.sin(ang / 180d * Math.PI);
- point[1] = displayContainer.height / 2.0f - rad * Math.cos(ang / 180d * Math.PI);
+ point[0] = width2 + rad * Math.sin(ang / 180d * Math.PI);
+ point[1] = height2 - rad * Math.cos(ang / 180d * Math.PI);
return point;
}
diff --git a/src/yugecin/opsudance/spinners/CubeSpinner.java b/src/yugecin/opsudance/spinners/CubeSpinner.java
index 622cbf0f..baa3b1b3 100644
--- a/src/yugecin/opsudance/spinners/CubeSpinner.java
+++ b/src/yugecin/opsudance/spinners/CubeSpinner.java
@@ -1,6 +1,6 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
- * Copyright (C) 2016 yugecin
+ * Copyright (C) 2016-2018 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
@@ -17,7 +17,7 @@
*/
package yugecin.opsudance.spinners;
-import static yugecin.opsudance.core.InstanceContainer.displayContainer;
+import static yugecin.opsudance.core.InstanceContainer.*;
public class CubeSpinner extends Spinner {
@@ -90,10 +90,10 @@ public class CubeSpinner extends Spinner {
x *= 3.0d / ( z + 3.0d + 5.0d + 0.5 );
y *= 3.0d / ( z + 3.0d + 5.0d + 0.5 );
- double scale = displayContainer.width / (3.0f + 0.5f * Math.cos(size / 180f * Math.PI));
+ double scale = width / (3.0f + 0.5f * Math.cos(size / 180f * Math.PI));
//double scale = Options.width / (3.0f + -1f * ((float)(Options.s.ElapsedMilliseconds % Options.beatTimeMs)/(float)Options.beatTimeMs));
- point[0] = (int) ( displayContainer.width / 2.0f + scale * x );
- point[1] = (int) ( displayContainer.height / 2.0f - scale * y );
+ point[0] = (int) (width2 + scale * x );
+ point[1] = (int) (height2 - scale * y );
return point;
}
diff --git a/src/yugecin/opsudance/spinners/DonutSpinner.java b/src/yugecin/opsudance/spinners/DonutSpinner.java
index 2d65fec2..1bb7e490 100644
--- a/src/yugecin/opsudance/spinners/DonutSpinner.java
+++ b/src/yugecin/opsudance/spinners/DonutSpinner.java
@@ -1,6 +1,6 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
- * Copyright (C) 2016 yugecin
+ * Copyright (C) 2016-2018 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
@@ -38,10 +38,10 @@ public class DonutSpinner extends Spinner {
ang += 15;
}
- double rad = displayContainer.width / 4.0f;
+ double rad = width / 4.0f;
- point[0] = displayContainer.width / 2.0f + rad * Math.sin(ang);
- point[1] = displayContainer.height / 2.0f - rad * Math.cos(ang);
+ point[0] = width2 + rad * Math.sin(ang);
+ point[1] = height2 - rad * Math.cos(ang);
return point;
}
diff --git a/src/yugecin/opsudance/spinners/FivePointStarApproachSpinner.java b/src/yugecin/opsudance/spinners/FivePointStarApproachSpinner.java
index b1f55d48..f3da8ea6 100644
--- a/src/yugecin/opsudance/spinners/FivePointStarApproachSpinner.java
+++ b/src/yugecin/opsudance/spinners/FivePointStarApproachSpinner.java
@@ -1,6 +1,6 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
- * Copyright (C) 2016 yugecin
+ * Copyright (C) 2016-2018 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
@@ -39,12 +39,12 @@ public class FivePointStarApproachSpinner extends Spinner {
odd = !odd;
}
- double rad = displayContainer.width / 4.0f * (1d - Spinner.PROGRESS);
+ double rad = width / 4.0f * (1d - Spinner.PROGRESS);
if (!odd) {
rad /= 3d;
}
- point[0] = displayContainer.width / 2d + Math.cos(ang) * rad;
- point[1] = displayContainer.height / 2d + Math.sin(ang) * rad;
+ point[0] = width2 + Math.cos(ang) * rad;
+ point[1] = height2 + Math.sin(ang) * rad;
return point;
}
diff --git a/src/yugecin/opsudance/spinners/FivePointStarSpinner.java b/src/yugecin/opsudance/spinners/FivePointStarSpinner.java
index d9eb8377..4e40eb3d 100644
--- a/src/yugecin/opsudance/spinners/FivePointStarSpinner.java
+++ b/src/yugecin/opsudance/spinners/FivePointStarSpinner.java
@@ -1,6 +1,6 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
- * Copyright (C) 2016 yugecin
+ * Copyright (C) 2016-2018 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
@@ -24,11 +24,9 @@ public class FivePointStarSpinner extends Spinner {
@Override
public void init() {
double[][] points = new double[10][];
- double midx = displayContainer.width / 2d;
- double midy = displayContainer.height / 2d;
double angleIncRads = Math.PI * 36d / 180d;
double ang = -Math.PI / 2d;
- double maxrad = displayContainer.width / 4d;
+ double maxrad = width / 4d;
double minrad = maxrad / 3d;
for (int i = 0; i < 10; i++) {
double rad = maxrad;
@@ -36,8 +34,8 @@ public class FivePointStarSpinner extends Spinner {
rad = minrad;
}
points[i] = new double[] {
- midx + Math.cos(ang) * rad,
- midy + Math.sin(ang) * rad
+ width2 + Math.cos(ang) * rad,
+ height2 + Math.sin(ang) * rad
};
ang += angleIncRads;
}
diff --git a/src/yugecin/opsudance/spinners/HalfCircleSpinner.java b/src/yugecin/opsudance/spinners/HalfCircleSpinner.java
index 18d08597..429e6bdb 100644
--- a/src/yugecin/opsudance/spinners/HalfCircleSpinner.java
+++ b/src/yugecin/opsudance/spinners/HalfCircleSpinner.java
@@ -1,6 +1,6 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
- * Copyright (C) 2016 yugecin
+ * Copyright (C) 2016-2018 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
@@ -17,9 +17,7 @@
*/
package yugecin.opsudance.spinners;
-import yugecin.opsudance.options.Options;
-
-import static yugecin.opsudance.core.InstanceContainer.displayContainer;
+import static yugecin.opsudance.core.InstanceContainer.*;
public class HalfCircleSpinner extends Spinner {
@@ -47,8 +45,8 @@ public class HalfCircleSpinner extends Spinner {
skipang += 359;
}
- point[0] = displayContainer.width / 2.0d + displayContainer.height / 2 * 0.8d * Math.cos(ang/180d*Math.PI);
- point[1] = displayContainer.height / 2.0d + displayContainer.height / 2 * 0.8d * Math.sin(ang/180d*Math.PI);
+ point[0] = width2 + height2 * 0.8d * Math.cos(ang/180d*Math.PI);
+ point[1] = height2 + height2 * 0.8d * Math.sin(ang/180d*Math.PI);
return point;
}
diff --git a/src/yugecin/opsudance/spinners/IlluminatiSpinner.java b/src/yugecin/opsudance/spinners/IlluminatiSpinner.java
index e4c946bd..cb9201bd 100644
--- a/src/yugecin/opsudance/spinners/IlluminatiSpinner.java
+++ b/src/yugecin/opsudance/spinners/IlluminatiSpinner.java
@@ -1,6 +1,6 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
- * Copyright (C) 2016 yugecin
+ * Copyright (C) 2016-2018 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
@@ -24,9 +24,9 @@ public class IlluminatiSpinner extends Spinner {
@Override
public void init() {
init( new double[][] {
- new double[] { displayContainer.width / 2d - 120, displayContainer.height / 2d + 80 },
- new double[] { displayContainer.width / 2d, displayContainer.height / 2d - 160 },
- new double[] { displayContainer.width / 2d + 120, displayContainer.height / 2d + 80 }
+ new double[] { width2 - 120, height2 + 80 },
+ new double[] { width2, height2 - 160 },
+ new double[] { width2 + 120, height2 + 80 }
} );
}
diff --git a/src/yugecin/opsudance/spinners/LessThanThreeSpinner.java b/src/yugecin/opsudance/spinners/LessThanThreeSpinner.java
index 4f099583..8c27d5b2 100644
--- a/src/yugecin/opsudance/spinners/LessThanThreeSpinner.java
+++ b/src/yugecin/opsudance/spinners/LessThanThreeSpinner.java
@@ -1,6 +1,6 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
- * Copyright (C) 2016 yugecin
+ * Copyright (C) 2016-2018 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
@@ -17,6 +17,7 @@
*/
package yugecin.opsudance.spinners;
+import static java.lang.Math.*;
import static yugecin.opsudance.core.InstanceContainer.*;
public class LessThanThreeSpinner extends Spinner {
@@ -24,9 +25,7 @@ public class LessThanThreeSpinner extends Spinner {
private int angle = 0;
@Override
- public void init()
- {
-
+ public void init() {
}
@Override
@@ -37,15 +36,12 @@ public class LessThanThreeSpinner extends Spinner {
}
if( angle > 360 ) angle = 0;
double theta = angle / 180d * Math.PI;
- double[] pos = new double[] {
- displayContainer.width / 2d,
- displayContainer.height / 2d
- };
+ double[] pos = { width2, height2 };
- double r = 2 - 2 * Math.sin( theta ) + Math.sin( theta ) * Math.sqrt( Math.abs( Math.cos( theta ) ) ) / ( Math.sin( theta ) + 1.4 );
+ double r = 2 - 2 * sin(theta) + sin(theta) * sqrt(abs(cos(theta))) / (sin(theta) + 1.4);
- pos[0] += Math.cos( theta ) * r * 100;
- pos[1] -= Math.sin( theta ) * r * 100 + 100;
+ pos[0] += Math.cos(theta) * r * 100;
+ pos[1] -= Math.sin(theta) * r * 100 + 100;
return pos;
}
diff --git a/src/yugecin/opsudance/spinners/RektCircleSpinner.java b/src/yugecin/opsudance/spinners/RektCircleSpinner.java
index c8c2341a..fcd83616 100644
--- a/src/yugecin/opsudance/spinners/RektCircleSpinner.java
+++ b/src/yugecin/opsudance/spinners/RektCircleSpinner.java
@@ -1,6 +1,6 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
- * Copyright (C) 2016 yugecin
+ * Copyright (C) 2016-2018 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
@@ -29,7 +29,7 @@ public class RektCircleSpinner extends Spinner {
@Override
public void init() {
index = 0;
- size = displayContainer.height * 0.8d;
+ size = height * 0.8d;
point = new double[2];
}
@@ -42,20 +42,20 @@ public class RektCircleSpinner extends Spinner {
final int INC = 50;
if( index == 0 ) {
- point[0] = displayContainer.width / 2d + size / 2d - pos;
- point[1] = displayContainer.height / 2d - size / 2d;
+ point[0] = width2 + size / 2d - pos;
+ point[1] = height2 - size / 2d;
index++;
} else if( index == 1 ) {
- point[0] = displayContainer.width / 2 - size / 2;
- point[1] = displayContainer.height / 2 - size / 2 + pos;
+ point[0] = width2 - size / 2;
+ point[1] = height2 - size / 2 + pos;
index++;
} else if( index == 2 ) {
- point[0] = displayContainer.width / 2 - size / 2 + pos;
- point[1] = displayContainer.height / 2 + size / 2;
+ point[0] = width2 - size / 2 + pos;
+ point[1] = height2 + size / 2;
index++;
} else if( index == 3 ) {
- point[0] = displayContainer.width / 2 + size / 2;
- point[1] = displayContainer.height / 2 + size / 2 - pos;
+ point[0] = width2 + size / 2;
+ point[1] = height2 + size / 2 - pos;
pos += INC;
if( pos > size ) {
pos = INC;
diff --git a/src/yugecin/opsudance/spinners/RektSpinner.java b/src/yugecin/opsudance/spinners/RektSpinner.java
index d1f75ca0..7cb6e616 100644
--- a/src/yugecin/opsudance/spinners/RektSpinner.java
+++ b/src/yugecin/opsudance/spinners/RektSpinner.java
@@ -1,6 +1,6 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
- * Copyright (C) 2016 yugecin
+ * Copyright (C) 2016-2018 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
@@ -25,11 +25,11 @@ public class RektSpinner extends Spinner {
public void init() {
init(new double[][] {
{ 10, 10 },
- { displayContainer.width / 2d, 10 },
- { displayContainer.width - 10, 10 },
- { displayContainer.width - 10, displayContainer.height - 10 },
- { displayContainer.width / 2d, displayContainer.height - 10 },
- { 10, displayContainer.height - 10 }
+ { width2, 10 },
+ { width - 10, 10 },
+ { width - 10, height - 10 },
+ { width2, height - 10 },
+ { 10, height - 10 }
});
}
diff --git a/src/yugecin/opsudance/ui/BackButton.java b/src/yugecin/opsudance/ui/BackButton.java
index c9a28ef1..fdb36fa2 100644
--- a/src/yugecin/opsudance/ui/BackButton.java
+++ b/src/yugecin/opsudance/ui/BackButton.java
@@ -1,6 +1,6 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
- * Copyright (C) 2017 yugecin
+ * Copyright (C) 2017-2018 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
@@ -23,7 +23,8 @@ import itdelatrisu.opsu.ui.Fonts;
import itdelatrisu.opsu.ui.MenuButton;
import itdelatrisu.opsu.ui.animations.AnimationEquation;
import org.newdawn.slick.*;
-import yugecin.opsudance.core.DisplayContainer;
+
+import static yugecin.opsudance.core.InstanceContainer.*;
public class BackButton {
@@ -80,7 +81,7 @@ public class BackButton {
/** The real button with, determined by the size and animations. */
private int realButtonWidth;
- public BackButton(DisplayContainer container) {
+ public BackButton() {
if (!GameImage.MENU_BACK.hasGameSkinImage()) {
backButton = null;
textWidth = Fonts.MEDIUM.getWidth("back");
@@ -90,7 +91,7 @@ public class BackButton {
paddingY *= 0.736f;
paddingX = paddingY / 2f;
chevronBaseSize = paddingY * 3f / 2f;
- buttonYpos = (int) (container.height - paddingY * 4f);
+ buttonYpos = height - (int) (paddingY * 4f);
slopeImageSize = (int) (paddingY * 3f);
slopeImageSlopeWidth = (int) (slopeImageSize * 0.295f);
firstButtonWidth = slopeImageSize;
@@ -101,10 +102,10 @@ public class BackButton {
if (GameImage.MENU_BACK.getImages() != null) {
Animation back = GameImage.MENU_BACK.getAnimation(120);
- backButton = new MenuButton(back, back.getWidth() / 2f, container.height - (back.getHeight() / 2f));
+ backButton = new MenuButton(back, back.getWidth() / 2f, height - (back.getHeight() / 2f));
} else {
Image back = GameImage.MENU_BACK.getImage();
- backButton = new MenuButton(back, back.getWidth() / 2f, container.height - (back.getHeight() / 2f));
+ backButton = new MenuButton(back, back.getWidth() / 2f, height - (back.getHeight() / 2f));
}
backButton.setHoverAnimationDuration(350);
backButton.setHoverAnimationEquation(AnimationEquation.IN_OUT_BACK);
@@ -171,11 +172,11 @@ public class BackButton {
/**
* Processes a hover action depending on whether or not the cursor
* is hovering over the button.
- * @param delta the delta interval
- * @param cx the x coordinate
- * @param cy the y coordinate
*/
- public void hoverUpdate(int delta, int cx, int cy) {
+ public void hoverUpdate() {
+ final int delta = renderDelta;
+ final int cx = mouseX;
+ final int cy = mouseY;
if (backButton != null) {
backButton.hoverUpdate(delta, cx, cy);
return;
diff --git a/src/yugecin/opsudance/ui/ImagePosition.java b/src/yugecin/opsudance/ui/ImagePosition.java
new file mode 100644
index 00000000..a50d4e8c
--- /dev/null
+++ b/src/yugecin/opsudance/ui/ImagePosition.java
@@ -0,0 +1,62 @@
+/*
+ * opsu!dance - fork of opsu! with cursordance auto
+ * Copyright (C) 2018 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 .
+ */
+package yugecin.opsudance.ui;
+
+import java.awt.geom.Rectangle2D;
+
+import org.newdawn.slick.Color;
+import org.newdawn.slick.Image;
+
+public class ImagePosition extends Rectangle2D.Float {
+
+ private Image image;
+
+ public ImagePosition(Image image) {
+ this.image = image;
+ }
+
+ public boolean contains(int x, int y, float alphaThreshold) {
+ if (!super.contains(x, y)) {
+ return false;
+ }
+ final int ix = x - (int) this.x;
+ final int iy = y - (int) this.y;
+ return this.image.getAlphaAt(ix, iy) > alphaThreshold;
+ }
+
+ public float middleX() {
+ return this.x + this.width / 2;
+ }
+
+ public float middleY() {
+ return this.y + this.height / 2;
+ }
+
+ public void scale(float scale) {
+ final float width = this.width * scale;
+ final float height = this.height * scale;
+ this.x -= (width - this.width) / 2f;
+ this.y -= (height - this.height) / 2f;
+ this.width = width;
+ this.height = height;
+ }
+
+ public void draw(Color filter) {
+ this.image.draw(this.x, this.y, this.width, this.height, filter);
+ }
+}
diff --git a/src/yugecin/opsudance/ui/OptionsOverlay.java b/src/yugecin/opsudance/ui/OptionsOverlay.java
index 331191ac..3ce0c5d3 100644
--- a/src/yugecin/opsudance/ui/OptionsOverlay.java
+++ b/src/yugecin/opsudance/ui/OptionsOverlay.java
@@ -1,6 +1,6 @@
/*
* opsu!dance - fork of opsu! with cursordance auto
- * Copyright (C) 2016 yugecin
+ * Copyright (C) 2016-2018 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
@@ -26,8 +26,10 @@ import itdelatrisu.opsu.ui.animations.AnimationEquation;
import org.lwjgl.input.Keyboard;
import org.newdawn.slick.*;
import org.newdawn.slick.gui.TextField;
-import yugecin.opsudance.core.DisplayContainer;
-import yugecin.opsudance.core.state.OverlayOpsuState;
+
+import yugecin.opsudance.core.Constants;
+import yugecin.opsudance.events.ResolutionChangedListener;
+import yugecin.opsudance.events.SkinChangedListener;
import yugecin.opsudance.options.*;
import yugecin.opsudance.utils.FontUtil;
@@ -35,11 +37,11 @@ import java.util.HashMap;
import java.util.LinkedList;
import java.util.Random;
+import static itdelatrisu.opsu.GameImage.*;
+import static yugecin.opsudance.core.InstanceContainer.*;
import static yugecin.opsudance.options.Options.*;
-public class OptionsOverlay extends OverlayOpsuState {
-
- private final DisplayContainer displayContainer;
+public class OptionsOverlay implements ResolutionChangedListener, SkinChangedListener {
private static final float BG_ALPHA = 0.7f;
private static final float LINEALPHA = 0.8f;
@@ -60,6 +62,9 @@ public class OptionsOverlay extends OverlayOpsuState {
private static final float INDICATOR_ALPHA = 0.8f;
private static final Color COL_INDICATOR = new Color(Color.black);
+ private boolean active;
+ private boolean acceptInput;
+ private boolean dirty;
/** Duration, in ms, of the show (slide-in) animation. */
private static final int SHOWANIMATIONTIME = 1000;
@@ -102,6 +107,7 @@ public class OptionsOverlay extends OverlayOpsuState {
private int sliderOptionStartX;
private int sliderOptionLength;
private boolean isAdjustingSlider;
+ private int unchangedSliderValue;
private final HashMap> dropdownMenus;
private final LinkedList> visibleDropdownMenus;
@@ -110,8 +116,7 @@ public class OptionsOverlay extends OverlayOpsuState {
private int openDropdownVirtualY;
private int targetWidth;
- private int width;
- private int height;
+ private int currentWidth;
private int navButtonSize;
private int navStartY;
@@ -141,8 +146,12 @@ public class OptionsOverlay extends OverlayOpsuState {
private final KineticScrolling scrollHandler;
private int maxScrollOffset;
+ private int lastOptionHeight;
private int mousePressY;
+
+ private boolean isDraggingFromOutside;
+ private boolean wasPressed;
private boolean keyEntryLeft;
private boolean keyEntryRight;
@@ -161,10 +170,9 @@ public class OptionsOverlay extends OverlayOpsuState {
private int invalidSearchAnimationProgress;
private final int INVALID_SEARCH_ANIMATION_TIME = 500;
- public OptionsOverlay(DisplayContainer displayContainer, OptionTab[] sections) {
- this.displayContainer = displayContainer;
-
+ public OptionsOverlay(OptionTab[] sections) {
this.sections = sections;
+ this.dirty = true;
dropdownMenus = new HashMap<>();
visibleDropdownMenus = new LinkedList<>();
@@ -174,29 +182,53 @@ public class OptionsOverlay extends OverlayOpsuState {
scrollHandler = new KineticScrolling();
scrollHandler.setAllowOverScroll(true);
+
+ displayContainer.addResolutionChangedListener(this);
+ skinservice.addSkinChangedListener(this);
+ }
+
+ @Override
+ public void onResolutionChanged(int w, int h) {
+ this.dirty = true;
+ if (this.active) {
+ this.revalidate();
+ }
+ }
+
+ @Override
+ public void onSkinChanged(String name) {
+ this.dirty = true;
+ if (this.active) {
+ this.revalidate();
+ }
+ }
+
+ public boolean isActive() {
+ return this.active;
+ }
+
+ public boolean containsMouse() {
+ return this.active && mouseX <= this.currentWidth;
}
public void setListener(Listener listener) {
this.listener = listener;
}
- @Override
public void revalidate() {
- super.revalidate();
+ this.dirty = false;
- boolean isWidescreen = displayContainer.isWidescreen();
- targetWidth = (int) (displayContainer.width * (isWidescreen ? 0.4f : 0.5f));
- height = displayContainer.height;
+ targetWidth = (int) (width * (isWidescreen ? 0.4f : 0.5f));
// calculate positions
float navIconWidthRatio = isWidescreen ? 0.046875f : 0.065f;
// non-widescreen ratio is not accurate
- navButtonSize = (int) (displayContainer.width * navIconWidthRatio);
+ navButtonSize = (int) (width * navIconWidthRatio);
navIndicatorSize = navButtonSize / 10;
navTargetWidth = (int) (targetWidth * 0.45f) - navButtonSize;
- paddingRight = (int) (displayContainer.width * 0.009375f); // not so accurate
- paddingLeft = navButtonSize + (int) (displayContainer.width * 0.0180f); // not so accurate
- paddingTextLeft = paddingLeft + LINEWIDTH + (int) (displayContainer.width * 0.00625f); // not so accurate
+ paddingRight = (int) (width * 0.009375f); // not so accurate
+ paddingLeft = navButtonSize + (int) (width * 0.0180f); // not so accurate
+ paddingTextLeft = paddingLeft + LINEWIDTH + (int) (width * 0.00625f); // not so accurate
optionStartX = paddingTextLeft;
textOptionsY = Fonts.LARGE.getLineHeight() * 2;
textChangeY = textOptionsY + Fonts.LARGE.getLineHeight();
@@ -206,8 +238,8 @@ public class OptionsOverlay extends OverlayOpsuState {
sectionLineHeight = (int) (Fonts.LARGE.getLineHeight() * 1.5f);
if (active) {
- width = targetWidth;
- optionWidth = width - optionStartX - paddingRight;
+ currentWidth = targetWidth;
+ optionWidth = currentWidth - optionStartX - paddingRight;
}
optionHeight = (int) (Fonts.MEDIUM.getLineHeight() * 1.3f);
@@ -215,9 +247,10 @@ public class OptionsOverlay extends OverlayOpsuState {
controlImageSize = (int) (Fonts.MEDIUM.getLineHeight() * 0.7f);
controlImagePadding = (optionHeight - controlImageSize) / 2;
- sliderBallImg = GameImage.CONTROL_SLIDER_BALL.getImage().getScaledCopy(controlImageSize, controlImageSize);
- checkOnImg = GameImage.CONTROL_CHECK_ON.getImage().getScaledCopy(controlImageSize, controlImageSize);
- checkOffImg = GameImage.CONTROL_CHECK_OFF.getImage().getScaledCopy(controlImageSize, controlImageSize);
+ final int s = controlImageSize;
+ sliderBallImg = CONTROL_SLIDER_BALL.getScaledImage(s, s);
+ checkOnImg = CONTROL_CHECK_ON.getScaledImage(s, s);
+ checkOffImg = CONTROL_CHECK_OFF.getScaledImage(s, s);
int navTotalHeight = 0;
dropdownMenus.clear();
@@ -232,23 +265,27 @@ public class OptionsOverlay extends OverlayOpsuState {
}
final ListOption listOption = (ListOption) option;
Object[] items = listOption.getListItems();
- DropdownMenu