Merge branch 'master' into kockout-wdata

# Conflicts:
#	src/itdelatrisu/opsu/states/Game.java
#	src/itdelatrisu/opsu/states/Splash.java
This commit is contained in:
yugecin 2018-10-22 21:59:11 +02:00
commit 3d470cbe7a
145 changed files with 2112 additions and 1884 deletions

View File

@ -21,6 +21,7 @@ The images included in opsu! belong to their respective authors.
* kouyang * kouyang
* teinecthel * teinecthel
* Font Awesome by Dave Gandy - http://fontawesome.io * Font Awesome by Dave Gandy - http://fontawesome.io
* Chaaoos/C0N - the opsu!dance logo
Projects Projects
-------- --------
@ -32,5 +33,4 @@ The following projects were referenced in creating opsu!:
Theme Song Theme Song
---------- ----------
The theme song is "On the Bach" by Jingle Punks, from the [YouTube Audio Library] The theme song is "On the Bach" by Jingle Punks, from the [YouTube Audio Library](https://www.youtube.com/audiolibrary/music).
(https://www.youtube.com/audiolibrary/music).

View File

@ -2,7 +2,7 @@
**Table of contents** **Table of contents**
* [What](#What) - [Why](#why) - [Downloads](#downloads) - [Running](#running) - [Building a JAR](#building-a-jar) - [Credits](#credits) - [License](#license) * [What](#what) - [Why](#why) - [Downloads](#downloads) - [Running](#running) - [Building a JAR](#building-a-jar) - [Credits](#credits) - [License](#license)
What What
---- ----
@ -38,10 +38,7 @@ You should know how to do this. It's recommended to use a working directory like
### Using apache ant ### Using apache ant
Resolve dependencies first, use either: Resolve dependencies first by doing `ant mvnresolve` or `mvn initialize`
* `ant ivyresolve` to download dependencies using apache ivy
* `ant mvnresolve` to download dependencies using apache mvn
Then do `ant run` Then do `ant run`

View File

@ -1,9 +1,8 @@
<project name="opsu!dance" default="hi" xmlns:ivy="antlib:org.apache.ivy.ant"> <project name="opsu!dance" default="hi">
<property name="dir.src" value="${basedir}/src" /> <property name="dir.src" value="${basedir}/src" />
<property name="dir.lib" value="${basedir}/lib" /> <property name="dir.lib" value="${basedir}/lib" />
<property name="dir.mvnlibs" value="${basedir}/mvnlibs" /> <property name="dir.mvnlibs" value="${basedir}/mvnlibs" />
<property name="dir.ivylibs" value="${basedir}/ivylibs" />
<property name="dir.res" value="${basedir}/res" /> <property name="dir.res" value="${basedir}/res" />
<property name="dir.out" value="${basedir}/bin" /> <property name="dir.out" value="${basedir}/bin" />
@ -21,14 +20,12 @@
<echo> <echo>
ant clean --> clean the ant working dir ant clean --> clean the ant working dir
ant cleanlib --> clean the lib folder ant cleanlib --> clean the lib folder
ant ivyresolve --> resolve dependencies using ivy
ant mvnresolve --> resolve dependencies using mvn ant mvnresolve --> resolve dependencies using mvn
ant compile --> compile the code ant compile --> compile the code
ant run --> prepare to run and run ant run --> prepare to run and run
ant jar --> package a jar ant jar --> package a jar
resolve dependencies first resolve dependencies first (mvnresolve)
(using either mvnresolve or ivyresolve),
then run (code is compiled automatically when you run) then run (code is compiled automatically when you run)
</echo> </echo>
</target> </target>
@ -40,12 +37,6 @@ then run (code is compiled automatically when you run)
<target name="cleanlib" description="--> clean the lib folder"> <target name="cleanlib" description="--> clean the lib folder">
<delete dir="${dir.lib}" /> <delete dir="${dir.lib}" />
<delete dir="${dir.mvnlibs}" /> <delete dir="${dir.mvnlibs}" />
<delete dir="${dir.ivylibs}" />
</target>
<target name="ivyresolve" depends="cleanlib" description="--> resolve dependencies using ivy">
<ivy:retrieve pattern="${dir.ivylibs}/[artifact]-[revision](-[classifier]).[ext]" />
<move file="${dir.ivylibs}" tofile="${dir.lib}" />
</target> </target>
<target name="mvnresolve" depends="cleanlib" description="--> resolve dependencies using mvn"> <target name="mvnresolve" depends="cleanlib" description="--> resolve dependencies using mvn">
@ -119,9 +110,6 @@ then run (code is compiled automatically when you run)
<attribute name="Manifest-Version" value="1.0" /> <attribute name="Manifest-Version" value="1.0" />
<attribute name="Built-By" value="${user.name}" /> <attribute name="Built-By" value="${user.name}" />
<attribute name="Main-Class" value="${main}" /> <attribute name="Main-Class" value="${main}" />
<attribute name="WinNatives" value="OpenAL32.dll,OpenAL64.dll,lwjgl.dll,lwjgl64.dll" />
<attribute name="NixNatives" value="liblwjgl.so,liblwjgl64.so,libopenal.so,libopenal64.so" />
<attribute name="MacNatives" value="liblwjgl.dylib,openal.dylib" />
</manifest> </manifest>
<fileset dir="${dir.out}/classes" /> <fileset dir="${dir.out}/classes" />
<zipfileset src="${dir.out}/lib.jar"> <zipfileset src="${dir.out}/lib.jar">

38
ivy.xml
View File

@ -1,38 +0,0 @@
<ivy-module
version="2.0"
xmlns:extra="http://ant.apache.org/ivy/extra"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ant.apache.org/ivy/schemas/ivy.xsd">
<info organisation="yugecin.opsudance" module="opsu!dance" />
<dependencies defaultconfmapping="default">
<dependency org="org.lwjgl.lwjgl" name="lwjgl" rev="2.9.3">
<exclude module="jinput" />
</dependency>
<dependency org="org.lwjgl.lwjgl" name="lwjgl-platform" rev="2.9.3">
<artifact name="lwjgl-platform" type="jar" extra:classifier="natives-linux" />
<artifact name="lwjgl-platform" type="jar" extra:classifier="natives-osx" />
<artifact name="lwjgl-platform" type="jar" extra:classifier="natives-windows" />
</dependency>
<dependency org="org.slick2d" name="slick2d-core" rev="1.0.1">
<exclude module="jnlp" />
<exclude module="lwjgl" />
</dependency>
<dependency org="org.jcraft" name="jorbis" rev="0.0.17" />
<dependency org="net.lingala.zip4j" name="zip4j" rev="1.3.2" />
<dependency org="com.googlecode.soundlibs" name="mp3spi" rev="1.9.5.4">
<exclude module="junit" />
</dependency>
<dependency org="org.xerial" name="sqlite-jdbc" rev="3.8.10.2" />
<dependency org="org.json" name="json" rev="20140107" />
<dependency org="net.java.dev.jna" name="jna" rev="4.1.0" />
<dependency org="net.java.dev.jna" name="jna-platform" rev="4.1.0" />
<dependency org="org.apache.maven" name="maven-artifact" rev="3.3.3" />
<dependency org="org.apache.commons" name="commons-compress" rev="1.9" />
<dependency org="org.tukaani" name="xz" rev="1.5" />
<dependency org="com.github.jponge" name="lzma-java" rev="1.3" />
<dependency org="gov.nist.math" name="jama" rev="1.0.3" />
</dependencies>
</ivy-module>

13
pom.xml
View File

@ -8,12 +8,12 @@
<artifactId>opsu-dance</artifactId> <artifactId>opsu-dance</artifactId>
<version>0.5.0-SNAPSHOT</version> <version>0.5.0-SNAPSHOT</version>
<properties> <properties>
<nativesTargetDir>target/Natives</nativesTargetDir>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<version>${project.version}</version> <version>${project.version}</version>
<timestamp>${maven.build.timestamp}</timestamp> <timestamp>${maven.build.timestamp}</timestamp>
<maven.build.timestamp.format>yyyy-MM-dd HH:mm</maven.build.timestamp.format> <maven.build.timestamp.format>yyyy-MM-dd HH:mm</maven.build.timestamp.format>
<mainClassName>yugecin.opsudance.core.Entrypoint</mainClassName> <mainClassName>yugecin.opsudance.core.Entrypoint</mainClassName>
<XDG>false</XDG>
</properties> </properties>
<build> <build>
<sourceDirectory>src</sourceDirectory> <sourceDirectory>src</sourceDirectory>
@ -147,10 +147,6 @@
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries> <manifestEntries>
<Main-Class>${mainClassName}</Main-Class> <Main-Class>${mainClassName}</Main-Class>
<Use-XDG>${XDG}</Use-XDG>
<WinNatives>OpenAL32.dll,OpenAL64.dll,lwjgl.dll,lwjgl64.dll</WinNatives>
<NixNatives>liblwjgl.so,liblwjgl64.so,libopenal.so,libopenal64.so</NixNatives>
<MacNatives>liblwjgl.dylib,openal.dylib</MacNatives>
</manifestEntries> </manifestEntries>
</transformer> </transformer>
</transformers> </transformers>
@ -236,11 +232,6 @@
<artifactId>jna-platform</artifactId> <artifactId>jna-platform</artifactId>
<version>4.1.0</version> <version>4.1.0</version>
</dependency> </dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-artifact</artifactId>
<version>3.3.3</version>
</dependency>
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId> <artifactId>commons-compress</artifactId>
@ -263,4 +254,4 @@
</dependency> </dependency>
</dependencies> </dependencies>
</project> </project>

BIN
res/epiwarning.pdn Normal file

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 822 B

After

Width:  |  Height:  |  Size: 404 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 845 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 310 KiB

BIN
res/logo2piece.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 994 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

BIN
res/logo2pulse.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 162 B

After

Width:  |  Height:  |  Size: 116 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 328 KiB

BIN
res/menu-background.pdn Normal file

Binary file not shown.

BIN
res/menu-background.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

BIN
res/menu-options-1.pdn Normal file

Binary file not shown.

BIN
res/menu-options-2.pdn Normal file

Binary file not shown.

BIN
res/menu-options-3.pdn Normal file

Binary file not shown.

Binary file not shown.

BIN
res/menu-options.pdn Normal file

Binary file not shown.

BIN
res/menu-options.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 568 B

After

Width:  |  Height:  |  Size: 306 B

BIN
res/music-np-bg-black.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 420 B

BIN
res/music-np-bg-white.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 360 B

BIN
res/music-np.pdn Normal file

Binary file not shown.

BIN
res/music-np.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 238 B

After

Width:  |  Height:  |  Size: 253 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 522 B

After

Width:  |  Height:  |  Size: 346 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 572 B

After

Width:  |  Height:  |  Size: 318 B

BIN
res/music-stop.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 340 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 408 KiB

After

Width:  |  Height:  |  Size: 116 B

BIN
res/selection-mode-over.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
res/selection-mode.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 484 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 767 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 918 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 696 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -10,7 +10,7 @@ import itdelatrisu.opsu.objects.curves.Vec2f;
import org.newdawn.slick.Color; import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics; import org.newdawn.slick.Graphics;
import 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. * 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() { public FakeGameObject() {
this.start = new Vec2f(); this.start = new Vec2f();
this.end = new Vec2f(); this.end = new Vec2f();
this.start.x = this.end.x = displayContainer.width / 2; this.start.x = this.end.x = width2;
this.start.y = this.end.y = displayContainer.height / 2; this.start.y = this.end.y = height2;
} }
public FakeGameObject(GameObject start, GameObject end) { public FakeGameObject(GameObject start, GameObject end) {

View File

@ -131,6 +131,6 @@ public class CombinedSpiralMover extends Mover {
} }
private boolean checkBounds(double[] pos) { 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;
} }
} }

View File

@ -8,7 +8,7 @@ import yugecin.opsudance.movers.Mover;
import awlex.ospu.movers.SpiralToMover; import awlex.ospu.movers.SpiralToMover;
import yugecin.opsudance.movers.factories.MoverFactory; import yugecin.opsudance.movers.factories.MoverFactory;
import static yugecin.opsudance.core.InstanceContainer.displayContainer; import static yugecin.opsudance.core.InstanceContainer.*;
/** /**
* Created by Alex Wieser on 09.10.2016. * Created by Alex Wieser on 09.10.2016.
@ -88,7 +88,7 @@ public class SpiralMoverFactory implements MoverFactory {
* @return * @return
*/ */
private boolean checkBounds(double[] pos) { 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 @Override

View File

@ -43,18 +43,16 @@ public class SpiralSpinner extends Spinner {
double ang; double ang;
double rad; double rad;
for (int i = 0; i < SIZE / 2; i++) { 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); ang = (DENSITY * (Math.PI / SIZE) * i);
rad = (MAX_RAD / (SIZE / 2)) * i; rad = (MAX_RAD / (SIZE / 2)) * i;
int offsetX = displayContainer.width / 2;
int offsetY = displayContainer.height / 2;
points[SIZE / 2 - 1 - i] = new double[]{ points[SIZE / 2 - 1 - i] = new double[]{
offsetX + rad * Math.cos(ang), width2 + rad * Math.cos(ang),
offsetY + rad * Math.sin(ang) height2 + rad * Math.sin(ang)
}; };
points[SIZE / 2 + i] = new double[]{ points[SIZE / 2 + i] = new double[]{
offsetX + rad * (Math.cos(ang) * Math.cos(Math.PI) - Math.sin(ang) * Math.sin(Math.PI)), width2 + rad * (Math.cos(ang) * Math.cos(Math.PI) - Math.sin(ang) * Math.sin(Math.PI)),
offsetY + rad * -Math.sin(ang) height2 + rad * -Math.sin(ang)
}; };
} }
} }
@ -84,12 +82,12 @@ public class SpiralSpinner extends Spinner {
} }
private void rotatePointAroundCenter(double[] point, double beta) { private void rotatePointAroundCenter(double[] point, double beta) {
double angle = Math.atan2(point[1] - displayContainer.height / 2, point[0] - displayContainer.width / 2); double angle = Math.atan2(point[1] - height2, point[0] - width2);
double rad = Utils.distance(point[0], point[1], displayContainer.width / 2, displayContainer.height / 2); double rad = Utils.distance(point[0], point[1], width2, height2);
//rotationMatrix //rotationMatrix
point[0] = displayContainer.width / 2 + rad * (Math.cos(angle) * Math.cos(beta) - Math.sin(angle) * Math.sin(beta)); point[0] = width2 + 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[1] = height2 + rad * (Math.cos(angle) * Math.sin(beta) + Math.sin(angle) * Math.cos(beta));
} }

View File

