Merge branch 'master' into kockout-wdata
# Conflicts: # src/itdelatrisu/opsu/states/Game.java # src/itdelatrisu/opsu/states/Splash.java
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ public class ScoreData implements Comparable<ScoreData> {
|
||||
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;
|
||||
|
||||
@@ -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)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -89,6 +89,9 @@ public class Beatmap implements Comparable<Beatmap> {
|
||||
/** The last time this beatmap was played (timestamp). */
|
||||
public long lastPlayed = 0;
|
||||
|
||||
/** The local music offset. */
|
||||
public int localMusicOffset = 0;
|
||||
|
||||
/**
|
||||
* [General]
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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("\\|");
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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())) {
|
||||
|
||||
@@ -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.");
|
||||
}
|
||||
|
||||
@@ -48,8 +48,6 @@ import static yugecin.opsudance.options.Options.*;
|
||||
* @author Bigpet {@literal <dravorek (at) gmail.com>}
|
||||
*/
|
||||
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]);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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<DownloadServer>(displayContainer, SERVERS, x, searchY, serverWidth) {
|
||||
serverMenu = new DropdownMenu<DownloadServer>(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; }
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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<BeatmapSortOrder> 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<BeatmapSortOrder>(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>(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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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() {}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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<E> 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<E> 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<E> 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<E> extends Component {
|
||||
return;
|
||||
}
|
||||
|
||||
int idx = getIndexAt(displayContainer.mouseY);
|
||||
int idx = getIndexAt(mouseY);
|
||||
if (idx == -2) {
|
||||
this.expanded = false;
|
||||
return;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<KeyListener> 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();
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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<ResolutionChangedListener> 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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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(
|
||||
"<html>Copy the text in the box below.<br/>"
|
||||
+ "Then click the button below.<br/>"
|
||||
+ "Your browser should open a page where you can report the issue.<br/>"
|
||||
+ "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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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<T> {
|
||||
|
||||
private final Class<T> type;
|
||||
private final LinkedList<T> listeners;
|
||||
|
||||
public Event(Class<T> 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;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package yugecin.opsudance.core.inject;
|
||||
|
||||
public interface Binder<T> {
|
||||
|
||||
void asEagerSingleton();
|
||||
void asLazySingleton();
|
||||
void to(Class<? extends T> type);
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package yugecin.opsudance.core.inject;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME) public @interface Inject {
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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<Class<?>, Object> instances;
|
||||
private final LinkedList<Class<?>> 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> T provide(Class<T> type) {
|
||||
Object instance = instances.get(type);
|
||||
if (instance != null) {
|
||||
return (T) instance;
|
||||
}
|
||||
ListIterator<Class<?>> 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> T createInstance(Class<T> 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> 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> T injectFields(T obj) {
|
||||
return injectFields(obj, obj.getClass());
|
||||
}
|
||||
|
||||
public final <T> Binder<T> bind(Class<T> 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));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package yugecin.opsudance.core.inject;
|
||||
|
||||
public interface InstanceContainer {
|
||||
|
||||
<T> T provide(Class<T> type);
|
||||
<T> T injectFields(T instance);
|
||||
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package yugecin.opsudance.events;
|
||||
|
||||
import yugecin.opsudance.core.events.Event;
|
||||
|
||||
public interface BarNotifListener {
|
||||
|
||||
Event<BarNotifListener> EVENT = new Event<>(BarNotifListener.class);
|
||||
|
||||
void onBarNotif(String message);
|
||||
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package yugecin.opsudance.events;
|
||||
|
||||
import org.newdawn.slick.Color;
|
||||
import yugecin.opsudance.core.events.Event;
|
||||
|
||||
@SuppressWarnings({"UnnecessaryInterfaceModifier", "unused"})
|
||||
public interface BubNotifListener {
|
||||
|
||||
Event<BubNotifListener> EVENT = new Event<>(BubNotifListener.class);
|
||||
|
||||
void onBubNotif(String message, Color borderColor);
|
||||
|
||||
}
|
||||
@@ -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<ResolutionChangedListener> EVENT = new Event<>(ResolutionChangedListener.class);
|
||||
|
||||
public interface ResolutionChangedListener
|
||||
{
|
||||
void onResolutionChanged(int w, int h);
|
||||
|
||||
}
|
||||
|
||||
@@ -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<SkinChangedListener> EVENT = new Event<>(SkinChangedListener.class);
|
||||
|
||||
void onSkinChanged(String stringName);
|
||||
|
||||
public interface SkinChangedListener
|
||||
{
|
||||
void onSkinChanged(String name);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
}),
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -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<SkinChangedListener> 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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 }
|
||||
} );
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 }
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
62
src/yugecin/opsudance/ui/ImagePosition.java
Normal file
62
src/yugecin/opsudance/ui/ImagePosition.java
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -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<ListOption, DropdownMenu<Object>> dropdownMenus;
|
||||
private final LinkedList<DropdownMenu<Object>> 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<Object> menu = new DropdownMenu<Object>(displayContainer, items, 0, 0, 0) {
|
||||
DropdownMenu<Object> menu = new DropdownMenu<Object>(items, 0, 0, 0) {
|
||||
@Override
|
||||
public void itemSelected(int index, Object item) {
|
||||
listOption.clickListItem(index);
|
||||
openDropdownMenu = null;
|
||||
}
|
||||
};
|
||||
// not the best way to determine the selected option AT ALL, but seems like it's the only one right now...
|
||||
String selectedValue = option.getValueString();
|
||||
int idx = 0;
|
||||
for (Object item : items) {
|
||||
if (item.toString().equals(selectedValue)) {
|
||||
break;
|
||||
final Runnable observer = () -> {
|
||||
// not the best way to determine the selected option AT ALL, but seems like it's the only one right now...
|
||||
String selectedValue = option.getValueString();
|
||||
int idx = 0;
|
||||
for (Object item : items) {
|
||||
if (item.toString().equals(selectedValue)) {
|
||||
break;
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
menu.setSelectedIndex(idx);
|
||||
menu.setSelectedIndex(idx);
|
||||
};
|
||||
observer.run();
|
||||
listOption.observer = observer;
|
||||
menu.setBackgroundColor(COL_BG);
|
||||
menu.setBorderColor(Color.transparent);
|
||||
menu.setChevronDownColor(COL_WHITE);
|
||||
@@ -265,13 +302,16 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||
searchImg = GameImage.SEARCH.getImage().getScaledCopy(searchImgSize, searchImgSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRender(Graphics g) {
|
||||
g.setClip(navButtonSize, 0, width - navButtonSize, height);
|
||||
public void render(Graphics g) {
|
||||
if (!this.active && this.currentWidth == this.navButtonSize) {
|
||||
return;
|
||||
}
|
||||
|
||||
g.setClip(navButtonSize, 0, currentWidth - navButtonSize, height);
|
||||
|
||||
// bg
|
||||
g.setColor(COL_BG);
|
||||
g.fillRect(navButtonSize, 0, width, height);
|
||||
g.fillRect(navButtonSize, 0, currentWidth, height);
|
||||
|
||||
// title
|
||||
renderTitle();
|
||||
@@ -291,16 +331,15 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||
|
||||
// scrollbar
|
||||
g.setColor(COL_WHITE);
|
||||
g.fillRect(width - 5, scrollHandler.getPosition() / maxScrollOffset * (height - 45), 5, 45);
|
||||
g.fillRect(currentWidth - 5, scrollHandler.getPosition() / maxScrollOffset * (height - 45), 5, 45);
|
||||
g.clearClip();
|
||||
|
||||
renderNavigation(g);
|
||||
|
||||
// UI
|
||||
UI.getBackButton().draw(g);
|
||||
|
||||
// tooltip
|
||||
renderTooltip(g);
|
||||
if (this.active) {
|
||||
renderTooltip(g);
|
||||
}
|
||||
|
||||
// key input options
|
||||
if (keyEntryLeft || keyEntryRight) {
|
||||
@@ -314,7 +353,7 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||
navWidth += navTargetWidth;
|
||||
} else if (navHoverTime > 300) {
|
||||
AnimationEquation anim = AnimationEquation.IN_EXPO;
|
||||
if (displayContainer.mouseX < navWidth) {
|
||||
if (mouseX < navWidth) {
|
||||
anim = AnimationEquation.OUT_EXPO;
|
||||
}
|
||||
float progress = anim.calc((navHoverTime - 300f) / 300f);
|
||||
@@ -363,7 +402,7 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||
g.setColor(COL_INDICATOR);
|
||||
int indicatorPos = this.indicatorPos;
|
||||
if (indicatorMoveAnimationTime > 0) {
|
||||
indicatorMoveAnimationTime += displayContainer.renderDelta;
|
||||
indicatorMoveAnimationTime += renderDelta;
|
||||
if (indicatorMoveAnimationTime > INDICATORMOVEANIMATIONTIME) {
|
||||
indicatorMoveAnimationTime = 0;
|
||||
indicatorPos += indicatorOffsetToNextPos;
|
||||
@@ -373,16 +412,16 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||
indicatorPos += AnimationEquation.OUT_BACK.calc((float) indicatorMoveAnimationTime / INDICATORMOVEANIMATIONTIME) * indicatorOffsetToNextPos;
|
||||
}
|
||||
}
|
||||
g.fillRect(navButtonSize, indicatorPos - scrollHandler.getPosition(), width, optionHeight);
|
||||
g.fillRect(navButtonSize, indicatorPos - scrollHandler.getPosition(), currentWidth, optionHeight);
|
||||
}
|
||||
|
||||
private void renderKeyEntry(Graphics g) {
|
||||
g.setColor(COL_BG);
|
||||
g.fillRect(0, 0, displayContainer.width, height);
|
||||
g.fillRect(0, 0, width, height);
|
||||
g.setColor(COL_WHITE);
|
||||
String prompt = (keyEntryLeft) ? "Please press the new left-click key." : "Please press the new right-click key.";
|
||||
int y = (displayContainer.height - Fonts.LARGE.getLineHeight()) / 2;
|
||||
FontUtil.drawCentered(Fonts.LARGE, displayContainer.width, 0, y, prompt, COL_WHITE);
|
||||
int y = height2 - Fonts.LARGE.getLineHeight() / 2;
|
||||
FontUtil.drawCentered(Fonts.LARGE, width, 0, y, prompt, COL_WHITE);
|
||||
}
|
||||
|
||||
private void renderTooltip(Graphics g) {
|
||||
@@ -391,7 +430,7 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||
if (hoverOption instanceof NumericOption) {
|
||||
tip = "(" + hoverOption.getValueString() + ") " + tip;
|
||||
}
|
||||
UI.updateTooltip(displayContainer.renderDelta, tip, true);
|
||||
UI.updateTooltip(renderDelta, tip, true);
|
||||
UI.drawTooltip(g);
|
||||
}
|
||||
}
|
||||
@@ -413,7 +452,7 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||
if (section != activeSection) {
|
||||
COL_CYAN.a *= 0.2f;
|
||||
}
|
||||
FontUtil.drawRightAligned(Fonts.XLARGE, width, -paddingRight,
|
||||
FontUtil.drawRightAligned(Fonts.XLARGE, currentWidth, -paddingRight,
|
||||
(int) (y + Fonts.XLARGE.getLineHeight() * 0.3f), section.name.toUpperCase(),
|
||||
COL_CYAN);
|
||||
COL_CYAN.a = previousAlpha;
|
||||
@@ -451,6 +490,7 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||
g.setColor(COL_GREY);
|
||||
g.fillRect(paddingLeft, lineStartY, LINEWIDTH, lineHeight);
|
||||
}
|
||||
lastOptionHeight = maxScrollOffset;
|
||||
// iterate over skipped options to correctly calculate max scroll offset
|
||||
for (; sectionIndex < sections.length; sectionIndex++) {
|
||||
if (sections[sectionIndex].filtered) {
|
||||
@@ -569,11 +609,22 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||
}
|
||||
|
||||
private void renderTitle() {
|
||||
int textWidth = width - navButtonSize;
|
||||
int textWidth = currentWidth - navButtonSize;
|
||||
FontUtil.drawCentered(Fonts.LARGE, textWidth, navButtonSize,
|
||||
textOptionsY - scrollHandler.getIntPosition(), "Options", COL_WHITE);
|
||||
FontUtil.drawCentered(Fonts.MEDIUM, textWidth, navButtonSize,
|
||||
textChangeY - scrollHandler.getIntPosition(), "Change the way opsu! behaves", COL_PINK);
|
||||
|
||||
int y = lastOptionHeight - scrollHandler.getIntPosition();
|
||||
y += Fonts.LARGE.getLineHeight() * 2.5f;
|
||||
FontUtil.drawCentered(Fonts.MEDIUM, textWidth, navButtonSize,
|
||||
y, Constants.PROJECT_NAME + " " + updater.getCurrentVersion(), COL_WHITE);
|
||||
y += Fonts.MEDIUM.getLineHeight() * 1.2f;
|
||||
FontUtil.drawCentered(Fonts.MEDIUM, textWidth, navButtonSize,
|
||||
y, Constants.DANCE_REPOSITORY_URI.toString(), COL_WHITE);
|
||||
y += Fonts.MEDIUM.getLineHeight() * 1.2f;
|
||||
FontUtil.drawCentered(Fonts.MEDIUM, textWidth, navButtonSize,
|
||||
y, Constants.REPOSITORY_URI.toString(), COL_WHITE);
|
||||
}
|
||||
|
||||
private void renderSearch(Graphics g) {
|
||||
@@ -581,7 +632,7 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||
if (scrollHandler.getIntPosition() > posSearchY) {
|
||||
ypos = textSearchYOffset;
|
||||
g.setColor(COL_BG);
|
||||
g.fillRect(navButtonSize, 0, width, textSearchYOffset * 2 + Fonts.LARGE.getLineHeight());
|
||||
g.fillRect(navButtonSize, 0, currentWidth, textSearchYOffset * 2 + Fonts.LARGE.getLineHeight());
|
||||
}
|
||||
Color searchCol = COL_WHITE;
|
||||
float invalidProgress = 0f;
|
||||
@@ -597,7 +648,7 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||
if (lastSearchText.length() > 0) {
|
||||
searchText = lastSearchText;
|
||||
}
|
||||
int textWidth = width - navButtonSize;
|
||||
int textWidth = currentWidth - navButtonSize;
|
||||
if (invalidSearchAnimationProgress > 0) {
|
||||
g.rotate(navButtonSize + textWidth / 2, ypos, invalidProgress * invalidSearchTextRotation);
|
||||
}
|
||||
@@ -611,33 +662,37 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||
g.resetTransform();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hide() {
|
||||
if (!this.active) {
|
||||
return;
|
||||
}
|
||||
acceptInput = active = false;
|
||||
searchField.setFocused(false);
|
||||
acceptInput = false;
|
||||
SoundController.playSound(SoundEffect.MENUBACK);
|
||||
hideAnimationTime = animationtime;
|
||||
hideAnimationStartProgress = (float) animationtime / SHOWANIMATIONTIME;
|
||||
hoverOption = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
navHoverTime = 0;
|
||||
indicatorPos = -optionHeight;
|
||||
indicatorOffsetToNextPos = 0;
|
||||
indicatorMoveAnimationTime = 0;
|
||||
indicatorHideAnimationTime = 0;
|
||||
acceptInput = true;
|
||||
active = true;
|
||||
acceptInput = active = true;
|
||||
animationtime = 0;
|
||||
resetSearch();
|
||||
if (this.dirty) {
|
||||
this.revalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPreRenderUpdate() {
|
||||
int mouseX = displayContainer.mouseX;
|
||||
int mouseY = displayContainer.mouseY;
|
||||
int delta = displayContainer.renderDelta;
|
||||
public void preRenderUpdate() {
|
||||
if (!this.active && this.currentWidth == this.navButtonSize) {
|
||||
return;
|
||||
}
|
||||
|
||||
int delta = renderDelta;
|
||||
|
||||
int prevscrollpos = scrollHandler.getIntPosition();
|
||||
scrollHandler.update(delta);
|
||||
@@ -684,7 +739,6 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||
prevMouseY = mouseY;
|
||||
updateHoverOption(mouseX, mouseY);
|
||||
updateIndicatorAlpha();
|
||||
UI.getBackButton().hoverUpdate(delta, mouseX, mouseY);
|
||||
if (isAdjustingSlider) {
|
||||
int sliderValue = ((NumericOption) hoverOption).val;
|
||||
updateSliderOption();
|
||||
@@ -716,7 +770,7 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||
private void updateIndicatorAlpha() {
|
||||
if (hoverOption == null) {
|
||||
if (indicatorHideAnimationTime < INDICATORHIDEANIMATIONTIME) {
|
||||
indicatorHideAnimationTime += displayContainer.renderDelta;
|
||||
indicatorHideAnimationTime += renderDelta;
|
||||
if (indicatorHideAnimationTime > INDICATORHIDEANIMATIONTIME) {
|
||||
indicatorHideAnimationTime = INDICATORHIDEANIMATIONTIME;
|
||||
}
|
||||
@@ -725,7 +779,7 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||
COL_INDICATOR.a = (1f - progress) * INDICATOR_ALPHA * showHideProgress;
|
||||
}
|
||||
} else if (indicatorHideAnimationTime > 0) {
|
||||
indicatorHideAnimationTime -= displayContainer.renderDelta * 3;
|
||||
indicatorHideAnimationTime -= renderDelta * 3;
|
||||
if (indicatorHideAnimationTime < 0) {
|
||||
indicatorHideAnimationTime = 0;
|
||||
}
|
||||
@@ -737,11 +791,11 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||
private void updateShowHideAnimation(int delta) {
|
||||
if (acceptInput && animationtime >= SHOWANIMATIONTIME) {
|
||||
// animation already finished
|
||||
width = targetWidth;
|
||||
currentWidth = targetWidth;
|
||||
showHideProgress = 1f;
|
||||
return;
|
||||
}
|
||||
optionWidth = width - optionStartX - paddingRight;
|
||||
optionWidth = currentWidth - optionStartX - paddingRight;
|
||||
|
||||
// navigation elemenst fade out with a different animation
|
||||
float navProgress;
|
||||
@@ -763,7 +817,7 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||
navProgress = hideAnimationStartProgress * AnimationEquation.IN_CIRC.calc(showHideProgress);
|
||||
showHideProgress = hideAnimationStartProgress * AnimationEquation.IN_EXPO.calc(showHideProgress);
|
||||
}
|
||||
width = navButtonSize + (int) (showHideProgress * (targetWidth - navButtonSize));
|
||||
currentWidth = navButtonSize + (int) (showHideProgress * (targetWidth - navButtonSize));
|
||||
COL_NAV_FILTERED.a = COL_NAV_INACTIVE.a = COL_NAV_FILTERED_HOVERED.a = COL_NAV_INDICATOR.a =
|
||||
COL_NAV_WHITE.a = COL_NAV_BG.a = navProgress;
|
||||
COL_BG.a = BG_ALPHA * showHideProgress;
|
||||
@@ -775,14 +829,23 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||
COL_COMBOBOX_HOVER.a = showHideProgress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMousePressed(int button, int x, int y) {
|
||||
public boolean mousePressed(int button, int x, int y) {
|
||||
if (!this.active) {
|
||||
return false;
|
||||
}
|
||||
if (x > this.currentWidth) {
|
||||
this.isDraggingFromOutside = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
wasPressed = true;
|
||||
|
||||
if (keyEntryLeft || keyEntryRight) {
|
||||
keyEntryLeft = keyEntryRight = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (x > width) {
|
||||
if (x > currentWidth) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -794,6 +857,7 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||
if (hoverOption != null && hoverOption instanceof NumericOption) {
|
||||
isAdjustingSlider = sliderOptionStartX <= x && x < sliderOptionStartX + sliderOptionLength;
|
||||
if (isAdjustingSlider) {
|
||||
unchangedSliderValue = ((NumericOption) hoverOption).val;
|
||||
updateSliderOption();
|
||||
}
|
||||
}
|
||||
@@ -801,15 +865,33 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMouseReleased(int button, int x, int y) {
|
||||
selectedOption = null;
|
||||
if (isAdjustingSlider && listener != null) {
|
||||
listener.onSaveOption(hoverOption);
|
||||
public boolean mouseReleased(int button, int x, int y) {
|
||||
this.isDraggingFromOutside = false;
|
||||
if (!this.active || (!wasPressed && x > this.currentWidth)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
wasPressed = false;
|
||||
|
||||
selectedOption = null;
|
||||
if (isAdjustingSlider) {
|
||||
if (listener != null) {
|
||||
listener.onSaveOption(hoverOption);
|
||||
}
|
||||
updateHoverOption(x, y);
|
||||
isAdjustingSlider = false;
|
||||
}
|
||||
isAdjustingSlider = false;
|
||||
sliderOptionLength = 0;
|
||||
|
||||
if (backButton.contains(x, y)){
|
||||
SoundController.playSound(SoundEffect.MENUBACK);
|
||||
hide();
|
||||
if (listener != null) {
|
||||
listener.onLeaveOptionsMenu();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (x > navWidth) {
|
||||
if (openDropdownMenu != null) {
|
||||
openDropdownMenu.mouseReleased(button);
|
||||
@@ -873,18 +955,14 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||
sectionPosition = Utils.clamp(sectionPosition, (int) scrollHandler.min, (int) scrollHandler.max);
|
||||
scrollHandler.scrollToPosition(sectionPosition);
|
||||
}
|
||||
|
||||
if (UI.getBackButton().contains(x, y)){
|
||||
hide();
|
||||
if (listener != null) {
|
||||
listener.onLeaveOptionsMenu();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMouseDragged(int oldx, int oldy, int newx, int newy) {
|
||||
public boolean mouseDragged(int oldx, int oldy, int newx, int newy) {
|
||||
if (!this.active || this.isDraggingFromOutside) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isAdjustingSlider) {
|
||||
int diff = newy - oldy;
|
||||
if (diff != 0) {
|
||||
@@ -894,16 +972,22 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMouseWheelMoved(int delta) {
|
||||
public boolean mouseWheelMoved(int delta) {
|
||||
if (!this.active || mouseX > this.currentWidth) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isAdjustingSlider) {
|
||||
scrollHandler.scrollOffset(-delta);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyPressed(int key, char c) {
|
||||
public boolean keyPressed(int key, char c) {
|
||||
if (!this.active) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (keyEntryRight) {
|
||||
if (Utils.isValidGameKey(key)) {
|
||||
OPTION_KEY_RIGHT.intval = key;
|
||||
@@ -921,6 +1005,9 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||
}
|
||||
|
||||
if (key == Keyboard.KEY_ESCAPE) {
|
||||
if (isAdjustingSlider) {
|
||||
cancelAdjustingSlider();
|
||||
}
|
||||
if (openDropdownMenu != null) {
|
||||
openDropdownMenu.keyPressed(key, c);
|
||||
return true;
|
||||
@@ -930,6 +1017,7 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||
updateHoverOption(prevMouseX, prevMouseY);
|
||||
return true;
|
||||
}
|
||||
SoundController.playSound(SoundEffect.MENUBACK);
|
||||
hide();
|
||||
if (listener != null) {
|
||||
listener.onLeaveOptionsMenu();
|
||||
@@ -961,14 +1049,20 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyReleased(int key, char c) {
|
||||
public boolean keyReleased(int key, char c) {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void cancelAdjustingSlider() {
|
||||
if (isAdjustingSlider) {
|
||||
isAdjustingSlider = false;
|
||||
((NumericOption) hoverOption).setValue(unchangedSliderValue);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateSliderOption() {
|
||||
NumericOption o = (NumericOption) hoverOption;
|
||||
int value = o.min + Math.round((float) (o.max - o.min) * (displayContainer.mouseX - sliderOptionStartX) / (sliderOptionLength));
|
||||
int value = o.min + Math.round((float) (o.max - o.min) * (mouseX - sliderOptionStartX) / (sliderOptionLength));
|
||||
o.setValue(Utils.clamp(value, o.min, o.max));
|
||||
}
|
||||
|
||||
@@ -1000,6 +1094,7 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||
|
||||
private void updateHoverOption(int mouseX, int mouseY) {
|
||||
if (mouseX < navWidth) {
|
||||
cancelAdjustingSlider();
|
||||
hoverOption = null;
|
||||
return;
|
||||
}
|
||||
@@ -1011,7 +1106,7 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||
return;
|
||||
}
|
||||
hoverOption = null;
|
||||
if (mouseX > width) {
|
||||
if (mouseX > currentWidth) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1118,5 +1213,4 @@ public class OptionsOverlay extends OverlayOpsuState {
|
||||
void onLeaveOptionsMenu();
|
||||
void onSaveOption(Option option);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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,7 +26,6 @@ import itdelatrisu.opsu.ui.Fonts;
|
||||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.Graphics;
|
||||
import yugecin.opsudance.ObjectColorOverrides;
|
||||
import yugecin.opsudance.core.DisplayContainer;
|
||||
import yugecin.opsudance.core.state.OverlayOpsuState;
|
||||
import yugecin.opsudance.options.OptionTab;
|
||||
import yugecin.opsudance.sbv2.MoveStoryboard;
|
||||
@@ -35,14 +34,12 @@ import java.util.*;
|
||||
|
||||
import static org.lwjgl.input.Keyboard.*;
|
||||
import static yugecin.opsudance.options.Options.*;
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class StoryboardOverlay extends OverlayOpsuState implements OptionsOverlay.Listener {
|
||||
|
||||
private final static List<Option> optionList = new ArrayList<>();
|
||||
|
||||
private final DisplayContainer displayContainer;
|
||||
|
||||
private boolean hide;
|
||||
|
||||
private int speed;
|
||||
@@ -58,12 +55,13 @@ public class StoryboardOverlay extends OverlayOpsuState implements OptionsOverla
|
||||
|
||||
static {
|
||||
for (OptionTab tab : OptionGroups.storyboardOptions) {
|
||||
optionList.addAll(Arrays.asList(tab.options));
|
||||
if (tab.options != null) {
|
||||
optionList.addAll(Arrays.asList(tab.options));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public StoryboardOverlay(DisplayContainer displayContainer, MoveStoryboard msb, OptionsOverlay optionsOverlay, Game game) {
|
||||
this.displayContainer = displayContainer;
|
||||
public StoryboardOverlay(MoveStoryboard msb, OptionsOverlay optionsOverlay, Game game) {
|
||||
this.msb = msb;
|
||||
this.optionsOverlay = optionsOverlay;
|
||||
this.game = game;
|
||||
@@ -78,18 +76,18 @@ public class StoryboardOverlay extends OverlayOpsuState implements OptionsOverla
|
||||
return;
|
||||
}
|
||||
int lh = Fonts.SMALL.getLineHeight();
|
||||
Fonts.SMALL.drawString(10, displayContainer.height - 50 + lh, "save position: ctrl+s, load position: ctrl+l", Color.cyan);
|
||||
Fonts.SMALL.drawString(10, displayContainer.height - 50, "speed: C " + (speed / 10f) + " V", Color.cyan);
|
||||
Fonts.SMALL.drawString(10, displayContainer.height - 50 - lh, "Menu: N", Color.cyan);
|
||||
Fonts.SMALL.drawString(10, displayContainer.height - 50 - lh * 2, "HIDE: H", Color.cyan);
|
||||
Fonts.SMALL.drawString(10, displayContainer.height - 50 - lh * 3, "obj: J " + index + " K", Color.cyan);
|
||||
Fonts.SMALL.drawString(10, height - 50 + lh, "save position: ctrl+s, load position: ctrl+l", Color.cyan);
|
||||
Fonts.SMALL.drawString(10, height - 50, "speed: C " + (speed / 10f) + " V", Color.cyan);
|
||||
Fonts.SMALL.drawString(10, height - 50 - lh, "Menu: N", Color.cyan);
|
||||
Fonts.SMALL.drawString(10, height - 50 - lh * 2, "HIDE: H", Color.cyan);
|
||||
Fonts.SMALL.drawString(10, height - 50 - lh * 3, "obj: J " + index + " K", Color.cyan);
|
||||
g.setColor(Color.red);
|
||||
if (index < optionsMap.length && optionsMap[index] != null) {
|
||||
int i = 0;
|
||||
for (Object o : optionsMap[index].entrySet()) {
|
||||
Map.Entry<Option, String> option = (Map.Entry<Option, String>) o;
|
||||
Fonts.SMALL.drawString(10, 50 + i * lh, option.getKey().name, Color.cyan);
|
||||
Fonts.SMALL.drawString(displayContainer.width / 5, 50 + i * lh, option.getKey().getValueString(), Color.cyan);
|
||||
Fonts.SMALL.drawString(width / 5, 50 + i * lh, option.getKey().getValueString(), Color.cyan);
|
||||
g.fillRect(0, 50 + i * lh + lh / 4, 10, 10);
|
||||
i++;
|
||||
}
|
||||
@@ -98,7 +96,7 @@ public class StoryboardOverlay extends OverlayOpsuState implements OptionsOverla
|
||||
int start = gameObjects[0].getTime();
|
||||
int end = gameObjects[gameObjects.length - 1].getEndTime();
|
||||
float curtime = (float) (MusicController.getPosition() - start) / (end - start);
|
||||
g.fillRect(curtime * displayContainer.width, displayContainer.height - 10f, 10f, 10f);
|
||||
g.fillRect(curtime * width, height - 10f, 10f, 10f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,54 +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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package yugecin.opsudance.utils;
|
||||
|
||||
import yugecin.opsudance.core.NotNull;
|
||||
import yugecin.opsudance.core.Nullable;
|
||||
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
public class ManifestWrapper {
|
||||
|
||||
@Nullable
|
||||
public final Manifest manifest;
|
||||
|
||||
public ManifestWrapper(@Nullable Manifest manifest) {
|
||||
this.manifest = manifest;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param attribute attribute in jarfile or null for default attributes
|
||||
*/
|
||||
public String valueOrDefault(@Nullable String attribute, @NotNull String key, @Nullable String dfault) {
|
||||
if (manifest == null) {
|
||||
return dfault;
|
||||
}
|
||||
Attributes attributes =
|
||||
attribute == null ? manifest.getMainAttributes() : manifest.getAttributes(attribute);
|
||||
if (attributes == null) {
|
||||
return dfault;
|
||||
}
|
||||
String val = attributes.getValue(key);
|
||||
if (val == null) {
|
||||
return dfault;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
}
|
||||
67
src/yugecin/opsudance/utils/SimpleVersion.java
Normal file
67
src/yugecin/opsudance/utils/SimpleVersion.java
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package yugecin.opsudance.utils;
|
||||
|
||||
import itdelatrisu.opsu.Utils;
|
||||
import yugecin.opsudance.core.NotNull;
|
||||
import yugecin.opsudance.core.Nullable;
|
||||
|
||||
public class SimpleVersion implements Comparable<SimpleVersion> {
|
||||
|
||||
@Nullable
|
||||
public static SimpleVersion parse(@NotNull String version) {
|
||||
int dashpos = version.indexOf('-');
|
||||
if (dashpos != -1) {
|
||||
version = version.substring(0, dashpos);
|
||||
}
|
||||
final String[] parts = version.split("\\.");
|
||||
if (parts.length < 3) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return new SimpleVersion(
|
||||
Integer.parseInt(parts[0]),
|
||||
Integer.parseInt(parts[1]),
|
||||
Integer.parseInt(parts[2])
|
||||
);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
final int major, minor, incremental;
|
||||
|
||||
public SimpleVersion(int major, int minor, int incremental) {
|
||||
this.major = major;
|
||||
this.minor = minor;
|
||||
this.incremental = incremental;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@NotNull SimpleVersion o) {
|
||||
return
|
||||
Utils.clamp(Integer.compare(major, o.major), -1, 1) * 100 +
|
||||
Utils.clamp(Integer.compare(minor, o.minor), -1, 1) * 10 +
|
||||
Utils.clamp(Integer.compare(incremental, o.incremental), -1, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "" + major + '.' + minor + '.' + incremental;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user