@ -603,8 +603,6 @@ public class GameData {
*/ */
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public void drawGameElements(Graphics g, boolean breakPeriod, boolean firstObject, float alpha) { 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()); boolean relaxAutoPilot = (GameMod.RELAX.isActive() || GameMod.AUTOPILOT.isActive());
int margin = (int) (width * 0.008f); int margin = (int) (width * 0.008f);
float uiScale = GameImage.getUIscale(); float uiScale = GameImage.getUIscale();
@ -796,9 +794,6 @@ public class GameData {
* @param beatmap the beatmap * @param beatmap the beatmap
*/ */
public void drawRankingElements(Graphics g, Beatmap beatmap) { public void drawRankingElements(Graphics g, Beatmap beatmap) {
int width = displayContainer.width;
int height = displayContainer.height;
// TODO Version 2 skins // TODO Version 2 skins
float rankingHeight = 75; float rankingHeight = 75;
float scoreTextScale = 1.0f; float scoreTextScale = 1.0f;
@ -863,7 +858,7 @@ public class GameData {
if (comboMax == fullObjectCount) { if (comboMax == fullObjectCount) {
GameImage.RANKING_PERFECT.getImage().draw( GameImage.RANKING_PERFECT.getImage().draw(
width * 0.08f, 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) { if (hitResult.hitResultType == HitObjectType.SPINNER && hitResult.result != HIT_MISS) {
Image spinnerOsu = GameImage.SPINNER_OSU.getImage(); Image spinnerOsu = GameImage.SPINNER_OSU.getImage();
spinnerOsu.setAlpha(hitResult.alpha); spinnerOsu.setAlpha(hitResult.alpha);
spinnerOsu.drawCentered(displayContainer.width / 2, displayContainer.height / 4); spinnerOsu.drawCentered(width2, height / 4);
spinnerOsu.setAlpha(1f); spinnerOsu.setAlpha(1f);
} else if (OPTION_SHOW_HIT_LIGHTING.state && !hitResult.hideResult && hitResult.result != HIT_MISS && } else if (OPTION_SHOW_HIT_LIGHTING.state && !hitResult.hideResult && hitResult.result != HIT_MISS &&
// hit lighting // hit lighting
@ -1185,7 +1180,7 @@ public class GameData {
// combo burst // combo burst
if (comboBurstIndex > -1 && OPTION_SHOW_COMBO_BURSTS.state) { if (comboBurstIndex > -1 && OPTION_SHOW_COMBO_BURSTS.state) {
int leftX = 0; int leftX = 0;
int rightX = displayContainer.width - comboBurstImages[comboBurstIndex].getWidth(); int rightX = width - comboBurstImages[comboBurstIndex].getWidth();
if (comboBurstX < leftX) { if (comboBurstX < leftX) {
comboBurstX += (delta / 2f) * GameImage.getUIscale(); comboBurstX += (delta / 2f) * GameImage.getUIscale();
if (comboBurstX > leftX) if (comboBurstX > leftX)
@ -1246,7 +1241,7 @@ public class GameData {
} }
comboBurstAlpha = 0.8f; comboBurstAlpha = 0.8f;
if ((comboBurstIndex % 2) == 0) { if ((comboBurstIndex % 2) == 0) {
comboBurstX = displayContainer.width; comboBurstX = width;
} else { } else {
comboBurstX = comboBurstImages[0].getWidth() * -1; comboBurstX = comboBurstImages[0].getWidth() * -1;
} }

View File

@ -18,7 +18,6 @@
package itdelatrisu.opsu; package itdelatrisu.opsu;
import itdelatrisu.opsu.ui.Colors;
import itdelatrisu.opsu.ui.Fonts; import itdelatrisu.opsu.ui.Fonts;
import java.io.File; import java.io.File;
@ -31,10 +30,11 @@ import org.newdawn.slick.SlickException;
import org.newdawn.slick.util.Log; import org.newdawn.slick.util.Log;
import org.newdawn.slick.util.ResourceLoader; import org.newdawn.slick.util.ResourceLoader;
import yugecin.opsudance.core.errorhandling.ErrorHandler; import yugecin.opsudance.core.errorhandling.ErrorHandler;
import yugecin.opsudance.events.BubNotifListener;
import yugecin.opsudance.skinning.SkinService; import yugecin.opsudance.skinning.SkinService;
import yugecin.opsudance.utils.SlickUtil; import yugecin.opsudance.utils.SlickUtil;
import static itdelatrisu.opsu.ui.Colors.*;
import static yugecin.opsudance.core.InstanceContainer.*;
import static yugecin.opsudance.options.Options.*; import static yugecin.opsudance.options.Options.*;
/** /**
@ -90,7 +90,9 @@ public enum GameImage {
PLAYFIELD ("playfield", "png|jpg", false, false) { PLAYFIELD ("playfield", "png|jpg", false, false) {
@Override @Override
protected Image process_sub(Image img, int w, int h) { 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); return img.getScaledCopy(w, h);
} }
}, },
@ -230,14 +232,14 @@ public enum GameImage {
MOD_AUTOPILOT ("selection-mod-relax2", "png", false, false), MOD_AUTOPILOT ("selection-mod-relax2", "png", false, false),
// Selection Buttons // 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 ("selection-mods", "png", false, false),
SELECTION_MODS_OVERLAY ("selection-mods-over", "png", false, false), SELECTION_MODS_OVERLAY ("selection-mods-over", "png", false, false),
SELECTION_RANDOM ("selection-random", "png", false, false), SELECTION_RANDOM ("selection-random", "png", false, false),
SELECTION_RANDOM_OVERLAY ("selection-random-over", "png", false, false), SELECTION_RANDOM_OVERLAY ("selection-random-over", "png", false, false),
SELECTION_OPTIONS ("selection-options", "png", false, false), SELECTION_OPTIONS ("selection-options", "png", false, false),
SELECTION_OPTIONS_OVERLAY ("selection-options-over", "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 Speed Buttons
REPLAY_PLAYBACK_NORMAL ("playback-normal", "png", false, false), REPLAY_PLAYBACK_NORMAL ("playback-normal", "png", false, false),
@ -299,25 +301,37 @@ public enum GameImage {
MENU_LOGO ("logo2", "png", false, true) { MENU_LOGO ("logo2", "png", false, true) {
@Override @Override
protected Image process_sub(Image img, int w, int h) { 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 @Override
protected Image process_sub(Image img, int w, int h) { 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 @Override
protected Image process_sub(Image img, int w, int h) { 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 @Override
protected Image process_sub(Image img, int w, int h) { 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), MENU_BUTTON_MID ("button-middle", "png", false, false),
@ -326,21 +340,25 @@ public enum GameImage {
STAR ("star", "png", false, false) { STAR ("star", "png", false, false) {
@Override @Override
protected Image process_sub(Image img, int w, int h) { 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) { STAR2 ("star2", "png", false, false) {
@Override @Override
protected Image process_sub(Image img, int w, int h) { 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 Player Buttons
MUSIC_PLAY ("music-play", "png", false, false), MUSIC_PLAY ("music-play", "png", false, false),
MUSIC_PAUSE ("music-pause", "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_NEXT ("music-next", "png", false, false),
MUSIC_PREVIOUS ("music-previous", "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) { DOWNLOADS ("downloads", "png", false, false) {
@Override @Override
@ -386,13 +404,6 @@ public enum GameImage {
return img.getScaledCopy((h / 14f) / img.getHeight()); 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_DOWN ("chevron-down", "png", false, false),
CHEVRON_RIGHT ("chevron-right", "png", false, false), CHEVRON_RIGHT ("chevron-right", "png", false, false),
@ -646,6 +657,30 @@ public enum GameImage {
return (skinImage != null) ? skinImage : defaultImage; 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. * Returns an Animation based on the image array.
* If no image array exists, returns the single image as an animation. * 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); String err = String.format("Could not find default image '%s'.", filename);
Log.warn(err); 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); img = img.getScaledCopy(0.5f);
list.add(img); list.add(img);
} catch (SlickException e) { } catch (SlickException e) {
BubNotifListener.EVENT.make().onBubNotif( bubNotifs.sendf(BUB_RED, "Failed to set image '%s'.", name);
String.format("Failed to set image '%s'.", name), Colors.BUB_RED);
break; break;
} }
} }
@ -834,8 +868,7 @@ public enum GameImage {
img = img.getScaledCopy(0.5f); img = img.getScaledCopy(0.5f);
return img; return img;
} catch (SlickException e) { } catch (SlickException e) {
BubNotifListener.EVENT.make().onBubNotif( bubNotifs.sendf(BUB_RED, "Failed to set image '%s'.", filename);
String.format("Failed to set image '%s'.", filename), Colors.BUB_RED);
} }
} }
return null; return null;

View File

@ -100,7 +100,7 @@ public enum GameMod {
*/ */
public void init(int width, int height) { public void init(int width, int height) {
float multY = Fonts.LARGE.getLineHeight() * 2 + height * 0.06f; 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.x = width / 30f;
this.y = multY + Fonts.LARGE.getLineHeight() * 3f + offsetY * index; this.y = multY + Fonts.LARGE.getLineHeight() * 3f + offsetY * index;
} }
@ -193,7 +193,7 @@ public enum GameMod {
// create buttons // create buttons
float baseX = Category.EASY.getX() + Fonts.LARGE.getWidth(Category.EASY.getName()) * 1.25f; 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()) { for (GameMod mod : GameMod.values()) {
Image img = mod.image.getImage(); Image img = mod.image.getImage();
mod.button = new MenuButton(img, mod.button = new MenuButton(img,

View File

@ -19,7 +19,6 @@
package itdelatrisu.opsu; package itdelatrisu.opsu;
import org.newdawn.slick.util.Log; import org.newdawn.slick.util.Log;
import yugecin.opsudance.utils.ManifestWrapper;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -50,42 +49,32 @@ public class NativeLoader {
* Unpacks natives for the current operating system to the natives directory. * Unpacks natives for the current operating system to the natives directory.
* @throws IOException if an I/O exception occurs * @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()) { if (!config.NATIVE_DIR.exists() && !config.NATIVE_DIR.mkdir()) {
String msg = String.format("Could not create folder '%s'", String msg = String.format("Could not create folder '%s'",
config.NATIVE_DIR.getAbsolutePath()); config.NATIVE_DIR.getAbsolutePath());
throw new RuntimeException(msg); throw new RuntimeException(msg);
} }
String osName = System.getProperty("os.name"); final String osName = System.getProperty("os.name");
String nativekey = null; final String[] files;
if (osName.startsWith("Win")) { if (osName.startsWith("Win")) {
nativekey = "WinNatives"; files = new String[] { "OpenAL32.dll", "OpenAL64.dll", "lwjgl.dll", "lwjgl64.dll" };
} else if (osName.startsWith("Linux")) { } 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")) { } else if (osName.startsWith("Mac") || osName.startsWith("Darwin")) {
nativekey = "MacNatives"; files = new String[] { "liblwjgl.dylib", "openal.dylib" };
} } else {
if (nativekey == null) {
Log.warn("Cannot determine natives for os " + osName); Log.warn("Cannot determine natives for os " + osName);
return; return;
} }
String natives = manifest.valueOrDefault(null, nativekey, null); for (String file : files) {
if (natives == null) { File unpackedFile = new File(config.NATIVE_DIR, file);
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);
if (unpackedFile.exists()) { if (unpackedFile.exists()) {
continue; continue;
} }
Utils.unpackFromJar(jarfile, unpackedFile, nativefile); Utils.unpackFromJar(jarfile, unpackedFile, file);
} }
} }

View File

@ -101,7 +101,7 @@ public class ScoreData implements Comparable<ScoreData> {
baseX = containerWidth * 0.01f; baseX = containerWidth * 0.01f;
baseY = topY; baseY = topY;
buttonWidth = containerWidth * 0.4f; 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); buttonHeight = Math.max(gradeHeight, Fonts.DEFAULT.getLineHeight() * 3.03f);
buttonOffset = buttonHeight + gradeHeight / 10f; buttonOffset = buttonHeight + gradeHeight / 10f;
buttonAreaHeight = (SongMenu.MAX_SCORE_BUTTONS - 1) * buttonOffset + buttonHeight; buttonAreaHeight = (SongMenu.MAX_SCORE_BUTTONS - 1) * buttonOffset + buttonHeight;

View File

@ -464,8 +464,8 @@ public class Utils {
*/ */
public static int getRegion(double x, double y) { public static int getRegion(double x, double y) {
int q = 0; int q = 0;
if (y < displayContainer.height / 2d) q = 2; if (y < height2) q = 2;
if (x < displayContainer.width / 2d) q |= 1; if (x < width2) q |= 1;
return q; return q;
} }
@ -483,24 +483,24 @@ public class Utils {
*/ */
public static float[] mirrorPoint(float x, float y) { public static float[] mirrorPoint(float x, float y) {
double dx = x - displayContainer.width / 2d; double dx = x - width2;
double dy = y - displayContainer.height / 2d; double dy = y - height2;
double ang = Math.atan2(dy, dx); double ang = Math.atan2(dy, dx);
double d = -Math.sqrt(dx * dx + dy * dy); double d = -Math.sqrt(dx * dx + dy * dy);
return new float[]{ return new float[]{
(float) (displayContainer.width / 2d + Math.cos(ang) * d), (float) (width2 + Math.cos(ang) * d),
(float) (displayContainer.height / 2d + Math.sin(ang) * d) (float) (height2 + Math.sin(ang) * d)
}; };
} }
public static float[] mirrorPoint(float x, float y, float degrees) { public static float[] mirrorPoint(float x, float y, float degrees) {
double dx = x - displayContainer.width / 2d; double dx = x - width2;
double dy = y - displayContainer.height / 2d; double dy = y - height2;
double ang = Math.atan2(dy, dx) + (degrees * Math.PI / 180d); double ang = Math.atan2(dy, dx) + (degrees * Math.PI / 180d);
double d = Math.sqrt(dx * dx + dy * dy); double d = Math.sqrt(dx * dx + dy * dy);
return new float[]{ return new float[]{
(float) (displayContainer.width / 2d + Math.cos(ang) * d), (float) (width2 + Math.cos(ang) * d),
(float) (displayContainer.height / 2d + Math.sin(ang) * d) (float) (height2 + Math.sin(ang) * d)
}; };
} }

View File

@ -22,6 +22,7 @@ import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.beatmap.Beatmap; import itdelatrisu.opsu.beatmap.Beatmap;
import itdelatrisu.opsu.beatmap.TimingPoint; import itdelatrisu.opsu.beatmap.TimingPoint;
import itdelatrisu.opsu.states.Game; import itdelatrisu.opsu.states.Game;
import yugecin.opsudance.options.Options;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -33,7 +34,6 @@ import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioSystem; import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException; import javax.sound.sampled.UnsupportedAudioFileException;
import itdelatrisu.opsu.ui.Colors;
import org.lwjgl.BufferUtils; import org.lwjgl.BufferUtils;
import org.lwjgl.openal.AL; import org.lwjgl.openal.AL;
import org.lwjgl.openal.AL10; 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.Log;
import org.newdawn.slick.util.ResourceLoader; import org.newdawn.slick.util.ResourceLoader;
import org.tritonus.share.sampled.file.TAudioFileFormat; 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.errorhandling.ErrorHandler.*;
import static yugecin.opsudance.core.InstanceContainer.*;
import static yugecin.opsudance.options.Options.*; import static yugecin.opsudance.options.Options.*;
/** /**
@ -103,8 +103,7 @@ public class MusicController {
if (lastBeatmap == null || !beatmap.audioFilename.equals(lastBeatmap.audioFilename)) { if (lastBeatmap == null || !beatmap.audioFilename.equals(lastBeatmap.audioFilename)) {
final File audioFile = beatmap.audioFilename; final File audioFile = beatmap.audioFilename;
if (!audioFile.isFile() && !ResourceLoader.resourceExists(audioFile.getPath())) { if (!audioFile.isFile() && !ResourceLoader.resourceExists(audioFile.getPath())) {
BarNotifListener.EVENT.make().onBarNotif(String.format("Could not find track '%s'.", barNotifs.sendf("Could not find track '%s'.", audioFile.getName());
audioFile.getName()));
return; return;
} }
@ -159,7 +158,7 @@ public class MusicController {
} catch (Exception e) { } catch (Exception e) {
String err = String.format("Could not play track '%s'.", file.getName()); String err = String.format("Could not play track '%s'.", file.getName());
Log.error(err, e); 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); 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. * Gets the progress of the current measure.
* @return a measure progress value [0,1) where 0 marks the start of the measure and * @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. * If no track is loaded, 0 will be returned.
*/ */
public static int getPosition() { public static int getPosition() {
int offset = OPTION_MUSIC_OFFSET.val;
if (lastBeatmap != null)
offset += lastBeatmap.localMusicOffset;
if (isPlaying()) if (isPlaying())
return (int) (player.getPosition() * 1000 + OPTION_MUSIC_OFFSET.val + Game.currentMapMusicOffset); return (int) (player.getPosition() * 1000 + offset);
else if (isPaused()) 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 else
return 0; return 0;
} }

View File

@ -36,15 +36,14 @@ import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineListener; import javax.sound.sampled.LineListener;
import javax.sound.sampled.LineUnavailableException; import javax.sound.sampled.LineUnavailableException;
import itdelatrisu.opsu.ui.Colors;
import org.newdawn.slick.SlickException; import org.newdawn.slick.SlickException;
import org.newdawn.slick.util.ResourceLoader; import org.newdawn.slick.util.ResourceLoader;
import yugecin.opsudance.events.BarNotifListener;
import yugecin.opsudance.events.BubNotifListener;
import yugecin.opsudance.options.Configuration; import yugecin.opsudance.options.Configuration;
import yugecin.opsudance.skinning.SkinService; import yugecin.opsudance.skinning.SkinService;
import static itdelatrisu.opsu.ui.Colors.*;
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*; import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
import static yugecin.opsudance.core.InstanceContainer.*;
import static yugecin.opsudance.options.Options.*; import static yugecin.opsudance.options.Options.*;
/** /**
@ -220,8 +219,8 @@ public class SoundController {
// menu and game sounds // menu and game sounds
for (SoundEffect s : SoundEffect.values()) { for (SoundEffect s : SoundEffect.values()) {
if ((currentFileName = getSoundFileName(s.getFileName())) == null) { if ((currentFileName = getSoundFileName(s.getFileName())) == null) {
BubNotifListener.EVENT.make().onBubNotif( final String name = s.getFileName();
"Could not find sound file " + s.getFileName(), Colors.BUB_ORANGE); bubNotifs.send(BUB_ORANGE, "Could not find sound file " + name);
continue; continue;
} }
MultiClip newClip = loadClip(currentFileName, currentFileName.endsWith(".mp3")); MultiClip newClip = loadClip(currentFileName, currentFileName.endsWith(".mp3"));
@ -240,8 +239,10 @@ public class SoundController {
for (HitSound s : HitSound.values()) { for (HitSound s : HitSound.values()) {
String filename = String.format("%s-%s", ss.getName(), s.getFileName()); String filename = String.format("%s-%s", ss.getName(), s.getFileName());
if ((currentFileName = getSoundFileName(filename)) == null) { if ((currentFileName = getSoundFileName(filename)) == null) {
BubNotifListener.EVENT.make().onBubNotif( bubNotifs.send(
"Could not find hit sound file " + filename, Colors.BUB_ORANGE); BUB_ORANGE,
"Could not find hit sound file " + filename
);
continue; continue;
} }
MultiClip newClip = loadClip(currentFileName, false); MultiClip newClip = loadClip(currentFileName, false);
@ -398,8 +399,7 @@ public class SoundController {
@Override @Override
public void error() { public void error() {
BarNotifListener.EVENT.make().onBarNotif( barNotifs.send("Failed to download track preview");
"Failed to download track preview");
} }
}); });
try { try {

View File

@ -89,6 +89,9 @@ public class Beatmap implements Comparable<Beatmap> {
/** The last time this beatmap was played (timestamp). */ /** The last time this beatmap was played (timestamp). */
public long lastPlayed = 0; public long lastPlayed = 0;
/** The local music offset. */
public int localMusicOffset = 0;
/** /**
* [General] * [General]
*/ */

View File

@ -31,13 +31,12 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import itdelatrisu.opsu.ui.Colors;
import org.newdawn.slick.Color; import org.newdawn.slick.Color;
import org.newdawn.slick.util.Log; import org.newdawn.slick.util.Log;
import yugecin.opsudance.core.Nullable; import yugecin.opsudance.core.Nullable;
import yugecin.opsudance.events.BubNotifListener;
import yugecin.opsudance.skinning.SkinService; import yugecin.opsudance.skinning.SkinService;
import static itdelatrisu.opsu.ui.Colors.*;
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*; import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
import static yugecin.opsudance.core.InstanceContainer.*; import static yugecin.opsudance.core.InstanceContainer.*;
import static yugecin.opsudance.options.Options.*; import static yugecin.opsudance.options.Options.*;
@ -890,7 +889,7 @@ public class BeatmapParser {
private static void logAndShowErrorNotification(Exception e, String message, Object... formatArgs) { private static void logAndShowErrorNotification(Exception e, String message, Object... formatArgs) {
message = String.format(message, formatArgs); message = String.format(message, formatArgs);
Log.error(message, e); Log.error(message, e);
BubNotifListener.EVENT.make().onBubNotif(message, Colors.BUB_RED); bubNotifs.send(BUB_RED, message);
} }
} }

View File

@ -21,8 +21,6 @@ package itdelatrisu.opsu.beatmap;
import itdelatrisu.opsu.Utils; import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.audio.MusicController; import itdelatrisu.opsu.audio.MusicController;
import itdelatrisu.opsu.db.BeatmapDB; import itdelatrisu.opsu.db.BeatmapDB;
import itdelatrisu.opsu.ui.Colors;
import yugecin.opsudance.events.BubNotifListener;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -36,6 +34,9 @@ import java.util.LinkedList;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; 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. * Indexed, expanding, doubly-linked list data type for song groups.
*/ */
@ -215,7 +216,7 @@ public class BeatmapSetList {
try { try {
Utils.deleteToTrash(dir); Utils.deleteToTrash(dir);
} catch (IOException e) { } 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) if (ws != null)
ws.resume(); ws.resume();
@ -271,7 +272,7 @@ public class BeatmapSetList {
try { try {
Utils.deleteToTrash(file); Utils.deleteToTrash(file);
} catch (IOException e) { } 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) if (ws != null)
ws.resume(); ws.resume();

View File

@ -38,11 +38,9 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import itdelatrisu.opsu.ui.Colors;
import org.newdawn.slick.util.Log; 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.core.InstanceContainer.*;
import static yugecin.opsudance.options.Options.*; import static yugecin.opsudance.options.Options.*;
@ -101,7 +99,7 @@ public class BeatmapWatchService {
ws.register(config.beatmapDir.toPath()); ws.register(config.beatmapDir.toPath());
} catch (IOException e) { } catch (IOException e) {
Log.error("Could not create watch service", 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; return;
} }
@ -124,7 +122,7 @@ public class BeatmapWatchService {
} catch (IOException e) { } catch (IOException e) {
String msg = "An I/O exception occurred while closing the previous watch service."; String msg = "An I/O exception occurred while closing the previous watch service.";
Log.error(msg, e); Log.error(msg, e);
BarNotifListener.EVENT.make().onBarNotif(msg); barNotifs.send(msg);
ws = null; ws = null;
} }
} }

View File

@ -240,7 +240,7 @@ public class HitObject {
String[] edgeHitSoundTokens = tokens[8].split("\\|"); String[] edgeHitSoundTokens = tokens[8].split("\\|");
this.edgeHitSound = new byte[edgeHitSoundTokens.length]; this.edgeHitSound = new byte[edgeHitSoundTokens.length];
for (int j = 0; j < edgeHitSoundTokens.length; j++) 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) { if (tokens.length > 9) {
String[] edgeAdditionTokens = tokens[9].split("\\|"); String[] edgeAdditionTokens = tokens[9].split("\\|");

View File

@ -23,12 +23,11 @@ import java.io.FilenameFilter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import itdelatrisu.opsu.ui.Colors;
import net.lingala.zip4j.core.ZipFile; import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException; import net.lingala.zip4j.exception.ZipException;
import org.newdawn.slick.util.Log; import org.newdawn.slick.util.Log;
import yugecin.opsudance.events.BubNotifListener;
import static itdelatrisu.opsu.ui.Colors.*;
import static yugecin.opsudance.core.InstanceContainer.*; import static yugecin.opsudance.core.InstanceContainer.*;
/** /**
@ -97,7 +96,7 @@ public class OszUnpacker {
} catch (ZipException e) { } catch (ZipException e) {
String err = String.format("Failed to unzip file %s to dest %s.", file.getAbsolutePath(), dest.getAbsolutePath()); String err = String.format("Failed to unzip file %s to dest %s.", file.getAbsolutePath(), dest.getAbsolutePath());
Log.error(err, e); Log.error(err, e);
BubNotifListener.EVENT.make().onBubNotif(err, Colors.BUB_RED); bubNotifs.send(BUB_RED, err);
} }
} }

View File

@ -20,6 +20,7 @@ package itdelatrisu.opsu.db;
import itdelatrisu.opsu.beatmap.Beatmap; import itdelatrisu.opsu.beatmap.Beatmap;
import itdelatrisu.opsu.beatmap.BeatmapParser; import itdelatrisu.opsu.beatmap.BeatmapParser;
import yugecin.opsudance.core.errorhandling.ErrorHandler;
import java.io.File; import java.io.File;
import java.sql.Connection; import java.sql.Connection;
@ -47,7 +48,7 @@ public class BeatmapDB {
* This value should be changed whenever the database format changes. * This value should be changed whenever the database format changes.
* Add any update queries to the {@link #getUpdateQueries(int)} method. * 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 * 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("ALTER TABLE beatmaps ADD COLUMN lastPlayed INTEGER");
list.add("UPDATE beatmaps SET dateAdded = 0, favorite = 0, playCount = 0, lastPlayed = 0"); 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 */ /* add future updates here */
@ -85,7 +90,7 @@ public class BeatmapDB {
/** Query statements. */ /** Query statements. */
private static PreparedStatement private static PreparedStatement
insertStmt, selectStmt, deleteMapStmt, deleteGroupStmt, insertStmt, selectStmt, deleteMapStmt, deleteGroupStmt,
setStarsStmt, updatePlayStatsStmt, setFavoriteStmt, updateSizeStmt; setStarsStmt, updatePlayStatsStmt, setFavoriteStmt, setLocalOffsetStmt, updateSizeStmt;
/** Current size of beatmap cache table. */ /** Current size of beatmap cache table. */
private static int cacheSize = -1; private static int cacheSize = -1;
@ -121,7 +126,7 @@ public class BeatmapDB {
"INSERT INTO beatmaps VALUES (" + "INSERT INTO beatmaps VALUES (" +
"?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?," + "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?," +
"?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?," + "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?," +
"?, ?, ?, ?, ?, ?" + "?, ?, ?, ?, ?, ?, ?" +
")" ")"
); );
selectStmt = connection.prepareStatement("SELECT * FROM beatmaps WHERE dir = ? AND file = ?"); 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 = ?"); setStarsStmt = connection.prepareStatement("UPDATE beatmaps SET stars = ? WHERE dir = ? AND file = ?");
updatePlayStatsStmt = connection.prepareStatement("UPDATE beatmaps SET playCount = ?, lastPlayed = ? 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 = ?"); 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) { } catch (SQLException e) {
explode("Failed to prepare beatmap statements.", e, DEFAULT_OPTIONS); explode("Failed to prepare beatmap statements.", e, DEFAULT_OPTIONS);
} }
@ -153,7 +159,7 @@ public class BeatmapDB {
"mode INTEGER, letterboxInBreaks BOOLEAN, widescreenStoryboard BOOLEAN, epilepsyWarning BOOLEAN, " + "mode INTEGER, letterboxInBreaks BOOLEAN, widescreenStoryboard BOOLEAN, epilepsyWarning BOOLEAN, " +
"bg TEXT, sliderBorder TEXT, timingPoints TEXT, breaks TEXT, combo TEXT, " + "bg TEXT, sliderBorder TEXT, timingPoints TEXT, breaks TEXT, combo TEXT, " +
"md5hash TEXT, stars REAL, " + "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 (" + "CREATE TABLE IF NOT EXISTS info (" +
"key TEXT NOT NULL UNIQUE, value TEXT" + "key TEXT NOT NULL UNIQUE, value TEXT" +
@ -402,6 +408,7 @@ public class BeatmapDB {
stmt.setBoolean(44, beatmap.favorite); stmt.setBoolean(44, beatmap.favorite);
stmt.setInt(45, beatmap.playCount); stmt.setInt(45, beatmap.playCount);
stmt.setLong(46, beatmap.lastPlayed); stmt.setLong(46, beatmap.lastPlayed);
stmt.setInt(47, beatmap.localMusicOffset);
} catch (SQLException e) { } catch (SQLException e) {
throw e; throw e;
} catch (Exception e) { } catch (Exception e) {
@ -549,6 +556,7 @@ public class BeatmapDB {
beatmap.favorite = rs.getBoolean(44); beatmap.favorite = rs.getBoolean(44);
beatmap.playCount = rs.getInt(45); beatmap.playCount = rs.getInt(45);
beatmap.lastPlayed = rs.getLong(46); beatmap.lastPlayed = rs.getLong(46);
beatmap.localMusicOffset = rs.getInt(47);
} catch (SQLException e) { } catch (SQLException e) {
throw e; throw e;
} catch (Exception 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. * Closes the connection to the database.
*/ */

View File

@ -33,10 +33,10 @@ import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.StandardCopyOption; import java.nio.file.StandardCopyOption;
import itdelatrisu.opsu.ui.Colors;
import org.newdawn.slick.util.Log; 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.*; import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
/** /**
@ -220,7 +220,7 @@ public class Download {
else if (redirectCount > MAX_REDIRECTS) else if (redirectCount > MAX_REDIRECTS)
error = String.format("Download for URL '%s' is attempting too many redirects (over %d).", base.toString(), MAX_REDIRECTS); error = String.format("Download for URL '%s' is attempting too many redirects (over %d).", base.toString(), MAX_REDIRECTS);
if (error != null) { if (error != null) {
BubNotifListener.EVENT.make().onBubNotif(error, Colors.BUB_ORANGE); bubNotifs.send(BUB_ORANGE, error);
throw new IOException(); throw new IOException();
} }

View File

@ -33,9 +33,8 @@ import java.io.File;
import org.newdawn.slick.Color; import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics; import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image; 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.core.InstanceContainer.*;
import static yugecin.opsudance.options.Options.*; 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) * @param index the index (to offset the button from the topmost button)
*/ */
public static boolean resultIconContains(float cx, float cy, int index) { 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 x = buttonBaseX + buttonWidth * 0.001f;
float y = buttonBaseY + (index * buttonOffset) + buttonHeight / 2f; float y = buttonBaseY + (index * buttonOffset) + buttonHeight / 2f;
return ((cx > x && cx < x + iconWidth) && 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) * @param index the index (to offset the button from the topmost button)
*/ */
public static boolean downloadIconContains(float cx, float cy, int index) { 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 edgeX = infoBaseX + infoWidth * 0.985f;
float y = infoBaseY + (index * infoHeight); float y = infoBaseY + (index * infoHeight);
float marginY = infoHeight * 0.04f; float marginY = infoHeight * 0.04f;
@ -280,14 +279,12 @@ public class DownloadNode {
download.setListener(new DownloadListener() { download.setListener(new DownloadListener() {
@Override @Override
public void completed() { public void completed() {
BarNotifListener.EVENT.make().onBarNotif( barNotifs.sendf("Download complete: %s", getTitle());
String.format("Download complete: %s", getTitle()));
} }
@Override @Override
public void error() { public void error() {
BarNotifListener.EVENT.make().onBarNotif( barNotifs.send("Download failed due to a connection error.");
"Download failed due to a connection error.");
} }
}); });
this.download = download; this.download = download;
@ -409,9 +406,10 @@ public class DownloadNode {
public void drawDownload(Graphics g, float position, int id, boolean hover) { public void drawDownload(Graphics g, float position, int id, boolean hover) {
Download download = this.download; // in case clearDownload() is called asynchronously Download download = this.download; // in case clearDownload() is called asynchronously
if (download == null) { if (download == null) {
BubNotifListener.EVENT.make().onBubNotif( bubNotifs.send(
"Trying to draw download information for button without Download object", BUB_ORANGE,
Colors.BUB_ORANGE); "Trying to draw download information for button without Download object"
);
return; return;
} }

View File

@ -32,11 +32,10 @@ import java.util.Date;
import java.util.Locale; import java.util.Locale;
import java.util.Properties; import java.util.Properties;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.newdawn.slick.util.Log; import org.newdawn.slick.util.Log;
import org.newdawn.slick.util.ResourceLoader; import org.newdawn.slick.util.ResourceLoader;
import yugecin.opsudance.core.Constants; 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.errorhandling.ErrorHandler.*;
import static yugecin.opsudance.core.InstanceContainer.*; import static yugecin.opsudance.core.InstanceContainer.*;
@ -92,7 +91,7 @@ public class Updater {
private Status status; private Status status;
/** The current and latest versions. */ /** The current and latest versions. */
private DefaultArtifactVersion currentVersion, latestVersion; private SimpleVersion currentVersion, latestVersion;
/** The version information if the program was just updated. */ /** The version information if the program was just updated. */
private String updatedFromVersion, updatedToVersion; private String updatedFromVersion, updatedToVersion;
@ -107,7 +106,7 @@ public class Updater {
if (currentVersion == null) { if (currentVersion == null) {
return "unknown version"; return "unknown version";
} }
return currentVersion.getMajorVersion() + "." + currentVersion.getMinorVersion() + "." + currentVersion.getIncrementalVersion(); return currentVersion.toString();
} }
public Updater() { public Updater() {
@ -182,13 +181,13 @@ public class Updater {
* @param props the set of properties * @param props the set of properties
* @return the version, or null if not found * @return the version, or null if not found
*/ */
private DefaultArtifactVersion getVersion(Properties props) { private SimpleVersion getVersion(Properties props) {
String version = props.getProperty("version"); final String version = props.getProperty("version");
if (version == null || version.equals("${pom.version}")) { if (version != null && !version.equals("${pom.version}")) {
status = Status.INTERNAL_ERROR; return SimpleVersion.parse(version);
return null; }
} else this.status = Status.INTERNAL_ERROR;
return new DefaultArtifactVersion(version); return null;
} }
/** /**
@ -196,7 +195,7 @@ public class Updater {
* @throws IOException if an I/O exception occurs * @throws IOException if an I/O exception occurs
*/ */
public void checkForUpdates() throws IOException { public void checkForUpdates() throws IOException {
if (status != Status.INITIAL || config.USE_XDG) if (status != Status.INITIAL)
return; return;
status = Status.CHECKING; status = Status.CHECKING;
@ -241,14 +240,13 @@ public class Updater {
@Override @Override
public void completed() { public void completed() {
status = Status.UPDATE_DOWNLOADED; status = Status.UPDATE_DOWNLOADED;
BarNotifListener.EVENT.make().onBarNotif("Update has finished downloading"); barNotifs.send("Update has finished downloading");
} }
@Override @Override
public void error() { public void error() {
status = Status.CONNECTION_ERROR; status = Status.CONNECTION_ERROR;
BarNotifListener.EVENT.make().onBarNotif( barNotifs.send("Update failed due to a connection error.");
"Update failed due to a connection error.");
} }
}); });
} }

View File

@ -370,13 +370,13 @@ public class Slider extends GameObject {
float followCircleScale = 1f + (tickExpandTime / (float) TICK_EXPAND_TIME) * 0.1f; float followCircleScale = 1f + (tickExpandTime / (float) TICK_EXPAND_TIME) * 0.1f;
float followAlpha = 1f; float followAlpha = 1f;
if (followCircleActive && followExpandTime < FOLLOW_EXPAND_TIME) { if (followCircleActive && followExpandTime < FOLLOW_EXPAND_TIME) {
followExpandTime += displayContainer.renderDelta; followExpandTime += renderDelta;
followCircleScale *= 0.5f; followCircleScale *= 0.5f;
float progress = AnimationEquation.OUT_QUAD.calc((float) followExpandTime / FOLLOW_EXPAND_TIME); float progress = AnimationEquation.OUT_QUAD.calc((float) followExpandTime / FOLLOW_EXPAND_TIME);
followCircleScale = followCircleScale + followCircleScale * progress; followCircleScale = followCircleScale + followCircleScale * progress;
followAlpha = progress; followAlpha = progress;
} else if (!followCircleActive) { } else if (!followCircleActive) {
followExpandTime -= displayContainer.renderDelta; followExpandTime -= renderDelta;
if (followExpandTime > FOLLOW_SHRINK_TIME) { if (followExpandTime > FOLLOW_SHRINK_TIME) {
followExpandTime = FOLLOW_SHRINK_TIME; followExpandTime = FOLLOW_SHRINK_TIME;
} }
@ -391,7 +391,7 @@ public class Slider extends GameObject {
float oldAlphaBlack = Colors.BLACK_ALPHA.a; float oldAlphaBlack = Colors.BLACK_ALPHA.a;
Colors.BLACK_ALPHA.a = 0.75f; Colors.BLACK_ALPHA.a = 0.75f;
g.setColor(Colors.BLACK_ALPHA); g.setColor(Colors.BLACK_ALPHA);
g.fillRect(0, 0, displayContainer.width, displayContainer.height); g.fillRect(0, 0, width, height);
Colors.BLACK_ALPHA.a = oldAlphaBlack; Colors.BLACK_ALPHA.a = oldAlphaBlack;
} }
} }

View File

@ -34,15 +34,14 @@ import itdelatrisu.opsu.ui.Colors;
import org.newdawn.slick.Color; import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics; import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image; import org.newdawn.slick.Image;
import yugecin.opsudance.core.DisplayContainer;
import yugecin.opsudance.skinning.SkinService; import yugecin.opsudance.skinning.SkinService;
import static yugecin.opsudance.core.InstanceContainer.*;
/** /**
* Data type representing a spinner object. * Data type representing a spinner object.
*/ */
public class Spinner extends GameObject { public class Spinner extends GameObject {
/** Container dimensions. */
private static int width, height;
/** The map's overall difficulty value. */ /** The map's overall difficulty value. */
private static float overallDifficulty = 5f; private static float overallDifficulty = 5f;
@ -112,9 +111,7 @@ public class Spinner extends GameObject {
* Initializes the Spinner data type with images and dimensions. * Initializes the Spinner data type with images and dimensions.
* @param difficulty the map's overall difficulty value * @param difficulty the map's overall difficulty value
*/ */
public static void init(DisplayContainer displayContainer, float difficulty) { public static void init(float difficulty) {
width = displayContainer.width;
height = displayContainer.height;
overallDifficulty = difficulty; overallDifficulty = difficulty;
} }
@ -207,7 +204,7 @@ public class Spinner extends GameObject {
// rpm // rpm
Image rpmImg = GameImage.SPINNER_RPM.getImage(); Image rpmImg = GameImage.SPINNER_RPM.getImage();
rpmImg.setAlpha(alpha); rpmImg.setAlpha(alpha);
rpmImg.drawCentered(width / 2f, height - rpmImg.getHeight() / 2f); rpmImg.drawCentered(width2, height - rpmImg.getHeight() / 2f);
if (timeDiff < 0) if (timeDiff < 0)
data.drawSymbolString(Integer.toString(drawnRPM), (width + rpmImg.getWidth() * 0.95f) / 2f, data.drawSymbolString(Integer.toString(drawnRPM), (width + rpmImg.getWidth() * 0.95f) / 2f,
height - data.getScoreSymbolImage('0').getHeight() * 1.025f, 1f, 1f, true); height - data.getScoreSymbolImage('0').getHeight() * 1.025f, 1f, 1f, true);
@ -225,21 +222,21 @@ public class Spinner extends GameObject {
// main spinner elements // main spinner elements
GameImage.SPINNER_CIRCLE.getImage().setAlpha(alpha); GameImage.SPINNER_CIRCLE.getImage().setAlpha(alpha);
GameImage.SPINNER_CIRCLE.getImage().setRotation(drawRotation * 360f); 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()) { if (!GameMod.HIDDEN.isActive()) {
float approachScale = 1 - Utils.clamp(((float) timeDiff / (hitObject.getTime() - hitObject.getEndTime())), 0f, 1f); float approachScale = 1 - Utils.clamp(((float) timeDiff / (hitObject.getTime() - hitObject.getEndTime())), 0f, 1f);
Image approachCircleScaled = GameImage.SPINNER_APPROACHCIRCLE.getImage().getScaledCopy(approachScale); Image approachCircleScaled = GameImage.SPINNER_APPROACHCIRCLE.getImage().getScaledCopy(approachScale);
approachCircleScaled.setAlpha(alpha); approachCircleScaled.setAlpha(alpha);
approachCircleScaled.drawCentered(width / 2, height / 2); approachCircleScaled.drawCentered(width2, height2);
} }
GameImage.SPINNER_SPIN.getImage().setAlpha(alpha); 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) { if (spinnerComplete) {
GameImage.SPINNER_CLEAR.getImage().drawCentered(width / 2, height / 4); GameImage.SPINNER_CLEAR.getImage().drawCentered(width2, height / 4);
int extraRotations = (int) (rotations - rotationsNeeded); int extraRotations = (int) (rotations - rotationsNeeded);
if (extraRotations > 0) 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 else
result = GameData.HIT_MISS; 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); Color.transparent, true, hitObject, HitObjectType.SPINNER, true, 0, null, false);
return result; return result;
} }
@Override @Override
public boolean mousePressed(int x, int y, int trackPosition) { 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; return false;
} }
@ -297,7 +294,7 @@ public class Spinner extends GameObject {
angleDiff = delta * SPUN_OUT_MULTIPLIER; angleDiff = delta * SPUN_OUT_MULTIPLIER;
isSpinning = true; isSpinning = true;
} else { } 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 // set initial angle to current mouse position to skip first click
if (!isSpinning && (keyPressed || GameMod.RELAX.isActive())) { if (!isSpinning && (keyPressed || GameMod.RELAX.isActive())) {

View File

@ -98,13 +98,13 @@ public abstract class Curve {
* @param circleDiameter the circle diameter * @param circleDiameter the circle diameter
* @param borderColor the curve border color * @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; Curve.borderColor = borderColor;
ContextCapabilities capabilities = GLContext.getCapabilities(); ContextCapabilities capabilities = GLContext.getCapabilities();
mmsliderSupported = capabilities.OpenGL30; mmsliderSupported = capabilities.OpenGL30;
if (mmsliderSupported) { if (mmsliderSupported) {
CurveRenderState.init(width, height, circleDiameter); CurveRenderState.init(circleDiameter);
} else if (SkinService.skin.getSliderStyle() != Skin.STYLE_PEPPYSLIDER) { } else if (SkinService.skin.getSliderStyle() != Skin.STYLE_PEPPYSLIDER) {
Log.warn("New slider style requires OpenGL 3.0."); Log.warn("New slider style requires OpenGL 3.0.");
} }

View File

@ -48,8 +48,6 @@ import static yugecin.opsudance.options.Options.*;
* @author Bigpet {@literal <dravorek (at) gmail.com>} * @author Bigpet {@literal <dravorek (at) gmail.com>}
*/ */
public class CurveRenderState { 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. */ /** Thickness of the curve. */
protected static int scale; protected static int scale;
@ -79,14 +77,9 @@ public class CurveRenderState {
/** /**
* Set the width and height of the container that Curves get drawn into. * Set the width and height of the container that Curves get drawn into.
* Should be called before any curves are drawn. * Should be called before any curves are drawn.
* @param width the container width
* @param height the container height
* @param circleDiameter the circle diameter * @param circleDiameter the circle diameter
*/ */
public static void init(int width, int height, float circleDiameter) { public static void init(float circleDiameter) {
containerWidth = width;
containerHeight = height;
// equivalent to what happens in Slider.init() // equivalent to what happens in Slider.init()
scale = (int) (circleDiameter * HitObject.getXMultiplier()); // convert from Osupixels (640x480) scale = (int) (circleDiameter * HitObject.getXMultiplier()); // convert from Osupixels (640x480)
//scale = scale * 118 / 128; //for curves exactly as big as the sliderball //scale = scale * 118 / 128; //for curves exactly as big as the sliderball
@ -410,8 +403,6 @@ public class CurveRenderState {
x1 = m[0]; x1 = m[0];
y1 = m[1]; y1 = m[1];
} }
float divx = containerWidth / 2.0f;
float divy = containerHeight / 2.0f;
float offx = -1.0f; float offx = -1.0f;
float offy = 1.0f; float offy = 1.0f;
float radius = scale / 2; float radius = scale / 2;
@ -419,8 +410,8 @@ public class CurveRenderState {
for (int i = 0; i < NewCurveStyleState.unitCone.length / 6; ++i) { for (int i = 0; i < NewCurveStyleState.unitCone.length / 6; ++i) {
buff.put(NewCurveStyleState.unitCone[i * 6 + 0]); buff.put(NewCurveStyleState.unitCone[i * 6 + 0]);
buff.put(NewCurveStyleState.unitCone[i * 6 + 1]); buff.put(NewCurveStyleState.unitCone[i * 6 + 1]);
buff.put(offx + (x1 + radius * NewCurveStyleState.unitCone[i * 6 + 2]) / divx); buff.put(offx + (x1 + radius * NewCurveStyleState.unitCone[i * 6 + 2]) / width2);
buff.put(offy - (y1 + radius * NewCurveStyleState.unitCone[i * 6 + 3]) / divy); buff.put(offy - (y1 + radius * NewCurveStyleState.unitCone[i * 6 + 3]) / height2);
buff.put(NewCurveStyleState.unitCone[i * 6 + 4]); buff.put(NewCurveStyleState.unitCone[i * 6 + 4]);
buff.put(NewCurveStyleState.unitCone[i * 6 + 5]); buff.put(NewCurveStyleState.unitCone[i * 6 + 5]);
} }

View File

@ -39,13 +39,12 @@ import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import itdelatrisu.opsu.ui.Colors;
import org.apache.commons.compress.compressors.lzma.LZMACompressorInputStream; import org.apache.commons.compress.compressors.lzma.LZMACompressorInputStream;
import org.newdawn.slick.util.Log; import org.newdawn.slick.util.Log;
import lzma.streams.LzmaOutputStream; 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.errorhandling.ErrorHandler.*;
import static yugecin.opsudance.core.InstanceContainer.*; import static yugecin.opsudance.core.InstanceContainer.*;
@ -275,7 +274,7 @@ public class Replay {
public void save() { public void save() {
// create replay directory // create replay directory
if (!config.replayDir.isDirectory() && !config.replayDir.mkdir()) { 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; return;
} }

View File

@ -28,10 +28,9 @@ import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.StandardCopyOption; import java.nio.file.StandardCopyOption;
import itdelatrisu.opsu.ui.Colors;
import org.newdawn.slick.util.Log; 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.InstanceContainer.*;
/** /**
@ -69,7 +68,7 @@ public class ReplayImporter {
if (!config.replayDir.isDirectory() && !config.replayDir.mkdir()) { if (!config.replayDir.isDirectory() && !config.replayDir.mkdir()) {
String err = String.format("Failed to create replay directory '%s'.", config.replayDir.getAbsolutePath()); String err = String.format("Failed to create replay directory '%s'.", config.replayDir.getAbsolutePath());
Log.error(err); Log.error(err);
BubNotifListener.EVENT.make().onBubNotif(err, Colors.BUB_RED); bubNotifs.send(BUB_RED, err);
return; return;
} }
@ -83,7 +82,7 @@ public class ReplayImporter {
moveToFailedDirectory(file); moveToFailedDirectory(file);
String err = String.format("Failed to import replay '%s'. The replay file could not be parsed.", file.getName()); String err = String.format("Failed to import replay '%s'. The replay file could not be parsed.", file.getName());
Log.error(err, e); Log.error(err, e);
BubNotifListener.EVENT.make().onBubNotif(err, Colors.BUB_RED); bubNotifs.send(BUB_RED, err);
continue; continue;
} }
Beatmap beatmap = BeatmapSetList.get().getBeatmapFromHash(r.beatmapHash); Beatmap beatmap = BeatmapSetList.get().getBeatmapFromHash(r.beatmapHash);
@ -102,7 +101,7 @@ public class ReplayImporter {
moveToFailedDirectory(file); moveToFailedDirectory(file);
String err = String.format("Failed to import replay '%s'. The associated beatmap could not be found.", file.getName()); String err = String.format("Failed to import replay '%s'. The associated beatmap could not be found.", file.getName());
Log.error(err); Log.error(err);
BubNotifListener.EVENT.make().onBubNotif(err, Colors.BUB_RED); bubNotifs.send(BUB_RED, err);
} }
} }

View File

@ -29,10 +29,11 @@ import java.io.InputStreamReader;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedList; import java.util.LinkedList;
import itdelatrisu.opsu.ui.Colors;
import org.newdawn.slick.Color; import org.newdawn.slick.Color;
import org.newdawn.slick.util.Log; 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. * Loads skin configuration files.
@ -293,7 +294,7 @@ public class SkinLoader {
} catch (IOException e) { } catch (IOException e) {
String err = String.format("Failed to read file '%s'.", skinFile.getAbsolutePath()); String err = String.format("Failed to read file '%s'.", skinFile.getAbsolutePath());
Log.error(err, e); Log.error(err, e);
BubNotifListener.EVENT.make().onBubNotif(err, Colors.BUB_RED); bubNotifs.send(BUB_RED, err);
} }
return skin; return skin;

View File

@ -181,7 +181,7 @@ public class ButtonMenu extends BaseOpsuState {
@Override @Override
protected float getBaseY() { protected float getBaseY() {
return displayContainer.height * 2f / 3; return height * 2f / 3;
} }
@Override @Override
@ -203,10 +203,9 @@ public class ButtonMenu extends BaseOpsuState {
float mult = GameMod.getScoreMultiplier(); float mult = GameMod.getScoreMultiplier();
String multString = String.format("Score Multiplier: %.2fx", mult); String multString = String.format("Score Multiplier: %.2fx", mult);
Color multColor = (mult == 1f) ? Color.white : (mult > 1f) ? Color.green : Color.red; Color multColor = (mult == 1f) ? Color.white : (mult > 1f) ? Color.green : Color.red;
float multY = Fonts.LARGE.getLineHeight() * 2 + displayContainer.height * 0.06f; float multY = Fonts.LARGE.getLineHeight() * 2 + height * 0.06f;
Fonts.LARGE.drawString( final float multX = width2 - Fonts.LARGE.getWidth(multString) / 2f;
(displayContainer.width - Fonts.LARGE.getWidth(multString)) / 2f, Fonts.LARGE.drawString(multX, multY, multString, multColor);
multY, multString, multColor);
// category text // category text
for (GameMod.Category category : GameMod.Category.values()) { for (GameMod.Category category : GameMod.Category.values()) {
@ -227,14 +226,14 @@ public class ButtonMenu extends BaseOpsuState {
super.preRenderUpdate(); super.preRenderUpdate();
GameMod hoverMod = null; GameMod hoverMod = null;
for (GameMod mod : GameMod.values()) { for (GameMod mod : GameMod.values()) {
mod.hoverUpdate(displayContainer.renderDelta, mod.isActive()); mod.hoverUpdate(renderDelta, mod.isActive());
if (hoverMod == null && mod.contains(displayContainer.mouseX, displayContainer.mouseY)) if (hoverMod == null && mod.contains(mouseX, mouseY))
hoverMod = mod; hoverMod = mod;
} }
// tooltips // tooltips
if (hoverMod != null) { 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. * Initializes the menu state.
*/ */
public void revalidate(Image button, Image buttonL, Image buttonR) { public void revalidate(Image button, Image buttonL, Image buttonR) {
float center = displayContainer.width / 2;
float baseY = getBaseY(); float baseY = getBaseY();
float offsetY = button.getHeight() * 1.25f; float offsetY = button.getHeight() * 1.25f;
menuButtons = new MenuButton[buttons.length]; menuButtons = new MenuButton[buttons.length];
for (int i = 0; i < buttons.length; i++) { 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.setText(String.format("%d. %s", i + 1, buttons[i].getText()), Fonts.XLARGE, Color.white);
b.setHoverFade(); b.setHoverFade();
menuButtons[i] = b; menuButtons[i] = b;
@ -313,7 +311,7 @@ public class ButtonMenu extends BaseOpsuState {
* Returns the base Y coordinate for the buttons. * Returns the base Y coordinate for the buttons.
*/ */
protected float getBaseY() { protected float getBaseY() {
float baseY = displayContainer.height * 0.2f; float baseY = height * 0.2f;
baseY += ((getTitle().length - 1) * Fonts.LARGE.getLineHeight()); baseY += ((getTitle().length - 1) * Fonts.LARGE.getLineHeight());
return baseY; return baseY;
} }
@ -325,7 +323,7 @@ public class ButtonMenu extends BaseOpsuState {
public void render(Graphics g) { public void render(Graphics g) {
// draw title // draw title
if (actualTitle != null) { 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(); int lineHeight = Fonts.LARGE.getLineHeight();
for (int i = 0, size = actualTitle.size(); i < size; i++) for (int i = 0, size = actualTitle.size(); i < size; i++)
Fonts.LARGE.drawString(marginX, marginY + (i * lineHeight), actualTitle.get(i), Color.white); 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. * Updates the menu state.
*/ */
public void preRenderUpdate() { public void preRenderUpdate() {
float center = displayContainer.width / 2f; boolean centerOffsetUpdated = centerOffset.update(renderDelta);
boolean centerOffsetUpdated = centerOffset.update(displayContainer.renderDelta);
float centerOffsetX = centerOffset.getValue(); float centerOffsetX = centerOffset.getValue();
final float[] offsets = { centerOffsetX, - centerOffsetX };
for (int i = 0; i < buttons.length; i++) { 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 // move button to center
if (centerOffsetUpdated) if (centerOffsetUpdated) {
menuButtons[i].setX((i % 2 == 0) ? center + centerOffsetX : center - centerOffsetX); menuButtons[i].setX(width2 + offsets[i & 1]);
}
} }
} }
@ -394,18 +393,17 @@ public class ButtonMenu extends BaseOpsuState {
* Processes a state enter request. * Processes a state enter request.
*/ */
public void enter() { public void enter() {
float center = displayContainer.width / 2f; float centerOffsetX = width * OFFSET_WIDTH_RATIO;
float centerOffsetX = displayContainer.width * OFFSET_WIDTH_RATIO;
centerOffset = new AnimatedValue(700, centerOffsetX, 0, AnimationEquation.OUT_BOUNCE); centerOffset = new AnimatedValue(700, centerOffsetX, 0, AnimationEquation.OUT_BOUNCE);
for (int i = 0; i < buttons.length; i++) { 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(); menuButtons[i].resetHover();
} }
// create title string list // create title string list
actualTitle = new ArrayList<>(); actualTitle = new ArrayList<>();
String[] title = getTitle(); String[] title = getTitle();
int maxLineWidth = (int) (displayContainer.width * 0.96f); int maxLineWidth = (int) (width * 0.96f);
for (String aTitle : title) { for (String aTitle : title) {
// wrap text if too long // wrap text if too long
if (Fonts.LARGE.getWidth(aTitle) > maxLineWidth) { if (Fonts.LARGE.getWidth(aTitle) > maxLineWidth) {
@ -601,7 +599,7 @@ public class ButtonMenu extends BaseOpsuState {
// initialize buttons // initialize buttons
Image button = GameImage.MENU_BUTTON_MID.getImage(); 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 buttonL = GameImage.MENU_BUTTON_LEFT.getImage();
Image buttonR = GameImage.MENU_BUTTON_RIGHT.getImage(); Image buttonR = GameImage.MENU_BUTTON_RIGHT.getImage();
for (MenuState ms : MenuState.values()) { for (MenuState ms : MenuState.values()) {
@ -624,7 +622,7 @@ public class ButtonMenu extends BaseOpsuState {
public void preRenderUpdate() { public void preRenderUpdate() {
super.preRenderUpdate(); super.preRenderUpdate();
UI.update(displayContainer.renderDelta); UI.update(renderDelta);
MusicController.loopTrackIfEnded(false); MusicController.loopTrackIfEnded(false);
menuState.preRenderUpdate(); menuState.preRenderUpdate();
} }

View File

@ -53,7 +53,6 @@ import org.newdawn.slick.SlickException;
import org.newdawn.slick.gui.TextField; import org.newdawn.slick.gui.TextField;
import org.newdawn.slick.util.Log; import org.newdawn.slick.util.Log;
import yugecin.opsudance.core.state.ComplexOpsuState; import yugecin.opsudance.core.state.ComplexOpsuState;
import yugecin.opsudance.events.BarNotifListener;
import static org.lwjgl.input.Keyboard.*; import static org.lwjgl.input.Keyboard.*;
import static yugecin.opsudance.core.InstanceContainer.*; 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. */ /** Beatmap set ID of the current beatmap being previewed, or -1 if none. */
private int previewID = -1; private int previewID = -1;
/** The bar notification to send upon entering the state. */
private String barNotificationOnLoad;
/** Search query, executed in {@code queryThread}. */ /** Search query, executed in {@code queryThread}. */
private SearchQuery searchQuery; private SearchQuery searchQuery;
@ -273,13 +269,12 @@ public class DownloadsMenu extends ComplexOpsuState {
if (this.importedNode == null) { if (this.importedNode == null) {
return; return;
} }
String msg;
if (dirs.length == 1) { if (dirs.length == 1) {
msg = "Imported 1 new song."; barNotifs.send("Imported 1 new song.");
} else { return;
msg = String.format("Imported %d new songs.", dirs.length);
} }
BarNotifListener.EVENT.make().onBarNotif(msg); barNotifs.sendf("Imported %d new songs.", dirs.length);
} }
} }
@ -298,8 +293,6 @@ public class DownloadsMenu extends ComplexOpsuState {
components.clear(); components.clear();
int width = displayContainer.width;
int height = displayContainer.height;
int baseX = (int) (width * 0.024f); int baseX = (int) (width * 0.024f);
int searchY = (int) (height * 0.04f + Fonts.LARGE.getLineHeight()); int searchY = (int) (height * 0.04f + Fonts.LARGE.getLineHeight());
int searchWidth = (int) (width * 0.3f); int searchWidth = (int) (width * 0.3f);
@ -371,7 +364,7 @@ public class DownloadsMenu extends ComplexOpsuState {
// dropdown menu // dropdown menu
int serverWidth = (int) (width * 0.12f); int serverWidth = (int) (width * 0.12f);
int x = baseX + searchWidth + buttonMarginX * 3 + resetButtonWidth + rankedButtonWidth; 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 @Override
public void itemSelected(int index, DownloadServer item) { public void itemSelected(int index, DownloadServer item) {
resultList = null; resultList = null;
@ -414,7 +407,7 @@ public class DownloadsMenu extends ComplexOpsuState {
GameImage.SEARCH_BG.getImage().draw(); GameImage.SEARCH_BG.getImage().draw();
// title // 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 // search
g.setColor(Color.white); g.setColor(Color.white);
@ -440,7 +433,7 @@ public class DownloadsMenu extends ComplexOpsuState {
if (index >= nodes.length) if (index >= nodes.length)
break; break;
nodes[index].drawResult(g, offset + i * DownloadNode.getButtonOffset(), 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())); (index == focusResult), (previewID == nodes[index].getID()));
} }
g.clearClip(); g.clearClip();
@ -451,9 +444,9 @@ public class DownloadsMenu extends ComplexOpsuState {
// pages // pages
if (nodes.length > 0) { if (nodes.length > 0) {
float baseX = displayContainer.width * 0.024f; float baseX = width * 0.024f;
float buttonY = displayContainer.height * 0.2f; float buttonY = height * 0.2f;
float buttonWidth = displayContainer.width * 0.7f; float buttonWidth = width * 0.7f;
Fonts.BOLD.drawString( Fonts.BOLD.drawString(
baseX + (buttonWidth - Fonts.BOLD.getWidth("Page 1")) / 2f, baseX + (buttonWidth - Fonts.BOLD.getWidth("Page 1")) / 2f,
buttonY - Fonts.BOLD.getLineHeight() * 1.3f, buttonY - Fonts.BOLD.getLineHeight() * 1.3f,
@ -467,11 +460,10 @@ public class DownloadsMenu extends ComplexOpsuState {
} }
// downloads // 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.setColor(Colors.BLACK_BG_NORMAL);
g.fillRect(downloadsX, downloadsY, g.fillRect(downloadsX, downloadsY, width * 0.25f, height - downloadsY * 2f);
displayContainer.width * 0.25f, displayContainer.height - downloadsY * 2f); Fonts.LARGE.drawString(downloadsX + width * 0.015f, downloadsY + height * 0.015f, "Downloads", Color.white);
Fonts.LARGE.drawString(downloadsX + displayContainer.width * 0.015f, downloadsY + displayContainer.height * 0.015f, "Downloads", Color.white);
int downloadsSize = DownloadList.get().size(); int downloadsSize = DownloadList.get().size();
if (downloadsSize > 0) { if (downloadsSize > 0) {
int maxDownloadsShown = DownloadNode.maxDownloadsShown(); int maxDownloadsShown = DownloadNode.maxDownloadsShown();
@ -487,7 +479,7 @@ public class DownloadsMenu extends ComplexOpsuState {
if (node == null) if (node == null)
break; break;
node.drawDownload(g, i * DownloadNode.getInfoHeight() + offset, index, node.drawDownload(g, i * DownloadNode.getInfoHeight() + offset, index,
DownloadNode.downloadContains(displayContainer.mouseX, displayContainer.mouseY - offset, i)); DownloadNode.downloadContains(mouseX, mouseY - offset, i));
} }
g.clearClip(); g.clearClip();
@ -510,15 +502,13 @@ public class DownloadsMenu extends ComplexOpsuState {
if (importThread != null) { if (importThread != null) {
// darken the screen // darken the screen
g.setColor(Colors.BLACK_ALPHA); g.setColor(Colors.BLACK_ALPHA);
g.fillRect(0, 0, displayContainer.width, displayContainer.height); g.fillRect(0, 0, width, height);
UI.drawLoadingProgress(g); UI.drawLoadingProgress(g);
} else {
backButton.draw(g);
} }
// back button
else
UI.getBackButton().draw(g);
UI.draw(g); UI.draw(g);
} }
@ -526,7 +516,7 @@ public class DownloadsMenu extends ComplexOpsuState {
public void preRenderUpdate() { public void preRenderUpdate() {
super.preRenderUpdate(); super.preRenderUpdate();
int delta = displayContainer.renderDelta; int delta = renderDelta;
UI.update(delta); UI.update(delta);
if (importThread == null) if (importThread == null)
MusicController.loopTrackIfEnded(false); MusicController.loopTrackIfEnded(false);
@ -547,9 +537,7 @@ public class DownloadsMenu extends ComplexOpsuState {
} }
importThread = null; importThread = null;
} }
int mouseX = displayContainer.mouseX; backButton.hoverUpdate();
int mouseY = displayContainer.mouseY;
UI.getBackButton().hoverUpdate(delta, mouseX, mouseY);
prevPage.hoverUpdate(delta, mouseX, mouseY); prevPage.hoverUpdate(delta, mouseX, mouseY);
nextPage.hoverUpdate(delta, mouseX, mouseY); nextPage.hoverUpdate(delta, mouseX, mouseY);
clearButton.hoverUpdate(delta, mouseX, mouseY); clearButton.hoverUpdate(delta, mouseX, mouseY);
@ -619,7 +607,7 @@ public class DownloadsMenu extends ComplexOpsuState {
} }
// back // back
if (UI.getBackButton().contains(x, y)) { if (backButton.contains(x, y)) {
SoundController.playSound(SoundEffect.MENUBACK); SoundController.playSound(SoundEffect.MENUBACK);
displayContainer.switchState(mainmenuState); displayContainer.switchState(mainmenuState);
return true; return true;
@ -686,7 +674,7 @@ public class DownloadsMenu extends ComplexOpsuState {
if (playing) if (playing)
previewID = node.getID(); previewID = node.getID();
} catch (SlickException e) { } 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); Log.error(e);
} }
} }
@ -709,7 +697,7 @@ public class DownloadsMenu extends ComplexOpsuState {
if (!DownloadList.get().contains(node.getID())) { if (!DownloadList.get().contains(node.getID())) {
node.createDownload(serverMenu.getSelectedItem()); node.createDownload(serverMenu.getSelectedItem());
if (node.getDownload() == null) { if (node.getDownload() == null) {
BarNotifListener.EVENT.make().onBarNotif("The download could not be started"); barNotifs.send("The download could not be started");
} else { } else {
DownloadList.get().addNode(node); DownloadList.get().addNode(node);
node.getDownload().start(); node.getDownload().start();
@ -856,7 +844,7 @@ public class DownloadsMenu extends ComplexOpsuState {
} }
int shift = (newValue < 0) ? 1 : -1; int shift = (newValue < 0) ? 1 : -1;
scrollLists(displayContainer.mouseX, displayContainer.mouseY, shift); scrollLists(mouseX, mouseY, shift);
return true; return true;
} }
@ -950,10 +938,6 @@ public class DownloadsMenu extends ComplexOpsuState {
startDownloadIndexPos.setPosition(0); startDownloadIndexPos.setPosition(0);
pageDir = Page.RESET; pageDir = Page.RESET;
previewID = -1; previewID = -1;
if (barNotificationOnLoad != null) {
BarNotifListener.EVENT.make().onBarNotif(barNotificationOnLoad);
barNotificationOnLoad = null;
}
} }
@Override @Override
@ -994,10 +978,4 @@ public class DownloadsMenu extends ComplexOpsuState {
else if (DownloadNode.downloadAreaContains(cx, cy)) else if (DownloadNode.downloadAreaContains(cx, cy))
startDownloadIndexPos.scrollOffset(shift * DownloadNode.getInfoHeight()); 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; }
} }

View File

@ -24,6 +24,7 @@ import itdelatrisu.opsu.audio.MusicController;
import itdelatrisu.opsu.audio.SoundController; import itdelatrisu.opsu.audio.SoundController;
import itdelatrisu.opsu.audio.SoundEffect; import itdelatrisu.opsu.audio.SoundEffect;
import itdelatrisu.opsu.beatmap.Beatmap; import itdelatrisu.opsu.beatmap.Beatmap;
import itdelatrisu.opsu.beatmap.BeatmapParser;
import itdelatrisu.opsu.beatmap.HitObject; import itdelatrisu.opsu.beatmap.HitObject;
import itdelatrisu.opsu.beatmap.TimingPoint; import itdelatrisu.opsu.beatmap.TimingPoint;
import itdelatrisu.opsu.db.BeatmapDB; import itdelatrisu.opsu.db.BeatmapDB;
@ -60,9 +61,6 @@ import org.newdawn.slick.SlickException;
import org.newdawn.slick.util.Log; import org.newdawn.slick.util.Log;
import yugecin.opsudance.*; import yugecin.opsudance.*;
import yugecin.opsudance.core.state.ComplexOpsuState; 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.objects.curves.FakeCombinedCurve;
import yugecin.opsudance.options.OptionGroups; import yugecin.opsudance.options.OptionGroups;
import yugecin.opsudance.sbv2.MoveStoryboard; import yugecin.opsudance.sbv2.MoveStoryboard;
@ -71,6 +69,8 @@ import yugecin.opsudance.ui.OptionsOverlay;
import yugecin.opsudance.ui.StoryboardOverlay; import yugecin.opsudance.ui.StoryboardOverlay;
import yugecin.opsudance.utils.GLHelper; import yugecin.opsudance.utils.GLHelper;
import static itdelatrisu.opsu.GameImage.*;
import static itdelatrisu.opsu.ui.Colors.*;
import static org.lwjgl.input.Keyboard.*; import static org.lwjgl.input.Keyboard.*;
import static yugecin.opsudance.options.Options.*; import static yugecin.opsudance.options.Options.*;
import static yugecin.opsudance.core.InstanceContainer.*; import static yugecin.opsudance.core.InstanceContainer.*;
@ -268,8 +268,6 @@ public class Game extends ComplexOpsuState {
/** Music position bar coordinates and dimensions (for replay seeking). */ /** Music position bar coordinates and dimensions (for replay seeking). */
private float musicBarX, musicBarY, musicBarWidth, musicBarHeight; private float musicBarX, musicBarY, musicBarWidth, musicBarHeight;
public static int currentMapMusicOffset;
private int mirrorFrom; private int mirrorFrom;
private int mirrorTo; private int mirrorTo;
@ -320,9 +318,9 @@ public class Game extends ComplexOpsuState {
public Game() { public Game() {
super(); super();
mirrorCursor = new Cursor(true); mirrorCursor = new Cursor(true);
this.moveStoryboardOverlay = new MoveStoryboard(displayContainer); this.moveStoryboardOverlay = new MoveStoryboard();
this.optionsOverlay = new OptionsOverlay(displayContainer, OptionGroups.storyboardOptions); this.optionsOverlay = new OptionsOverlay(OptionGroups.storyboardOptions);
this.storyboardOverlay = new StoryboardOverlay(displayContainer, moveStoryboardOverlay, optionsOverlay, this); this.storyboardOverlay = new StoryboardOverlay(moveStoryboardOverlay, optionsOverlay, this);
storyboardOverlay.show(); storyboardOverlay.show();
moveStoryboardOverlay.show(); moveStoryboardOverlay.show();
optionsOverlay.setListener(storyboardOverlay); optionsOverlay.setListener(storyboardOverlay);
@ -334,25 +332,26 @@ public class Game extends ComplexOpsuState {
// create offscreen graphics // create offscreen graphics
try { try {
offscreen = new Image(displayContainer.width, displayContainer.height); offscreen = new Image(width, height);
gOffscreen = offscreen.getGraphics(); gOffscreen = offscreen.getGraphics();
gOffscreen.setBackground(Color.black); gOffscreen.setBackground(Color.black);
} catch (SlickException e) { } catch (SlickException e) {
Log.error("could not create offscreen graphics", e); Log.error("could not create offscreen graphics", e);
BubNotifListener.EVENT.make().onBubNotif( bubNotifs.send(
"Exception while creating offscreen graphics. See logfile for details.", BUB_RED,
Colors.BUB_RED); "Exception while creating offscreen graphics. See logfile for details."
);
} }
// initialize music position bar location // initialize music position bar location
musicBarX = displayContainer.width * 0.01f; musicBarX = width * 0.01f;
musicBarY = displayContainer.height * 0.05f; musicBarY = height * 0.05f;
musicBarWidth = Math.max(displayContainer.width * 0.005f, 7); musicBarWidth = Math.max(width * 0.005f, 7);
musicBarHeight = displayContainer.height * 0.9f; musicBarHeight = height * 0.9f;
// initialize scoreboard star stream // initialize scoreboard star stream
scoreboardStarStream = new StarStream(0, displayContainer.height * 2f / 3f, displayContainer.width / 4, 0, 0); scoreboardStarStream = new StarStream(0, height * 2f / 3f, width / 4, 0, 0);
scoreboardStarStream.setPositionSpread(displayContainer.height / 20f); scoreboardStarStream.setPositionSpread(height / 20f);
scoreboardStarStream.setDirectionSpread(10f); scoreboardStarStream.setDirectionSpread(10f);
scoreboardStarStream.setDurationSpread(700, 100); scoreboardStarStream.setDurationSpread(700, 100);
@ -386,12 +385,9 @@ public class Game extends ComplexOpsuState {
@Override @Override
public void render(Graphics g) { public void render(Graphics g) {
int width = displayContainer.width;
int height = displayContainer.height;
int trackPosition = MusicController.getPosition(); int trackPosition = MusicController.getPosition();
if (isLeadIn()) { if (isLeadIn()) {
trackPosition -= leadInTime - currentMapMusicOffset - OPTION_MUSIC_OFFSET.val; trackPosition -= leadInTime - OPTION_MUSIC_OFFSET.val - beatmap.localMusicOffset;
} }
if (pauseTime > -1) // returning from pause screen if (pauseTime > -1) // returning from pause screen
trackPosition = pauseTime; trackPosition = pauseTime;
@ -444,7 +440,7 @@ public class Game extends ComplexOpsuState {
if (GameMod.FLASHLIGHT.isActive()) { if (GameMod.FLASHLIGHT.isActive()) {
// render hit objects offscreen // render hit objects offscreen
Graphics.setCurrent(gOffscreen); Graphics.setCurrent(gOffscreen);
int trackPos = (isLeadIn()) ? (leadInTime - OPTION_MUSIC_OFFSET.val) * -1 : trackPosition; int trackPos = (isLeadIn()) ? (leadInTime - OPTION_MUSIC_OFFSET.val - beatmap.localMusicOffset) * -1 : trackPosition;
drawHitObjects(gOffscreen, trackPos); drawHitObjects(gOffscreen, trackPos);
// restore original graphics context // restore original graphics context
@ -454,23 +450,23 @@ public class Game extends ComplexOpsuState {
// draw alpha map around cursor // draw alpha map around cursor
g.setDrawMode(Graphics.MODE_ALPHA_MAP); g.setDrawMode(Graphics.MODE_ALPHA_MAP);
g.clearAlphaMap(); g.clearAlphaMap();
int mouseX, mouseY; int mx, my;
if (pauseTime > -1 && pausedMousePosition != null) { if (pauseTime > -1 && pausedMousePosition != null) {
mouseX = (int) pausedMousePosition.x; mx = (int) pausedMousePosition.x;
mouseY = (int) pausedMousePosition.y; my = (int) pausedMousePosition.y;
} else if (GameMod.AUTO.isActive() || GameMod.AUTOPILOT.isActive()) { } else if (GameMod.AUTO.isActive() || GameMod.AUTOPILOT.isActive()) {
mouseX = (int) autoMousePosition.x; mx = (int) autoMousePosition.x;
mouseY = (int) autoMousePosition.y; my = (int) autoMousePosition.y;
} else if (isReplay) { } else if (isReplay) {
mouseX = replayX; mx = replayX;
mouseY = replayY; my = replayY;
} else { } else {
mouseX = displayContainer.mouseX; mx = mouseX;
mouseY = displayContainer.mouseY; my = mouseY;
} }
int alphaRadius = flashlightRadius * 256 / 215; int alphaRadius = flashlightRadius * 256 / 215;
int alphaX = mouseX - alphaRadius / 2; int alphaX = mx - alphaRadius / 2;
int alphaY = mouseY - alphaRadius / 2; int alphaY = my - alphaRadius / 2;
GameImage.ALPHA_MAP.getImage().draw(alphaX, alphaY, alphaRadius, alphaRadius); GameImage.ALPHA_MAP.getImage().draw(alphaX, alphaY, alphaRadius, alphaRadius);
// blend offscreen image // blend offscreen image
@ -557,8 +553,8 @@ public class Game extends ComplexOpsuState {
// show retries // show retries
if (retries >= 2 && timeDiff >= -1000) { if (retries >= 2 && timeDiff >= -1000) {
int retryHeight = Math.max( int retryHeight = Math.max(
GameImage.SCOREBAR_BG.getImage().getHeight(), GameImage.SCOREBAR_BG.getHeight(),
GameImage.SCOREBAR_KI.getImage().getHeight() GameImage.SCOREBAR_KI.getHeight()
); );
float oldAlpha = Colors.WHITE_FADE.a; float oldAlpha = Colors.WHITE_FADE.a;
if (timeDiff < -500) if (timeDiff < -500)
@ -571,8 +567,8 @@ public class Game extends ComplexOpsuState {
Colors.WHITE_FADE.a = oldAlpha; Colors.WHITE_FADE.a = oldAlpha;
} }
if (isLeadIn()) if (isLeadIn()) // render approach circles during song lead-in
trackPosition = (leadInTime - OPTION_MUSIC_OFFSET.val) * -1; // render approach circles during song lead-in trackPosition = (leadInTime - OPTION_MUSIC_OFFSET.val - beatmap.localMusicOffset) * -1;
// countdown // countdown
if (beatmap.countdown > 0) { if (beatmap.countdown > 0) {
@ -594,7 +590,7 @@ public class Game extends ComplexOpsuState {
} }
} }
if (timeDiff < 1500 * speedModifier) { 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) { if (!countdown2Sound) {
SoundController.playSound(SoundEffect.COUNT2); SoundController.playSound(SoundEffect.COUNT2);
countdown2Sound = true; countdown2Sound = true;
@ -641,7 +637,7 @@ public class Game extends ComplexOpsuState {
float animation = AnimationEquation.IN_OUT_QUAD.calc( float animation = AnimationEquation.IN_OUT_QUAD.calc(
Utils.clamp((trackPosition - lastRankUpdateTime) / SCOREBOARD_ANIMATION_TIME, 0f, 1f) 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 // draw star stream behind the scores
scoreboardStarStream.draw(); scoreboardStarStream.draw();
@ -682,7 +678,7 @@ public class Game extends ComplexOpsuState {
// draw music position bar (for replay seeking) // draw music position bar (for replay seeking)
if (isReplay && OPTION_REPLAY_SEEKING.state) { 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); g.fillRoundRect(musicBarX, musicBarY, musicBarWidth, musicBarHeight, 4);
if (!isLeadIn()) { if (!isLeadIn()) {
g.setColor(MUSICBAR_FILL); g.setColor(MUSICBAR_FILL);
@ -698,8 +694,8 @@ public class Game extends ComplexOpsuState {
g.fillRect(0, 0, width, height); g.fillRect(0, 0, width, height);
// draw glowing hit select circle and pulse effect // draw glowing hit select circle and pulse effect
int circleDiameter = GameImage.HITCIRCLE.getImage().getWidth(); int circleDiameter = HITCIRCLE.getWidth();
Image cursorCircle = GameImage.HITCIRCLE_SELECT.getImage().getScaledCopy(circleDiameter, circleDiameter); Image cursorCircle = HITCIRCLE_SELECT.getScaledImage(circleDiameter, circleDiameter);
cursorCircle.setAlpha(1.0f); cursorCircle.setAlpha(1.0f);
cursorCircle.drawCentered(pausedMousePosition.x, pausedMousePosition.y); cursorCircle.drawCentered(pausedMousePosition.x, pausedMousePosition.y);
Image cursorCirclePulse = cursorCircle.getScaledCopy(1f + pausePulse); Image cursorCirclePulse = cursorCircle.getScaledCopy(1f + pausePulse);
@ -718,6 +714,15 @@ public class Game extends ComplexOpsuState {
displayContainer.cursor.draw(Utils.isGameKeyPressed()); 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); UI.draw(g);
//g.setColor(new Color(0.2f, 0.2f, 0.2f)); //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); replayPlayback.render(displayContainer.renderDelta, g, ypos, trackPosition);
//} //}
} }
super.render(g);
} }
@Override @Override
public void preRenderUpdate() { public void preRenderUpdate() {
super.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); UI.update(delta);
Pippi.update(delta); Pippi.update(delta);
@ -752,8 +762,6 @@ public class Game extends ComplexOpsuState {
epiImgTime -= delta; epiImgTime -= delta;
} }
yugecin.opsudance.spinners.Spinner.update(delta); yugecin.opsudance.spinners.Spinner.update(delta);
int mouseX = displayContainer.mouseX;
int mouseY = displayContainer.mouseY;
skipButton.hoverUpdate(delta, mouseX, mouseY); skipButton.hoverUpdate(delta, mouseX, mouseY);
if (isReplay || GameMod.AUTO.isActive()) if (isReplay || GameMod.AUTO.isActive())
playbackSpeed.getButton().hoverUpdate(delta, mouseX, mouseY); playbackSpeed.getButton().hoverUpdate(delta, mouseX, mouseY);
@ -929,16 +937,16 @@ public class Game extends ComplexOpsuState {
} else if (GameMod.AUTO.isActive()) { } else if (GameMod.AUTO.isActive()) {
displayContainer.cursor.setCursorPosition(displayContainer.delta, (int) autoMousePosition.x, (int) autoMousePosition.y); displayContainer.cursor.setCursorPosition(displayContainer.delta, (int) autoMousePosition.x, (int) autoMousePosition.y);
if (OPTION_DANCE_MIRROR.state && GameMod.AUTO.isActive()) { if (OPTION_DANCE_MIRROR.state && GameMod.AUTO.isActive()) {
double dx = autoMousePosition.x - displayContainer.width / 2d; double dx = autoMousePosition.x - width2;
double dy = autoMousePosition.y - displayContainer.height / 2d; double dy = autoMousePosition.y - height2;
double d = Math.sqrt(dx * dx + dy * dy); double d = Math.sqrt(dx * dx + dy * dy);
double a = Math.atan2(dy, dx) + Math.PI; 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()) { } else if (GameMod.AUTOPILOT.isActive()) {
displayContainer.cursor.setCursorPosition(displayContainer.delta, (int) autoMousePosition.x, (int) autoMousePosition.y); displayContainer.cursor.setCursorPosition(displayContainer.delta, (int) autoMousePosition.x, (int) autoMousePosition.y);
} else { } 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) { if (restart != Restart.LOSE) {
// update objects (loop in unlikely event of any skipped indexes) // update objects (loop in unlikely event of any skipped indexes)
boolean keyPressed = keys != ReplayFrame.KEY_NONE; boolean keyPressed = keys != ReplayFrame.KEY_NONE;
boolean skippedObject = false;
while (objectIndex < gameObjects.length && trackPosition > beatmap.objects[objectIndex].getTime()) { while (objectIndex < gameObjects.length && trackPosition > beatmap.objects[objectIndex].getTime()) {
// check if we've already passed the next object's start time // check if we've already passed the next object's start time
boolean overlap = (objectIndex + 1 < gameObjects.length && boolean overlap = (objectIndex + 1 < gameObjects.length &&
@ -1096,7 +1103,6 @@ public class Game extends ComplexOpsuState {
// update hit object and check completion status // update hit object and check completion status
if (gameObjects[objectIndex].update(overlap, delta, mouseX, mouseY, keyPressed, trackPosition)) { if (gameObjects[objectIndex].update(overlap, delta, mouseX, mouseY, keyPressed, trackPosition)) {
skippedObject = true;
objectIndex++; // done, so increment object index objectIndex++; // done, so increment object index
storyboardOverlay.updateIndex(objectIndex); storyboardOverlay.updateIndex(objectIndex);
if (objectIndex >= mirrorTo) { if (objectIndex >= mirrorTo) {
@ -1119,6 +1125,10 @@ public class Game extends ComplexOpsuState {
@Override @Override
public boolean keyPressed(int key, char c) { public boolean keyPressed(int key, char c) {
if (OPTION_DANCE_ENABLE_SB.state && optionsOverlay.keyPressed(key, c)) {
return true;
}
if (super.keyPressed(key, c)) { if (super.keyPressed(key, c)) {
return true; return true;
} }
@ -1128,8 +1138,6 @@ public class Game extends ComplexOpsuState {
} }
int trackPosition = MusicController.getPosition(); int trackPosition = MusicController.getPosition();
int mouseX = displayContainer.mouseX;
int mouseY = displayContainer.mouseY;
// game keys // game keys
if (!Keyboard.isRepeatEvent()) { if (!Keyboard.isRepeatEvent()) {
@ -1189,7 +1197,7 @@ public class Game extends ComplexOpsuState {
if (0 <= time && time < 3600) { if (0 <= time && time < 3600) {
OPTION_CHECKPOINT.setValue(time); OPTION_CHECKPOINT.setValue(time);
SoundController.playSound(SoundEffect.MENUCLICK); SoundController.playSound(SoundEffect.MENUCLICK);
BarNotifListener.EVENT.make().onBarNotif("Checkpoint saved."); barNotifs.send("Checkpoint saved.");
} }
} }
break; break;
@ -1201,7 +1209,7 @@ public class Game extends ComplexOpsuState {
break; // invalid checkpoint break; // invalid checkpoint
loadCheckpoint(checkpoint); loadCheckpoint(checkpoint);
SoundController.playSound(SoundEffect.MENUHIT); SoundController.playSound(SoundEffect.MENUHIT);
BarNotifListener.EVENT.make().onBarNotif("Checkpoint loaded."); barNotifs.send("Checkpoint loaded.");
} }
break; break;
case KEY_F: case KEY_F:
@ -1242,14 +1250,13 @@ public class Game extends ComplexOpsuState {
} }
OPTION_DANCE_MIRROR.toggle(); OPTION_DANCE_MIRROR.toggle();
break; break;
case KEY_SUBTRACT:
case KEY_MINUS: case KEY_MINUS:
currentMapMusicOffset += 5; adjustLocalMusicOffset(-5);
BarNotifListener.EVENT.make().onBarNotif("Current map offset: " + currentMapMusicOffset);
break; break;
} }
if (key == KEY_ADD || c == '+') { if (key == KEY_EQUALS || key == KEY_ADD || c == '+') {
currentMapMusicOffset -= 5; adjustLocalMusicOffset(5);
BarNotifListener.EVENT.make().onBarNotif("Current map offset: " + currentMapMusicOffset);
} }
return true; return true;
@ -1257,14 +1264,21 @@ public class Game extends ComplexOpsuState {
@Override @Override
public boolean mouseDragged(int oldx, int oldy, int newx, int newy) { 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 true;
return super.mouseDragged(oldx, oldy, newx, newy);
} }
@Override @Override
public boolean mousePressed(int button, int x, int y) { 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)) { if (super.mousePressed(button, x, y)) {
return true; return true;
} }
@ -1340,7 +1354,7 @@ public class Game extends ComplexOpsuState {
// returning from pause screen // returning from pause screen
if (pauseTime > -1) { if (pauseTime > -1) {
double distance = Math.hypot(pausedMousePosition.x - x, pausedMousePosition.y - y); 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) { if (distance < circleRadius) {
// unpause the game // unpause the game
pauseTime = -1; pauseTime = -1;
@ -1370,6 +1384,10 @@ public class Game extends ComplexOpsuState {
@Override @Override
public boolean mouseReleased(int button, int x, int y) { 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)) { if (super.mouseReleased(button, x, y)) {
return true; return true;
} }
@ -1399,6 +1417,10 @@ public class Game extends ComplexOpsuState {
@Override @Override
public boolean keyReleased(int key, char c) { public boolean keyReleased(int key, char c) {
if (OPTION_DANCE_ENABLE_SB.state && optionsOverlay.keyReleased(key, c)) {
return true;
}
if (super.keyReleased(key, c)) { if (super.keyReleased(key, c)) {
return true; return true;
} }
@ -1436,6 +1458,10 @@ public class Game extends ComplexOpsuState {
@Override @Override
public boolean mouseWheelMoved(int newValue) { public boolean mouseWheelMoved(int newValue) {
if (OPTION_DANCE_ENABLE_SB.state && optionsOverlay.mouseWheelMoved(newValue)) {
return true;
}
if (super.mouseWheelMoved(newValue)) { if (super.mouseWheelMoved(newValue)) {
return true; return true;
} }
@ -1453,11 +1479,9 @@ public class Game extends ComplexOpsuState {
public void enter() { public void enter() {
overlays.clear(); overlays.clear();
if (OPTION_DANCE_ENABLE_SB.state) { if (OPTION_DANCE_ENABLE_SB.state) {
overlays.add(optionsOverlay);
overlays.add(moveStoryboardOverlay); overlays.add(moveStoryboardOverlay);
overlays.add(storyboardOverlay); overlays.add(storyboardOverlay);
storyboardOverlay.onEnter(); storyboardOverlay.onEnter();
optionsOverlay.revalidate();
} }
super.enter(); super.enter();
@ -1523,8 +1547,9 @@ public class Game extends ComplexOpsuState {
} }
if (beatmap == null || beatmap.objects == null) { 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); displayContainer.switchStateInstantly(songMenuState);
return;
} }
Dancer.instance.reset(); Dancer.instance.reset();
@ -1552,10 +1577,9 @@ public class Game extends ComplexOpsuState {
epiImgTime = OPTION_EPILEPSY_WARNING.val * 100; epiImgTime = OPTION_EPILEPSY_WARNING.val * 100;
if (epiImgTime > 0) { if (epiImgTime > 0) {
epiImg = GameImage.EPILEPSY_WARNING.getImage(); epiImg = GameImage.EPILEPSY_WARNING.getImage();
float desWidth = displayContainer.width / 2; epiImg = epiImg.getScaledCopy(width2 / epiImg.getWidth());
epiImg = epiImg.getScaledCopy(desWidth / epiImg.getWidth()); epiImgX = width2 - epiImg.getWidth() / 2;
epiImgX = (displayContainer.width - epiImg.getWidth()) / 2; epiImgY = height2 - epiImg.getHeight() / 2;
epiImgY = (displayContainer.height - epiImg.getHeight()) / 2;
} }
// load mods // load mods
@ -1630,7 +1654,7 @@ public class Game extends ComplexOpsuState {
} catch (Exception e) { } catch (Exception e) {
String message = String.format("Failed to create %s at index %d:\n%s", hitObject.getTypeName(), i, hitObject.toString()); String message = String.format("Failed to create %s at index %d:\n%s", hitObject.getTypeName(), i, hitObject.toString());
Log.error(message, e); Log.error(message, e);
BubNotifListener.EVENT.make().onBubNotif(message, Colors.BUB_RED); bubNotifs.send(BUB_RED, message);
gameObjects[i] = new DummyObject(hitObject); gameObjects[i] = new DummyObject(hitObject);
} }
} }
@ -1657,8 +1681,8 @@ public class Game extends ComplexOpsuState {
// load replay frames // load replay frames
if (isReplay) { if (isReplay) {
// load initial data // load initial data
replayX = displayContainer.width / 2; replayX = width2;
replayY = displayContainer.height / 2; replayY = height2;
replayKeyPressed = false; replayKeyPressed = false;
replaySkipTime = -1; replaySkipTime = -1;
for (replayIndex = 0; replayIndex < replay.frames.length; replayIndex++) { for (replayIndex = 0; replayIndex < replay.frames.length; replayIndex++) {
@ -1680,7 +1704,7 @@ public class Game extends ComplexOpsuState {
lastKeysPressed = ReplayFrame.KEY_NONE; lastKeysPressed = ReplayFrame.KEY_NONE;
replaySkipTime = -1; replaySkipTime = -1;
replayFrames = new LinkedList<>(); 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++) { for (int i = 0; i < gameObjects.length; i++) {
@ -1698,6 +1722,10 @@ public class Game extends ComplexOpsuState {
scoreboardVisible = true; scoreboardVisible = true;
currentScoreboardAlpha = 0f; 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 // needs to play before setting position to resume without lag later
MusicController.play(false); MusicController.play(false);
MusicController.setPosition(0); MusicController.setPosition(0);
@ -1773,6 +1801,8 @@ public class Game extends ComplexOpsuState {
storyboardOverlay.onLeave(); storyboardOverlay.onLeave();
} }
optionsOverlay.hide();
isInGame = false; isInGame = false;
// container.setMouseGrabbed(false); // container.setMouseGrabbed(false);
skippedToCheckpoint = false; skippedToCheckpoint = false;
@ -1796,6 +1826,18 @@ public class Game extends ComplexOpsuState {
GameMod.loadModState(previousMods); 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) { public void addMergedSliderPointsToRender(int from, int to) {
knorkesliders.addRange(from, to); knorkesliders.addRange(from, to);
} }
@ -1850,7 +1892,7 @@ public class Game extends ComplexOpsuState {
} }
if (lastObjectIndex != -1 && !beatmap.objects[index].isNewCombo()) { if (lastObjectIndex != -1 && !beatmap.objects[index].isNewCombo()) {
// calculate points // calculate points
final int followPointInterval = displayContainer.height / 14; final int followPointInterval = height / 14;
int lastObjectEndTime = gameObjects[lastObjectIndex].getEndTime() + 1; int lastObjectEndTime = gameObjects[lastObjectIndex].getEndTime() + 1;
int objectStartTime = beatmap.objects[index].getTime(); int objectStartTime = beatmap.objects[index].getTime();
Vec2f startPoint = gameObjects[lastObjectIndex].getPointAt(lastObjectEndTime); Vec2f startPoint = gameObjects[lastObjectIndex].getPointAt(lastObjectEndTime);
@ -1858,7 +1900,7 @@ public class Game extends ComplexOpsuState {
float xDiff = endPoint.x - startPoint.x; float xDiff = endPoint.x - startPoint.x;
float yDiff = endPoint.y - startPoint.y; float yDiff = endPoint.y - startPoint.y;
float dist = (float) Math.hypot(xDiff, yDiff); 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) { if (numPoints > 0) {
// set the image angle // set the image angle
Image followPoint = GameImage.FOLLOWPOINT.getImage(); Image followPoint = GameImage.FOLLOWPOINT.getImage();
@ -1911,7 +1953,7 @@ public class Game extends ComplexOpsuState {
gameObj.draw(g, trackPosition, false); gameObj.draw(g, trackPosition, false);
if (OPTION_DANCE_MIRROR.state && GameMod.AUTO.isActive() && idx < mirrorTo && idx >= mirrorFrom) { if (OPTION_DANCE_MIRROR.state && GameMod.AUTO.isActive() && idx < mirrorTo && idx >= mirrorFrom) {
g.pushTransform(); g.pushTransform();
g.rotate(displayContainer.width / 2f, displayContainer.height / 2f, 180f); g.rotate(width2, height2, 180f);
gameObj.draw(g, trackPosition, true); gameObj.draw(g, trackPosition, true);
g.popTransform(); g.popTransform();
} }
@ -1939,7 +1981,7 @@ public class Game extends ComplexOpsuState {
g.pushTransform(); g.pushTransform();
// translate and rotate the object // 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); Vec2f rotationCenter = gameObj.getPointAt((beatmap.objects[idx].getTime() + beatmap.objects[idx].getEndTime()) / 2);
g.rotate(rotationCenter.x, rotationCenter.y, rotSpeed * dt); g.rotate(rotationCenter.x, rotationCenter.y, rotSpeed * dt);
gameObj.draw(g, trackPosition, false); gameObj.draw(g, trackPosition, false);
@ -1954,15 +1996,12 @@ public class Game extends ComplexOpsuState {
* @param beatmap the beatmap to load * @param beatmap the beatmap to load
*/ */
public void loadBeatmap(Beatmap beatmap) { public void loadBeatmap(Beatmap beatmap) {
if (this.beatmap == null || this.beatmap.beatmapID != beatmap.beatmapID) {
currentMapMusicOffset = 0;
}
this.beatmap = beatmap; this.beatmap = beatmap;
Display.setTitle(String.format("opsu!dance - %s", beatmap.toString())); Display.setTitle(String.format("opsu!dance - %s", beatmap.toString()));
if (beatmap.breaks == null) { if (beatmap.breaks == null) {
BeatmapDB.load(beatmap, BeatmapDB.LOAD_ARRAY); BeatmapDB.load(beatmap, BeatmapDB.LOAD_ARRAY);
} }
beatmapParser.parseHitObjects(beatmap); BeatmapParser.parseHitObjects(beatmap);
HitSound.setDefaultSampleSet(beatmap.sampleSet); HitSound.setDefaultSampleSet(beatmap.sampleSet);
} }
@ -1993,7 +2032,7 @@ public class Game extends ComplexOpsuState {
lastReplayTime = 0; lastReplayTime = 0;
autoMousePosition = new Vec2f(); autoMousePosition = new Vec2f();
autoMousePressed = false; autoMousePressed = false;
flashlightRadius = displayContainer.height * 2 / 3; flashlightRadius = height * 2 / 3;
if (scoreboardStarStream != null) { if (scoreboardStarStream != null) {
scoreboardStarStream.clear(); scoreboardStarStream.clear();
} }
@ -2045,10 +2084,10 @@ public class Game extends ComplexOpsuState {
// skip button // skip button
if (GameImage.SKIP.getImages() != null) { if (GameImage.SKIP.getImages() != null) {
Animation skip = GameImage.SKIP.getAnimation(120); 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 { } else {
Image skip = GameImage.SKIP.getImage(); 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.setHoverAnimationDuration(350);
skipButton.setHoverAnimationEquation(AnimationEquation.IN_OUT_BACK); skipButton.setHoverAnimationEquation(AnimationEquation.IN_OUT_BACK);
@ -2093,12 +2132,12 @@ public class Game extends ComplexOpsuState {
// initialize objects // initialize objects
gameObjectRenderer.initForGame(data, diameter); gameObjectRenderer.initForGame(data, diameter);
Slider.init(gameObjectRenderer.circleDiameter, beatmap); Slider.init(gameObjectRenderer.circleDiameter, beatmap);
Spinner.init(displayContainer, overallDifficulty); Spinner.init(overallDifficulty);
Color sliderBorderColor = SkinService.skin.getSliderBorderColor(); Color sliderBorderColor = SkinService.skin.getSliderBorderColor();
if (!OPTION_IGNORE_BEATMAP_SKINS.state && beatmap.getSliderBorderColor() != null) { if (!OPTION_IGNORE_BEATMAP_SKINS.state && beatmap.getSliderBorderColor() != null) {
sliderBorderColor = beatmap.getSliderBorderColor(); sliderBorderColor = beatmap.getSliderBorderColor();
} }
Curve.init(displayContainer.width, displayContainer.height, diameter, sliderBorderColor); Curve.init(diameter, sliderBorderColor);
// approachRate (hit object approach time) // approachRate (hit object approach time)
if (approachRate < 5) if (approachRate < 5)
@ -2214,15 +2253,16 @@ public class Game extends ComplexOpsuState {
if (replay == null) { if (replay == null) {
this.isReplay = false; this.isReplay = false;
this.replay = null; this.replay = null;
} else { return;
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;
} }
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()) { if (isLeadIn()) {
// lead-in: expand area // lead-in: expand area
float progress = Math.max((float) (leadInTime - beatmap.audioLeadIn) / approachTime, 0f); 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) { } else if (firstObject) {
// before first object: shrink area // before first object: shrink area
int timeDiff = beatmap.objects[0].getTime() - trackPosition; int timeDiff = beatmap.objects[0].getTime() - trackPosition;
flashlightRadius = displayContainer.width; flashlightRadius = width;
if (timeDiff < approachTime) { if (timeDiff < approachTime) {
float progress = (float) timeDiff / approachTime; float progress = (float) timeDiff / approachTime;
flashlightRadius -= (displayContainer.width - (displayContainer.height * 2 / 3)) * (1 - progress); flashlightRadius -= (width - (height * 2 / 3)) * (1 - progress);
} }
} else { } else {
// gameplay: size based on combo // gameplay: size based on combo
int targetRadius; int targetRadius;
int combo = data.getComboStreak(); int combo = data.getComboStreak();
if (combo < 100) if (combo < 100)
targetRadius = displayContainer.height * 2 / 3; targetRadius = height * 2 / 3;
else if (combo < 200) else if (combo < 200)
targetRadius = displayContainer.height / 2; targetRadius = height2;
else else
targetRadius = displayContainer.height / 3; targetRadius = height / 3;
if (beatmap.breaks != null && breakIndex < beatmap.breaks.size() && breakTime > 0) { if (beatmap.breaks != null && breakIndex < beatmap.breaks.size() && breakTime > 0) {
// breaks: expand at beginning, shrink at end // breaks: expand at beginning, shrink at end
flashlightRadius = targetRadius; flashlightRadius = targetRadius;
@ -2346,11 +2386,11 @@ public class Game extends ComplexOpsuState {
progress = (float) (trackPosition - breakTime) / approachTime; progress = (float) (trackPosition - breakTime) / approachTime;
else if (endTime - trackPosition < approachTime) else if (endTime - trackPosition < approachTime)
progress = (float) (endTime - trackPosition) / approachTime; progress = (float) (endTime - trackPosition) / approachTime;
flashlightRadius += (displayContainer.width - flashlightRadius) * progress; flashlightRadius += (width - flashlightRadius) * progress;
} }
} else if (flashlightRadius != targetRadius) { } else if (flashlightRadius != targetRadius) {
// radius size change // radius size change
float radiusDiff = displayContainer.height * delta / 2000f; float radiusDiff = height * delta / 2000f;
if (flashlightRadius > targetRadius) { if (flashlightRadius > targetRadius) {
flashlightRadius -= radiusDiff; flashlightRadius -= radiusDiff;
if (flashlightRadius < targetRadius) if (flashlightRadius < targetRadius)

View File

@ -32,6 +32,7 @@ import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input; import org.newdawn.slick.Input;
import yugecin.opsudance.core.state.BaseOpsuState; import yugecin.opsudance.core.state.BaseOpsuState;
import static itdelatrisu.opsu.GameImage.*;
import static org.lwjgl.input.Keyboard.*; import static org.lwjgl.input.Keyboard.*;
import static yugecin.opsudance.core.InstanceContainer.*; import static yugecin.opsudance.core.InstanceContainer.*;
import static yugecin.opsudance.options.Options.*; import static yugecin.opsudance.options.Options.*;
@ -73,11 +74,11 @@ public class GamePauseMenu extends BaseOpsuState {
@Override @Override
public void preRenderUpdate() { public void preRenderUpdate() {
int delta = displayContainer.renderDelta; int delta = renderDelta;
UI.update(delta); UI.update(delta);
continueButton.hoverUpdate(delta, displayContainer.mouseX, displayContainer.mouseY); continueButton.hoverUpdate(delta, mouseX, mouseY);
retryButton.hoverUpdate(delta, displayContainer.mouseX, displayContainer.mouseY); retryButton.hoverUpdate(delta, mouseX, mouseY);
backButton.hoverUpdate(delta, displayContainer.mouseX, displayContainer.mouseY); backButton.hoverUpdate(delta, mouseX, mouseY);
} }
@Override @Override
@ -89,9 +90,9 @@ public class GamePauseMenu extends BaseOpsuState {
// game keys // game keys
if (!Keyboard.isRepeatEvent()) { if (!Keyboard.isRepeatEvent()) {
if (key == OPTION_KEY_LEFT.intval) { 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) { } 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; 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; return false;
} }
@ -193,9 +203,9 @@ public class GamePauseMenu extends BaseOpsuState {
*/ */
public void loadImages() { public void loadImages() {
// initialize buttons // initialize buttons
continueButton = new MenuButton(GameImage.PAUSE_CONTINUE.getImage(), displayContainer.width / 2f, displayContainer.height * 0.25f); continueButton = new MenuButton(PAUSE_CONTINUE.getImage(), width2, height * 0.25f);
retryButton = new MenuButton(GameImage.PAUSE_RETRY.getImage(), displayContainer.width / 2f, displayContainer.height * 0.5f); retryButton = new MenuButton(PAUSE_RETRY.getImage(), width2, height2);
backButton = new MenuButton(GameImage.PAUSE_BACK.getImage(), displayContainer.width / 2f, displayContainer.height * 0.75f); backButton = new MenuButton(PAUSE_BACK.getImage(), width2, height * 0.75f);
final int buttonAnimationDuration = 300; final int buttonAnimationDuration = 300;
continueButton.setHoverAnimationDuration(buttonAnimationDuration); continueButton.setHoverAnimationDuration(buttonAnimationDuration);
retryButton.setHoverAnimationDuration(buttonAnimationDuration); retryButton.setHoverAnimationDuration(buttonAnimationDuration);

View File

@ -38,7 +38,6 @@ import org.newdawn.slick.Image;
import org.newdawn.slick.Input; import org.newdawn.slick.Input;
import org.newdawn.slick.util.Log; import org.newdawn.slick.util.Log;
import yugecin.opsudance.core.state.BaseOpsuState; import yugecin.opsudance.core.state.BaseOpsuState;
import yugecin.opsudance.events.BarNotifListener;
import static yugecin.opsudance.core.InstanceContainer.*; import static yugecin.opsudance.core.InstanceContainer.*;
@ -67,10 +66,10 @@ public class GameRanking extends BaseOpsuState {
// buttons // buttons
Image retry = GameImage.PAUSE_RETRY.getImage(); Image retry = GameImage.PAUSE_RETRY.getImage();
Image replay = GameImage.PAUSE_REPLAY.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); retryY = replayY - (replay.getHeight() / 2f) - (retry.getHeight() / 1.975f);
retryButton = new MenuButton(retry, displayContainer.width - (retry.getWidth() / 2f), retryY); retryButton = new MenuButton(retry, width - (retry.getWidth() / 2f), retryY);
replayButton = new MenuButton(replay, displayContainer.width - (replay.getWidth() / 2f), replayY); replayButton = new MenuButton(replay, width - (replay.getWidth() / 2f), replayY);
retryButton.setHoverFade(); retryButton.setHoverFade();
replayButton.setHoverFade(); replayButton.setHoverFade();
} }
@ -80,7 +79,7 @@ public class GameRanking extends BaseOpsuState {
Beatmap beatmap = MusicController.getBeatmap(); Beatmap beatmap = MusicController.getBeatmap();
// background // 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); GameImage.PLAYFIELD.getImage().draw(0, 0);
} }
@ -91,7 +90,7 @@ public class GameRanking extends BaseOpsuState {
replayButton.draw(); replayButton.draw();
if (data.isGameplay() && !GameMod.AUTO.isActive()) if (data.isGameplay() && !GameMod.AUTO.isActive())
retryButton.draw(); retryButton.draw();
UI.getBackButton().draw(g); backButton.draw(g);
UI.draw(g); UI.draw(g);
@ -100,15 +99,15 @@ public class GameRanking extends BaseOpsuState {
@Override @Override
public void preRenderUpdate() { public void preRenderUpdate() {
int delta = displayContainer.renderDelta; int delta = renderDelta;
UI.update(delta); UI.update(delta);
replayButton.hoverUpdate(delta, displayContainer.mouseX, displayContainer.mouseY); replayButton.hoverUpdate(delta, mouseX, mouseY);
if (data.isGameplay()) { if (data.isGameplay()) {
retryButton.hoverUpdate(delta, displayContainer.mouseX, displayContainer.mouseY); retryButton.hoverUpdate(delta, mouseX, mouseY);
} else { } else {
MusicController.loopTrackIfEnded(true); MusicController.loopTrackIfEnded(true);
} }
UI.getBackButton().hoverUpdate(delta, displayContainer.mouseX, displayContainer.mouseY); backButton.hoverUpdate();
} }
@Override @Override
@ -140,7 +139,7 @@ public class GameRanking extends BaseOpsuState {
} }
// back to menu // back to menu
if (UI.getBackButton().contains(x, y)) { if (backButton.contains(x, y)) {
returnToSongMenu(); returnToSongMenu();
return true; return true;
} }
@ -157,14 +156,14 @@ public class GameRanking extends BaseOpsuState {
gameState.setRestart((data.isGameplay()) ? Game.Restart.REPLAY : Game.Restart.NEW); gameState.setRestart((data.isGameplay()) ? Game.Restart.REPLAY : Game.Restart.NEW);
returnToGame = true; returnToGame = true;
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
BarNotifListener.EVENT.make().onBarNotif("Replay file not found."); barNotifs.send("Replay file not found.");
} catch (IOException e) { } catch (IOException e) {
Log.error("Failed to load replay data.", e); Log.error("Failed to load replay data.", e);
BarNotifListener.EVENT.make().onBarNotif( barNotifs.send("Failed to load replay data. See log for details.");
"Failed to load replay data. See log for details.");
} }
} else } else {
BarNotifListener.EVENT.make().onBarNotif("Replay file not found."); barNotifs.send("Replay file not found.");
}
} }
// retry // retry

File diff suppressed because it is too large Load Diff

View File

@ -48,6 +48,7 @@ import itdelatrisu.opsu.ui.UI;
import itdelatrisu.opsu.ui.animations.AnimatedValue; import itdelatrisu.opsu.ui.animations.AnimatedValue;
import itdelatrisu.opsu.ui.animations.AnimationEquation; import itdelatrisu.opsu.ui.animations.AnimationEquation;
import java.awt.Point;
import java.io.File; import java.io.File;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.StandardWatchEventKinds; import java.nio.file.StandardWatchEventKinds;
@ -63,11 +64,11 @@ import org.newdawn.slick.Image;
import org.newdawn.slick.Input; import org.newdawn.slick.Input;
import org.newdawn.slick.SpriteSheet; import org.newdawn.slick.SpriteSheet;
import org.newdawn.slick.gui.TextField; 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 org.lwjgl.input.Keyboard.*;
import static yugecin.opsudance.core.InstanceContainer.*; import static yugecin.opsudance.core.InstanceContainer.*;
import static yugecin.opsudance.options.Options.*; import static yugecin.opsudance.options.Options.*;
@ -99,7 +100,7 @@ public class SongMenu extends ComplexOpsuState {
private static final int SEARCH_TRANSITION_TIME = 250; private static final int SEARCH_TRANSITION_TIME = 250;
/** Line width of the header/footer divider. */ /** 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. */ /** Song node class representing an BeatmapSetNode and file index. */
private static class SongNode { private static class SongNode {
@ -161,7 +162,7 @@ public class SongMenu extends ComplexOpsuState {
private BeatmapSetNode hoverIndex = null; private BeatmapSetNode hoverIndex = null;
/** The selection buttons. */ /** The selection buttons. */
private MenuButton selectModsButton, selectRandomButton, selectMapOptionsButton, selectOptionsButton; private MenuButton selectModeButton, selectModsButton, selectRandomButton, selectMapOptionsButton;
/** The search textfield. */ /** The search textfield. */
private TextField searchTextField; private TextField searchTextField;
@ -311,12 +312,8 @@ public class SongMenu extends ComplexOpsuState {
/** Sort order dropdown menu. */ /** Sort order dropdown menu. */
private DropdownMenu<BeatmapSortOrder> sortMenu; private DropdownMenu<BeatmapSortOrder> sortMenu;
private final OptionsOverlay optionsOverlay;
public SongMenu() { public SongMenu() {
super(); super();
optionsOverlay = new OptionsOverlay(displayContainer, OptionGroups.normalOptions);
overlays.add(optionsOverlay);
} }
@Override @Override
@ -325,26 +322,27 @@ public class SongMenu extends ComplexOpsuState {
components.clear(); components.clear();
final float footerHeight = height * 0.116666666666f;
// header/footer coordinates // 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.BOLD.getLineHeight() + Fonts.DEFAULT.getLineHeight() +
Fonts.SMALL.getLineHeight(); Fonts.SMALL.getLineHeight();
footerY = displayContainer.height - GameImage.SELECTION_MODS.getImage().getHeight(); footerY = height - footerHeight;
// footer logo coordinates // footer logo coordinates
float footerHeight = displayContainer.height - footerY;
footerLogoSize = footerHeight * 3.25f; footerLogoSize = footerHeight * 3.25f;
Image logo = GameImage.MENU_LOGO.getImage(); Image logo = GameImage.MENU_LOGO.getImage();
logo = logo.getScaledCopy(footerLogoSize / logo.getWidth()); 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.setHoverAnimationDuration(1);
footerLogoButton.setHoverExpand(1.2f); footerLogoButton.setHoverExpand(1.2f);
// initialize sorts // initialize sorts
int sortWidth = (int) (displayContainer.width * 0.12f); int sortWidth = (int) (width * 0.12f);
int posX = (int) (displayContainer.width * 0.87f); int posX = (int) (width * 0.87f);
int posY = (int) (headerY - GameImage.MENU_TAB.getImage().getHeight() * 2.25f); int posY = (int) (headerY - GameImage.MENU_TAB.getHeight() * 2.25f);
sortMenu = new DropdownMenu<BeatmapSortOrder>(displayContainer, BeatmapSortOrder.values(), posX, posY, sortWidth) { sortMenu = new DropdownMenu<BeatmapSortOrder>(BeatmapSortOrder.values(), posX, posY, sortWidth) {
@Override @Override
public void itemSelected(int index, BeatmapSortOrder item) { public void itemSelected(int index, BeatmapSortOrder item) {
BeatmapSortOrder.set(item); BeatmapSortOrder.set(item);
@ -373,25 +371,25 @@ public class SongMenu extends ComplexOpsuState {
// initialize group tabs // initialize group tabs
for (BeatmapGroup group : BeatmapGroup.values()) 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 // 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 // song button background & graphics context
Image menuBackground = GameImage.MENU_BUTTON_BG.getImage(); Image menuBackground = GameImage.MENU_BUTTON_BG.getImage();
// song button coordinates // song button coordinates
buttonX = displayContainer.width * 0.6f; buttonX = width * 0.6f;
//buttonY = headerY; //buttonY = headerY;
buttonWidth = menuBackground.getWidth(); buttonWidth = menuBackground.getWidth();
buttonHeight = menuBackground.getHeight(); buttonHeight = menuBackground.getHeight();
buttonOffset = (footerY - headerY - DIVIDER_LINE_WIDTH) / MAX_SONG_BUTTONS; buttonOffset = (footerY - headerY - DIVIDER_LINE_WIDTH) / MAX_SONG_BUTTONS;
// search // 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); 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 @Override
public boolean isFocusable() { public boolean isFocusable() {
return false; return false;
@ -405,33 +403,23 @@ public class SongMenu extends ComplexOpsuState {
components.add(searchTextField); components.add(searchTextField);
// selection buttons // selection buttons
Image selectionMods = GameImage.SELECTION_MODS.getImage(); // TODO: the origin should be bottomleft or something
int selectButtonsWidth = selectionMods.getWidth(); float selectX = width * (isWidescreen ? 0.164f : 0.1875f);
int selectButtonsHeight = selectionMods.getHeight(); final float footerButtonWidth = footerHeight * 0.84f;
if (selectButtonsHeight < 20) { selectModeButton = new MenuButton(SELECTION_MODE_OVERLAY, selectX, footerY);
selectButtonsHeight = 100; selectX += footerHeight + 2;
} selectModsButton = new MenuButton(SELECTION_MODS_OVERLAY, selectX, footerY);
if (selectButtonsWidth < 20) { selectX += footerButtonWidth;
selectButtonsWidth = 100; selectRandomButton = new MenuButton(SELECTION_RANDOM_OVERLAY, selectX, footerY);
} selectX += footerButtonWidth;
float selectX = displayContainer.width * 0.183f + selectButtonsWidth / 2f; selectMapOptionsButton = new MenuButton(SELECTION_OPTIONS_OVERLAY, selectX, footerY);
float selectY = displayContainer.height - selectButtonsHeight / 2f; selectModeButton.setHoverFade(0f);
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);
selectModsButton.setHoverFade(0f); selectModsButton.setHoverFade(0f);
selectRandomButton.setHoverFade(0f); selectRandomButton.setHoverFade(0f);
selectMapOptionsButton.setHoverFade(0f); selectMapOptionsButton.setHoverFade(0f);
selectOptionsButton.setHoverFade(0f);
// loader // loader
int loaderDim = GameImage.MENU_MUSICNOTE.getImage().getWidth(); int loaderDim = GameImage.MENU_MUSICNOTE.getWidth();
SpriteSheet spr = new SpriteSheet(GameImage.MENU_LOADER.getImage(), loaderDim, loaderDim); SpriteSheet spr = new SpriteSheet(GameImage.MENU_LOADER.getImage(), loaderDim, loaderDim);
loader = new Animation(spr, 50); loader = new Animation(spr, 50);
@ -446,14 +434,13 @@ public class SongMenu extends ComplexOpsuState {
if (!displayContainer.isInState(SongMenu.class)) { if (!displayContainer.isInState(SongMenu.class)) {
return; return;
} }
BarNotifListener.EVENT.make().onBarNotif( barNotifs.send("Changes in Songs folder detected. Hit F5 to refresh.");
"Changed is Songs folder detected. Hit F5 to refresh.");
} }
}); });
// star stream // star stream
starStream = new StarStream(displayContainer.width, (displayContainer.height - GameImage.STAR.getImage().getHeight()) / 2, -displayContainer.width, 0, MAX_STREAM_STARS); starStream = new StarStream(width, height2 - GameImage.STAR.getImage().getHeight() / 2, -width, 0, MAX_STREAM_STARS);
starStream.setPositionSpread(displayContainer.height / 20f); starStream.setPositionSpread(height / 20f);
starStream.setDirectionSpread(10f); starStream.setDirectionSpread(10f);
} }
@ -461,11 +448,6 @@ public class SongMenu extends ComplexOpsuState {
public void render(Graphics g) { public void render(Graphics g) {
g.setBackground(Color.black); g.setBackground(Color.black);
int width = displayContainer.width;
int height = displayContainer.height;
int mouseX = displayContainer.mouseX;
int mouseY = displayContainer.mouseY;
// background // background
if (focusNode != null) { if (focusNode != null) {
Beatmap focusNodeBeatmap = focusNode.getSelectedBeatmap(); Beatmap focusNodeBeatmap = focusNode.getSelectedBeatmap();
@ -542,14 +524,12 @@ public class SongMenu extends ComplexOpsuState {
} }
// top/bottom bars // top/bottom bars
g.setColor(Colors.BLACK_ALPHA); g.setColor(Color.black);
g.fillRect(0, 0, width, headerY); g.fillRect(0, 0, width, headerY);
g.fillRect(0, footerY, width, height - footerY); g.fillRect(0, footerY, width, height - footerY);
g.setColor(Colors.BLUE_DIVIDER); g.setColor(Colors.BLUE_DIVIDER);
g.setLineWidth(DIVIDER_LINE_WIDTH); g.fillRect(0, headerY, width, DIVIDER_LINE_WIDTH);
g.drawLine(0, headerY, width, headerY); g.fillRect(0, footerY, width, DIVIDER_LINE_WIDTH);
g.drawLine(0, footerY, width, footerY);
g.resetLineWidth();
// footer logo (pulsing) // footer logo (pulsing)
Float position = MusicController.getBeatProgress(); Float position = MusicController.getBeatProgress();
@ -563,10 +543,8 @@ public class SongMenu extends ComplexOpsuState {
footerLogoButton.draw(Color.white, 1f - expand); footerLogoButton.draw(Color.white, 1f - expand);
Image ghostLogo = GameImage.MENU_LOGO.getImage(); Image ghostLogo = GameImage.MENU_LOGO.getImage();
ghostLogo = ghostLogo.getScaledCopy((1f + expand) * footerLogoSize / ghostLogo.getWidth()); ghostLogo = ghostLogo.getScaledCopy((1f + expand) * footerLogoSize / ghostLogo.getWidth());
float oldGhostAlpha = Colors.GHOST_LOGO.a; ghostLogo.setAlpha(0.25f * (1f - position));
Colors.GHOST_LOGO.a *= (1f - position); ghostLogo.drawCentered(footerLogoButton.getX(), footerLogoButton.getY());
ghostLogo.drawCentered(footerLogoButton.getX(), footerLogoButton.getY(), Colors.GHOST_LOGO);
Colors.GHOST_LOGO.a = oldGhostAlpha;
} }
// header // header
@ -636,14 +614,19 @@ public class SongMenu extends ComplexOpsuState {
} }
// selection buttons // 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(); 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(); 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(); selectMapOptionsButton.draw();
GameImage.SELECTION_OTHER_OPTIONS.getImage().drawCentered(selectOptionsButton.getX(), selectOptionsButton.getY());
selectOptionsButton.draw();
// group tabs // group tabs
BeatmapGroup currentGroup = BeatmapGroup.current(); BeatmapGroup currentGroup = BeatmapGroup.current();
@ -701,11 +684,11 @@ public class SongMenu extends ComplexOpsuState {
g.fillRect(0, 0, width, height); g.fillRect(0, 0, width, height);
UI.drawLoadingProgress(g); UI.drawLoadingProgress(g);
} else {
optionsOverlay.render(g);
backButton.draw(g);
} }
// back button
else
UI.getBackButton().draw(g);
UI.draw(g); UI.draw(g);
@ -715,8 +698,18 @@ public class SongMenu extends ComplexOpsuState {
@Override @Override
public void preRenderUpdate() { public void preRenderUpdate() {
super.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); UI.update(delta);
if (reloadThread == null) if (reloadThread == null)
MusicController.loopTrackIfEnded(true); MusicController.loopTrackIfEnded(true);
@ -732,13 +725,11 @@ public class SongMenu extends ComplexOpsuState {
MusicController.playThemeSong(config.themeBeatmap); MusicController.playThemeSong(config.themeBeatmap);
reloadThread = null; reloadThread = null;
} }
int mouseX = displayContainer.mouseX; backButton.hoverUpdate();
int mouseY = displayContainer.mouseY; selectModeButton.hoverUpdate(delta, mouseX, mouseY);
UI.getBackButton().hoverUpdate(delta, mouseX, mouseY);
selectModsButton.hoverUpdate(delta, mouseX, mouseY); selectModsButton.hoverUpdate(delta, mouseX, mouseY);
selectRandomButton.hoverUpdate(delta, mouseX, mouseY); selectRandomButton.hoverUpdate(delta, mouseX, mouseY);
selectMapOptionsButton.hoverUpdate(delta, mouseX, mouseY); selectMapOptionsButton.hoverUpdate(delta, mouseX, mouseY);
selectOptionsButton.hoverUpdate(delta, mouseX, mouseY);
footerLogoButton.hoverUpdate(delta, mouseX, mouseY, 0.25f); footerLogoButton.hoverUpdate(delta, mouseX, mouseY, 0.25f);
// beatmap menu timer // beatmap menu timer
@ -873,6 +864,10 @@ public class SongMenu extends ComplexOpsuState {
if (super.mousePressed(button, x, y)) { if (super.mousePressed(button, x, y)) {
return true; return true;
} }
if (optionsOverlay.mousePressed(button, x, y)) {
return true;
}
if (button == Input.MOUSE_MIDDLE_BUTTON) { if (button == Input.MOUSE_MIDDLE_BUTTON) {
return false; return false;
@ -892,6 +887,10 @@ public class SongMenu extends ComplexOpsuState {
if (super.mouseReleased(button, x, y)) { if (super.mouseReleased(button, x, y)) {
return true; return true;
} }
if (optionsOverlay.mouseReleased(button, x, y)) {
return true;
}
if (button == Input.MOUSE_MIDDLE_BUTTON) { if (button == Input.MOUSE_MIDDLE_BUTTON) {
return false; return false;
@ -908,14 +907,17 @@ public class SongMenu extends ComplexOpsuState {
return true; return true;
} }
if (UI.getBackButton().contains(x, y)) { if (backButton.contains(x, y)) {
SoundController.playSound(SoundEffect.MENUBACK); SoundController.playSound(SoundEffect.MENUBACK);
displayContainer.switchState(mainmenuState); displayContainer.switchState(mainmenuState);
return true; return true;
} }
// selection buttons // 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'); this.keyPressed(KEY_F1, '\0');
return true; return true;
} else if (selectRandomButton.contains(x, y)) { } else if (selectRandomButton.contains(x, y)) {
@ -924,10 +926,6 @@ public class SongMenu extends ComplexOpsuState {
} else if (selectMapOptionsButton.contains(x, y)) { } else if (selectMapOptionsButton.contains(x, y)) {
this.keyPressed(KEY_F3, '\0'); this.keyPressed(KEY_F3, '\0');
return true; return true;
} else if (selectOptionsButton.contains(x, y)) {
SoundController.playSound(SoundEffect.MENUHIT);
optionsOverlay.show();
return true;
} }
// group tabs // group tabs
@ -955,7 +953,7 @@ public class SongMenu extends ComplexOpsuState {
setFocus(BeatmapSetList.get().getRandomNode(), -1, true, true); setFocus(BeatmapSetList.get().getRandomNode(), -1, true, true);
if (BeatmapSetList.get().size() < 1 && group.getEmptyMessage() != null) { if (BeatmapSetList.get().size() < 1 && group.getEmptyMessage() != null) {
BarNotifListener.EVENT.make().onBarNotif(group.getEmptyMessage()); barNotifs.send(group.getEmptyMessage());
} }
return true; return true;
} }
@ -1038,6 +1036,10 @@ public class SongMenu extends ComplexOpsuState {
if (super.keyPressed(key, c)) { if (super.keyPressed(key, c)) {
return true; return true;
} }
if (optionsOverlay.keyPressed(key, c)) {
return true;
}
// block input // block input
if ((reloadThread != null && key != KEY_ESCAPE) || beatmapMenuTimer > -1 || isScrollingToFocusNode) { 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)) { if (super.mouseDragged(oldx, oldy, newx, newy)) {
return true; return true;
} }
if (optionsOverlay.mouseDragged(oldx, oldy, newx, newy)) {
return true;
}
if (isInputBlocked()) { if (isInputBlocked()) {
return true; return true;
@ -1225,6 +1231,10 @@ public class SongMenu extends ComplexOpsuState {
if (super.mouseWheelMoved(newValue)) { if (super.mouseWheelMoved(newValue)) {
return true; return true;
} }
if (optionsOverlay.mouseWheelMoved(newValue)) {
return true;
}
if (isInputBlocked()) { if (isInputBlocked()) {
return true; return true;
@ -1242,16 +1252,25 @@ public class SongMenu extends ComplexOpsuState {
changeIndex(shift); changeIndex(shift);
return false; return false;
} }
@Override
public boolean keyReleased(int key, char c) {
if (super.keyReleased(key, c)) {
return true;
}
return optionsOverlay.keyReleased(key, c);
}
@Override @Override
public void enter() { public void enter() {
super.enter(); super.enter();
UI.enter(); UI.enter();
selectModeButton.resetHover();
selectModsButton.resetHover(); selectModsButton.resetHover();
selectRandomButton.resetHover(); selectRandomButton.resetHover();
selectMapOptionsButton.resetHover(); selectMapOptionsButton.resetHover();
selectOptionsButton.resetHover();
hoverOffset.setTime(0); hoverOffset.setTime(0);
hoverIndex = null; hoverIndex = null;
isScrollingToFocusNode = false; isScrollingToFocusNode = false;
@ -1761,7 +1780,7 @@ public class SongMenu extends ComplexOpsuState {
Beatmap beatmap = MusicController.getBeatmap(); Beatmap beatmap = MusicController.getBeatmap();
if (focusNode == null || beatmap != focusNode.getSelectedBeatmap()) { 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; return;
} }

View File

@ -22,13 +22,12 @@ import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.audio.MusicController; import itdelatrisu.opsu.audio.MusicController;
import itdelatrisu.opsu.audio.SoundController; import itdelatrisu.opsu.audio.SoundController;
import itdelatrisu.opsu.beatmap.BeatmapSetList; import itdelatrisu.opsu.beatmap.BeatmapSetList;
import itdelatrisu.opsu.ui.Cursor;
import itdelatrisu.opsu.ui.UI; import itdelatrisu.opsu.ui.UI;
import org.lwjgl.input.Keyboard; import org.lwjgl.input.Keyboard;
import org.newdawn.slick.Color; import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics; import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import org.newdawn.slick.opengl.renderer.Renderer;
import org.newdawn.slick.util.Log; import org.newdawn.slick.util.Log;
import yugecin.opsudance.core.state.BaseOpsuState; import yugecin.opsudance.core.state.BaseOpsuState;
@ -65,9 +64,6 @@ public class Splash extends BaseOpsuState {
return; return;
} }
System.out.println(
Renderer.get().getClass()
);
inited = true; inited = true;
thread = new Thread() { thread = new Thread() {
@Override @Override
@ -111,7 +107,13 @@ public class Splash extends BaseOpsuState {
@Override @Override
public void render(Graphics g) { public void render(Graphics g) {
g.setBackground(Color.black); 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); UI.drawLoadingProgress(g);
} }

View File

@ -28,6 +28,7 @@ public class Colors {
BLACK_ALPHA = new Color(0, 0, 0, 0.5f), BLACK_ALPHA = new Color(0, 0, 0, 0.5f),
BLACK_ALPHA_75 = new Color(0, 0, 0, 0.75f), BLACK_ALPHA_75 = new Color(0, 0, 0, 0.75f),
BLACK_ALPHA_85 = new Color(0, 0, 0, 0.85f), 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), WHITE_ALPHA = new Color(255, 255, 255, 0.5f),
BLUE_DIVIDER = new Color(49, 94, 237), BLUE_DIVIDER = new Color(49, 94, 237),
BLUE_BACKGROUND = new Color(74, 130, 255), BLUE_BACKGROUND = new Color(74, 130, 255),
@ -53,8 +54,7 @@ public class Colors {
BUB_WHITE = new Color(220, 220, 220), BUB_WHITE = new Color(220, 220, 220),
BUB_PURPLE = new Color(94, 46, 149), BUB_PURPLE = new Color(94, 46, 149),
BUB_RED = new Color(141, 49, 16), BUB_RED = new Color(141, 49, 16),
BUB_ORANGE = new Color(138, 72, 51), BUB_ORANGE = new Color(138, 72, 51);
GHOST_LOGO = new Color(1.0f, 1.0f, 1.0f, 0.25f);
// This class should not be instantiated. // This class should not be instantiated.
private Colors() {} private Colors() {}

View File

@ -30,6 +30,7 @@ import yugecin.opsudance.Dancer;
import yugecin.opsudance.skinning.SkinService; import yugecin.opsudance.skinning.SkinService;
import static yugecin.opsudance.options.Options.*; import static yugecin.opsudance.options.Options.*;
import static yugecin.opsudance.core.InstanceContainer.*;
/** /**
* Updates and draws the cursor. * Updates and draws the cursor.
@ -263,8 +264,8 @@ public class Cursor {
* If the old style cursor is being used, this will do nothing. * If the old style cursor is being used, this will do nothing.
* @param delta the delta interval since the last call * @param delta the delta interval since the last call
*/ */
public void updateAngle(int delta) { public void updateAngle() {
cursorAngle += delta / 40f; cursorAngle += renderDelta / 40f;
cursorAngle %= 360; cursorAngle %= 360;
} }

View File

@ -29,15 +29,14 @@ import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image; import org.newdawn.slick.Image;
import org.newdawn.slick.Input; import org.newdawn.slick.Input;
import org.newdawn.slick.UnicodeFont; import org.newdawn.slick.UnicodeFont;
import yugecin.opsudance.core.DisplayContainer;
import yugecin.opsudance.core.components.Component; import yugecin.opsudance.core.components.Component;
import static yugecin.opsudance.core.InstanceContainer.*;
public class DropdownMenu<E> extends Component { public class DropdownMenu<E> extends Component {
private static final float PADDING_Y = 0.1f, CHEVRON_X = 0.03f; private static final float PADDING_Y = 0.1f, CHEVRON_X = 0.03f;
private final DisplayContainer displayContainer;
private E[] items; private E[] items;
private String[] itemNames; private String[] itemNames;
private int selectedItemIndex; private int selectedItemIndex;
@ -61,8 +60,7 @@ public class DropdownMenu<E> extends Component {
private Image chevronDown; private Image chevronDown;
private Image chevronRight; private Image chevronRight;
public DropdownMenu(DisplayContainer displayContainer, E[] items, int x, int y, int width) { public DropdownMenu(E[] items, int x, int y, int width) {
this.displayContainer = displayContainer;
init(items, x, y, width); init(items, x, y, width);
} }
@ -143,13 +141,13 @@ public class DropdownMenu<E> extends Component {
@Override @Override
public void render(Graphics g) { public void render(Graphics g) {
int delta = displayContainer.renderDelta; int delta = renderDelta;
// update animation // update animation
expandProgress.update((expanded) ? delta : -delta * 2); expandProgress.update((expanded) ? delta : -delta * 2);
// get parameters // get parameters
int idx = getIndexAt(displayContainer.mouseY); int idx = getIndexAt(mouseY);
float t = expandProgress.getValue(); float t = expandProgress.getValue();
if (expanded) { if (expanded) {
t = AnimationEquation.OUT_CUBIC.calc(t); t = AnimationEquation.OUT_CUBIC.calc(t);
@ -245,7 +243,7 @@ public class DropdownMenu<E> extends Component {
return; return;
} }
int idx = getIndexAt(displayContainer.mouseY); int idx = getIndexAt(mouseY);
if (idx == -2) { if (idx == -2) {
this.expanded = false; this.expanded = false;
return; return;

View File

@ -18,10 +18,13 @@
package itdelatrisu.opsu.ui; package itdelatrisu.opsu.ui;
import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.Utils; import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.ui.animations.AnimatedValue; import itdelatrisu.opsu.ui.animations.AnimatedValue;
import itdelatrisu.opsu.ui.animations.AnimationEquation; import itdelatrisu.opsu.ui.animations.AnimationEquation;
import java.awt.Point;
import org.newdawn.slick.Animation; import org.newdawn.slick.Animation;
import org.newdawn.slick.Color; import org.newdawn.slick.Color;
import org.newdawn.slick.Font; import org.newdawn.slick.Font;
@ -98,9 +101,6 @@ public class MenuButton {
/** The default max rotation angle of the button. */ /** The default max rotation angle of the button. */
private static final float DEFAULT_ANGLE_MAX = 30f; 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. * Creates a new button from an Image.
* @param img the image * @param img the image
@ -115,6 +115,14 @@ public class MenuButton {
this.yRadius = img.getHeight() / 2f; 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. * Creates a new button from a 3-part Image.
* @param imgCenter the center image * @param imgCenter the center image
@ -168,11 +176,20 @@ public class MenuButton {
* Returns the center y coordinate. * Returns the center y coordinate.
*/ */
public float getY() { return y; } 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. * Sets text to draw in the middle of the button.
@ -229,7 +246,6 @@ public class MenuButton {
xScaleOffset = image.getWidth() / 2f - xRadius; xScaleOffset = image.getWidth() / 2f - xRadius;
yScaleOffset = image.getHeight() / 2f - yRadius; yScaleOffset = image.getHeight() / 2f - yRadius;
} }
lastScale = scaleOverride;
if (hoverEffect == 0) if (hoverEffect == 0)
image.draw(x - xRadius, y - yRadius, filter); image.draw(x - xRadius, y - yRadius, filter);
else { else {
@ -243,7 +259,6 @@ public class MenuButton {
xScaleOffset = image.getWidth() / 2f - xRadius; xScaleOffset = image.getWidth() / 2f - xRadius;
yScaleOffset = image.getHeight() / 2f - yRadius; yScaleOffset = image.getHeight() / 2f - yRadius;
} }
lastScale *= scale.getValue();
} }
} }
if ((hoverEffect & EFFECT_FADE) > 0) if ((hoverEffect & EFFECT_FADE) > 0)

View File

@ -22,27 +22,21 @@ import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.Utils; import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.audio.SoundController; import itdelatrisu.opsu.audio.SoundController;
import itdelatrisu.opsu.beatmap.BeatmapParser; import itdelatrisu.opsu.beatmap.BeatmapParser;
import itdelatrisu.opsu.beatmap.OszUnpacker;
import itdelatrisu.opsu.replay.ReplayImporter;
import itdelatrisu.opsu.ui.animations.AnimatedValue; import itdelatrisu.opsu.ui.animations.AnimatedValue;
import itdelatrisu.opsu.ui.animations.AnimationEquation; import itdelatrisu.opsu.ui.animations.AnimationEquation;
import org.newdawn.slick.Color; import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics; import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image; import org.newdawn.slick.Image;
import yugecin.opsudance.core.DisplayContainer;
import yugecin.opsudance.ui.BackButton;
import static yugecin.opsudance.options.Options.*; import static yugecin.opsudance.options.Options.*;
import static yugecin.opsudance.core.InstanceContainer.*;
/** /**
* Draws common UI components. * Draws common UI components.
*/ */
public class UI { public class UI {
/** Back button. */
private static BackButton backButton;
/** Time to show volume image, in milliseconds. */ /** Time to show volume image, in milliseconds. */
private static final int VOLUME_DISPLAY_TIME = 1500; private static final int VOLUME_DISPLAY_TIME = 1500;
@ -58,20 +52,9 @@ public class UI {
/** The alpha level of the current tooltip (if any). */ /** The alpha level of the current tooltip (if any). */
private static AnimatedValue tooltipAlpha = new AnimatedValue(200, 0f, 1f, AnimationEquation.LINEAR); private static AnimatedValue tooltipAlpha = new AnimatedValue(200, 0f, 1f, AnimationEquation.LINEAR);
// game-related variables
private static DisplayContainer displayContainer;
// This class should not be instantiated. // This class should not be instantiated.
private UI() {} 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. * Updates all UI components by a delta interval.
* @param delta the delta interval since the last call. * @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. * Resets the necessary UI components upon entering a state.
*/ */
public static void enter() { public static void enter() {
backButton.resetHover();
resetTooltip(); resetTooltip();
} }
/**
* Returns the 'menu-back' MenuButton.
*/
public static BackButton getBackButton() { return backButton; }
/** /**
* Draws a tab image and text centered at a location. * Draws a tab image and text centered at a location.
* @param x the center x coordinate * @param x the center x coordinate
@ -145,13 +122,13 @@ public class UI {
else if (ratio >= 0.9f) else if (ratio >= 0.9f)
xOffset = img.getWidth() * (1 - ((1 - ratio) * 10f)); 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 barHeight = img.getHeight() * 0.9f;
float volume = OPTION_MASTER_VOLUME.val / 100f; float volume = OPTION_MASTER_VOLUME.val / 100f;
g.setColor(Color.white); g.setColor(Color.white);
g.fillRoundRect( g.fillRoundRect(
displayContainer.width - (img.getWidth() * 0.368f) + xOffset, width - (img.getWidth() * 0.368f) + xOffset,
(displayContainer.height / 2f) - (img.getHeight() * 0.47f) + (barHeight * (1 - volume)), height2 - (img.getHeight() * 0.47f) + (barHeight * (1 - volume)),
img.getWidth() * 0.15f, barHeight * volume, 3 img.getWidth() * 0.15f, barHeight * volume, 3
); );
} }
@ -193,33 +170,25 @@ public class UI {
int progress; int progress;
// determine current action // determine current action
// if ((file = oszunpacker.getCurrentFileName()) != null) {
/*
TODO
if ((file = OszUnpacker.getCurrentFileName()) != null) {
text = "Unpacking new beatmaps..."; text = "Unpacking new beatmaps...";
progress = OszUnpacker.getUnpackerProgress(); progress = oszunpacker.getUnpackerProgress();
} else if ((file = BeatmapParser.getCurrentFileName()) != null) { } else if ((file = beatmapParser.getCurrentFileName()) != null) {
text = (BeatmapParser.getStatus() == BeatmapParser.Status.INSERTING) ? text = (beatmapParser.getStatus() == BeatmapParser.Status.INSERTING) ?
"Updating database..." : "Loading beatmaps..."; "Updating database..." : "Loading beatmaps...";
progress = BeatmapParser.getParserProgress(); progress = beatmapParser.getParserProgress();
} else if ((file = ReplayImporter.getCurrentFileName()) != null) { } else if ((file = replayImporter.getCurrentFileName()) != null) {
text = "Importing replays..."; text = "Importing replays...";
progress = ReplayImporter.getLoadingProgress(); progress = replayImporter.getLoadingProgress();
} else if ((file = SoundController.getCurrentFileName()) != null) { } else if ((file = SoundController.getCurrentFileName()) != null) {
text = "Loading sounds..."; text = "Loading sounds...";
progress = SoundController.getLoadingProgress(); progress = SoundController.getLoadingProgress();
} else } else
return; return;
*/
if (true) {
return; // TODO
}
// draw loading info // draw loading info
float marginX = displayContainer.width * 0.02f, marginY = displayContainer.height * 0.02f; float marginX = width * 0.02f, marginY = height * 0.02f;
float lineY = displayContainer.height - marginY; float lineY = height - marginY;
int lineOffsetY = Fonts.MEDIUM.getLineHeight(); int lineOffsetY = Fonts.MEDIUM.getLineHeight();
if (OPTION_LOAD_VERBOSE.state) { if (OPTION_LOAD_VERBOSE.state) {
// verbose: display percentages and file names // verbose: display percentages and file names
@ -232,7 +201,7 @@ public class UI {
Fonts.MEDIUM.drawString(marginX, lineY - (lineOffsetY * 2), text, Color.white); Fonts.MEDIUM.drawString(marginX, lineY - (lineOffsetY * 2), text, Color.white);
g.setColor(Color.white); g.setColor(Color.white);
g.fillRoundRect(marginX, lineY - (lineOffsetY / 2f), 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, float unitBaseX, float unitBaseY, float unitWidth, float scrollAreaHeight,
Color bgColor, Color scrollbarColor, boolean right Color bgColor, Color scrollbarColor, boolean right
) { ) {
float scrollbarWidth = displayContainer.width * 0.00347f; float scrollbarWidth = width * 0.00347f;
float scrollbarHeight = scrollAreaHeight * lengthShown / totalLength; float scrollbarHeight = scrollAreaHeight * lengthShown / totalLength;
float offsetY = (scrollAreaHeight - scrollbarHeight) * (position / (totalLength - lengthShown)); float offsetY = (scrollAreaHeight - scrollbarHeight) * (position / (totalLength - lengthShown));
float scrollbarX = unitBaseX + unitWidth - ((right) ? scrollbarWidth : 0); float scrollbarX = unitBaseX + unitWidth - ((right) ? scrollbarWidth : 0);
@ -292,8 +261,8 @@ public class UI {
if (tooltipAlpha.getTime() == 0 || tooltip == null) if (tooltipAlpha.getTime() == 0 || tooltip == null)
return; return;
int margin = displayContainer.width / 100, textMarginX = 2; int margin = width / 100, textMarginX = 2;
int offset = GameImage.CURSOR_MIDDLE.getImage().getWidth() / 2; int offset = GameImage.CURSOR_MIDDLE.getWidth() / 2;
int lineHeight = Fonts.SMALL.getLineHeight(); int lineHeight = Fonts.SMALL.getLineHeight();
int textWidth = textMarginX * 2, textHeight = lineHeight; int textWidth = textMarginX * 2, textHeight = lineHeight;
if (tooltipNewlines) { if (tooltipNewlines) {
@ -310,14 +279,14 @@ public class UI {
textWidth += Fonts.SMALL.getWidth(tooltip); textWidth += Fonts.SMALL.getWidth(tooltip);
// get drawing coordinates // get drawing coordinates
int x = displayContainer.mouseX + offset; int x = mouseX + offset;
int y = displayContainer.mouseY + offset; int y = mouseY + offset;
if (x + textWidth > displayContainer.width - margin) if (x + textWidth > width - margin)
x = displayContainer.width - margin - textWidth; x = width - margin - textWidth;
else if (x < margin) else if (x < margin)
x = margin; x = margin;
if (y + textHeight > displayContainer.height - margin) if (y + textHeight > height - margin)
y = displayContainer.height - margin - textHeight; y = height - margin - textHeight;
else if (y < margin) else if (y < margin)
y = margin; y = margin;

View File

@ -57,6 +57,41 @@ public class AnimatedValue {
this.diff = max - min; this.diff = max - min;
this.eqn = eqn; 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. * Returns the current value.

View File

@ -312,4 +312,19 @@ public enum AnimationEquation {
* @return the new {@code t} value [0,1] * @return the new {@code t} value [0,1]
*/ */
public abstract float calc(float t); 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;
}
} }

View File

@ -43,7 +43,7 @@ import static org.lwjgl.input.Keyboard.*;
* *
* @author kevin * @author kevin
*/ */
@SuppressWarnings({"rawtypes", "unchecked", "unused"}) @SuppressWarnings({"unused"})
public class Input { public class Input {
/** A helper for left ALT */ /** A helper for left ALT */
@ -98,8 +98,6 @@ public class Input {
protected char[] keys = new char[1024]; protected char[] keys = new char[1024];
/** True if the key has been pressed since last queries */ /** True if the key has been pressed since last queries */
protected boolean[] pressed = new boolean[1024]; 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 */ /** The listeners to notify of key events */
protected ArrayList<KeyListener> keyListeners = new ArrayList<>(); protected ArrayList<KeyListener> keyListeners = new ArrayList<>();
@ -113,13 +111,6 @@ public class Input {
/** True if the display is active */ /** True if the display is active */
private boolean displayActive = true; 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 */ /** The clicked button */
private int clickButton; private int clickButton;
@ -344,7 +335,6 @@ public class Input {
keys[eventKey] = Keyboard.getEventCharacter(); keys[eventKey] = Keyboard.getEventCharacter();
pressed[eventKey] = true; pressed[eventKey] = true;
nextRepeat[eventKey] = System.currentTimeMillis() + keyRepeatInitial;
for (KeyListener listener : keyListeners) { for (KeyListener listener : keyListeners) {
if (listener.keyPressed(eventKey, Keyboard.getEventCharacter())) { if (listener.keyPressed(eventKey, Keyboard.getEventCharacter())) {
@ -353,7 +343,6 @@ public class Input {
} }
} else { } else {
int eventKey = Keyboard.getEventKey(); int eventKey = Keyboard.getEventKey();
nextRepeat[eventKey] = 0;
for (KeyListener listener : keyListeners) { for (KeyListener listener : keyListeners) {
if (listener.keyReleased(eventKey, keys[eventKey])) { if (listener.keyReleased(eventKey, keys[eventKey])) {
@ -424,21 +413,6 @@ public class Input {
lastMouseY = getMouseY(); 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()) { if (Display.isCreated()) {
displayActive = Display.isActive(); displayActive = Display.isActive();

View File

@ -1,6 +1,6 @@
/* /*
* opsu!dance - fork of opsu! with cursordance auto * 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 * 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 * 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.DefaultSliderMoverController;
import yugecin.opsudance.movers.slidermovers.InheritedSliderMoverController; import yugecin.opsudance.movers.slidermovers.InheritedSliderMoverController;
import yugecin.opsudance.movers.slidermovers.SliderMoverController; import yugecin.opsudance.movers.slidermovers.SliderMoverController;
import yugecin.opsudance.render.GameObjectRenderer;
import yugecin.opsudance.spinners.*; import yugecin.opsudance.spinners.*;
import java.awt.*; import java.awt.*;
@ -252,8 +251,8 @@ public class Dancer {
} }
} }
Pippi.dance(time, c, isCurrentLazySlider); Pippi.dance(time, c, isCurrentLazySlider);
x = Utils.clamp(x, 10, displayContainer.width - 10); x = Utils.clamp(x, 10, width - 10);
y = Utils.clamp(y, 10, displayContainer.height - 10); y = Utils.clamp(y, 10, height - 10);
} }
private void createNewMover() { private void createNewMover() {

View File

@ -1,6 +1,6 @@
/* /*
* opsu!dance - fork of opsu! with cursordance auto * 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 * 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 * 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.DownloadNode;
import itdelatrisu.opsu.downloads.Updater; import itdelatrisu.opsu.downloads.Updater;
import itdelatrisu.opsu.render.CurveRenderState; import itdelatrisu.opsu.render.CurveRenderState;
import itdelatrisu.opsu.render.FrameBufferCache;
import itdelatrisu.opsu.replay.PlaybackSpeed; import itdelatrisu.opsu.replay.PlaybackSpeed;
import itdelatrisu.opsu.ui.Colors;
import itdelatrisu.opsu.ui.Cursor; import itdelatrisu.opsu.ui.Cursor;
import itdelatrisu.opsu.ui.Fonts; import itdelatrisu.opsu.ui.Fonts;
import itdelatrisu.opsu.ui.UI; import itdelatrisu.opsu.ui.UI;
@ -43,16 +43,16 @@ import org.newdawn.slick.opengl.renderer.SGL;
import org.newdawn.slick.util.Log; import org.newdawn.slick.util.Log;
import yugecin.opsudance.core.errorhandling.ErrorDumpable; import yugecin.opsudance.core.errorhandling.ErrorDumpable;
import yugecin.opsudance.core.state.OpsuState; import yugecin.opsudance.core.state.OpsuState;
import yugecin.opsudance.core.state.specialstates.BarNotificationState;
import yugecin.opsudance.core.state.specialstates.BubNotifState;
import yugecin.opsudance.core.state.specialstates.FpsRenderState;
import yugecin.opsudance.events.BubNotifListener;
import yugecin.opsudance.events.ResolutionChangedListener; import yugecin.opsudance.events.ResolutionChangedListener;
import yugecin.opsudance.events.SkinChangedListener; import yugecin.opsudance.events.SkinChangedListener;
import yugecin.opsudance.ui.BackButton;
import yugecin.opsudance.utils.GLHelper; import yugecin.opsudance.utils.GLHelper;
import java.io.StringWriter; 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.Entrypoint.sout;
import static yugecin.opsudance.core.InstanceContainer.*; import static yugecin.opsudance.core.InstanceContainer.*;
import static yugecin.opsudance.options.Options.*; import static yugecin.opsudance.options.Options.*;
@ -60,33 +60,23 @@ import static yugecin.opsudance.options.Options.*;
/** /**
* based on org.newdawn.slick.AppGameContainer * 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 static SGL GL = Renderer.get();
private FpsRenderState fpsState;
private BarNotificationState barNotifState;
private BubNotifState bubNotifState;
private OpsuState state; private OpsuState state;
public final DisplayMode nativeDisplayMode; public final DisplayMode nativeDisplayMode;
private Graphics graphics; private Graphics graphics;
public int width;
public int height;
public int mouseX;
public int mouseY;
private int targetUpdatesPerSecond; private int targetUpdatesPerSecond;
public int targetUpdateInterval; public int targetUpdateInterval;
private int targetRendersPerSecond; private int targetRendersPerSecond;
public int targetRenderInterval; public int targetRenderInterval;
public int targetBackgroundRenderInterval; public int targetBackgroundRenderInterval;
public int renderDelta; private boolean rendering;
public int delta; public int delta;
public boolean exitRequested; public boolean exitRequested;
@ -104,53 +94,22 @@ public class DisplayContainer implements ErrorDumpable, ResolutionChangedListene
public final Cursor cursor; public final Cursor cursor;
public boolean drawCursor; public boolean drawCursor;
private final List<ResolutionChangedListener> resolutionChangedListeners;
class Transition { private int tIn;
int in; private int tOut;
int out; private int tProgress = -1;
int total; private OpsuState tNextState;
int progress = -1; private final Color tOVERLAY = new Color(Color.black);
OpsuState nextstate;
Color OVERLAY = new Color(Color.black);
public void update() { public DisplayContainer()
if (progress == -1) { {
return; this.resolutionChangedListeners = new ArrayList<>();
}
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() {
this.cursor = new Cursor(); this.cursor = new Cursor();
drawCursor = true; drawCursor = true;
ResolutionChangedListener.EVENT.addListener(this); skinservice.addSkinChangedListener(this);
SkinChangedListener.EVENT.addListener(this);
this.nativeDisplayMode = Display.getDisplayMode(); this.nativeDisplayMode = Display.getDisplayMode();
targetBackgroundRenderInterval = 41; // ~24 fps targetBackgroundRenderInterval = 41; // ~24 fps
@ -159,10 +118,9 @@ public class DisplayContainer implements ErrorDumpable, ResolutionChangedListene
renderDelta = 1; renderDelta = 1;
} }
@Override public void addResolutionChangedListener(ResolutionChangedListener l)
public void onResolutionChanged(int w, int h) { {
destroyImages(); this.resolutionChangedListeners.add(l);
reinit();
} }
@Override @Override
@ -186,12 +144,13 @@ public class DisplayContainer implements ErrorDumpable, ResolutionChangedListene
} }
} }
backButton = new BackButton();
// TODO clean this up // TODO clean this up
GameMod.init(width, height); GameMod.init(width, height);
PlaybackSpeed.init(width, height); PlaybackSpeed.init(width, height);
HitObject.init(width, height); HitObject.init(width, height);
DownloadNode.init(width, height); DownloadNode.init(width, height);
UI.init(this);
} }
public void setUPS(int ups) { public void setUPS(int ups) {
@ -205,13 +164,9 @@ public class DisplayContainer implements ErrorDumpable, ResolutionChangedListene
} }
public void init(OpsuState startingState) { public void init(OpsuState startingState) {
setUPS(OPTION_TARGET_UPS.val); setUPS(targetUPS[OPTION_TARGET_UPS.val]);
setFPS(targetFPS[targetFPSIndex]); setFPS(targetFPS[targetFPSIndex]);
fpsState = new FpsRenderState();
bubNotifState = new BubNotifState();
barNotifState = new BarNotificationState();
state = startingState; state = startingState;
state.enter(); state.enter();
} }
@ -228,8 +183,18 @@ public class DisplayContainer implements ErrorDumpable, ResolutionChangedListene
mouseX = input.getMouseX(); mouseX = input.getMouseX();
mouseY = input.getMouseY(); mouseY = input.getMouseY();
transition.update(); // state transition
fpsState.update(); if (tProgress != -1) {
tProgress += delta;
if (tProgress > tOut && tNextState != null) {
switchStateInstantly(tNextState);
tNextState = null;
}
if (tProgress > tIn + tOut) {
tProgress = -1;
}
}
fpsDisplay.update();
state.update(); state.update();
if (drawCursor) { if (drawCursor) {
@ -244,6 +209,7 @@ public class DisplayContainer implements ErrorDumpable, ResolutionChangedListene
} }
if (timeSinceLastRender >= maxRenderInterval) { if (timeSinceLastRender >= maxRenderInterval) {
rendering = true;
GL.glClear(SGL.GL_COLOR_BUFFER_BIT); GL.glClear(SGL.GL_COLOR_BUFFER_BIT);
/* /*
@ -257,32 +223,44 @@ public class DisplayContainer implements ErrorDumpable, ResolutionChangedListene
state.preRenderUpdate(); state.preRenderUpdate();
state.render(graphics); state.render(graphics);
fpsState.render(graphics); fpsDisplay.render(graphics);
bubNotifState.render(graphics); bubNotifs.render(graphics);
barNotifState.render(graphics); barNotifs.render(graphics);
cursor.updateAngle(renderDelta); cursor.updateAngle();
if (drawCursor) { if (drawCursor) {
cursor.draw(Mouse.isButtonDown(Input.MOUSE_LEFT_BUTTON) || cursor.draw(Mouse.isButtonDown(Input.MOUSE_LEFT_BUTTON) ||
Mouse.isButtonDown(Input.MOUSE_RIGHT_BUTTON)); Mouse.isButtonDown(Input.MOUSE_RIGHT_BUTTON));
} }
UI.drawTooltip(graphics); 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; timeSinceLastRender = 0;
Display.update(false); Display.update(false);
GL11.glFlush(); GL11.glFlush();
rendering = false;
} }
Display.processMessages(); Display.processMessages();
Display.sync(targetUpdatesPerSecond); if (targetUpdatesPerSecond >= 60) {
Display.sync(targetUpdatesPerSecond);
}
} }
} }
public void setup() throws Exception { public void setup() throws Exception {
width = height = -1; width = height = width2 = height2 = -1;
Display.setTitle("opsu!dance"); Display.setTitle("opsu!dance");
setupResolutionOptionlist(nativeDisplayMode.getWidth(), nativeDisplayMode.getHeight()); setupResolutionOptionlist(nativeDisplayMode.getWidth(), nativeDisplayMode.getHeight());
updateDisplayMode(OPTION_SCREEN_RESOLUTION.getValueString()); updateDisplayMode(OPTION_SCREEN_RESOLUTION.getValueString());
@ -318,6 +296,7 @@ public class DisplayContainer implements ErrorDumpable, ResolutionChangedListene
GameImage.destroyImages(); GameImage.destroyImages();
GameData.Grade.destroyImages(); GameData.Grade.destroyImages();
Beatmap.destroyBackgroundImageCache(); Beatmap.destroyBackgroundImageCache();
FrameBufferCache.shutdown();
} }
public void teardownAL() { public void teardownAL() {
@ -342,13 +321,13 @@ public class DisplayContainer implements ErrorDumpable, ResolutionChangedListene
return true; return true;
} }
if (DownloadList.get().hasActiveDownloads()) { if (DownloadList.get().hasActiveDownloads()) {
BubNotifListener.EVENT.make().onBubNotif(DownloadList.EXIT_CONFIRMATION, Colors.BUB_RED); bubNotifs.send(BUB_RED, DownloadList.EXIT_CONFIRMATION);
exitRequested = false; exitRequested = false;
exitconfirmation = System.currentTimeMillis(); exitconfirmation = System.currentTimeMillis();
return false; return false;
} }
if (updater.getStatus() == Updater.Status.UPDATE_DOWNLOADING) { 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; exitRequested = false;
exitconfirmation = System.currentTimeMillis(); exitconfirmation = System.currentTimeMillis();
return false; return false;
@ -372,6 +351,13 @@ public class DisplayContainer implements ErrorDumpable, ResolutionChangedListene
width = Integer.parseInt(res[0]); width = Integer.parseInt(res[0]);
height = Integer.parseInt(res[1]); 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 // check for larger-than-screen dimensions
if (!OPTION_ALLOW_LARGER_RESOLUTIONS.state && (screenWidth < width || screenHeight < height)) { if (!OPTION_ALLOW_LARGER_RESOLUTIONS.state && (screenWidth < width || screenHeight < height)) {
@ -387,34 +373,35 @@ public class DisplayContainer implements ErrorDumpable, ResolutionChangedListene
try { try {
setDisplayMode(width, height, OPTION_FULLSCREEN.state); setDisplayMode(width, height, OPTION_FULLSCREEN.state);
} catch (Exception e) { } 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); Log.error("Failed to set display mode.", e);
} }
} }
public void setDisplayMode(int width, int height, boolean fullscreen) throws Exception { public void setDisplayMode(int w, int h, boolean fullscreen) throws Exception {
if (this.width == width && this.height == height) {
Display.setFullscreen(fullscreen);
return;
}
DisplayMode displayMode = null; DisplayMode displayMode = null;
if (fullscreen) { 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) { if (displayMode == null) {
displayMode = new DisplayMode(width, height); displayMode = new DisplayMode(w, h);
if (fullscreen) { if (fullscreen) {
fullscreen = false; 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); Log.warn(msg);
BubNotifListener.EVENT.make().onBubNotif(msg, Colors.BUB_ORANGE); bubNotifs.send(BUB_ORANGE, msg);
} }
} }
this.width = displayMode.getWidth(); width = displayMode.getWidth();
this.height = displayMode.getHeight(); height = displayMode.getHeight();
width2 = width / 2;
height2 = height / 2;
isWidescreen = width * 1000 / height > 1500; // 1777 = 16:9, 1333 = 4:3
Display.setDisplayMode(displayMode); Display.setDisplayMode(displayMode);
Display.setFullscreen(fullscreen); Display.setFullscreen(fullscreen);
@ -439,7 +426,7 @@ public class DisplayContainer implements ErrorDumpable, ResolutionChangedListene
input = new Input(height); input = new Input(height);
input.enableKeyRepeat(); input.enableKeyRepeat();
input.addListener(new GlobalInputListener()); input.addListener(new GlobalInputListener());
input.addMouseListener(bubNotifState); input.addMouseListener(bubNotifs);
} }
input.addListener(state); input.addListener(state);
@ -448,7 +435,15 @@ public class DisplayContainer implements ErrorDumpable, ResolutionChangedListene
GameImage.init(width, height); GameImage.init(width, height);
Fonts.init(); 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() { public void resetCursor() {
@ -466,10 +461,6 @@ public class DisplayContainer implements ErrorDumpable, ResolutionChangedListene
return (Sys.getTime() * 1000) / Sys.getTimerResolution(); return (Sys.getTime() * 1000) / Sys.getTimerResolution();
} }
public boolean isWidescreen() {
return width * 1000 / height > 1500; // 1777 = 16:9, 1333 = 4:3
}
@Override @Override
public void writeErrorDump(StringWriter dump) { public void writeErrorDump(StringWriter dump) {
dump.append("> DisplayContainer dump\n"); dump.append("> DisplayContainer dump\n");
@ -487,22 +478,32 @@ public class DisplayContainer implements ErrorDumpable, ResolutionChangedListene
} }
public void switchState(OpsuState state) { public void switchState(OpsuState state) {
switchState(state, 200, 300); switchState(state, 150, 250);
} }
public void switchState(OpsuState newstate, int outtime, int intime) { public void switchState(OpsuState newstate, int outtime, int intime) {
if (transition.progress != -1) { if (tProgress != -1 && tProgress <= tOut) {
return; return;
} }
if (outtime == 0) { if (outtime == 0) {
switchStateInstantly(newstate); switchStateInstantly(newstate);
newstate = null; newstate = null;
} else {
input.removeListener(this.state);
} }
transition.nextstate = newstate;
transition.total = transition.in = intime; if (tProgress == -1) {
transition.out = outtime; tProgress = 0;
transition.total += outtime; } else {
transition.progress = 0; // 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) { public void switchStateInstantly(OpsuState state) {
@ -511,6 +512,13 @@ public class DisplayContainer implements ErrorDumpable, ResolutionChangedListene
this.state = state; this.state = state;
this.state.enter(); this.state.enter();
input.addListener(this.state); 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();
}
} }
} }

View File

@ -1,6 +1,6 @@
/* /*
* opsu!dance - fork of opsu! with cursordance auto * 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 * 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 * 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 itdelatrisu.opsu.ui.UI;
import org.newdawn.slick.Input; import org.newdawn.slick.Input;
import org.newdawn.slick.InputListener; import org.newdawn.slick.InputListener;
import yugecin.opsudance.events.BarNotifListener;
import static org.lwjgl.input.Keyboard.*; import static org.lwjgl.input.Keyboard.*;
import static yugecin.opsudance.core.InstanceContainer.*; import static yugecin.opsudance.core.InstanceContainer.*;
@ -38,8 +37,8 @@ public class GlobalInputListener implements InputListener {
public boolean keyReleased(int key, char c) { public boolean keyReleased(int key, char c) {
if (key == KEY_F7) { if (key == KEY_F7) {
OPTION_TARGET_FPS.clickListItem((targetFPSIndex + 1) % targetFPS.length); OPTION_TARGET_FPS.clickListItem((targetFPSIndex + 1) % targetFPS.length);
BarNotifListener.EVENT.make().onBarNotif(String.format("Frame limiter: %s", final String value = OPTION_TARGET_FPS.getValueString();
OPTION_TARGET_FPS.getValueString())); barNotifs.sendf("Frame limiter: %s", value);
return true; return true;
} }
if (key == KEY_F10) { if (key == KEY_F10) {

View File

@ -1,6 +1,6 @@
/* /*
* opsu!dance - fork of opsu! with cursordance auto * 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 * 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 * 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.Input;
import org.newdawn.slick.util.FileSystemLocation; import org.newdawn.slick.util.FileSystemLocation;
import org.newdawn.slick.util.ResourceLoader; 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.Configuration;
import yugecin.opsudance.options.OptionGroups;
import yugecin.opsudance.options.OptionsService; import yugecin.opsudance.options.OptionsService;
import yugecin.opsudance.render.GameObjectRenderer; import yugecin.opsudance.render.GameObjectRenderer;
import yugecin.opsudance.skinning.SkinService; 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.File;
import java.io.IOException; import java.io.IOException;
@ -51,10 +57,17 @@ public class InstanceContainer {
public static BeatmapParser beatmapParser; public static BeatmapParser beatmapParser;
public static Updater updater; public static Updater updater;
public static BackButton backButton;
public static DisplayContainer displayContainer; public static DisplayContainer displayContainer;
public static Input input; public static Input input;
public static GameObjectRenderer gameObjectRenderer; 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 Splash splashState;
public static MainMenu mainmenuState; public static MainMenu mainmenuState;
@ -64,17 +77,21 @@ public class InstanceContainer {
public static Game gameState; public static Game gameState;
public static GameRanking gameRankingState; public static GameRanking gameRankingState;
public static GamePauseMenu pauseState; 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() { public static void kickstart() {
updater = new Updater(); updater = new Updater();
env = new Environment(); env = new Environment();
JarFile jarfile = getJarfile(); JarFile jarfile = getJarfile();
ManifestWrapper manifest = new ManifestWrapper(getJarManifest(jarfile)); config = new Configuration();
config = new Configuration(manifest);
if (jarfile != null) { if (jarfile != null) {
try { try {
NativeLoader.loadNatives(jarfile, manifest); NativeLoader.loadNatives(jarfile);
} catch (IOException e) { } catch (IOException e) {
String msg = String.format("Could not unpack native(s): %s", e.getMessage()); String msg = String.format("Could not unpack native(s): %s", e.getMessage());
throw new RuntimeException(msg, e); throw new RuntimeException(msg, e);
@ -94,9 +111,15 @@ public class InstanceContainer {
updater = new Updater(); updater = new Updater();
displayContainer = new DisplayContainer(); displayContainer = new DisplayContainer();
barNotifs = new BarNotificationState();
bubNotifs = new BubNotifState();
fpsDisplay = new FpsRenderState();
gameObjectRenderer = new GameObjectRenderer(); gameObjectRenderer = new GameObjectRenderer();
optionsOverlay = new OptionsOverlay(OptionGroups.normalOptions);
splashState = new Splash(); splashState = new Splash();
mainmenuState = new MainMenu(); mainmenuState = new MainMenu();
buttonState = new ButtonMenu(); buttonState = new ButtonMenu();

View File

@ -24,6 +24,11 @@ import yugecin.opsudance.utils.MiscUtils;
import javax.swing.*; import javax.swing.*;
import java.awt.Desktop; 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.Cursor;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
@ -94,30 +99,15 @@ public class ErrorHandler {
} }
JLabel message = new JLabel(messageText); 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() { ActionListener reportAction = new ActionListener() {
@Override @Override
public void actionPerformed(ActionEvent event) { public void actionPerformed(ActionEvent event) {
try { Window parent = SwingUtilities.getWindowAncestor(message);
URI url = createGithubIssueUrl(customMessage, cause, errorDump); showCreateIssueDialog(parent, errorDump, customMessage, cause);
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);
}
} }
}; };
Object[] messageComponents = new Object[] { message, new JScrollPane(textArea), createViewLogButton(), Object[] messageComponents = new Object[] { message, readonlyTextarea(messageBody), createViewLogButton(),
createReportButton(flags, reportAction) }; createReportButton(flags, reportAction) };
String[] buttons; String[] buttons;
@ -181,8 +171,71 @@ public class ErrorHandler {
button.setEnabled(false); button.setEnabled(false);
return button; 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(); StringWriter dump = new StringWriter();
dump.append(customMessage).append("\n"); dump.append(customMessage).append("\n");
@ -203,25 +256,19 @@ public class ErrorHandler {
dump.append("**info dump**").append('\n'); dump.append("**info dump**").append('\n');
dump.append("```\n").append(errorDump).append("\n```\n\n"); dump.append("```\n").append(errorDump).append("\n```\n\n");
return dump.toString();
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));
} }
private static String truncateGithubIssueBody(String body) { private static JComponent readonlyTextarea(String contents) {
if (body.replaceAll("[^a-zA-Z+-]", "").length() < 1750) { JTextArea textArea = new JTextArea(15, 100);
return body; textArea.setEditable(false);
} textArea.setBackground(UIManager.getColor("Panel.background"));
Log.warn("error dump too long to fit into github issue url, truncating"); textArea.setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
return body.substring(0, 1640) + "** TRUNCATED **\n```"; textArea.setTabSize(2);
textArea.setLineWrap(false);
textArea.setWrapStyleWord(true);
textArea.setFont(new JLabel().getFont());
textArea.setText(contents);
return new JScrollPane(textArea);
} }
} }

View File

@ -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;
}
});
}
}

View File

@ -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);
}

Some files were not shown because too many files have changed in this diff Show More