diff --git a/src/itdelatrisu/opsu/Container.java b/src/itdelatrisu/opsu/Container.java
deleted file mode 100644
index 63880381..00000000
--- a/src/itdelatrisu/opsu/Container.java
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * opsu! - an open-source osu! client
- * Copyright (C) 2014, 2015 Jeffrey Han
- *
- * opsu! is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * opsu! is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with opsu!. If not, see .
- */
-
-package itdelatrisu.opsu;
-
-import itdelatrisu.opsu.audio.MusicController;
-import itdelatrisu.opsu.audio.SoundController;
-import itdelatrisu.opsu.beatmap.Beatmap;
-import itdelatrisu.opsu.beatmap.BeatmapGroup;
-import itdelatrisu.opsu.beatmap.BeatmapSetList;
-import itdelatrisu.opsu.beatmap.BeatmapSortOrder;
-import itdelatrisu.opsu.beatmap.BeatmapWatchService;
-import itdelatrisu.opsu.downloads.DownloadList;
-import itdelatrisu.opsu.downloads.Updater;
-import itdelatrisu.opsu.render.CurveRenderState;
-import itdelatrisu.opsu.ui.UI;
-
-import org.lwjgl.opengl.Display;
-import org.newdawn.slick.AppGameContainer;
-import org.newdawn.slick.Game;
-import org.newdawn.slick.SlickException;
-import org.newdawn.slick.opengl.InternalTextureLoader;
-
-/**
- * AppGameContainer extension that sends critical errors to ErrorHandler.
- */
-public class Container extends AppGameContainer {
- /** Exception causing game failure. */
- protected Exception e = null;
-
- public static Container instance;
-
- /**
- * Create a new container wrapping a game
- *
- * @param game The game to be wrapped
- * @throws SlickException Indicates a failure to initialise the display
- */
- public Container(Game game) throws SlickException {
- super(game);
- instance = this;
- }
-
- /**
- * Create a new container wrapping a game
- *
- * @param game The game to be wrapped
- * @param width The width of the display required
- * @param height The height of the display required
- * @param fullscreen True if we want fullscreen mode
- * @throws SlickException Indicates a failure to initialise the display
- */
- public Container(Game game, int width, int height, boolean fullscreen) throws SlickException {
- super(game, width, height, fullscreen);
- }
-
- @Override
- public void start() throws SlickException {
- try {
- setup();
- ErrorHandler.setGlString();
- getDelta();
- while (running())
- gameLoop();
- } catch (Exception e) {
- this.e = e;
- }
-
- // destroy the game container
- try {
- close_sub();
- } catch (Exception e) {
- if (this.e == null) // suppress if caused by a previous exception
- this.e = e;
- }
- destroy();
-
- // report any critical errors
- if (e != null) {
- ErrorHandler.error(null, e, true);
- e = null;
- forceExit = true;
- }
-
- if (forceExit) {
- Opsu.close();
- System.exit(0);
- }
- }
-
- @Override
- protected void gameLoop() throws SlickException {
- int delta = getDelta();
- if (!Display.isVisible() && updateOnlyOnVisible) {
- try { Thread.sleep(100); } catch (Exception e) {}
- } else {
- try {
- updateAndRender(delta);
- } catch (SlickException e) {
- this.e = e; // store exception to display later
- running = false;
- return;
- }
- }
- updateFPS();
- Display.update();
- if (Display.isCloseRequested()) {
- if (game.closeRequested())
- running = false;
- }
- }
-
- /**
- * Actions to perform before destroying the game container.
- */
- private void close_sub() {
- // save user options
- Options.saveOptions();
-
- // reset cursor
- UI.getCursor().reset();
-
- // destroy images
- InternalTextureLoader.get().clear();
-
- // reset image references
- GameImage.clearReferences();
- GameData.Grade.clearReferences();
- Beatmap.clearBackgroundImageCache();
-
- // prevent loading tracks from re-initializing OpenAL
- MusicController.reset();
-
- // stop any playing track
- SoundController.stopTrack();
-
- // reset BeatmapSetList data
- BeatmapGroup.set(BeatmapGroup.ALL);
- BeatmapSortOrder.set(BeatmapSortOrder.TITLE);
- if (BeatmapSetList.get() != null)
- BeatmapSetList.get().reset();
-
- // delete OpenGL objects involved in the Curve rendering
- CurveRenderState.shutdown();
-
- // destroy watch service
- if (!Options.isWatchServiceEnabled())
- BeatmapWatchService.destroy();
- BeatmapWatchService.removeListeners();
-
- // delete temporary directory
- Utils.deleteDirectory(Options.TEMP_DIR);
- }
-
- @Override
- public void exit() {
- // show confirmation dialog if any downloads are active
- if (forceExit) {
- if (DownloadList.get().hasActiveDownloads() &&
- UI.showExitConfirmation(DownloadList.EXIT_CONFIRMATION))
- return;
- if (Updater.get().getStatus() == Updater.Status.UPDATE_DOWNLOADING &&
- UI.showExitConfirmation(Updater.EXIT_CONFIRMATION))
- return;
- }
-
- super.exit();
- }
-}
diff --git a/src/itdelatrisu/opsu/ErrorHandler.java b/src/itdelatrisu/opsu/ErrorHandler.java
deleted file mode 100644
index 1ccead20..00000000
--- a/src/itdelatrisu/opsu/ErrorHandler.java
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * opsu! - an open-source osu! client
- * Copyright (C) 2014, 2015 Jeffrey Han
- *
- * opsu! is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * opsu! is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with opsu!. If not, see .
- */
-
-package itdelatrisu.opsu;
-
-import java.awt.Cursor;
-import java.awt.Desktop;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.io.UnsupportedEncodingException;
-import java.net.URI;
-import java.net.URLEncoder;
-import java.util.Properties;
-
-import javax.swing.JOptionPane;
-import javax.swing.JScrollPane;
-import javax.swing.JTextArea;
-import javax.swing.UIManager;
-
-import org.lwjgl.opengl.GL11;
-import org.newdawn.slick.util.Log;
-import org.newdawn.slick.util.ResourceLoader;
-
-/**
- * Error handler to log and display errors.
- */
-public class ErrorHandler {
- /** Error popup title. */
- private static final String title = "Error";
-
- /** Error popup description text. */
- private static final String
- desc = "opsu! has encountered an error.",
- descReport = "opsu! has encountered an error. Please report this!";
-
- /** Error popup button options. */
- private static final String[]
- optionsLog = {"View Error Log", "Close"},
- optionsReport = {"Send Report", "Close"},
- optionsLogReport = {"Send Report", "View Error Log", "Close"};
-
- /** Text area for Exception. */
- private static final JTextArea textArea = new JTextArea(15, 100);
- static {
- 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);
- }
-
- /** Scroll pane holding JTextArea. */
- private static final JScrollPane scroll = new JScrollPane(textArea);
-
- /** Error popup objects. */
- private static final Object[]
- message = { desc, scroll },
- messageReport = { descReport, scroll };
-
- /** OpenGL string (if any). */
- private static String glString = null;
-
- // This class should not be instantiated.
- private ErrorHandler() {}
-
- /**
- * Sets the OpenGL version string.
- */
- public static void setGlString() {
- try {
- String glVersion = GL11.glGetString(GL11.GL_VERSION);
- String glVendor = GL11.glGetString(GL11.GL_VENDOR);
- glString = String.format("%s (%s)", glVersion, glVendor);
- } catch (Exception e) {}
- }
-
- /**
- * Displays an error popup and logs the given error.
- * @param error a description of the error
- * @param e the exception causing the error
- * @param report whether to ask to report the error
- */
- public static void error(String error, Throwable e, boolean report) {
- if (error == null && e == null)
- return;
-
- // log the error
- if (error == null)
- Log.error(e);
- else if (e == null)
- Log.error(error);
- else
- Log.error(error, e);
-
- // set the textArea to the error message
- textArea.setText(null);
- if (error != null) {
- textArea.append(error);
- textArea.append("\n");
- }
- String trace = null;
- if (e != null) {
- StringWriter sw = new StringWriter();
- e.printStackTrace(new PrintWriter(sw));
- trace = sw.toString();
- textArea.append(trace);
- }
-
- // display popup
- try {
- UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
- Desktop desktop = null;
- boolean isBrowseSupported = false, isOpenSupported = false;
- if (Desktop.isDesktopSupported()) {
- desktop = Desktop.getDesktop();
- isBrowseSupported = desktop.isSupported(Desktop.Action.BROWSE);
- isOpenSupported = desktop.isSupported(Desktop.Action.OPEN);
- }
- if (desktop != null && (isOpenSupported || (report && isBrowseSupported))) { // try to open the log file and/or issues webpage
- if (report && isBrowseSupported) { // ask to report the error
- if (isOpenSupported) { // also ask to open the log
- int n = JOptionPane.showOptionDialog(null, messageReport, title,
- JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE,
- null, optionsLogReport, optionsLogReport[2]);
- if (n == 0)
- desktop.browse(getIssueURI(error, e, trace));
- else if (n == 1)
- desktop.open(Options.LOG_FILE);
- } else { // only ask to report the error
- int n = JOptionPane.showOptionDialog(null, message, title,
- JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE,
- null, optionsReport, optionsReport[1]);
- if (n == 0)
- desktop.browse(getIssueURI(error, e, trace));
- }
- } else { // don't report the error
- int n = JOptionPane.showOptionDialog(null, message, title,
- JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE,
- null, optionsLog, optionsLog[1]);
- if (n == 0)
- desktop.open(Options.LOG_FILE);
- }
- } else { // display error only
- JOptionPane.showMessageDialog(null, report ? messageReport : message,
- title, JOptionPane.ERROR_MESSAGE);
- }
- } catch (Exception e1) {
- Log.error("An error occurred in the crash popup.", e1);
- }
- }
-
- /**
- * Returns the issue reporting URI.
- * This will auto-fill the report with the relevant information if possible.
- * @param error a description of the error
- * @param e the exception causing the error
- * @param trace the stack trace
- * @return the created URI
- */
- private static URI getIssueURI(String error, Throwable e, String trace) {
- // generate report information
- String issueTitle = (error != null) ? error : e.getMessage();
- StringBuilder sb = new StringBuilder();
- try {
- // read version and build date from version file, if possible
- Properties props = new Properties();
- props.load(ResourceLoader.getResourceAsStream(Options.VERSION_FILE));
- String version = props.getProperty("version");
- if (version != null && !version.equals("${pom.version}")) {
- sb.append("**Version:** ");
- sb.append(version);
- String hash = Utils.getGitHash();
- if (hash != null) {
- sb.append(" (");
- sb.append(hash.substring(0, 12));
- sb.append(')');
- }
- sb.append('\n');
- }
- String timestamp = props.getProperty("build.date");
- if (timestamp != null &&
- !timestamp.equals("${maven.build.timestamp}") && !timestamp.equals("${timestamp}")) {
- sb.append("**Build date:** ");
- sb.append(timestamp);
- sb.append('\n');
- }
- } catch (IOException e1) {
- Log.warn("Could not read version file.", e1);
- }
- sb.append("**OS:** ");
- sb.append(System.getProperty("os.name"));
- sb.append(" (");
- sb.append(System.getProperty("os.arch"));
- sb.append(")\n");
- sb.append("**JRE:** ");
- sb.append(System.getProperty("java.version"));
- sb.append('\n');
- if (glString != null) {
- sb.append("**OpenGL Version:** ");
- sb.append(glString);
- sb.append('\n');
- }
- if (error != null) {
- sb.append("**Error:** `");
- sb.append(error);
- sb.append("`\n");
- }
- if (trace != null) {
- sb.append("**Stack trace:**");
- sb.append("\n```\n");
- sb.append(trace);
- sb.append("```");
- }
-
- // return auto-filled URI
- try {
- return URI.create(String.format(Options.ISSUES_URL,
- URLEncoder.encode(issueTitle, "UTF-8"),
- URLEncoder.encode(sb.toString(), "UTF-8")));
- } catch (UnsupportedEncodingException e1) {
- Log.warn("URLEncoder failed to encode the auto-filled issue report URL.");
- return URI.create(String.format(Options.ISSUES_URL, "", ""));
- }
- }
-}
diff --git a/src/itdelatrisu/opsu/GameData.java b/src/itdelatrisu/opsu/GameData.java
index e35a079e..9138d725 100644
--- a/src/itdelatrisu/opsu/GameData.java
+++ b/src/itdelatrisu/opsu/GameData.java
@@ -42,7 +42,7 @@ import org.newdawn.slick.Animation;
import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
-import yugecin.opsudance.Dancer;
+import yugecin.opsudance.utils.SlickUtil;
/**
* Holds game data and renders all related elements.
@@ -101,8 +101,16 @@ public class GameData {
* This does NOT destroy images, so be careful of memory leaks!
*/
public static void clearReferences() {
- for (Grade grade : Grade.values())
+ for (Grade grade : Grade.values()) {
grade.menuImage = null;
+ }
+ }
+
+ public static void destroyImages() {
+ for (Grade grade : Grade.values()) {
+ SlickUtil.destroyImage(grade.menuImage);
+ grade.menuImage = null;
+ }
}
/**
diff --git a/src/itdelatrisu/opsu/GameImage.java b/src/itdelatrisu/opsu/GameImage.java
index 21d10812..17efa2de 100644
--- a/src/itdelatrisu/opsu/GameImage.java
+++ b/src/itdelatrisu/opsu/GameImage.java
@@ -27,7 +27,12 @@ import java.util.List;
import org.newdawn.slick.Animation;
import org.newdawn.slick.Image;
import org.newdawn.slick.SlickException;
+import org.newdawn.slick.util.Log;
import org.newdawn.slick.util.ResourceLoader;
+import yugecin.opsudance.core.errorhandling.ErrorHandler;
+import yugecin.opsudance.core.events.EventBus;
+import yugecin.opsudance.events.BubbleNotificationEvent;
+import yugecin.opsudance.utils.SlickUtil;
/**
* Game images.
@@ -461,6 +466,18 @@ public enum GameImage {
}
}
+ public static void destroyImages() {
+ for (GameImage img : GameImage.values()) {
+ SlickUtil.destroyImages(img.defaultImages);
+ SlickUtil.destroyImage(img.defaultImage);
+ SlickUtil.destroyImages(img.skinImages);
+ SlickUtil.destroyImage(img.skinImage);
+ img.isSkinned = false;
+ img.defaultImages = img.skinImages = null;
+ img.defaultImage = img.skinImage = null;
+ }
+ }
+
/**
* Returns the bitmask image type from a type string.
* @param type the type string
@@ -693,7 +710,9 @@ public enum GameImage {
return;
}
- ErrorHandler.error(String.format("Could not find default image '%s'.", filename), null, false);
+ String err = String.format("Could not find default image '%s'.", filename);
+ Log.warn(err);
+ EventBus.instance.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
}
/**
@@ -752,7 +771,7 @@ public enum GameImage {
img = img.getScaledCopy(0.5f);
list.add(img);
} catch (SlickException e) {
- ErrorHandler.error(String.format("Failed to set image '%s'.", name), null, false);
+ EventBus.instance.post(new BubbleNotificationEvent(String.format("Failed to set image '%s'.", name), BubbleNotificationEvent.COMMONCOLOR_RED));
break;
}
}
@@ -766,7 +785,7 @@ public enum GameImage {
img = img.getScaledCopy(0.5f);
list.add(img);
} catch (SlickException e) {
- ErrorHandler.error(String.format("Failed to set image '%s'.", name), null, false);
+ EventBus.instance.post(new BubbleNotificationEvent(String.format("Failed to set image '%s'.", name), BubbleNotificationEvent.COMMONCOLOR_RED));
break;
}
}
@@ -793,7 +812,7 @@ public enum GameImage {
img = img.getScaledCopy(0.5f);
return img;
} catch (SlickException e) {
- ErrorHandler.error(String.format("Failed to set image '%s'.", filename), null, false);
+ EventBus.instance.post(new BubbleNotificationEvent(String.format("Failed to set image '%s'.", filename), BubbleNotificationEvent.COMMONCOLOR_RED));
}
}
}
@@ -838,7 +857,7 @@ public enum GameImage {
skinImages = null;
}
} catch (SlickException e) {
- ErrorHandler.error(String.format("Failed to destroy beatmap skin images for '%s'.", this.name()), e, true);
+ ErrorHandler.error(String.format("Failed to destroy beatmap skin images for '%s'.", this.name()), e).show();
}
}
diff --git a/src/itdelatrisu/opsu/Opsu.java b/src/itdelatrisu/opsu/Opsu.java
deleted file mode 100644
index 485210a9..00000000
--- a/src/itdelatrisu/opsu/Opsu.java
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * opsu! - an open-source osu! client
- * Copyright (C) 2014, 2015 Jeffrey Han
- *
- * opsu! is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * opsu! is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with opsu!. If not, see .
- */
-
-package itdelatrisu.opsu;
-
-import itdelatrisu.opsu.audio.MusicController;
-import itdelatrisu.opsu.db.DBController;
-import itdelatrisu.opsu.downloads.DownloadList;
-import itdelatrisu.opsu.downloads.Updater;
-import itdelatrisu.opsu.states.ButtonMenu;
-import itdelatrisu.opsu.states.DownloadsMenu;
-import itdelatrisu.opsu.states.Game;
-import itdelatrisu.opsu.states.GamePauseMenu;
-import itdelatrisu.opsu.states.GameRanking;
-import itdelatrisu.opsu.states.MainMenu;
-import itdelatrisu.opsu.states.OptionsMenu;
-import itdelatrisu.opsu.states.SongMenu;
-import itdelatrisu.opsu.states.Splash;
-import itdelatrisu.opsu.ui.UI;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.PrintStream;
-import java.lang.reflect.Field;
-import java.net.InetAddress;
-import java.net.ServerSocket;
-import java.net.UnknownHostException;
-
-import org.newdawn.slick.GameContainer;
-import org.newdawn.slick.Input;
-import org.newdawn.slick.SlickException;
-import org.newdawn.slick.state.StateBasedGame;
-import org.newdawn.slick.state.transition.FadeInTransition;
-import org.newdawn.slick.state.transition.EasedFadeOutTransition;
-import org.newdawn.slick.util.DefaultLogSystem;
-import org.newdawn.slick.util.FileSystemLocation;
-import org.newdawn.slick.util.Log;
-import org.newdawn.slick.util.ResourceLoader;
-
-/**
- * Main class.
- *
- * Creates game container, adds all other states, and initializes song data.
- */
-public class Opsu extends StateBasedGame {
- /** Game states. */
- public static final int
- STATE_SPLASH = 0,
- STATE_MAINMENU = 1,
- STATE_BUTTONMENU = 2,
- STATE_SONGMENU = 3,
- STATE_GAME = 4,
- STATE_GAMEPAUSEMENU = 5,
- STATE_GAMERANKING = 6,
- STATE_OPTIONSMENU = 7,
- STATE_DOWNLOADSMENU = 8;
-
- /** Server socket for restricting the program to a single instance. */
- private static ServerSocket SERVER_SOCKET;
-
- /**
- * Constructor.
- * @param name the program name
- */
- public Opsu(String name) {
- super(name);
- }
-
- @Override
- public void initStatesList(GameContainer container) throws SlickException {
- addState(new Splash(STATE_SPLASH));
- addState(new MainMenu(STATE_MAINMENU));
- addState(new ButtonMenu(STATE_BUTTONMENU));
- addState(new SongMenu(STATE_SONGMENU));
- addState(new Game(STATE_GAME));
- addState(new GamePauseMenu(STATE_GAMEPAUSEMENU));
- addState(new GameRanking(STATE_GAMERANKING));
- addState(new OptionsMenu(STATE_OPTIONSMENU));
- addState(new DownloadsMenu(STATE_DOWNLOADSMENU));
- }
-
- /**
- * Launches opsu!.
- */
- public static void main(String[] args) {
- // log all errors to a file
- Log.setVerbose(false);
- try {
- DefaultLogSystem.out = new PrintStream(new FileOutputStream(Options.LOG_FILE, true));
- } catch (FileNotFoundException e) {
- Log.error(e);
- }
-
- // set default exception handler
- Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
- @Override
- public void uncaughtException(Thread t, Throwable e) {
- ErrorHandler.error("** Uncaught Exception! **", e, true);
- System.exit(1);
- }
- });
-
- // parse configuration file
- Options.parseOptions();
-
- // only allow a single instance
- if (!Options.noSingleInstance()) {
- try {
- SERVER_SOCKET = new ServerSocket(Options.getPort(), 1, InetAddress.getLocalHost());
- } catch (UnknownHostException e) {
- // shouldn't happen
- } catch (IOException e) {
- errorAndExit(
- null,
- String.format(
- "opsu! could not be launched for one of these reasons:\n" +
- "- An instance of opsu! is already running.\n" +
- "- Another program is bound to port %d. " +
- "You can change the port opsu! uses by editing the \"Port\" field in the configuration file.",
- Options.getPort()
- ),
- false
- );
- }
- }
-
- // load natives
- File nativeDir;
- if (!Utils.isJarRunning() && (
- (nativeDir = new File("./target/natives/")).isDirectory() ||
- (nativeDir = new File("./build/natives/")).isDirectory()))
- ;
- else {
- nativeDir = Options.NATIVE_DIR;
- try {
- new NativeLoader(nativeDir).loadNatives();
- } catch (IOException e) {
- Log.error("Error loading natives.", e);
- }
- }
- System.setProperty("org.lwjgl.librarypath", nativeDir.getAbsolutePath());
- System.setProperty("java.library.path", nativeDir.getAbsolutePath());
- try {
- // Workaround for "java.library.path" property being read-only.
- // http://stackoverflow.com/a/24988095
- Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
- fieldSysPath.setAccessible(true);
- fieldSysPath.set(null, null);
- } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
- Log.warn("Failed to set 'sys_paths' field.", e);
- }
-
- // set the resource paths
- ResourceLoader.addResourceLocation(new FileSystemLocation(new File("./res/")));
-
- // initialize databases
- try {
- DBController.init();
- } catch (UnsatisfiedLinkError e) {
- errorAndExit(e, "The databases could not be initialized.", true);
- }
-
- // check if just updated
- if (args.length >= 2)
- Updater.get().setUpdateInfo(args[0], args[1]);
-
- // check for updates
- if (!Options.isUpdaterDisabled()) {
- new Thread() {
- @Override
- public void run() {
- try {
- Updater.get().checkForUpdates();
- } catch (IOException e) {
- Log.warn("Check for updates failed.", e);
- }
- }
- }.start();
- }
-
- // disable jinput
- Input.disableControllers();
-
- // start the game
- try {
- // loop until force exit
- while (true) {
- Opsu opsu = new Opsu("opsu!");
- Container app = new Container(opsu);
-
- // basic game settings
- Options.setDisplayMode(app);
- String[] icons = { "icon16.png", "icon32.png" };
- try {
- app.setIcons(icons);
- } catch (Exception e) {
- Log.error("could not set icon");
- }
- app.setForceExit(true);
-
- app.start();
-
- // run update if available
- if (Updater.get().getStatus() == Updater.Status.UPDATE_FINAL) {
- close();
- Updater.get().runUpdate();
- break;
- }
- }
- } catch (SlickException e) {
- errorAndExit(e, "An error occurred while creating the game container.", true);
- }
- }
-
- @Override
- public boolean closeRequested() {
- int id = this.getCurrentStateID();
-
- // intercept close requests in game-related states and return to song menu
- if (id == STATE_GAME || id == STATE_GAMEPAUSEMENU || id == STATE_GAMERANKING) {
- // start playing track at preview position
- SongMenu songMenu = (SongMenu) this.getState(Opsu.STATE_SONGMENU);
- if (id == STATE_GAMERANKING) {
- GameData data = ((GameRanking) this.getState(Opsu.STATE_GAMERANKING)).getGameData();
- if (data != null && data.isGameplay())
- songMenu.resetTrackOnLoad();
- } else {
- if (id == STATE_GAME) {
- MusicController.pause();
- MusicController.setPitch(1.0f);
- MusicController.resume();
- } else
- songMenu.resetTrackOnLoad();
- }
-
- // reset game data
- if (UI.getCursor().isBeatmapSkinned())
- UI.getCursor().reset();
- songMenu.resetGameDataOnLoad();
-
- this.enterState(Opsu.STATE_SONGMENU, new EasedFadeOutTransition(), new FadeInTransition());
- return false;
- }
-
- // show confirmation dialog if any downloads are active
- if (DownloadList.get().hasActiveDownloads() &&
- UI.showExitConfirmation(DownloadList.EXIT_CONFIRMATION))
- return false;
- if (Updater.get().getStatus() == Updater.Status.UPDATE_DOWNLOADING &&
- UI.showExitConfirmation(Updater.EXIT_CONFIRMATION))
- return false;
-
- return true;
- }
-
- /**
- * Closes all resources.
- */
- public static void close() {
- // close databases
- DBController.closeConnections();
-
- // cancel all downloads
- DownloadList.get().cancelAllDownloads();
-
- // close server socket
- if (SERVER_SOCKET != null) {
- try {
- SERVER_SOCKET.close();
- } catch (IOException e) {
- ErrorHandler.error("Failed to close server socket.", e, false);
- }
- }
- }
-
- /**
- * Throws an error and exits the application with the given message.
- * @param e the exception that caused the crash
- * @param message the message to display
- * @param report whether to ask to report the error
- */
- private static void errorAndExit(Throwable e, String message, boolean report) {
- // JARs will not run properly inside directories containing '!'
- // http://bugs.java.com/view_bug.do?bug_id=4523159
- if (Utils.isJarRunning() && Utils.getRunningDirectory() != null &&
- Utils.getRunningDirectory().getAbsolutePath().indexOf('!') != -1)
- ErrorHandler.error("JARs cannot be run from some paths containing '!'. Please move or rename the file and try again.", null, false);
- else
- ErrorHandler.error(message, e, report);
- System.exit(1);
- }
-}
diff --git a/src/itdelatrisu/opsu/Options.java b/src/itdelatrisu/opsu/Options.java
index 19db44b0..553c54cb 100644
--- a/src/itdelatrisu/opsu/Options.java
+++ b/src/itdelatrisu/opsu/Options.java
@@ -59,6 +59,10 @@ import com.sun.jna.platform.win32.Advapi32Util;
import com.sun.jna.platform.win32.Win32Exception;
import com.sun.jna.platform.win32.WinReg;
import yugecin.opsudance.*;
+import yugecin.opsudance.core.DisplayContainer;
+import yugecin.opsudance.core.errorhandling.ErrorHandler;
+import yugecin.opsudance.core.events.EventBus;
+import yugecin.opsudance.events.BubbleNotificationEvent;
import yugecin.opsudance.movers.factories.ExgonMoverFactory;
import yugecin.opsudance.movers.factories.QuadraticBezierMoverFactory;
import yugecin.opsudance.movers.slidermovers.DefaultSliderMoverController;
@@ -195,7 +199,7 @@ public class Options {
}
File dir = new File(rootPath, "opsu");
if (!dir.isDirectory() && !dir.mkdir())
- ErrorHandler.error(String.format("Failed to create configuration folder at '%s/opsu'.", rootPath), null, false);
+ ErrorHandler.error(String.format("Failed to create configuration folder at '%s/opsu'.", rootPath), new Exception("empty")).preventReport().show();
return dir;
} else
return workingDir;
@@ -393,8 +397,7 @@ public class Options {
@Override
public void clickListItem(int index) {
targetFPSindex = index;
- Container.instance.setTargetFrameRate(targetFPS[index]);
- Container.instance.setVSync(targetFPS[index] == 60);
+ displayContainer.setFPS(targetFPS[index]);
}
@Override
@@ -414,8 +417,7 @@ public class Options {
SHOW_FPS ("Show FPS Counter", "FpsCounter", "Show an FPS counter in the bottom-right hand corner.", true),
SHOW_UNICODE ("Prefer Non-English Metadata", "ShowUnicode", "Where available, song titles will be shown in their native language.", false) {
@Override
- public void click(GameContainer container) {
- super.click(container);
+ public void click() {
if (bool) {
try {
Fonts.LARGE.loadGlyphs();
@@ -465,13 +467,7 @@ public class Options {
val = i;
}
},
- NEW_CURSOR ("Enable New Cursor", "NewCursor", "Use the new cursor style (may cause higher CPU usage).", true) {
- @Override
- public void click(GameContainer container) {
- super.click(container);
- UI.getCursor().reset();
- }
- },
+ NEW_CURSOR ("Enable New Cursor", "NewCursor", "Use the new cursor style (may cause higher CPU usage).", true),
DYNAMIC_BACKGROUND ("Enable Dynamic Backgrounds", "DynamicBackground", "The song background will be used as the main menu background.", true),
LOAD_VERBOSE ("Show Detailed Loading Progress", "LoadVerbose", "Display more specific loading information in the splash screen.", false),
COLOR_MAIN_MENU_LOGO ("Use cursor color as main menu logo tint", "ColorMainMenuLogo", "Colorful main menu logo", false),
@@ -983,6 +979,7 @@ public class Options {
PIPPI_SLIDER_FOLLOW_EXPAND ("Followcircle expand", "PippiFollowExpand", "Increase radius in followcircles", false),
PIPPI_PREVENT_WOBBLY_STREAMS ("Prevent wobbly streams", "PippiPreventWobblyStreams", "Force linear mover while doing streams to prevent wobbly pippi", true);
+ public static DisplayContainer displayContainer;
/** Option name. */
private final String name;
@@ -1129,9 +1126,8 @@ public class Options {
* Processes a mouse click action (via override).
*
* By default, this inverts the current {@code bool} field.
- * @param container the game container
*/
- public void click(GameContainer container) { bool = !bool; }
+ public void click() { bool = !bool; }
/**
* Get a list of values to choose from
@@ -1279,9 +1275,9 @@ public class Options {
/**
* Sets the target frame rate to the next available option, and sends a
* bar notification about the action.
- * @param container the game container
*/
- public static void setNextFPS(GameContainer container) {
+ public static void setNextFPS(DisplayContainer displayContainer) {
+ GameOption.displayContainer = displayContainer; // TODO dirty shit
GameOption.TARGET_FPS.clickListItem((targetFPSindex + 1) % targetFPS.length);
UI.sendBarNotification(String.format("Frame limiter: %s", GameOption.TARGET_FPS.getValueString()));
}
@@ -1294,10 +1290,9 @@ public class Options {
/**
* Sets the master volume level (if within valid range).
- * @param container the game container
* @param volume the volume [0, 1]
*/
- public static void setMasterVolume(GameContainer container, float volume) {
+ public static void setMasterVolume(float volume) {
if (volume >= 0f && volume <= 1f) {
GameOption.MASTER_VOLUME.setValue((int) (volume * 100f));
MusicController.setVolume(getMasterVolume() * getMusicVolume());
@@ -1346,11 +1341,10 @@ public class Options {
*
* If the configured resolution is larger than the screen size, the smallest
* available resolution will be used.
- * @param app the game container
*/
- public static void setDisplayMode(Container app) {
- int screenWidth = app.getScreenWidth();
- int screenHeight = app.getScreenHeight();
+ public static void setDisplayMode(DisplayContainer container) {
+ int screenWidth = container.nativeDisplayMode.getWidth();
+ int screenHeight = container.nativeDisplayMode.getHeight();
resolutions[0] = screenWidth + "x" + screenHeight;
if (resolutionIdx < 0 || resolutionIdx > resolutions.length) {
@@ -1370,9 +1364,10 @@ public class Options {
}
try {
- app.setDisplayMode(width, height, isFullscreen());
- } catch (SlickException e) {
- ErrorHandler.error("Failed to set display mode.", e, true);
+ container.setDisplayMode(width, height, isFullscreen());
+ } catch (Exception e) {
+ container.eventBus.post(new BubbleNotificationEvent("Failed to change resolution", BubbleNotificationEvent.COMMONCOLOR_RED));
+ Log.error("Failed to set display mode.", e);
}
if (!isFullscreen()) {
@@ -1696,7 +1691,7 @@ public class Options {
* sends a bar notification about the action.
*/
public static void toggleMouseDisabled() {
- GameOption.DISABLE_MOUSE_BUTTONS.click(null);
+ GameOption.DISABLE_MOUSE_BUTTONS.click();
UI.sendBarNotification((GameOption.DISABLE_MOUSE_BUTTONS.getBooleanValue()) ?
"Mouse buttons are disabled." : "Mouse buttons are enabled.");
}
@@ -1787,7 +1782,7 @@ public class Options {
// use default directory
beatmapDir = BEATMAP_DIR;
if (!beatmapDir.isDirectory() && !beatmapDir.mkdir())
- ErrorHandler.error(String.format("Failed to create beatmap directory at '%s'.", beatmapDir.getAbsolutePath()), null, false);
+ EventBus.instance.post(new BubbleNotificationEvent(String.format("Failed to create beatmap directory at '%s'.", beatmapDir.getAbsolutePath()), BubbleNotificationEvent.COMMONCOLOR_RED));
return beatmapDir;
}
@@ -1802,7 +1797,7 @@ public class Options {
oszDir = new File(DATA_DIR, "SongPacks/");
if (!oszDir.isDirectory() && !oszDir.mkdir())
- ErrorHandler.error(String.format("Failed to create song packs directory at '%s'.", oszDir.getAbsolutePath()), null, false);
+ EventBus.instance.post(new BubbleNotificationEvent(String.format("Failed to create song packs directory at '%s'.", oszDir.getAbsolutePath()), BubbleNotificationEvent.COMMONCOLOR_RED));
return oszDir;
}
@@ -1817,7 +1812,7 @@ public class Options {
replayImportDir = new File(DATA_DIR, "ReplayImport/");
if (!replayImportDir.isDirectory() && !replayImportDir.mkdir())
- ErrorHandler.error(String.format("Failed to create replay import directory at '%s'.", replayImportDir.getAbsolutePath()), null, false);
+ EventBus.instance.post(new BubbleNotificationEvent(String.format("Failed to create replay import directory at '%s'.", replayImportDir.getAbsolutePath()), BubbleNotificationEvent.COMMONCOLOR_RED));
return replayImportDir;
}
@@ -1867,7 +1862,7 @@ public class Options {
// use default directory
skinRootDir = SKIN_ROOT_DIR;
if (!skinRootDir.isDirectory() && !skinRootDir.mkdir())
- ErrorHandler.error(String.format("Failed to create skins directory at '%s'.", skinRootDir.getAbsolutePath()), null, false);
+ EventBus.instance.post(new BubbleNotificationEvent(String.format("Failed to create skins directory at '%s'.", skinRootDir.getAbsolutePath()), BubbleNotificationEvent.COMMONCOLOR_RED));
return skinRootDir;
}
@@ -2000,7 +1995,9 @@ public class Options {
}
GameOption.DANCE_HIDE_WATERMARK.setValue(false);
} catch (IOException e) {
- ErrorHandler.error(String.format("Failed to read file '%s'.", OPTIONS_FILE.getAbsolutePath()), e, false);
+ String err = String.format("Failed to read file '%s'.", OPTIONS_FILE.getAbsolutePath());
+ Log.error(err, e);
+ EventBus.instance.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
}
}
@@ -2029,7 +2026,9 @@ public class Options {
}
writer.close();
} catch (IOException e) {
- ErrorHandler.error(String.format("Failed to write to file '%s'.", OPTIONS_FILE.getAbsolutePath()), e, false);
+ String err = String.format("Failed to write to file '%s'.", OPTIONS_FILE.getAbsolutePath());
+ Log.error(err, e);
+ EventBus.instance.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
}
}
}
diff --git a/src/itdelatrisu/opsu/Utils.java b/src/itdelatrisu/opsu/Utils.java
index 930b4eac..746a5e68 100644
--- a/src/itdelatrisu/opsu/Utils.java
+++ b/src/itdelatrisu/opsu/Utils.java
@@ -18,6 +18,7 @@
package itdelatrisu.opsu;
+import itdelatrisu.opsu.audio.MusicController;
import itdelatrisu.opsu.audio.SoundController;
import itdelatrisu.opsu.audio.SoundEffect;
import itdelatrisu.opsu.beatmap.HitObject;
@@ -71,6 +72,10 @@ import org.newdawn.slick.state.StateBasedGame;
import org.newdawn.slick.util.Log;
import com.sun.jna.platform.FileUtils;
+import yugecin.opsudance.core.DisplayContainer;
+import yugecin.opsudance.core.errorhandling.ErrorHandler;
+import yugecin.opsudance.core.events.EventBus;
+import yugecin.opsudance.events.BubbleNotificationEvent;
/**
* Contains miscellaneous utilities.
@@ -89,40 +94,18 @@ public class Utils {
Arrays.sort(illegalChars);
}
- // game-related variables
- private static Input input;
-
// This class should not be instantiated.
private Utils() {}
/**
* Initializes game settings and class data.
- * @param container the game container
- * @param game the game object
*/
- public static void init(GameContainer container, StateBasedGame game) {
- input = container.getInput();
- int width = container.getWidth();
- int height = container.getHeight();
+ public static void init(DisplayContainer displayContainer) {
+ // TODO clean this up
// game settings
- container.setTargetFrameRate(Options.getTargetFPS());
- container.setVSync(Options.getTargetFPS() == 60);
- container.setMusicVolume(Options.getMusicVolume() * Options.getMasterVolume());
- container.setShowFPS(false);
- container.getInput().enableKeyRepeat();
- container.setAlwaysRender(true);
- container.setUpdateOnlyWhenVisible(false);
-
- // calculate UI scale
- GameImage.init(width, height);
-
- // create fonts
- try {
- Fonts.init();
- } catch (Exception e) {
- ErrorHandler.error("Failed to load fonts.", e, true);
- }
+ displayContainer.setFPS(Options.getTargetFPS()); // TODO move this elsewhere
+ MusicController.setMusicVolume(Options.getMusicVolume() * Options.getMasterVolume());
// load skin
Options.loadSkin();
@@ -134,19 +117,19 @@ public class Utils {
}
// initialize game mods
- GameMod.init(width, height);
+ GameMod.init(displayContainer.width, displayContainer.height);
// initialize playback buttons
- PlaybackSpeed.init(width, height);
+ PlaybackSpeed.init(displayContainer.width, displayContainer.height);
// initialize hit objects
- HitObject.init(width, height);
+ HitObject.init(displayContainer.width, displayContainer.height);
// initialize download nodes
- DownloadNode.init(width, height);
+ DownloadNode.init(displayContainer.width, displayContainer.height);
// initialize UI components
- UI.init(container, game);
+ UI.init(displayContainer);
}
/**
@@ -246,12 +229,15 @@ public class Utils {
* @return true if pressed
*/
public static boolean isGameKeyPressed() {
+ /*
boolean mouseDown = !Options.isMouseDisabled() && (
input.isMouseButtonDown(Input.MOUSE_LEFT_BUTTON) ||
input.isMouseButtonDown(Input.MOUSE_RIGHT_BUTTON));
return (mouseDown ||
input.isKeyDown(Options.getGameKeyLeft()) ||
input.isKeyDown(Options.getGameKeyRight()));
+ */
+ return true;
}
/**
@@ -262,14 +248,14 @@ public class Utils {
// create the screenshot directory
File dir = Options.getScreenshotDir();
if (!dir.isDirectory() && !dir.mkdir()) {
- ErrorHandler.error(String.format("Failed to create screenshot directory at '%s'.", dir.getAbsolutePath()), null, false);
+ EventBus.instance.post(new BubbleNotificationEvent(String.format("Failed to create screenshot directory at '%s'.", dir.getAbsolutePath()), BubbleNotificationEvent.COMMONCOLOR_RED));
return;
}
// create file name
SimpleDateFormat date = new SimpleDateFormat("yyyyMMdd_HHmmss");
- final File file = new File(dir, String.format("screenshot_%s.%s",
- date.format(new Date()), Options.getScreenshotFormat()));
+ final String fileName = String.format("screenshot_%s.%s", date.format(new Date()), Options.getScreenshotFormat());
+ final File file = new File(dir, fileName);
SoundController.playSound(SoundEffect.SHUTTER);
@@ -296,8 +282,9 @@ public class Utils {
}
}
ImageIO.write(image, Options.getScreenshotFormat(), file);
+ EventBus.instance.post(new BubbleNotificationEvent("Created " + fileName, BubbleNotificationEvent.COMMONCOLOR_PURPLE));
} catch (Exception e) {
- ErrorHandler.error("Failed to take a screenshot.", e, true);
+ ErrorHandler.error("Failed to take a screenshot.", e).show();
}
}
}.start();
@@ -446,7 +433,7 @@ public class Utils {
try {
json = new JSONObject(s);
} catch (JSONException e) {
- ErrorHandler.error("Failed to create JSON object.", e, true);
+ ErrorHandler.error("Failed to create JSON object.", e).show();
}
}
return json;
@@ -465,7 +452,7 @@ public class Utils {
try {
json = new JSONArray(s);
} catch (JSONException e) {
- ErrorHandler.error("Failed to create JSON array.", e, true);
+ ErrorHandler.error("Failed to create JSON array.", e).show();
}
}
return json;
@@ -507,7 +494,7 @@ public class Utils {
result.append(String.format("%02x", b));
return result.toString();
} catch (NoSuchAlgorithmException | IOException e) {
- ErrorHandler.error("Failed to calculate MD5 hash.", e, true);
+ ErrorHandler.error("Failed to calculate MD5 hash.", e).show();
}
return null;
}
@@ -531,7 +518,7 @@ public class Utils {
* @return true if JAR, false if file
*/
public static boolean isJarRunning() {
- return Opsu.class.getResource(String.format("%s.class", Opsu.class.getSimpleName())).toString().startsWith("jar:");
+ return Utils.class.getResource(String.format("%s.class", Utils.class.getSimpleName())).toString().startsWith("jar:");
}
/**
@@ -543,7 +530,7 @@ public class Utils {
return null;
try {
- return new JarFile(new File(Opsu.class.getProtectionDomain().getCodeSource().getLocation().toURI()), false);
+ return new JarFile(new File(Utils.class.getProtectionDomain().getCodeSource().getLocation().toURI()), false);
} catch (URISyntaxException | IOException e) {
Log.error("Could not determine the JAR file.", e);
return null;
@@ -556,7 +543,7 @@ public class Utils {
*/
public static File getRunningDirectory() {
try {
- return new File(Opsu.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath());
+ return new File(Utils.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath());
} catch (URISyntaxException e) {
Log.error("Could not get the running directory.", e);
return null;
diff --git a/src/itdelatrisu/opsu/audio/MultiClip.java b/src/itdelatrisu/opsu/audio/MultiClip.java
index 3193aac7..d314815f 100644
--- a/src/itdelatrisu/opsu/audio/MultiClip.java
+++ b/src/itdelatrisu/opsu/audio/MultiClip.java
@@ -1,6 +1,6 @@
package itdelatrisu.opsu.audio;
-import itdelatrisu.opsu.ErrorHandler;
+import yugecin.opsudance.core.errorhandling.ErrorHandler;
import java.io.IOException;
import java.util.Iterator;
@@ -194,7 +194,7 @@ public class MultiClip {
try {
audioIn.close();
} catch (IOException e) {
- ErrorHandler.error(String.format("Could not close AudioInputStream for MultiClip %s.", name), e, true);
+ ErrorHandler.error(String.format("Could not close AudioInputStream for MultiClip %s.", name), e).show();
}
}
}
diff --git a/src/itdelatrisu/opsu/audio/MusicController.java b/src/itdelatrisu/opsu/audio/MusicController.java
index c5e24e7b..e8c6a0ad 100644
--- a/src/itdelatrisu/opsu/audio/MusicController.java
+++ b/src/itdelatrisu/opsu/audio/MusicController.java
@@ -18,7 +18,6 @@
package itdelatrisu.opsu.audio;
-import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.beatmap.Beatmap;
import itdelatrisu.opsu.beatmap.BeatmapParser;
@@ -44,8 +43,12 @@ import org.newdawn.slick.MusicListener;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.openal.Audio;
import org.newdawn.slick.openal.SoundStore;
+import org.newdawn.slick.util.Log;
import org.newdawn.slick.util.ResourceLoader;
import org.tritonus.share.sampled.file.TAudioFileFormat;
+import yugecin.opsudance.core.errorhandling.ErrorHandler;
+import yugecin.opsudance.core.events.EventBus;
+import yugecin.opsudance.events.BubbleNotificationEvent;
/**
* Controller for all music.
@@ -152,7 +155,9 @@ public class MusicController {
});
playAt(position, loop);
} catch (Exception e) {
- ErrorHandler.error(String.format("Could not play track '%s'.", file.getName()), e, false);
+ String err = String.format("Could not play track '%s'.", file.getName());
+ Log.error(err, e);
+ EventBus.instance.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
}
}
@@ -496,9 +501,7 @@ public class MusicController {
trackLoader.interrupt();
try {
trackLoader.join();
- } catch (InterruptedException e) {
- ErrorHandler.error(null, e, true);
- }
+ } catch (InterruptedException ignored) { }
}
trackLoader = null;
@@ -575,7 +578,16 @@ public class MusicController {
player = null;
} catch (Exception e) {
- ErrorHandler.error("Failed to destroy OpenAL.", e, true);
+ ErrorHandler.error("Failed to destroy OpenAL.", e).show();
}
}
+
+ /**
+ * Set the default volume for music
+ * @param volume the new default value for music volume
+ */
+ public static void setMusicVolume(float volume) {
+ SoundStore.get().setMusicVolume(volume);
+ }
+
}
diff --git a/src/itdelatrisu/opsu/audio/SoundController.java b/src/itdelatrisu/opsu/audio/SoundController.java
index 7db7f608..10e8e850 100644
--- a/src/itdelatrisu/opsu/audio/SoundController.java
+++ b/src/itdelatrisu/opsu/audio/SoundController.java
@@ -18,7 +18,6 @@
package itdelatrisu.opsu.audio;
-import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.audio.HitSound.SampleSet;
import itdelatrisu.opsu.beatmap.HitObject;
@@ -41,6 +40,9 @@ import javax.sound.sampled.LineUnavailableException;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.util.ResourceLoader;
+import yugecin.opsudance.core.errorhandling.ErrorHandler;
+import yugecin.opsudance.core.events.EventBus;
+import yugecin.opsudance.events.BubbleNotificationEvent;
/**
* Controller for all (non-music) sound components.
@@ -99,7 +101,7 @@ public class SoundController {
AudioInputStream audioIn = AudioSystem.getAudioInputStream(url);
return loadClip(ref, audioIn, isMP3);
} catch (Exception e) {
- ErrorHandler.error(String.format("Failed to load file '%s'.", ref), e, true);
+ ErrorHandler.error(String.format("Failed to load file '%s'.", ref), e).show();
return null;
}
}
@@ -214,7 +216,7 @@ public class SoundController {
// menu and game sounds
for (SoundEffect s : SoundEffect.values()) {
if ((currentFileName = getSoundFileName(s.getFileName())) == null) {
- ErrorHandler.error(String.format("Could not find sound file '%s'.", s.getFileName()), null, false);
+ EventBus.instance.post(new BubbleNotificationEvent("Could not find sound file " + s.getFileName(), BubbleNotificationEvent.COLOR_ORANGE));
continue;
}
MultiClip newClip = loadClip(currentFileName, currentFileName.endsWith(".mp3"));
@@ -233,7 +235,7 @@ public class SoundController {
for (HitSound s : HitSound.values()) {
String filename = String.format("%s-%s", ss.getName(), s.getFileName());
if ((currentFileName = getSoundFileName(filename)) == null) {
- ErrorHandler.error(String.format("Could not find hit sound file '%s'.", filename), null, false);
+ EventBus.instance.post(new BubbleNotificationEvent("Could not find hit sound file " + filename, BubbleNotificationEvent.COLOR_ORANGE));
continue;
}
MultiClip newClip = loadClip(currentFileName, false);
@@ -277,7 +279,7 @@ public class SoundController {
try {
clip.start(volume, listener);
} catch (LineUnavailableException e) {
- ErrorHandler.error(String.format("Could not start a clip '%s'.", clip.getName()), e, true);
+ ErrorHandler.error(String.format("Could not start a clip '%s'.", clip.getName()), e).show();
}
}
}
diff --git a/src/itdelatrisu/opsu/beatmap/Beatmap.java b/src/itdelatrisu/opsu/beatmap/Beatmap.java
index a87cc236..55a34ab5 100644
--- a/src/itdelatrisu/opsu/beatmap/Beatmap.java
+++ b/src/itdelatrisu/opsu/beatmap/Beatmap.java
@@ -22,6 +22,7 @@ import itdelatrisu.opsu.Options;
import java.io.File;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.LinkedList;
import java.util.Map;
@@ -59,6 +60,14 @@ public class Beatmap implements Comparable {
*/
public static void clearBackgroundImageCache() { bgImageCache.clear(); }
+ public static void destroyBackgroundImageCache() {
+ Collection values = bgImageCache.values();
+ for (ImageLoader value : values) {
+ value.destroy();
+ }
+ bgImageCache.clear();
+ }
+
/** The OSU File object associated with this beatmap. */
private File file;
diff --git a/src/itdelatrisu/opsu/beatmap/BeatmapParser.java b/src/itdelatrisu/opsu/beatmap/BeatmapParser.java
index 3e3fa4f1..97e6442a 100644
--- a/src/itdelatrisu/opsu/beatmap/BeatmapParser.java
+++ b/src/itdelatrisu/opsu/beatmap/BeatmapParser.java
@@ -18,7 +18,6 @@
package itdelatrisu.opsu.beatmap;
-import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.db.BeatmapDB;
@@ -35,6 +34,9 @@ import java.util.Map;
import org.newdawn.slick.Color;
import org.newdawn.slick.util.Log;
+import yugecin.opsudance.core.errorhandling.ErrorHandler;
+import yugecin.opsudance.core.events.EventBus;
+import yugecin.opsudance.events.BubbleNotificationEvent;
/**
* Parser for beatmaps.
@@ -243,9 +245,11 @@ public class BeatmapParser {
}
map.timingPoints.trimToSize();
} catch (IOException e) {
- ErrorHandler.error(String.format("Failed to read file '%s'.", map.getFile().getAbsolutePath()), e, false);
+ String err = String.format("Failed to read file '%s'.", map.getFile().getAbsolutePath());
+ Log.error(err, e);
+ EventBus.instance.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
} catch (NoSuchAlgorithmException e) {
- ErrorHandler.error("Failed to get MD5 hash stream.", e, true);
+ ErrorHandler.error("Failed to get MD5 hash stream.", e).show();
// retry without MD5
hasNoMD5Algorithm = true;
@@ -646,9 +650,11 @@ public class BeatmapParser {
if (md5stream != null)
beatmap.md5Hash = md5stream.getMD5();
} catch (IOException e) {
- ErrorHandler.error(String.format("Failed to read file '%s'.", file.getAbsolutePath()), e, false);
+ String err = String.format("Failed to read file '%s'.", file.getAbsolutePath());
+ Log.error(err, e);
+ EventBus.instance.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
} catch (NoSuchAlgorithmException e) {
- ErrorHandler.error("Failed to get MD5 hash stream.", e, true);
+ ErrorHandler.error("Failed to get MD5 hash stream.", e).show();
// retry without MD5
hasNoMD5Algorithm = true;
@@ -727,7 +733,9 @@ public class BeatmapParser {
}
beatmap.timingPoints.trimToSize();
} catch (IOException e) {
- ErrorHandler.error(String.format("Failed to read file '%s'.", beatmap.getFile().getAbsolutePath()), e, false);
+ String err = String.format("Failed to read file '%s'.", beatmap.getFile().getAbsolutePath());
+ Log.error(err, e);
+ EventBus.instance.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
}
}
@@ -803,9 +811,11 @@ public class BeatmapParser {
// check that all objects were parsed
if (objectIndex != beatmap.objects.length)
ErrorHandler.error(String.format("Parsed %d objects for beatmap '%s', %d objects expected.",
- objectIndex, beatmap.toString(), beatmap.objects.length), null, true);
+ objectIndex, beatmap.toString(), beatmap.objects.length), new Exception("no")).show();
} catch (IOException e) {
- ErrorHandler.error(String.format("Failed to read file '%s'.", beatmap.getFile().getAbsolutePath()), e, false);
+ String err = String.format("Failed to read file '%s'.", beatmap.getFile().getAbsolutePath());
+ Log.error(err, e);
+ EventBus.instance.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
}
}
diff --git a/src/itdelatrisu/opsu/beatmap/BeatmapSetList.java b/src/itdelatrisu/opsu/beatmap/BeatmapSetList.java
index dc9471ce..eda1338a 100644
--- a/src/itdelatrisu/opsu/beatmap/BeatmapSetList.java
+++ b/src/itdelatrisu/opsu/beatmap/BeatmapSetList.java
@@ -18,11 +18,12 @@
package itdelatrisu.opsu.beatmap;
-import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.audio.MusicController;
import itdelatrisu.opsu.db.BeatmapDB;
+import yugecin.opsudance.core.events.EventBus;
+import yugecin.opsudance.events.BubbleNotificationEvent;
import java.io.File;
import java.io.IOException;
@@ -215,7 +216,7 @@ public class BeatmapSetList {
try {
Utils.deleteToTrash(dir);
} catch (IOException e) {
- ErrorHandler.error("Could not delete song group.", e, true);
+ EventBus.instance.post(new BubbleNotificationEvent("Could not delete song group", BubbleNotificationEvent.COLOR_ORANGE));
}
if (ws != null)
ws.resume();
@@ -270,7 +271,7 @@ public class BeatmapSetList {
try {
Utils.deleteToTrash(file);
} catch (IOException e) {
- ErrorHandler.error("Could not delete song.", e, true);
+ EventBus.instance.post(new BubbleNotificationEvent("Could not delete song", BubbleNotificationEvent.COLOR_ORANGE));
}
if (ws != null)
ws.resume();
diff --git a/src/itdelatrisu/opsu/beatmap/BeatmapWatchService.java b/src/itdelatrisu/opsu/beatmap/BeatmapWatchService.java
index 8399cc22..f864c2ad 100644
--- a/src/itdelatrisu/opsu/beatmap/BeatmapWatchService.java
+++ b/src/itdelatrisu/opsu/beatmap/BeatmapWatchService.java
@@ -18,7 +18,6 @@
package itdelatrisu.opsu.beatmap;
-import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.Options;
import java.io.IOException;
@@ -42,6 +41,8 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.newdawn.slick.util.Log;
+import yugecin.opsudance.core.events.EventBus;
+import yugecin.opsudance.events.BubbleNotificationEvent;
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
@@ -96,7 +97,8 @@ public class BeatmapWatchService {
ws = new BeatmapWatchService();
ws.register(Options.getBeatmapDir().toPath());
} catch (IOException e) {
- ErrorHandler.error("An I/O exception occurred while creating the watch service.", e, true);
+ Log.error("Could not create watch service", e);
+ EventBus.instance.post(new BubbleNotificationEvent("Could not create watch service", BubbleNotificationEvent.COMMONCOLOR_RED));
return;
}
@@ -117,8 +119,9 @@ public class BeatmapWatchService {
ws.service.shutdownNow();
ws = null;
} catch (IOException e) {
+ Log.error("An I/O exception occurred while closing the previous watch service.", e);
+ EventBus.instance.post(new BubbleNotificationEvent("An I/O exception occurred while closing the previous watch service.", BubbleNotificationEvent.COMMONCOLOR_RED));
ws = null;
- ErrorHandler.error("An I/O exception occurred while closing the previous watch service.", e, true);
}
}
diff --git a/src/itdelatrisu/opsu/beatmap/OszUnpacker.java b/src/itdelatrisu/opsu/beatmap/OszUnpacker.java
index 5b9c1071..e1e40f41 100644
--- a/src/itdelatrisu/opsu/beatmap/OszUnpacker.java
+++ b/src/itdelatrisu/opsu/beatmap/OszUnpacker.java
@@ -18,7 +18,6 @@
package itdelatrisu.opsu.beatmap;
-import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.Options;
import java.io.File;
@@ -28,6 +27,9 @@ import java.util.List;
import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;
+import org.newdawn.slick.util.Log;
+import yugecin.opsudance.core.events.EventBus;
+import yugecin.opsudance.events.BubbleNotificationEvent;
/**
* Unpacker for OSZ (ZIP) archives.
@@ -97,8 +99,9 @@ public class OszUnpacker {
ZipFile zipFile = new ZipFile(file);
zipFile.extractAll(dest.getAbsolutePath());
} catch (ZipException e) {
- ErrorHandler.error(String.format("Failed to unzip file %s to dest %s.",
- file.getAbsolutePath(), dest.getAbsolutePath()), e, false);
+ String err = String.format("Failed to unzip file %s to dest %s.", file.getAbsolutePath(), dest.getAbsolutePath());
+ Log.error(err, e);
+ EventBus.instance.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
}
}
diff --git a/src/itdelatrisu/opsu/db/BeatmapDB.java b/src/itdelatrisu/opsu/db/BeatmapDB.java
index 2dbb1e2f..e6e0e4d5 100644
--- a/src/itdelatrisu/opsu/db/BeatmapDB.java
+++ b/src/itdelatrisu/opsu/db/BeatmapDB.java
@@ -18,7 +18,6 @@
package itdelatrisu.opsu.db;
-import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.beatmap.Beatmap;
import itdelatrisu.opsu.beatmap.BeatmapParser;
@@ -35,6 +34,7 @@ import java.util.List;
import java.util.Map;
import org.newdawn.slick.util.Log;
+import yugecin.opsudance.core.errorhandling.ErrorHandler;
/**
* Handles connections and queries with the cached beatmap database.
@@ -110,7 +110,7 @@ public class BeatmapDB {
try {
updateSizeStmt = connection.prepareStatement("REPLACE INTO info (key, value) VALUES ('size', ?)");
} catch (SQLException e) {
- ErrorHandler.error("Failed to prepare beatmap statements.", e, true);
+ ErrorHandler.error("Failed to prepare beatmap statements.", e).show();
}
// retrieve the cache size
@@ -132,7 +132,7 @@ public class BeatmapDB {
updatePlayStatsStmt = connection.prepareStatement("UPDATE beatmaps SET playCount = ?, lastPlayed = ? WHERE dir = ? AND file = ?");
setFavoriteStmt = connection.prepareStatement("UPDATE beatmaps SET favorite = ? WHERE dir = ? AND file = ?");
} catch (SQLException e) {
- ErrorHandler.error("Failed to prepare beatmap statements.", e, true);
+ ErrorHandler.error("Failed to prepare beatmap statements.", e).show();
}
}
@@ -170,7 +170,7 @@ public class BeatmapDB {
sql = String.format("INSERT OR IGNORE INTO info(key, value) VALUES('version', '%s')", DATABASE_VERSION);
stmt.executeUpdate(sql);
} catch (SQLException e) {
- ErrorHandler.error("Could not create beatmap database.", e, true);
+ ErrorHandler.error("Coudl not create beatmap database.", e).show();
}
}
@@ -222,7 +222,7 @@ public class BeatmapDB {
ps.close();
}
} catch (SQLException e) {
- ErrorHandler.error("Failed to update beatmap database.", e, true);
+ ErrorHandler.error("Failed to update beatmap database.", e).show();
}
}
@@ -240,7 +240,7 @@ public class BeatmapDB {
}
rs.close();
} catch (SQLException e) {
- ErrorHandler.error("Could not get beatmap cache size.", e, true);
+ ErrorHandler.error("Could not get beatmap cache size.", e).show();
}
}
@@ -255,7 +255,7 @@ public class BeatmapDB {
updateSizeStmt.setString(1, Integer.toString(Math.max(cacheSize, 0)));
updateSizeStmt.executeUpdate();
} catch (SQLException e) {
- ErrorHandler.error("Could not update beatmap cache size.", e, true);
+ ErrorHandler.error("Could not update beatmap cache size.", e).show();
}
}
@@ -273,7 +273,7 @@ public class BeatmapDB {
cacheSize = 0;
updateCacheSize();
} catch (SQLException e) {
- ErrorHandler.error("Could not drop beatmap database.", e, true);
+ ErrorHandler.error("Could not drop beatmap database.", e).show();
}
createDatabase();
}
@@ -291,7 +291,7 @@ public class BeatmapDB {
cacheSize += insertStmt.executeUpdate();
updateCacheSize();
} catch (SQLException e) {
- ErrorHandler.error("Failed to add beatmap to database.", e, true);
+ ErrorHandler.error("Failed to add beatmap to database.", e).show();
}
}
@@ -344,7 +344,7 @@ public class BeatmapDB {
// update cache size
updateCacheSize();
} catch (SQLException e) {
- ErrorHandler.error("Failed to add beatmaps to database.", e, true);
+ ErrorHandler.error("Failed to add beatmaps to database.", e).show();
}
}
@@ -432,7 +432,7 @@ public class BeatmapDB {
}
rs.close();
} catch (SQLException e) {
- ErrorHandler.error("Failed to load Beatmap from database.", e, true);
+ ErrorHandler.error("Failed to load Beatmap from database.", e).show();
}
}
@@ -495,7 +495,7 @@ public class BeatmapDB {
}
rs.close();
} catch (SQLException e) {
- ErrorHandler.error("Failed to load beatmaps from database.", e, true);
+ ErrorHandler.error("Failed to load beatmaps from database.", e).show();
}
}
@@ -596,7 +596,7 @@ public class BeatmapDB {
rs.close();
return map;
} catch (SQLException e) {
- ErrorHandler.error("Failed to get last modified map from database.", e, true);
+ ErrorHandler.error("Failed to get last modified map from database.", e).show();
return null;
}
}
@@ -616,7 +616,7 @@ public class BeatmapDB {
cacheSize -= deleteMapStmt.executeUpdate();
updateCacheSize();
} catch (SQLException e) {
- ErrorHandler.error("Failed to delete beatmap entry from database.", e, true);
+ ErrorHandler.error("Failed to delete beatmap entry from database.", e).show();
}
}
@@ -633,7 +633,7 @@ public class BeatmapDB {
cacheSize -= deleteGroupStmt.executeUpdate();
updateCacheSize();
} catch (SQLException e) {
- ErrorHandler.error("Failed to delete beatmap group entry from database.", e, true);
+ ErrorHandler.error("Failed to delete beatmap group entry from database.", e).show();
}
}
@@ -652,7 +652,7 @@ public class BeatmapDB {
setStarsStmt.executeUpdate();
} catch (SQLException e) {
ErrorHandler.error(String.format("Failed to save star rating '%.4f' for beatmap '%s' in database.",
- beatmap.starRating, beatmap.toString()), e, true);
+ beatmap.starRating, beatmap.toString()), e).show();
}
}
@@ -672,7 +672,7 @@ public class BeatmapDB {
updatePlayStatsStmt.executeUpdate();
} catch (SQLException e) {
ErrorHandler.error(String.format("Failed to update play statistics for beatmap '%s' in database.",
- beatmap.toString()), e, true);
+ beatmap.toString()), e).show();
}
}
@@ -691,7 +691,7 @@ public class BeatmapDB {
setFavoriteStmt.executeUpdate();
} catch (SQLException e) {
ErrorHandler.error(String.format("Failed to update favorite status for beatmap '%s' in database.",
- beatmap.toString()), e, true);
+ beatmap.toString()), e).show();
}
}
@@ -711,7 +711,7 @@ public class BeatmapDB {
connection.close();
connection = null;
} catch (SQLException e) {
- ErrorHandler.error("Failed to close beatmap database.", e, true);
+ ErrorHandler.error("Failed to close beatmap database.", e).show();
}
}
}
diff --git a/src/itdelatrisu/opsu/db/DBController.java b/src/itdelatrisu/opsu/db/DBController.java
index aebd414b..61e0d5ca 100644
--- a/src/itdelatrisu/opsu/db/DBController.java
+++ b/src/itdelatrisu/opsu/db/DBController.java
@@ -18,7 +18,7 @@
package itdelatrisu.opsu.db;
-import itdelatrisu.opsu.ErrorHandler;
+import yugecin.opsudance.core.errorhandling.ErrorHandler;
import java.sql.Connection;
import java.sql.DriverManager;
@@ -39,7 +39,7 @@ public class DBController {
try {
Class.forName("org.sqlite.JDBC");
} catch (ClassNotFoundException e) {
- ErrorHandler.error("Could not load sqlite-JDBC driver.", e, true);
+ ErrorHandler.error("Could not load sqlite-JDBC driver.", e).show();
}
// initialize the databases
@@ -65,7 +65,7 @@ public class DBController {
return DriverManager.getConnection(String.format("jdbc:sqlite:%s", path));
} catch (SQLException e) {
// if the error message is "out of memory", it probably means no database file is found
- ErrorHandler.error(String.format("Could not connect to database: '%s'.", path), e, true);
+ ErrorHandler.error(String.format("Could not connect to database: '%s'.", path), e).show();
return null;
}
}
diff --git a/src/itdelatrisu/opsu/db/ScoreDB.java b/src/itdelatrisu/opsu/db/ScoreDB.java
index babf1841..6fa86910 100644
--- a/src/itdelatrisu/opsu/db/ScoreDB.java
+++ b/src/itdelatrisu/opsu/db/ScoreDB.java
@@ -18,10 +18,10 @@
package itdelatrisu.opsu.db;
-import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.ScoreData;
import itdelatrisu.opsu.beatmap.Beatmap;
+import yugecin.opsudance.core.errorhandling.ErrorHandler;
import java.sql.Connection;
import java.sql.PreparedStatement;
@@ -124,7 +124,7 @@ public class ScoreDB {
// TODO: extra playerName checks not needed if name is guaranteed not null
);
} catch (SQLException e) {
- ErrorHandler.error("Failed to prepare score statements.", e, true);
+ ErrorHandler.error("Failed to prepare score statements.", e).show();
}
}
@@ -157,7 +157,7 @@ public class ScoreDB {
sql = String.format("INSERT OR IGNORE INTO info(key, value) VALUES('version', %d)", DATABASE_VERSION);
stmt.executeUpdate(sql);
} catch (SQLException e) {
- ErrorHandler.error("Could not create score database.", e, true);
+ ErrorHandler.error("Could not create score database.", e).show();
}
}
@@ -209,7 +209,7 @@ public class ScoreDB {
ps.close();
}
} catch (SQLException e) {
- ErrorHandler.error("Failed to update score database.", e, true);
+ ErrorHandler.error("Failed to update score database.", e).show();
}
}
@@ -227,7 +227,7 @@ public class ScoreDB {
insertStmt.setString(19, data.playerName);
insertStmt.executeUpdate();
} catch (SQLException e) {
- ErrorHandler.error("Failed to save score to database.", e, true);
+ ErrorHandler.error("Failed to save score to database.", e).show();
}
}
@@ -247,7 +247,7 @@ public class ScoreDB {
deleteScoreStmt.setString(21, data.playerName);
deleteScoreStmt.executeUpdate();
} catch (SQLException e) {
- ErrorHandler.error("Failed to delete score from database.", e, true);
+ ErrorHandler.error("Failed to delete score from database.", e).show();
}
}
@@ -267,7 +267,7 @@ public class ScoreDB {
deleteSongStmt.setString(5, beatmap.version);
deleteSongStmt.executeUpdate();
} catch (SQLException e) {
- ErrorHandler.error("Failed to delete scores from database.", e, true);
+ ErrorHandler.error("Failed to delete scores from database.", e).show();
}
}
@@ -335,7 +335,7 @@ public class ScoreDB {
}
rs.close();
} catch (SQLException e) {
- ErrorHandler.error("Failed to read scores from database.", e, true);
+ ErrorHandler.error("Failed to read scores from database.", e).show();
return null;
}
return getSortedArray(list);
@@ -377,7 +377,7 @@ public class ScoreDB {
map.put(version, getSortedArray(list));
rs.close();
} catch (SQLException e) {
- ErrorHandler.error("Failed to read scores from database.", e, true);
+ ErrorHandler.error("Failed to read scores from database.", e).show();
return null;
}
return map;
@@ -406,7 +406,7 @@ public class ScoreDB {
connection.close();
connection = null;
} catch (SQLException e) {
- ErrorHandler.error("Failed to close score database.", e, true);
+ ErrorHandler.error("Failed to close score database.", e).show();
}
}
}
diff --git a/src/itdelatrisu/opsu/downloads/Download.java b/src/itdelatrisu/opsu/downloads/Download.java
index 58818490..218533d3 100644
--- a/src/itdelatrisu/opsu/downloads/Download.java
+++ b/src/itdelatrisu/opsu/downloads/Download.java
@@ -18,7 +18,6 @@
package itdelatrisu.opsu.downloads;
-import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.Utils;
import java.io.File;
@@ -35,6 +34,9 @@ import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import org.newdawn.slick.util.Log;
+import yugecin.opsudance.core.errorhandling.ErrorHandler;
+import yugecin.opsudance.core.events.EventBus;
+import yugecin.opsudance.events.BubbleNotificationEvent;
/**
* File download.
@@ -142,7 +144,7 @@ public class Download {
this.url = new URL(remoteURL);
} catch (MalformedURLException e) {
this.status = Status.ERROR;
- ErrorHandler.error(String.format("Bad download URL: '%s'", remoteURL), e, true);
+ ErrorHandler.error(String.format("Bad download URL: '%s'", remoteURL), e).show();
return;
}
this.localPath = localPath;
@@ -215,7 +217,7 @@ public class Download {
else if (redirectCount > MAX_REDIRECTS)
error = String.format("Download for URL '%s' is attempting too many redirects (over %d).", base.toString(), MAX_REDIRECTS);
if (error != null) {
- ErrorHandler.error(error, null, false);
+ EventBus.instance.post(new BubbleNotificationEvent(error, BubbleNotificationEvent.COLOR_ORANGE));
throw new IOException();
}
@@ -417,7 +419,7 @@ public class Download {
}
} catch (IOException e) {
this.status = Status.ERROR;
- ErrorHandler.error("Failed to cancel download.", e, true);
+ ErrorHandler.error("Failed to cancel download.", e).show();
}
}
}
diff --git a/src/itdelatrisu/opsu/downloads/DownloadNode.java b/src/itdelatrisu/opsu/downloads/DownloadNode.java
index 728dacf5..d8869fe4 100644
--- a/src/itdelatrisu/opsu/downloads/DownloadNode.java
+++ b/src/itdelatrisu/opsu/downloads/DownloadNode.java
@@ -18,7 +18,6 @@
package itdelatrisu.opsu.downloads;
-import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.Utils;
@@ -35,6 +34,8 @@ import java.io.File;
import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
+import yugecin.opsudance.core.events.EventBus;
+import yugecin.opsudance.events.BubbleNotificationEvent;
/**
* Node containing song data and a Download object.
@@ -402,7 +403,7 @@ public class DownloadNode {
public void drawDownload(Graphics g, float position, int id, boolean hover) {
Download download = this.download; // in case clearDownload() is called asynchronously
if (download == null) {
- ErrorHandler.error("Trying to draw download information for button without Download object.", null, false);
+ EventBus.instance.post(new BubbleNotificationEvent("Trying to draw download information for button without Download object", BubbleNotificationEvent.COLOR_ORANGE));
return;
}
diff --git a/src/itdelatrisu/opsu/downloads/Updater.java b/src/itdelatrisu/opsu/downloads/Updater.java
index 307b8e54..fbd607ea 100644
--- a/src/itdelatrisu/opsu/downloads/Updater.java
+++ b/src/itdelatrisu/opsu/downloads/Updater.java
@@ -18,7 +18,6 @@
package itdelatrisu.opsu.downloads;
-import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.downloads.Download.DownloadListener;
@@ -38,6 +37,7 @@ import java.util.Properties;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.newdawn.slick.util.Log;
import org.newdawn.slick.util.ResourceLoader;
+import yugecin.opsudance.core.errorhandling.ErrorHandler;
/**
* Handles automatic program updates.
@@ -298,7 +298,7 @@ public class Updater {
pb.start();
} catch (IOException e) {
status = Status.INTERNAL_ERROR;
- ErrorHandler.error("Failed to start new process.", e, true);
+ ErrorHandler.error("Failed to start new process.", e).show();
}
}
}
diff --git a/src/itdelatrisu/opsu/downloads/servers/BloodcatServer.java b/src/itdelatrisu/opsu/downloads/servers/BloodcatServer.java
index 335982e9..d86a4579 100644
--- a/src/itdelatrisu/opsu/downloads/servers/BloodcatServer.java
+++ b/src/itdelatrisu/opsu/downloads/servers/BloodcatServer.java
@@ -18,7 +18,6 @@
package itdelatrisu.opsu.downloads.servers;
-import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.downloads.DownloadNode;
@@ -34,6 +33,7 @@ import java.util.Date;
import org.json.JSONArray;
import org.json.JSONObject;
+import yugecin.opsudance.core.errorhandling.ErrorHandler;
/**
* Download server: http://bloodcat.com/osu/
@@ -97,7 +97,7 @@ public class BloodcatServer extends DownloadServer {
resultCount++;
this.totalResults = resultCount;
} catch (MalformedURLException | UnsupportedEncodingException e) {
- ErrorHandler.error(String.format("Problem loading result list for query '%s'.", query), e, true);
+ ErrorHandler.error(String.format("Problem loading result list for query '%s'.", query), e).show();
}
return nodes;
}
diff --git a/src/itdelatrisu/opsu/downloads/servers/HexideServer.java b/src/itdelatrisu/opsu/downloads/servers/HexideServer.java
index e9b7c683..f0c6cb7d 100644
--- a/src/itdelatrisu/opsu/downloads/servers/HexideServer.java
+++ b/src/itdelatrisu/opsu/downloads/servers/HexideServer.java
@@ -18,7 +18,6 @@
package itdelatrisu.opsu.downloads.servers;
-import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.downloads.DownloadNode;
@@ -30,6 +29,7 @@ import java.net.URLEncoder;
import org.json.JSONArray;
import org.json.JSONObject;
+import yugecin.opsudance.core.errorhandling.ErrorHandler;
/**
* Download server: https://osu.hexide.com/
@@ -128,7 +128,7 @@ public class HexideServer extends DownloadServer {
// all results at once; this approach just gets pagination correct.
this.totalResults = arr.length() + resultIndex;
} catch (MalformedURLException | UnsupportedEncodingException e) {
- ErrorHandler.error(String.format("Problem loading result list for query '%s'.", query), e, true);
+ ErrorHandler.error(String.format("Problem loading result list for query '%s'.", query), e).show();
}
return nodes;
}
diff --git a/src/itdelatrisu/opsu/downloads/servers/MengSkyServer.java b/src/itdelatrisu/opsu/downloads/servers/MengSkyServer.java
index 1c72dff5..a2e298a4 100644
--- a/src/itdelatrisu/opsu/downloads/servers/MengSkyServer.java
+++ b/src/itdelatrisu/opsu/downloads/servers/MengSkyServer.java
@@ -18,7 +18,6 @@
package itdelatrisu.opsu.downloads.servers;
-import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.downloads.DownloadNode;
@@ -30,6 +29,7 @@ import java.net.URLEncoder;
import org.json.JSONArray;
import org.json.JSONObject;
+import yugecin.opsudance.core.errorhandling.ErrorHandler;
/**
* Download server: http://osu.mengsky.net/
@@ -101,7 +101,7 @@ public class MengSkyServer extends DownloadServer {
resultCount = 1 + (pageTotal - 1) * PAGE_LIMIT;
this.totalResults = resultCount;
} catch (MalformedURLException | UnsupportedEncodingException e) {
- ErrorHandler.error(String.format("Problem loading result list for query '%s'.", query), e, true);
+ ErrorHandler.error(String.format("Problem loading result list for query '%s'.", query), e).show();
}
return nodes;
}
diff --git a/src/itdelatrisu/opsu/downloads/servers/MnetworkServer.java b/src/itdelatrisu/opsu/downloads/servers/MnetworkServer.java
index 4341512a..e9c2e3c6 100644
--- a/src/itdelatrisu/opsu/downloads/servers/MnetworkServer.java
+++ b/src/itdelatrisu/opsu/downloads/servers/MnetworkServer.java
@@ -18,9 +18,9 @@
package itdelatrisu.opsu.downloads.servers;
-import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.downloads.DownloadNode;
+import yugecin.opsudance.core.errorhandling.ErrorHandler;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
@@ -120,7 +120,7 @@ public class MnetworkServer extends DownloadServer {
// store total result count
this.totalResults = nodes.length;
} catch (MalformedURLException | UnsupportedEncodingException e) {
- ErrorHandler.error(String.format("Problem loading result list for query '%s'.", query), e, true);
+ ErrorHandler.error(String.format("Problem loading result list for query '%s'.", query), e).show();
}
return nodes;
}
diff --git a/src/itdelatrisu/opsu/downloads/servers/OsuMirrorServer.java b/src/itdelatrisu/opsu/downloads/servers/OsuMirrorServer.java
index 834f2b9f..435eee2f 100644
--- a/src/itdelatrisu/opsu/downloads/servers/OsuMirrorServer.java
+++ b/src/itdelatrisu/opsu/downloads/servers/OsuMirrorServer.java
@@ -18,7 +18,6 @@
package itdelatrisu.opsu.downloads.servers;
-import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.downloads.DownloadNode;
@@ -36,6 +35,7 @@ import java.util.TimeZone;
import org.json.JSONArray;
import org.json.JSONObject;
+import yugecin.opsudance.core.errorhandling.ErrorHandler;
/**
* Download server: http://loli.al/
@@ -123,7 +123,7 @@ public class OsuMirrorServer extends DownloadServer {
else
this.totalResults = maxServerID;
} catch (MalformedURLException | UnsupportedEncodingException e) {
- ErrorHandler.error(String.format("Problem loading result list for query '%s'.", query), e, true);
+ ErrorHandler.error(String.format("Problem loading result list for query '%s'.", query), e).show();
}
return nodes;
}
diff --git a/src/itdelatrisu/opsu/downloads/servers/YaSOnlineServer.java b/src/itdelatrisu/opsu/downloads/servers/YaSOnlineServer.java
index 3d25459a..9e13dc58 100644
--- a/src/itdelatrisu/opsu/downloads/servers/YaSOnlineServer.java
+++ b/src/itdelatrisu/opsu/downloads/servers/YaSOnlineServer.java
@@ -17,7 +17,6 @@
*/
package itdelatrisu.opsu.downloads.servers;
-import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.downloads.DownloadNode;
@@ -34,6 +33,7 @@ import java.util.Iterator;
import java.util.List;
import org.json.JSONObject;
+import yugecin.opsudance.core.errorhandling.ErrorHandler;
/**
* Download server: http://osu.yas-online.net/
@@ -114,7 +114,7 @@ public class YaSOnlineServer extends DownloadServer {
String downloadLink = item.getString("downloadLink");
return String.format(DOWNLOAD_FETCH_URL, downloadLink);
} catch (MalformedURLException | UnsupportedEncodingException e) {
- ErrorHandler.error(String.format("Problem retrieving download URL for beatmap '%d'.", beatmapSetID), e, true);
+ ErrorHandler.error(String.format("Problem retrieving download URL for beatmap '%d'.", beatmapSetID), e).show();
return null;
} finally {
Utils.setSSLCertValidation(true);
@@ -186,7 +186,7 @@ public class YaSOnlineServer extends DownloadServer {
else
this.totalResults = maxServerID;
} catch (MalformedURLException | UnsupportedEncodingException e) {
- ErrorHandler.error(String.format("Problem loading result list for query '%s'.", query), e, true);
+ ErrorHandler.error(String.format("Problem loading result list for query '%s'.", query), e).show();
} finally {
Utils.setSSLCertValidation(true);
}
diff --git a/src/itdelatrisu/opsu/objects/Circle.java b/src/itdelatrisu/opsu/objects/Circle.java
index 7c0d5756..56d393b2 100644
--- a/src/itdelatrisu/opsu/objects/Circle.java
+++ b/src/itdelatrisu/opsu/objects/Circle.java
@@ -64,10 +64,9 @@ public class Circle extends GameObject {
/**
* Initializes the Circle data type with map modifiers, images, and dimensions.
- * @param container the game container
* @param circleDiameter the circle diameter
*/
- public static void init(GameContainer container, float circleDiameter) {
+ public static void init(float circleDiameter) {
diameter = circleDiameter * HitObject.getXMultiplier(); // convert from Osupixels (640x480)
int diameterInt = (int) diameter;
GameImage.HITCIRCLE.setImage(GameImage.HITCIRCLE.getImage().getScaledCopy(diameterInt, diameterInt));
diff --git a/src/itdelatrisu/opsu/objects/Slider.java b/src/itdelatrisu/opsu/objects/Slider.java
index f8ad3441..6ffaee19 100644
--- a/src/itdelatrisu/opsu/objects/Slider.java
+++ b/src/itdelatrisu/opsu/objects/Slider.java
@@ -37,6 +37,7 @@ import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import yugecin.opsudance.Dancer;
+import yugecin.opsudance.core.DisplayContainer;
/**
* Data type representing a slider object.
@@ -127,13 +128,12 @@ public class Slider extends GameObject {
/**
* Initializes the Slider data type with images and dimensions.
- * @param container the game container
* @param circleDiameter the circle diameter
* @param beatmap the associated beatmap
*/
- public static void init(GameContainer container, float circleDiameter, Beatmap beatmap) {
- containerWidth = container.getWidth();
- containerHeight = container.getHeight();
+ public static void init(DisplayContainer displayContainer, float circleDiameter, Beatmap beatmap) {
+ containerWidth = displayContainer.width;
+ containerHeight = displayContainer.height;
diameter = circleDiameter * HitObject.getXMultiplier(); // convert from Osupixels (640x480)
int diameterInt = (int) diameter;
diff --git a/src/itdelatrisu/opsu/objects/Spinner.java b/src/itdelatrisu/opsu/objects/Spinner.java
index 551c80f8..bb3ed811 100644
--- a/src/itdelatrisu/opsu/objects/Spinner.java
+++ b/src/itdelatrisu/opsu/objects/Spinner.java
@@ -35,6 +35,7 @@ import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
+import yugecin.opsudance.core.DisplayContainer;
/**
* Data type representing a spinner object.
@@ -109,12 +110,11 @@ public class Spinner extends GameObject {
/**
* Initializes the Spinner data type with images and dimensions.
- * @param container the game container
* @param difficulty the map's overall difficulty value
*/
- public static void init(GameContainer container, float difficulty) {
- width = container.getWidth();
- height = container.getHeight();
+ public static void init(DisplayContainer displayContainer, float difficulty) {
+ width = displayContainer.width;
+ height = displayContainer.height;
overallDifficulty = difficulty;
}
diff --git a/src/itdelatrisu/opsu/render/CurveRenderState.java b/src/itdelatrisu/opsu/render/CurveRenderState.java
index a70846b6..9ca3a33e 100644
--- a/src/itdelatrisu/opsu/render/CurveRenderState.java
+++ b/src/itdelatrisu/opsu/render/CurveRenderState.java
@@ -96,7 +96,7 @@ public class CurveRenderState {
*/
public static void shutdown() {
staticState.shutdown();
- FrameBufferCache.shutdown();
+ //FrameBufferCache.shutdown();
}
/**
diff --git a/src/itdelatrisu/opsu/render/FrameBufferCache.java b/src/itdelatrisu/opsu/render/FrameBufferCache.java
index c27a80cb..bf1a96aa 100644
--- a/src/itdelatrisu/opsu/render/FrameBufferCache.java
+++ b/src/itdelatrisu/opsu/render/FrameBufferCache.java
@@ -128,6 +128,7 @@ public class FrameBufferCache {
*
* This is necessary for cases when the game gets restarted with a
* different resolution without closing the process.
+ * // TODO d do we still need this
*/
public static void shutdown() {
FrameBufferCache fbcInstance = FrameBufferCache.getInstance();
diff --git a/src/itdelatrisu/opsu/replay/Replay.java b/src/itdelatrisu/opsu/replay/Replay.java
index 6f2d9fb4..5ee6e271 100644
--- a/src/itdelatrisu/opsu/replay/Replay.java
+++ b/src/itdelatrisu/opsu/replay/Replay.java
@@ -18,7 +18,6 @@
package itdelatrisu.opsu.replay;
-import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.ScoreData;
import itdelatrisu.opsu.Utils;
@@ -45,6 +44,9 @@ import org.apache.commons.compress.compressors.lzma.LZMACompressorInputStream;
import org.newdawn.slick.util.Log;
import lzma.streams.LzmaOutputStream;
+import yugecin.opsudance.core.errorhandling.ErrorHandler;
+import yugecin.opsudance.core.events.EventBus;
+import yugecin.opsudance.events.BubbleNotificationEvent;
/**
* Captures osu! replay data.
@@ -273,7 +275,7 @@ public class Replay {
File dir = Options.getReplayDir();
if (!dir.isDirectory()) {
if (!dir.mkdir()) {
- ErrorHandler.error("Failed to create replay directory.", null, false);
+ EventBus.instance.post(new BubbleNotificationEvent("Failed to create replay directory.", BubbleNotificationEvent.COMMONCOLOR_RED));
return;
}
}
@@ -343,7 +345,7 @@ public class Replay {
compressedOut.write(bytes);
} catch (IOException e) {
// possible OOM: https://github.com/jponge/lzma-java/issues/9
- ErrorHandler.error("LZMA compression failed (possible out-of-memory error).", e, true);
+ ErrorHandler.error("LZMA compression failed (possible out-of-memory error).", e).show();
}
compressedOut.close();
bout.close();
@@ -357,7 +359,7 @@ public class Replay {
writer.close();
} catch (IOException e) {
- ErrorHandler.error("Could not save replay data.", e, true);
+ ErrorHandler.error("Could not save replay data.", e).show();
}
}
}.start();
diff --git a/src/itdelatrisu/opsu/replay/ReplayImporter.java b/src/itdelatrisu/opsu/replay/ReplayImporter.java
index 22e4a7dd..ee901143 100644
--- a/src/itdelatrisu/opsu/replay/ReplayImporter.java
+++ b/src/itdelatrisu/opsu/replay/ReplayImporter.java
@@ -18,7 +18,7 @@
package itdelatrisu.opsu.replay;
-import itdelatrisu.opsu.ErrorHandler;
+import com.sun.deploy.security.EnhancedJarVerifier;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.beatmap.Beatmap;
import itdelatrisu.opsu.beatmap.BeatmapSetList;
@@ -31,6 +31,8 @@ import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import org.newdawn.slick.util.Log;
+import yugecin.opsudance.core.events.EventBus;
+import yugecin.opsudance.events.BubbleNotificationEvent;
/**
* Importer for replay files.
@@ -70,7 +72,9 @@ public class ReplayImporter {
File replayDir = Options.getReplayDir();
if (!replayDir.isDirectory()) {
if (!replayDir.mkdir()) {
- ErrorHandler.error(String.format("Failed to create replay directory '%s'.", replayDir.getAbsolutePath()), null, false);
+ String err = String.format("Failed to create replay directory '%s'.", replayDir.getAbsolutePath());
+ Log.error(err);
+ EventBus.instance.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
return;
}
}
@@ -83,7 +87,9 @@ public class ReplayImporter {
r.loadHeader();
} catch (IOException e) {
moveToFailedDirectory(file);
- ErrorHandler.error(String.format("Failed to import replay '%s'. The replay file could not be parsed.", file.getName()), e, false);
+ String err = String.format("Failed to import replay '%s'. The replay file could not be parsed.", file.getName());
+ Log.error(err, e);
+ EventBus.instance.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
continue;
}
Beatmap beatmap = BeatmapSetList.get().getBeatmapFromHash(r.beatmapHash);
@@ -100,8 +106,9 @@ public class ReplayImporter {
}
} else {
moveToFailedDirectory(file);
- ErrorHandler.error(String.format("Failed to import replay '%s'. The associated beatmap could not be found.", file.getName()), null, false);
- continue;
+ String err = String.format("Failed to import replay '%s'. The associated beatmap could not be found.", file.getName());
+ Log.error(err);
+ EventBus.instance.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
}
}
diff --git a/src/itdelatrisu/opsu/skins/SkinLoader.java b/src/itdelatrisu/opsu/skins/SkinLoader.java
index b7ac04ec..5c9be6e6 100644
--- a/src/itdelatrisu/opsu/skins/SkinLoader.java
+++ b/src/itdelatrisu/opsu/skins/SkinLoader.java
@@ -18,7 +18,6 @@
package itdelatrisu.opsu.skins;
-import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.Utils;
@@ -32,6 +31,8 @@ import java.util.LinkedList;
import org.newdawn.slick.Color;
import org.newdawn.slick.util.Log;
+import yugecin.opsudance.core.events.EventBus;
+import yugecin.opsudance.events.BubbleNotificationEvent;
/**
* Loads skin configuration files.
@@ -290,7 +291,9 @@ public class SkinLoader {
}
}
} catch (IOException e) {
- ErrorHandler.error(String.format("Failed to read file '%s'.", skinFile.getAbsolutePath()), e, false);
+ String err = String.format("Failed to read file '%s'.", skinFile.getAbsolutePath());
+ Log.error(err, e);
+ EventBus.instance.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
}
return skin;
diff --git a/src/itdelatrisu/opsu/states/ButtonMenu.java b/src/itdelatrisu/opsu/states/ButtonMenu.java
index df9e7db1..ca899a0d 100644
--- a/src/itdelatrisu/opsu/states/ButtonMenu.java
+++ b/src/itdelatrisu/opsu/states/ButtonMenu.java
@@ -20,7 +20,6 @@ package itdelatrisu.opsu.states;
import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.GameMod;
-import itdelatrisu.opsu.Opsu;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.ScoreData;
import itdelatrisu.opsu.Utils;
@@ -39,114 +38,112 @@ import java.util.ArrayList;
import java.util.List;
import org.newdawn.slick.Color;
-import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.Input;
-import org.newdawn.slick.SlickException;
-import org.newdawn.slick.state.BasicGameState;
-import org.newdawn.slick.state.StateBasedGame;
-import org.newdawn.slick.state.transition.EmptyTransition;
-import org.newdawn.slick.state.transition.FadeInTransition;
+import yugecin.opsudance.core.DisplayContainer;
+import yugecin.opsudance.core.inject.InstanceContainer;
+import yugecin.opsudance.core.state.BaseOpsuState;
/**
* Generic button menu state.
*
* Displays a header and a set of defined options to the player.
*/
-public class ButtonMenu extends BasicGameState {
+public class ButtonMenu extends BaseOpsuState {
+
/** Menu states. */
public enum MenuState {
/** The exit confirmation screen. */
EXIT (new Button[] { Button.YES, Button.NO }) {
@Override
- public String[] getTitle(GameContainer container, StateBasedGame game) {
+ public String[] getTitle() {
return new String[] { "Are you sure you want to exit opsu!?" };
}
@Override
- public void leave(GameContainer container, StateBasedGame game) {
- Button.NO.click(container, game);
+ public void leave() {
+ Button.NO.click();
}
},
/** The initial beatmap management screen (for a non-"favorite" beatmap). */
BEATMAP (new Button[] { Button.CLEAR_SCORES, Button.FAVORITE_ADD, Button.DELETE, Button.CANCEL }) {
@Override
- public String[] getTitle(GameContainer container, StateBasedGame game) {
- BeatmapSetNode node = ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).getNode();
+ public String[] getTitle() {
+ BeatmapSetNode node = instanceContainer.provide(ButtonMenu.class).getNode();
String beatmapString = (node != null) ? BeatmapSetList.get().getBaseNode(node.index).toString() : "";
return new String[] { beatmapString, "What do you want to do with this beatmap?" };
}
@Override
- public void leave(GameContainer container, StateBasedGame game) {
- Button.CANCEL.click(container, game);
+ public void leave() {
+ Button.CANCEL.click();
}
@Override
- public void scroll(GameContainer container, StateBasedGame game, int newValue) {
- Input input = container.getInput();
- if (input.isKeyDown(Input.KEY_LALT) || input.isKeyDown(Input.KEY_RALT))
- super.scroll(container, game, newValue);
+ public void mouseWheelMoved(int newValue) {
+ if (displayContainer.input.isKeyDown(Input.KEY_LALT) || displayContainer.input.isKeyDown(Input.KEY_RALT)) {
+ super.mouseWheelMoved(newValue);
+ }
}
},
/** The initial beatmap management screen (for a "favorite" beatmap). */
BEATMAP_FAVORITE (new Button[] { Button.CLEAR_SCORES, Button.FAVORITE_REMOVE, Button.DELETE, Button.CANCEL }) {
@Override
- public String[] getTitle(GameContainer container, StateBasedGame game) {
- return BEATMAP.getTitle(container, game);
+ public String[] getTitle() {
+ return BEATMAP.getTitle();
}
@Override
- public void leave(GameContainer container, StateBasedGame game) {
- BEATMAP.leave(container, game);
+ public void leave() {
+ BEATMAP.leave();
}
@Override
- public void scroll(GameContainer container, StateBasedGame game, int newValue) {
- BEATMAP.scroll(container, game, newValue);
+ public void mouseWheelMoved(int newValue) {
+ BEATMAP.mouseWheelMoved(newValue);
}
},
/** The beatmap deletion screen for a beatmap set with multiple beatmaps. */
BEATMAP_DELETE_SELECT (new Button[] { Button.DELETE_GROUP, Button.DELETE_SONG, Button.CANCEL_DELETE }) {
@Override
- public String[] getTitle(GameContainer container, StateBasedGame game) {
- BeatmapSetNode node = ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).getNode();
+ public String[] getTitle() {
+ BeatmapSetNode node = instanceContainer.provide(ButtonMenu.class).getNode();
String beatmapString = (node != null) ? node.toString() : "";
return new String[] { String.format("Are you sure you wish to delete '%s' from disk?", beatmapString) };
}
@Override
- public void leave(GameContainer container, StateBasedGame game) {
- Button.CANCEL_DELETE.click(container, game);
+ public void leave() {
+ Button.CANCEL_DELETE.click();
}
@Override
- public void scroll(GameContainer container, StateBasedGame game, int newValue) {
- MenuState.BEATMAP.scroll(container, game, newValue);
+ public void mouseWheelMoved(int newValue) {
+ MenuState.BEATMAP.mouseWheelMoved(newValue);
}
},
/** The beatmap deletion screen for a single beatmap. */
BEATMAP_DELETE_CONFIRM (new Button[] { Button.DELETE_CONFIRM, Button.CANCEL_DELETE }) {
@Override
- public String[] getTitle(GameContainer container, StateBasedGame game) {
- return BEATMAP_DELETE_SELECT.getTitle(container, game);
+ public String[] getTitle() {
+ return BEATMAP_DELETE_SELECT.getTitle();
}
@Override
- public void leave(GameContainer container, StateBasedGame game) {
- Button.CANCEL_DELETE.click(container, game);
+ public void leave() {
+ Button.CANCEL_DELETE.click();
}
@Override
- public void scroll(GameContainer container, StateBasedGame game, int newValue) {
- MenuState.BEATMAP.scroll(container, game, newValue);
+ public void mouseWheelMoved(int newValue) {
+ MenuState.BEATMAP.mouseWheelMoved(newValue);
}
},
/** The beatmap reloading confirmation screen. */
RELOAD (new Button[] { Button.RELOAD_CONFIRM, Button.RELOAD_CANCEL }) {
@Override
- public String[] getTitle(GameContainer container, StateBasedGame game) {
+ public String[] getTitle() {
return new String[] {
"You have requested a full process of your beatmaps.",
"This could take a few minutes.",
@@ -155,70 +152,68 @@ public class ButtonMenu extends BasicGameState {
}
@Override
- public void leave(GameContainer container, StateBasedGame game) {
- Button.RELOAD_CANCEL.click(container, game);
+ public void leave() {
+ Button.RELOAD_CANCEL.click();
}
@Override
- public void scroll(GameContainer container, StateBasedGame game, int newValue) {
- MenuState.BEATMAP.scroll(container, game, newValue);
+ public void mouseWheelMoved(int newValue) {
+ MenuState.BEATMAP.mouseWheelMoved(newValue);
}
},
/** The score management screen. */
SCORE (new Button[] { Button.DELETE_SCORE, Button.CLOSE }) {
@Override
- public String[] getTitle(GameContainer container, StateBasedGame game) {
+ public String[] getTitle() {
return new String[] { "Score Management" };
}
@Override
- public void leave(GameContainer container, StateBasedGame game) {
- Button.CLOSE.click(container, game);
+ public void leave() {
+ Button.CLOSE.click();
}
@Override
- public void scroll(GameContainer container, StateBasedGame game, int newValue) {
- MenuState.BEATMAP.scroll(container, game, newValue);
+ public void mouseWheelMoved(int newValue) {
+ MenuState.BEATMAP.mouseWheelMoved(newValue);
}
},
/** The game mod selection screen. */
MODS (new Button[] { Button.RESET_MODS, Button.CLOSE }) {
@Override
- public String[] getTitle(GameContainer container, StateBasedGame game) {
+ public String[] getTitle() {
return new String[] {
"Mods provide different ways to enjoy gameplay. Some have an effect on the score you can achieve during ranked play. Others are just for fun."
};
}
@Override
- protected float getBaseY(GameContainer container, StateBasedGame game) {
- return container.getHeight() * 2f / 3;
+ protected float getBaseY(DisplayContainer displayContainer) {
+ return displayContainer.height * 2f / 3;
}
@Override
- public void enter(GameContainer container, StateBasedGame game) {
- super.enter(container, game);
- for (GameMod mod : GameMod.values())
+ public void enter() {
+ super.enter();
+ for (GameMod mod : GameMod.values()) {
mod.resetHover();
+ }
}
@Override
- public void leave(GameContainer container, StateBasedGame game) {
- Button.CLOSE.click(container, game);
+ public void leave() {
+ Button.CLOSE.click();
}
@Override
- public void draw(GameContainer container, StateBasedGame game, Graphics g) {
- int width = container.getWidth();
- int height = container.getHeight();
-
+ public void render(Graphics g) {
// score multiplier (TODO: fade in color changes)
float mult = GameMod.getScoreMultiplier();
String multString = String.format("Score Multiplier: %.2fx", mult);
Color multColor = (mult == 1f) ? Color.white : (mult > 1f) ? Color.green : Color.red;
- float multY = Fonts.LARGE.getLineHeight() * 2 + height * 0.06f;
+ float multY = Fonts.LARGE.getLineHeight() * 2 + displayContainer.height * 0.06f;
Fonts.LARGE.drawString(
- (width - Fonts.LARGE.getWidth(multString)) / 2f,
+ (displayContainer.width - Fonts.LARGE.getWidth(multString)) / 2f,
multY, multString, multColor);
// category text
@@ -232,27 +227,28 @@ public class ButtonMenu extends BasicGameState {
for (GameMod mod : GameMod.values())
mod.draw();
- super.draw(container, game, g);
+ super.render(g);
}
@Override
- public void update(GameContainer container, int delta, int mouseX, int mouseY) {
- super.update(container, delta, mouseX, mouseY);
+ public void preRenderUpdate() {
+ super.preRenderUpdate();
GameMod hoverMod = null;
for (GameMod mod : GameMod.values()) {
- mod.hoverUpdate(delta, mod.isActive());
- if (hoverMod == null && mod.contains(mouseX, mouseY))
+ mod.hoverUpdate(displayContainer.renderDelta, mod.isActive());
+ if (hoverMod == null && mod.contains(displayContainer.mouseX, displayContainer.mouseY))
hoverMod = mod;
}
// tooltips
- if (hoverMod != null)
- UI.updateTooltip(delta, hoverMod.getDescription(), true);
+ if (hoverMod != null) {
+ UI.updateTooltip(displayContainer.renderDelta, hoverMod.getDescription(), true);
+ }
}
@Override
- public void keyPress(GameContainer container, StateBasedGame game, int key, char c) {
- super.keyPress(container, game, key, c);
+ public void keyPressed(int key, char c) {
+ super.keyPressed(key, c);
for (GameMod mod : GameMod.values()) {
if (key == mod.getKey()) {
mod.toggle(true);
@@ -262,8 +258,8 @@ public class ButtonMenu extends BasicGameState {
}
@Override
- public void click(GameContainer container, StateBasedGame game, int cx, int cy) {
- super.click(container, game, cx, cy);
+ public void mousePressed(int cx, int cy) {
+ super.mousePressed(cx, cy);
for (GameMod mod : GameMod.values()) {
if (mod.contains(cx, cy)) {
boolean prevState = mod.isActive();
@@ -276,11 +272,14 @@ public class ButtonMenu extends BasicGameState {
}
@Override
- public void scroll(GameContainer container, StateBasedGame game, int newValue) {
- MenuState.BEATMAP.scroll(container, game, newValue);
+ public void mouseWheelMoved(int newValue) {
+ MenuState.BEATMAP.mouseWheelMoved(newValue);
}
};
+ public static DisplayContainer displayContainer;
+ public static InstanceContainer instanceContainer;
+
/** The buttons in the state. */
private final Button[] buttons;
@@ -306,15 +305,10 @@ public class ButtonMenu extends BasicGameState {
/**
* Initializes the menu state.
- * @param container the game container
- * @param game the game
- * @param button the center button image
- * @param buttonL the left button image
- * @param buttonR the right button image
*/
- public void init(GameContainer container, StateBasedGame game, Image button, Image buttonL, Image buttonR) {
- float center = container.getWidth() / 2f;
- float baseY = getBaseY(container, game);
+ public void revalidate(Image button, Image buttonL, Image buttonR) {
+ float center = displayContainer.width / 2;
+ float baseY = getBaseY(displayContainer);
float offsetY = button.getHeight() * 1.25f;
menuButtons = new MenuButton[buttons.length];
@@ -328,25 +322,21 @@ public class ButtonMenu extends BasicGameState {
/**
* Returns the base Y coordinate for the buttons.
- * @param container the game container
- * @param game the game
*/
- protected float getBaseY(GameContainer container, StateBasedGame game) {
- float baseY = container.getHeight() * 0.2f;
- baseY += ((getTitle(container, game).length - 1) * Fonts.LARGE.getLineHeight());
+ protected float getBaseY(DisplayContainer displayContainer) {
+ float baseY = displayContainer.height * 0.2f;
+ baseY += ((getTitle().length - 1) * Fonts.LARGE.getLineHeight());
return baseY;
}
/**
* Draws the title and buttons to the graphics context.
- * @param container the game container
- * @param game the game
* @param g the graphics context
*/
- public void draw(GameContainer container, StateBasedGame game, Graphics g) {
+ public void render(Graphics g) {
// draw title
if (actualTitle != null) {
- float marginX = container.getWidth() * 0.015f, marginY = container.getHeight() * 0.01f;
+ float marginX = displayContainer.width * 0.015f, marginY = displayContainer.height * 0.01f;
int lineHeight = Fonts.LARGE.getLineHeight();
for (int i = 0, size = actualTitle.size(); i < size; i++)
Fonts.LARGE.drawString(marginX, marginY + (i * lineHeight), actualTitle.get(i), Color.white);
@@ -361,17 +351,13 @@ public class ButtonMenu extends BasicGameState {
/**
* Updates the menu state.
- * @param container the game container
- * @param delta the delta interval
- * @param mouseX the mouse x coordinate
- * @param mouseY the mouse y coordinate
*/
- public void update(GameContainer container, int delta, int mouseX, int mouseY) {
- float center = container.getWidth() / 2f;
- boolean centerOffsetUpdated = centerOffset.update(delta);
+ public void preRenderUpdate() {
+ float center = displayContainer.width / 2f;
+ boolean centerOffsetUpdated = centerOffset.update(displayContainer.renderDelta);
float centerOffsetX = centerOffset.getValue();
for (int i = 0; i < buttons.length; i++) {
- menuButtons[i].hoverUpdate(delta, mouseX, mouseY);
+ menuButtons[i].hoverUpdate(displayContainer.renderDelta, displayContainer.mouseX, displayContainer.mouseY);
// move button to center
if (centerOffsetUpdated)
@@ -381,15 +367,11 @@ public class ButtonMenu extends BasicGameState {
/**
* Processes a mouse click action.
- * @param container the game container
- * @param game the game
- * @param cx the x coordinate
- * @param cy the y coordinate
*/
- public void click(GameContainer container, StateBasedGame game, int cx, int cy) {
+ public void mousePressed(int x, int y) {
for (int i = 0; i < buttons.length; i++) {
- if (menuButtons[i].contains(cx, cy)) {
- buttons[i].click(container, game);
+ if (menuButtons[i].contains(x, y)) {
+ buttons[i].click();
break;
}
}
@@ -397,42 +379,34 @@ public class ButtonMenu extends BasicGameState {
/**
* Processes a key press action.
- * @param container the game container
- * @param game the game
* @param key the key code that was pressed (see {@link org.newdawn.slick.Input})
* @param c the character of the key that was pressed
*/
- public void keyPress(GameContainer container, StateBasedGame game, int key, char c) {
+ public void keyPressed(int key, char c) {
int index = Character.getNumericValue(c) - 1;
if (index >= 0 && index < buttons.length)
- buttons[index].click(container, game);
+ buttons[index].click();
}
/**
* Retrieves the title strings for the menu state (via override).
- * @param container the game container
- * @param game the game
*/
- public String[] getTitle(GameContainer container, StateBasedGame game) { return new String[0]; }
+ public String[] getTitle() { return new String[0]; }
/**
* Processes a mouse wheel movement.
- * @param container the game container
- * @param game the game
* @param newValue the amount that the mouse wheel moved
*/
- public void scroll(GameContainer container, StateBasedGame game, int newValue) {
+ public void mouseWheelMoved(int newValue) {
UI.changeVolume((newValue < 0) ? -1 : 1);
}
/**
* Processes a state enter request.
- * @param container the game container
- * @param game the game
*/
- public void enter(GameContainer container, StateBasedGame game) {
- float center = container.getWidth() / 2f;
- float centerOffsetX = container.getWidth() * OFFSET_WIDTH_RATIO;
+ public void enter() {
+ float center = displayContainer.width / 2f;
+ float centerOffsetX = displayContainer.width * OFFSET_WIDTH_RATIO;
centerOffset = new AnimatedValue(700, centerOffsetX, 0, AnimationEquation.OUT_BOUNCE);
for (int i = 0; i < buttons.length; i++) {
menuButtons[i].setX(center + ((i % 2 == 0) ? centerOffsetX : centerOffsetX * -1));
@@ -440,150 +414,149 @@ public class ButtonMenu extends BasicGameState {
}
// create title string list
- actualTitle = new ArrayList();
- String[] title = getTitle(container, game);
- int maxLineWidth = (int) (container.getWidth() * 0.96f);
- for (int i = 0; i < title.length; i++) {
+ actualTitle = new ArrayList<>();
+ String[] title = getTitle();
+ int maxLineWidth = (int) (displayContainer.width * 0.96f);
+ for (String aTitle : title) {
// wrap text if too long
- if (Fonts.LARGE.getWidth(title[i]) > maxLineWidth) {
- List list = Fonts.wrap(Fonts.LARGE, title[i], maxLineWidth, false);
+ if (Fonts.LARGE.getWidth(aTitle) > maxLineWidth) {
+ List list = Fonts.wrap(Fonts.LARGE, aTitle, maxLineWidth, false);
actualTitle.addAll(list);
- } else
- actualTitle.add(title[i]);
+ } else {
+ actualTitle.add(aTitle);
+ }
}
}
/**
* Processes a state exit request (via override).
- * @param container the game container
- * @param game the game
*/
- public void leave(GameContainer container, StateBasedGame game) {}
- };
+ public void leave() {}
+ }
/** Button types. */
private enum Button {
YES ("Yes", Color.green) {
@Override
- public void click(GameContainer container, StateBasedGame game) {
- container.exit();
+ public void click() {
+ displayContainer.exitRequested = true;
}
},
NO ("No", Color.red) {
@Override
- public void click(GameContainer container, StateBasedGame game) {
+ public void click() {
SoundController.playSound(SoundEffect.MENUBACK);
- game.enterState(Opsu.STATE_MAINMENU, new EmptyTransition(), new FadeInTransition());
+ displayContainer.switchState(MainMenu.class);
}
},
CLEAR_SCORES ("Clear local scores", Color.magenta) {
@Override
- public void click(GameContainer container, StateBasedGame game) {
+ public void click() {
SoundController.playSound(SoundEffect.MENUHIT);
- BeatmapSetNode node = ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).getNode();
- ((SongMenu) game.getState(Opsu.STATE_SONGMENU)).doStateActionOnLoad(MenuState.BEATMAP, node);
- game.enterState(Opsu.STATE_SONGMENU, new EmptyTransition(), new FadeInTransition());
+ BeatmapSetNode node = instanceContainer.provide(ButtonMenu.class).getNode();
+ instanceContainer.provide(SongMenu.class).doStateActionOnLoad(MenuState.BEATMAP, node);
+ displayContainer.switchState(SongMenu.class);
}
},
FAVORITE_ADD ("Add to Favorites", Color.blue) {
@Override
- public void click(GameContainer container, StateBasedGame game) {
+ public void click() {
SoundController.playSound(SoundEffect.MENUHIT);
- BeatmapSetNode node = ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).getNode();
+ BeatmapSetNode node = instanceContainer.provide(ButtonMenu.class).getNode();
node.getBeatmapSet().setFavorite(true);
- game.enterState(Opsu.STATE_SONGMENU, new EmptyTransition(), new FadeInTransition());
+ displayContainer.switchState(SongMenu.class);
}
},
FAVORITE_REMOVE ("Remove from Favorites", Color.blue) {
@Override
- public void click(GameContainer container, StateBasedGame game) {
+ public void click() {
SoundController.playSound(SoundEffect.MENUHIT);
- BeatmapSetNode node = ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).getNode();
+ BeatmapSetNode node = instanceContainer.provide(ButtonMenu.class).getNode();
node.getBeatmapSet().setFavorite(false);
- ((SongMenu) game.getState(Opsu.STATE_SONGMENU)).doStateActionOnLoad(MenuState.BEATMAP_FAVORITE);
- game.enterState(Opsu.STATE_SONGMENU, new EmptyTransition(), new FadeInTransition());
+ instanceContainer.provide(SongMenu.class).doStateActionOnLoad(MenuState.BEATMAP_FAVORITE);
+ displayContainer.switchState(SongMenu.class);
}
},
DELETE ("Delete...", Color.red) {
@Override
- public void click(GameContainer container, StateBasedGame game) {
+ public void click() {
SoundController.playSound(SoundEffect.MENUHIT);
- BeatmapSetNode node = ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).getNode();
+ BeatmapSetNode node = instanceContainer.provide(ButtonMenu.class).getNode();
MenuState ms = (node.beatmapIndex == -1 || node.getBeatmapSet().size() == 1) ?
MenuState.BEATMAP_DELETE_CONFIRM : MenuState.BEATMAP_DELETE_SELECT;
- ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).setMenuState(ms, node);
- game.enterState(Opsu.STATE_BUTTONMENU);
+ instanceContainer.provide(ButtonMenu.class).setMenuState(ms, node);
+ displayContainer.switchState(ButtonMenu.class);
}
},
CANCEL ("Cancel", Color.gray) {
@Override
- public void click(GameContainer container, StateBasedGame game) {
+ public void click() {
SoundController.playSound(SoundEffect.MENUBACK);
- game.enterState(Opsu.STATE_SONGMENU, new EmptyTransition(), new FadeInTransition());
+ displayContainer.switchState(SongMenu.class);
}
},
DELETE_CONFIRM ("Yes, delete this beatmap!", Color.red) {
@Override
- public void click(GameContainer container, StateBasedGame game) {
+ public void click() {
SoundController.playSound(SoundEffect.MENUHIT);
- BeatmapSetNode node = ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).getNode();
- ((SongMenu) game.getState(Opsu.STATE_SONGMENU)).doStateActionOnLoad(MenuState.BEATMAP_DELETE_CONFIRM, node);
- game.enterState(Opsu.STATE_SONGMENU, new EmptyTransition(), new FadeInTransition());
+ BeatmapSetNode node = instanceContainer.provide(ButtonMenu.class).getNode();
+ instanceContainer.provide(SongMenu.class).doStateActionOnLoad(MenuState.BEATMAP_DELETE_CONFIRM, node);
+ displayContainer.switchState(SongMenu.class);
}
},
DELETE_GROUP ("Yes, delete all difficulties!", Color.red) {
@Override
- public void click(GameContainer container, StateBasedGame game) {
- DELETE_CONFIRM.click(container, game);
+ public void click() {
+ DELETE_CONFIRM.click();
}
},
DELETE_SONG ("Yes, but only this difficulty", Color.red) {
@Override
- public void click(GameContainer container, StateBasedGame game) {
+ public void click() {
SoundController.playSound(SoundEffect.MENUHIT);
- BeatmapSetNode node = ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).getNode();
- ((SongMenu) game.getState(Opsu.STATE_SONGMENU)).doStateActionOnLoad(MenuState.BEATMAP_DELETE_SELECT, node);
- game.enterState(Opsu.STATE_SONGMENU, new EmptyTransition(), new FadeInTransition());
+ BeatmapSetNode node = instanceContainer.provide(ButtonMenu.class).getNode();
+ instanceContainer.provide(SongMenu.class).doStateActionOnLoad(MenuState.BEATMAP_DELETE_SELECT, node);
+ displayContainer.switchState(SongMenu.class);
}
},
CANCEL_DELETE ("Nooooo! I didn't mean to!", Color.gray) {
@Override
- public void click(GameContainer container, StateBasedGame game) {
- CANCEL.click(container, game);
+ public void click() {
+ CANCEL.click();
}
},
RELOAD_CONFIRM ("Let's do it!", Color.green) {
@Override
- public void click(GameContainer container, StateBasedGame game) {
+ public void click() {
SoundController.playSound(SoundEffect.MENUHIT);
- ((SongMenu) game.getState(Opsu.STATE_SONGMENU)).doStateActionOnLoad(MenuState.RELOAD);
- game.enterState(Opsu.STATE_SONGMENU, new EmptyTransition(), new FadeInTransition());
+ instanceContainer.provide(SongMenu.class).doStateActionOnLoad(MenuState.RELOAD);
+ displayContainer.switchState(SongMenu.class);
}
},
RELOAD_CANCEL ("Cancel", Color.red) {
@Override
- public void click(GameContainer container, StateBasedGame game) {
- CANCEL.click(container, game);
+ public void click() {
+ CANCEL.click();
}
},
DELETE_SCORE ("Delete score", Color.green) {
@Override
- public void click(GameContainer container, StateBasedGame game) {
+ public void click() {
SoundController.playSound(SoundEffect.MENUHIT);
- ScoreData scoreData = ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).getScoreData();
- ((SongMenu) game.getState(Opsu.STATE_SONGMENU)).doStateActionOnLoad(MenuState.SCORE, scoreData);
- game.enterState(Opsu.STATE_SONGMENU, new EmptyTransition(), new FadeInTransition());
+ ScoreData scoreData = instanceContainer.provide(ButtonMenu.class).getScoreData();
+ instanceContainer.provide(SongMenu.class).doStateActionOnLoad(MenuState.SCORE, scoreData);
+ displayContainer.switchState(SongMenu.class);
}
},
CLOSE ("Close", Color.gray) {
@Override
- public void click(GameContainer container, StateBasedGame game) {
- CANCEL.click(container, game);
+ public void click() {
+ CANCEL.click();
}
},
RESET_MODS ("Reset All Mods", Color.red) {
@Override
- public void click(GameContainer container, StateBasedGame game) {
+ public void click() {
SoundController.playSound(SoundEffect.MENUCLICK);
for (GameMod mod : GameMod.values()) {
if (mod.isActive())
@@ -592,6 +565,9 @@ public class ButtonMenu extends BasicGameState {
}
};
+ public static DisplayContainer displayContainer;
+ public static InstanceContainer instanceContainer;
+
/** The text to show on the button. */
private final String text;
@@ -620,10 +596,8 @@ public class ButtonMenu extends BasicGameState {
/**
* Processes a mouse click action (via override).
- * @param container the game container
- * @param game the game
*/
- public void click(GameContainer container, StateBasedGame game) {}
+ public void click() {}
}
/** The current menu state. */
@@ -635,97 +609,83 @@ public class ButtonMenu extends BasicGameState {
/** The score data to process in the state. */
private ScoreData scoreData;
- // game-related variables
- private GameContainer container;
- private StateBasedGame game;
- private Input input;
- private final int state;
-
- public ButtonMenu(int state) {
- this.state = state;
+ public ButtonMenu(DisplayContainer displayContainer, InstanceContainer instanceContainer) {
+ super(displayContainer);
+ Button.displayContainer = MenuState.displayContainer = displayContainer;
+ Button.instanceContainer = MenuState.instanceContainer = instanceContainer;
}
@Override
- public void init(GameContainer container, StateBasedGame game)
- throws SlickException {
- this.container = container;
- this.game = game;
- this.input = container.getInput();
+ public void revalidate() {
+ super.revalidate();
// initialize buttons
Image button = GameImage.MENU_BUTTON_MID.getImage();
- button = button.getScaledCopy(container.getWidth() / 2, button.getHeight());
+ button = button.getScaledCopy(displayContainer.width / 2, button.getHeight());
Image buttonL = GameImage.MENU_BUTTON_LEFT.getImage();
Image buttonR = GameImage.MENU_BUTTON_RIGHT.getImage();
- for (MenuState ms : MenuState.values())
- ms.init(container, game, button, buttonL, buttonR);
- }
-
- @Override
- public void render(GameContainer container, StateBasedGame game, Graphics g)
- throws SlickException {
- g.setBackground(Color.black);
- if (menuState != null)
- menuState.draw(container, game, g);
- }
-
- @Override
- public void update(GameContainer container, StateBasedGame game, int delta)
- throws SlickException {
- UI.update(delta);
- MusicController.loopTrackIfEnded(false);
- if (menuState != null)
- menuState.update(container, delta, input.getMouseX(), input.getMouseY());
- }
-
- @Override
- public int getID() { return state; }
-
- @Override
- public void mousePressed(int button, int x, int y) {
- // check mouse button
- if (button == Input.MOUSE_MIDDLE_BUTTON)
- return;
-
- if (menuState != null)
- menuState.click(container, game, x, y);
- }
-
- @Override
- public void mouseWheelMoved(int newValue) {
- if (menuState != null)
- menuState.scroll(container, game, newValue);
- }
-
- @Override
- public void keyPressed(int key, char c) {
- switch (key) {
- case Input.KEY_ESCAPE:
- if (menuState != null)
- menuState.leave(container, game);
- break;
- case Input.KEY_F7:
- Options.setNextFPS(container);
- break;
- case Input.KEY_F10:
- Options.toggleMouseDisabled();
- break;
- case Input.KEY_F12:
- Utils.takeScreenShot();
- break;
- default:
- if (menuState != null)
- menuState.keyPress(container, game, key, c);
- break;
+ for (MenuState ms : MenuState.values()) {
+ ms.revalidate(button, buttonL, buttonR);
}
}
@Override
- public void enter(GameContainer container, StateBasedGame game)
- throws SlickException {
+ public void render(Graphics g) {
+ super.render(g);
+
+ g.setBackground(Color.black);
+ if (menuState == null) {
+ return;
+ }
+ menuState.render(g);
+ }
+
+ @Override
+ public void preRenderUpdate() {
+ super.preRenderUpdate();
+
+ UI.update(displayContainer.renderDelta);
+ MusicController.loopTrackIfEnded(false);
+ menuState.preRenderUpdate();
+ }
+
+ @Override
+ public boolean mousePressed(int button, int x, int y) {
+ if (button == Input.MOUSE_MIDDLE_BUTTON) {
+ return false;
+ }
+
+ menuState.mousePressed(x, y);
+ return true;
+ }
+
+ @Override
+ public boolean mouseWheelMoved(int newValue) {
+ menuState.mouseWheelMoved(newValue);
+ return true;
+ }
+
+ @Override
+ public boolean keyPressed(int key, char c) {
+ if (super.keyPressed(key, c)) {
+ return true;
+ }
+
+ if (key == Input.KEY_ESCAPE) {
+ menuState.leave();
+ return true;
+ }
+
+ menuState.keyPressed(key, c);
+ return true;
+ }
+
+ @Override
+ public void enter() {
+ super.enter();
+
UI.enter();
- if (menuState != null)
- menuState.enter(container, game);
+ menuState.enter();
}
/**
diff --git a/src/itdelatrisu/opsu/states/DownloadsMenu.java b/src/itdelatrisu/opsu/states/DownloadsMenu.java
index 76fd7376..83a31bf6 100644
--- a/src/itdelatrisu/opsu/states/DownloadsMenu.java
+++ b/src/itdelatrisu/opsu/states/DownloadsMenu.java
@@ -19,7 +19,6 @@
package itdelatrisu.opsu.states;
import itdelatrisu.opsu.GameImage;
-import itdelatrisu.opsu.Opsu;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.audio.MusicController;
@@ -51,17 +50,15 @@ import javax.sound.sampled.LineEvent;
import javax.sound.sampled.LineListener;
import org.newdawn.slick.Color;
-import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.gui.TextField;
-import org.newdawn.slick.state.BasicGameState;
-import org.newdawn.slick.state.StateBasedGame;
-import org.newdawn.slick.state.transition.EasedFadeOutTransition;
-import org.newdawn.slick.state.transition.FadeInTransition;
import org.newdawn.slick.util.Log;
+import yugecin.opsudance.core.DisplayContainer;
+import yugecin.opsudance.core.inject.InstanceContainer;
+import yugecin.opsudance.core.state.ComplexOpsuState;
/**
* Downloads menu.
@@ -69,7 +66,10 @@ import org.newdawn.slick.util.Log;
* Players are able to download beatmaps off of various servers and import them
* from this state.
*/
-public class DownloadsMenu extends BasicGameState {
+public class DownloadsMenu extends ComplexOpsuState {
+
+ private final InstanceContainer instanceContainer;
+
/** Delay time, in milliseconds, between each search. */
private static final int SEARCH_DELAY = 700;
@@ -288,45 +288,42 @@ public class DownloadsMenu extends BasicGameState {
}
}
- // game-related variables
- private GameContainer container;
- private StateBasedGame game;
- private Input input;
- private final int state;
-
- public DownloadsMenu(int state) {
- this.state = state;
+ public DownloadsMenu(DisplayContainer displayContainer, InstanceContainer instanceContainer) {
+ super(displayContainer);
+ this.instanceContainer = instanceContainer;
}
@Override
- public void init(GameContainer container, StateBasedGame game)
- throws SlickException {
- this.container = container;
- this.game = game;
- this.input = container.getInput();
+ public void revalidate() {
+ super.revalidate();
- int width = container.getWidth();
- int height = container.getHeight();
- float baseX = width * 0.024f;
- float searchY = (height * 0.04f) + Fonts.LARGE.getLineHeight();
- float searchWidth = width * 0.3f;
+ components.clear();
+
+ int width = displayContainer.width;
+ int height = displayContainer.height;
+ int baseX = (int) (width * 0.024f);
+ int searchY = (int) (height * 0.04f + Fonts.LARGE.getLineHeight());
+ int searchWidth = (int) (width * 0.3f);
// search
searchTimer = SEARCH_DELAY;
searchResultString = "Loading data from server...";
- search = new TextField(
- container, Fonts.DEFAULT, (int) baseX, (int) searchY,
- (int) searchWidth, Fonts.MEDIUM.getLineHeight()
- );
+ search = new TextField(displayContainer, Fonts.DEFAULT, baseX, searchY, searchWidth, Fonts.MEDIUM.getLineHeight()) {
+ @Override
+ public boolean isFocusable() {
+ return false;
+ }
+ };
+ search.setFocused(true);
search.setBackgroundColor(Colors.BLACK_BG_NORMAL);
search.setBorderColor(Color.white);
search.setTextColor(Color.white);
- search.setConsumeEvents(false);
search.setMaxLength(255);
+ components.add(search);
// page buttons
- float pageButtonY = height * 0.2f;
- float pageButtonWidth = width * 0.7f;
+ int pageButtonY = (int) (height * 0.2f);
+ int pageButtonWidth = (int) (width * 0.7f);
Image prevImg = GameImage.MUSIC_PREVIOUS.getImage();
Image nextImg = GameImage.MUSIC_NEXT.getImage();
prevPage = new MenuButton(prevImg, baseX + prevImg.getWidth() / 2f,
@@ -337,25 +334,25 @@ public class DownloadsMenu extends BasicGameState {
nextPage.setHoverExpand(1.5f);
// buttons
- float buttonMarginX = width * 0.004f;
- float buttonHeight = height * 0.038f;
- float resetWidth = width * 0.085f;
- float rankedWidth = width * 0.15f;
- float lowerWidth = width * 0.12f;
- float topButtonY = searchY + Fonts.MEDIUM.getLineHeight() / 2f;
- float lowerButtonY = height * 0.995f - searchY - buttonHeight / 2f;
+ int buttonMarginX = (int) (width * 0.004f);
+ int buttonHeight = (int) (height * 0.038f);
+ int resetWidth = (int) (width * 0.085f);
+ int rankedWidth = (int) (width * 0.15f);
+ int lowerWidth = (int) (width * 0.12f);
+ int topButtonY = (int) (searchY + Fonts.MEDIUM.getLineHeight() / 2f);
+ int lowerButtonY = (int) (height * 0.995f - searchY - buttonHeight / 2f);
Image button = GameImage.MENU_BUTTON_MID.getImage();
Image buttonL = GameImage.MENU_BUTTON_LEFT.getImage();
Image buttonR = GameImage.MENU_BUTTON_RIGHT.getImage();
buttonL = buttonL.getScaledCopy(buttonHeight / buttonL.getHeight());
buttonR = buttonR.getScaledCopy(buttonHeight / buttonR.getHeight());
int lrButtonWidth = buttonL.getWidth() + buttonR.getWidth();
- Image resetButtonImage = button.getScaledCopy((int) resetWidth - lrButtonWidth, (int) buttonHeight);
- Image rankedButtonImage = button.getScaledCopy((int) rankedWidth - lrButtonWidth, (int) buttonHeight);
- Image lowerButtonImage = button.getScaledCopy((int) lowerWidth - lrButtonWidth, (int) buttonHeight);
- float resetButtonWidth = resetButtonImage.getWidth() + lrButtonWidth;
- float rankedButtonWidth = rankedButtonImage.getWidth() + lrButtonWidth;
- float lowerButtonWidth = lowerButtonImage.getWidth() + lrButtonWidth;
+ Image resetButtonImage = button.getScaledCopy(resetWidth - lrButtonWidth, buttonHeight);
+ Image rankedButtonImage = button.getScaledCopy(rankedWidth - lrButtonWidth, buttonHeight);
+ Image lowerButtonImage = button.getScaledCopy(lowerWidth - lrButtonWidth, buttonHeight);
+ int resetButtonWidth = resetButtonImage.getWidth() + lrButtonWidth;
+ int rankedButtonWidth = rankedButtonImage.getWidth() + lrButtonWidth;
+ int lowerButtonWidth = lowerButtonImage.getWidth() + lrButtonWidth;
clearButton = new MenuButton(lowerButtonImage, buttonL, buttonR,
width * 0.75f + buttonMarginX + lowerButtonWidth / 2f, lowerButtonY);
importButton = new MenuButton(lowerButtonImage, buttonL, buttonR,
@@ -374,8 +371,8 @@ public class DownloadsMenu extends BasicGameState {
// dropdown menu
int serverWidth = (int) (width * 0.12f);
- serverMenu = new DropdownMenu(container, SERVERS,
- baseX + searchWidth + buttonMarginX * 3f + resetButtonWidth + rankedButtonWidth, searchY, serverWidth) {
+ int x = baseX + searchWidth + buttonMarginX * 3 + resetButtonWidth + rankedButtonWidth;
+ serverMenu = new DropdownMenu(displayContainer, SERVERS, x, searchY, serverWidth) {
@Override
public void itemSelected(int index, DownloadServer item) {
resultList = null;
@@ -388,13 +385,14 @@ public class DownloadsMenu extends BasicGameState {
searchResultString = "Loading data from server...";
lastQuery = null;
pageDir = Page.RESET;
- if (searchQuery != null)
+ if (searchQuery != null) {
searchQuery.interrupt();
+ }
resetSearchTimer();
}
@Override
- public boolean menuClicked(int index) {
+ public boolean canSelect(int index) {
// block input during beatmap importing
if (importThread != null)
return false;
@@ -406,28 +404,25 @@ public class DownloadsMenu extends BasicGameState {
serverMenu.setBackgroundColor(Colors.BLACK_BG_HOVER);
serverMenu.setBorderColor(Color.black);
serverMenu.setChevronRightColor(Color.white);
+ components.add(serverMenu);
}
@Override
- public void render(GameContainer container, StateBasedGame game, Graphics g)
- throws SlickException {
- int width = container.getWidth();
- int height = container.getHeight();
- int mouseX = input.getMouseX(), mouseY = input.getMouseY();
- boolean inDropdownMenu = serverMenu.contains(mouseX, mouseY);
+ public void render(Graphics g) {
+ super.render(g);
// background
GameImage.SEARCH_BG.getImage().draw();
// title
- Fonts.LARGE.drawString(width * 0.024f, height * 0.03f, "Download Beatmaps!", Color.white);
+ Fonts.LARGE.drawString(displayContainer.width * 0.024f, displayContainer.height * 0.03f, "Download Beatmaps!", Color.white);
// search
g.setColor(Color.white);
g.setLineWidth(2f);
- search.render(container, g);
+ search.render(g);
Fonts.BOLD.drawString(
- search.getX() + search.getWidth() * 0.01f, search.getY() + search.getHeight() * 1.3f,
+ search.x + search.width * 0.01f, search.y + search.height * 1.3f,
searchResultString, Color.white
);
@@ -446,7 +441,7 @@ public class DownloadsMenu extends BasicGameState {
if (index >= nodes.length)
break;
nodes[index].drawResult(g, offset + i * DownloadNode.getButtonOffset(),
- DownloadNode.resultContains(mouseX, mouseY - offset, i) && !inDropdownMenu,
+ DownloadNode.resultContains(displayContainer.mouseX, displayContainer.mouseY - offset, i) && !serverMenu.isHovered(),
(index == focusResult), (previewID == nodes[index].getID()));
}
g.clearClip();
@@ -457,9 +452,9 @@ public class DownloadsMenu extends BasicGameState {
// pages
if (nodes.length > 0) {
- float baseX = width * 0.024f;
- float buttonY = height * 0.2f;
- float buttonWidth = width * 0.7f;
+ float baseX = displayContainer.width * 0.024f;
+ float buttonY = displayContainer.height * 0.2f;
+ float buttonWidth = displayContainer.width * 0.7f;
Fonts.BOLD.drawString(
baseX + (buttonWidth - Fonts.BOLD.getWidth("Page 1")) / 2f,
buttonY - Fonts.BOLD.getLineHeight() * 1.3f,
@@ -473,11 +468,11 @@ public class DownloadsMenu extends BasicGameState {
}
// downloads
- float downloadsX = width * 0.75f, downloadsY = search.getY();
+ float downloadsX = displayContainer.width * 0.75f, downloadsY = search.y;
g.setColor(Colors.BLACK_BG_NORMAL);
g.fillRect(downloadsX, downloadsY,
- width * 0.25f, height - downloadsY * 2f);
- Fonts.LARGE.drawString(downloadsX + width * 0.015f, downloadsY + height * 0.015f, "Downloads", Color.white);
+ displayContainer.width * 0.25f, displayContainer.height - downloadsY * 2f);
+ Fonts.LARGE.drawString(downloadsX + displayContainer.width * 0.015f, downloadsY + displayContainer.height * 0.015f, "Downloads", Color.white);
int downloadsSize = DownloadList.get().size();
if (downloadsSize > 0) {
int maxDownloadsShown = DownloadNode.maxDownloadsShown();
@@ -493,7 +488,7 @@ public class DownloadsMenu extends BasicGameState {
if (node == null)
break;
node.drawDownload(g, i * DownloadNode.getInfoHeight() + offset, index,
- DownloadNode.downloadContains(mouseX, mouseY - offset, i));
+ DownloadNode.downloadContains(displayContainer.mouseX, displayContainer.mouseY - offset, i));
}
g.clearClip();
@@ -510,13 +505,13 @@ public class DownloadsMenu extends BasicGameState {
rankedButton.draw(Color.magenta);
// dropdown menu
- serverMenu.render(container, g);
+ serverMenu.render(g);
// importing beatmaps
if (importThread != null) {
// darken the screen
g.setColor(Colors.BLACK_ALPHA);
- g.fillRect(0, 0, width, height);
+ g.fillRect(0, 0, displayContainer.width, displayContainer.height);
UI.drawLoadingProgress(g);
}
@@ -529,8 +524,10 @@ public class DownloadsMenu extends BasicGameState {
}
@Override
- public void update(GameContainer container, StateBasedGame game, int delta)
- throws SlickException {
+ public void preRenderUpdate() {
+ super.preRenderUpdate();
+
+ int delta = displayContainer.renderDelta;
UI.update(delta);
if (importThread == null)
MusicController.loopTrackIfEnded(false);
@@ -547,11 +544,12 @@ public class DownloadsMenu extends BasicGameState {
// focus new beatmap
// NOTE: This can't be called in another thread because it makes OpenGL calls.
- ((SongMenu) game.getState(Opsu.STATE_SONGMENU)).setFocus(importedNode, -1, true, true);
+ instanceContainer.provide(SongMenu.class).setFocus(importedNode, -1, true, true);
}
importThread = null;
}
- int mouseX = input.getMouseX(), mouseY = input.getMouseY();
+ int mouseX = displayContainer.mouseX;
+ int mouseY = displayContainer.mouseY;
UI.getBackButton().hoverUpdate(delta, mouseX, mouseY);
prevPage.hoverUpdate(delta, mouseX, mouseY);
nextPage.hoverUpdate(delta, mouseX, mouseY);
@@ -572,7 +570,6 @@ public class DownloadsMenu extends BasicGameState {
focusTimer += delta;
// search
- search.setFocus(true);
searchTimer += delta;
if (searchTimer >= SEARCH_DELAY && importThread == null) {
searchTimer = 0;
@@ -608,24 +605,25 @@ public class DownloadsMenu extends BasicGameState {
}
@Override
- public int getID() { return state; }
+ public boolean mousePressed(int button, int x, int y) {
+ if (super.mousePressed(button, x, y)) {
+ return true;
+ }
- @Override
- public void mousePressed(int button, int x, int y) {
- // check mouse button
- if (button == Input.MOUSE_MIDDLE_BUTTON)
- return;
+ if (button == Input.MOUSE_MIDDLE_BUTTON) {
+ return false;
+ }
// block input during beatmap importing
- if (importThread != null)
- return;
+ if (importThread != null) {
+ return true;
+ }
// back
if (UI.getBackButton().contains(x, y)) {
SoundController.playSound(SoundEffect.MENUBACK);
- ((MainMenu) game.getState(Opsu.STATE_MAINMENU)).reset();
- game.enterState(Opsu.STATE_MAINMENU, new EasedFadeOutTransition(), new FadeInTransition());
- return;
+ displayContainer.switchState(MainMenu.class);
+ return true;
}
// search results
@@ -694,11 +692,12 @@ public class DownloadsMenu extends BasicGameState {
}
}.start();
}
- return;
+ return true;
}
- if (isLoaded)
- return;
+ if (isLoaded) {
+ return true;
+ }
SoundController.playSound(SoundEffect.MENUCLICK);
if (index == focusResult) {
@@ -725,7 +724,7 @@ public class DownloadsMenu extends BasicGameState {
break;
}
}
- return;
+ return true;
}
// pages
@@ -741,7 +740,7 @@ public class DownloadsMenu extends BasicGameState {
searchQuery.interrupt();
resetSearchTimer();
}
- return;
+ return true;
}
if (pageResultTotal < totalResults && nextPage.contains(x, y)) {
if (lastQueryDir == Page.NEXT && searchQuery != null && !searchQuery.isComplete())
@@ -753,7 +752,7 @@ public class DownloadsMenu extends BasicGameState {
if (searchQuery != null)
searchQuery.interrupt();
resetSearchTimer();
- return;
+ return true;
}
}
}
@@ -763,7 +762,7 @@ public class DownloadsMenu extends BasicGameState {
if (clearButton.contains(x, y)) {
SoundController.playSound(SoundEffect.MENUCLICK);
DownloadList.get().clearInactiveDownloads();
- return;
+ return true;
}
if (importButton.contains(x, y)) {
SoundController.playSound(SoundEffect.MENUCLICK);
@@ -771,7 +770,7 @@ public class DownloadsMenu extends BasicGameState {
// import songs in new thread
importThread = new BeatmapImportThread();
importThread.start();
- return;
+ return true;
}
if (resetButton.contains(x, y)) {
SoundController.playSound(SoundEffect.MENUCLICK);
@@ -781,7 +780,7 @@ public class DownloadsMenu extends BasicGameState {
if (searchQuery != null)
searchQuery.interrupt();
resetSearchTimer();
- return;
+ return true;
}
if (rankedButton.contains(x, y)) {
SoundController.playSound(SoundEffect.MENUCLICK);
@@ -791,7 +790,7 @@ public class DownloadsMenu extends BasicGameState {
if (searchQuery != null)
searchQuery.interrupt();
resetSearchTimer();
- return;
+ return true;
}
// downloads
@@ -807,8 +806,9 @@ public class DownloadsMenu extends BasicGameState {
if (DownloadNode.downloadIconContains(x, y - offset, i)) {
SoundController.playSound(SoundEffect.MENUCLICK);
DownloadNode node = DownloadList.get().getNode(index);
- if (node == null)
- return;
+ if (node == null) {
+ return true;
+ }
Download dl = node.getDownload();
switch (dl.getStatus()) {
case CANCELLED:
@@ -822,62 +822,78 @@ public class DownloadsMenu extends BasicGameState {
dl.cancel();
break;
}
- return;
+ return true;
}
}
}
+ return false;
}
@Override
- public void mouseReleased(int button, int x, int y) {
- // check mouse button
- if (button == Input.MOUSE_MIDDLE_BUTTON)
- return;
+ public boolean mouseReleased(int button, int x, int y) {
+ if (super.mouseReleased(button, x, y)) {
+ return true;
+ }
+
+ if (button == Input.MOUSE_MIDDLE_BUTTON) {
+ return false;
+ }
startDownloadIndexPos.released();
startResultPos.released();
+ return true;
}
@Override
- public void mouseWheelMoved(int newValue) {
+ public boolean mouseWheelMoved(int newValue) {
// change volume
- if (input.isKeyDown(Input.KEY_LALT) || input.isKeyDown(Input.KEY_RALT)) {
+ if (displayContainer.input.isKeyDown(Input.KEY_LALT) || displayContainer.input.isKeyDown(Input.KEY_RALT)) {
UI.changeVolume((newValue < 0) ? -1 : 1);
- return;
+ return true;
}
// block input during beatmap importing
- if (importThread != null)
- return;
+ if (importThread != null) {
+ return true;
+ }
int shift = (newValue < 0) ? 1 : -1;
- int mouseX = input.getMouseX(), mouseY = input.getMouseY();
- scrollLists(mouseX, mouseY, shift);
+ scrollLists(displayContainer.mouseX, displayContainer.mouseY, shift);
+ return true;
}
@Override
- public void mouseDragged(int oldx, int oldy, int newx, int newy) {
+ public boolean mouseDragged(int oldx, int oldy, int newx, int newy) {
// block input during beatmap importing
- if (importThread != null)
- return;
-
- // check mouse button
- if (!input.isMouseButtonDown(Input.MOUSE_RIGHT_BUTTON) &&
- !input.isMouseButtonDown(Input.MOUSE_LEFT_BUTTON))
- return;
+ if (importThread != null) {
+ return true;
+ }
int diff = newy - oldy;
- if (diff == 0)
- return;
+ if (diff == 0) {
+ return false;
+ }
+
startDownloadIndexPos.dragged(-diff);
startResultPos.dragged(-diff);
+ return true;
}
@Override
- public void keyPressed(int key, char c) {
+ public boolean keyReleased(int key, char c) {
+ return super.keyReleased(key, c);
+ }
+
+ @Override
+ public boolean keyPressed(int key, char c) {
+ if (super.keyPressed(key, c)) {
+ return true;
+ }
+
// block input during beatmap importing
- if (importThread != null && !(key == Input.KEY_ESCAPE || key == Input.KEY_F12))
- return;
+ if (importThread != null && key != Input.KEY_ESCAPE) {
+ return true;
+ }
switch (key) {
case Input.KEY_ESCAPE:
@@ -892,16 +908,15 @@ public class DownloadsMenu extends BasicGameState {
} else {
// return to main menu
SoundController.playSound(SoundEffect.MENUBACK);
- ((MainMenu) game.getState(Opsu.STATE_MAINMENU)).reset();
- game.enterState(Opsu.STATE_MAINMENU, new EasedFadeOutTransition(), new FadeInTransition());
+ displayContainer.switchState(MainMenu.class);
}
- break;
+ return true;
case Input.KEY_ENTER:
if (!search.getText().isEmpty()) {
pageDir = Page.RESET;
resetSearchTimer();
}
- break;
+ return true;
case Input.KEY_F5:
SoundController.playSound(SoundEffect.MENUCLICK);
lastQuery = null;
@@ -909,29 +924,21 @@ public class DownloadsMenu extends BasicGameState {
if (searchQuery != null)
searchQuery.interrupt();
resetSearchTimer();
- break;
- case Input.KEY_F7:
- Options.setNextFPS(container);
- break;
- case Input.KEY_F10:
- Options.toggleMouseDisabled();
- break;
- case Input.KEY_F12:
- Utils.takeScreenShot();
- break;
- default:
- // wait for user to finish typing
- if (Character.isLetterOrDigit(c) || key == Input.KEY_BACK) {
- searchTimer = 0;
- pageDir = Page.RESET;
- }
- break;
+ return true;
}
+ // wait for user to finish typing
+ if (Character.isLetterOrDigit(c) || key == Input.KEY_BACK) {
+ search.keyPressed(key, c);
+ searchTimer = 0;
+ pageDir = Page.RESET;
+ }
+ return true;
}
@Override
- public void enter(GameContainer container, StateBasedGame game)
- throws SlickException {
+ public void enter() {
+ super.enter();
+
UI.enter();
prevPage.resetHover();
nextPage.resetHover();
@@ -939,7 +946,6 @@ public class DownloadsMenu extends BasicGameState {
importButton.resetHover();
resetButton.resetHover();
rankedButton.resetHover();
- serverMenu.activate();
serverMenu.reset();
focusResult = -1;
startResultPos.setPosition(0);
@@ -953,10 +959,10 @@ public class DownloadsMenu extends BasicGameState {
}
@Override
- public void leave(GameContainer container, StateBasedGame game)
- throws SlickException {
- search.setFocus(false);
- serverMenu.deactivate();
+ public void leave() {
+ super.leave();
+
+ focusComponent(search);
SoundController.stopTrack();
MusicController.resume();
}
diff --git a/src/itdelatrisu/opsu/states/Game.java b/src/itdelatrisu/opsu/states/Game.java
index 0c29abae..1cfc90c8 100644
--- a/src/itdelatrisu/opsu/states/Game.java
+++ b/src/itdelatrisu/opsu/states/Game.java
@@ -18,11 +18,9 @@
package itdelatrisu.opsu.states;
-import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.GameData;
import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.GameMod;
-import itdelatrisu.opsu.Opsu;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.ScoreData;
import itdelatrisu.opsu.Utils;
@@ -59,26 +57,31 @@ import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.Display;
import org.newdawn.slick.Animation;
import org.newdawn.slick.Color;
-import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
-import org.newdawn.slick.state.BasicGameState;
-import org.newdawn.slick.state.StateBasedGame;
-import org.newdawn.slick.state.transition.DelayedFadeOutTransition;
-import org.newdawn.slick.state.transition.EasedFadeOutTransition;
-import org.newdawn.slick.state.transition.EmptyTransition;
-import org.newdawn.slick.state.transition.FadeInTransition;
+import org.newdawn.slick.util.Log;
import yugecin.opsudance.*;
+import yugecin.opsudance.core.DisplayContainer;
+import yugecin.opsudance.core.inject.InstanceContainer;
+import yugecin.opsudance.core.state.ComplexOpsuState;
+import yugecin.opsudance.core.state.transitions.FadeInTransitionState;
+import yugecin.opsudance.core.state.transitions.FadeOutTransitionState;
+import yugecin.opsudance.events.BubbleNotificationEvent;
import yugecin.opsudance.objects.curves.FakeCombinedCurve;
import yugecin.opsudance.sbv2.MoveStoryboard;
-import yugecin.opsudance.ui.SBOverlay;
+import yugecin.opsudance.ui.OptionsOverlay;
+import yugecin.opsudance.ui.StoryboardOverlay;
+import yugecin.opsudance.utils.GLHelper;
/**
* "Game" state.
*/
-public class Game extends BasicGameState {
+public class Game extends ComplexOpsuState {
+
+ private final InstanceContainer instanceContainer;
+
public static boolean isInGame; // TODO delete this when #79 is fixed
/** Game restart states. */
public enum Restart {
@@ -307,101 +310,95 @@ public class Game extends BasicGameState {
MUSICBAR_HOVER = new Color(12, 9, 10, 0.35f),
MUSICBAR_FILL = new Color(255, 255, 255, 0.75f);
- // game-related variables
- private GameContainer container;
- private StateBasedGame game;
- private Input input;
- private final int state;
-
private final Cursor mirrorCursor;
- private MoveStoryboard msb;
- private SBOverlay sbOverlay;
+ private final MoveStoryboard moveStoryboardOverlay;
+ private final StoryboardOverlay storyboardOverlay;
+ private final OptionsOverlay optionsOverlay;
private FakeCombinedCurve knorkesliders;
private boolean skippedToCheckpoint;
- public Game(int state) {
- this.state = state;
+ public Game(DisplayContainer displayContainer, InstanceContainer instanceContainer) {
+ super(displayContainer);
+ this.instanceContainer = instanceContainer;
mirrorCursor = new Cursor(true);
- }
-
- public void loadCheckpoint(int checkpoint) {
- try {
- restart = Restart.MANUAL;
- checkpointLoaded = true;
- skippedToCheckpoint = true;
- enter(container, game);
- if (isLeadIn()) {
- leadInTime = 0;
- epiImgTime = 0;
- MusicController.resume();
- }
- // skip to checkpoint
- MusicController.setPosition(checkpoint);
- while (objectIndex < gameObjects.length && beatmap.objects[objectIndex].getTime() <= checkpoint) {
- objectIndex++;
- }
- if (objectIndex > 0) {
- objectIndex--;
- }
- if (Options.isMergingSliders()) {
- int obj = objectIndex;
- while (obj < gameObjects.length) {
- if (gameObjects[obj] instanceof Slider) {
- slidercurveFrom = slidercurveTo = ((Slider) gameObjects[obj]).baseSliderFrom;
- break;
- }
- obj++;
- }
- spliceSliderCurve(-1, -1);
- }
- Dancer.instance.setObjectIndex(objectIndex);
- sbOverlay.updateIndex(objectIndex);
- lastReplayTime = beatmap.objects[objectIndex].getTime();
- } catch (SlickException e) {
- e.printStackTrace();
- }
+ this.moveStoryboardOverlay = new MoveStoryboard(displayContainer);
+ this.optionsOverlay = new OptionsOverlay(displayContainer, OptionsMenu.storyboardOptions, 0);
+ this.storyboardOverlay = new StoryboardOverlay(displayContainer, moveStoryboardOverlay, optionsOverlay, this);
+ storyboardOverlay.show();
+ moveStoryboardOverlay.show();
+ optionsOverlay.setListener(storyboardOverlay);
}
@Override
- public void init(GameContainer container, StateBasedGame game)
- throws SlickException {
- this.msb = new MoveStoryboard(container);
- this.sbOverlay = new SBOverlay(this, msb, container);
- this.container = container;
- this.game = game;
- input = container.getInput();
-
- int width = container.getWidth();
- int height = container.getHeight();
-
+ public void revalidate() {
// create offscreen graphics
- offscreen = new Image(width, height);
- gOffscreen = offscreen.getGraphics();
- gOffscreen.setBackground(Color.black);
+ try {
+ offscreen = new Image(displayContainer.width, displayContainer.height);
+ gOffscreen = offscreen.getGraphics();
+ gOffscreen.setBackground(Color.black);
+ } catch (SlickException e) {
+ Log.error("could not create offscreen graphics", e);
+ displayContainer.eventBus.post(new BubbleNotificationEvent("Exception while creating offscreen graphics. See logfile for details.", BubbleNotificationEvent.COMMONCOLOR_RED));
+ }
// initialize music position bar location
- musicBarX = width * 0.01f;
- musicBarY = height * 0.05f;
- musicBarWidth = Math.max(width * 0.005f, 7);
- musicBarHeight = height * 0.9f;
+ musicBarX = displayContainer.width * 0.01f;
+ musicBarY = displayContainer.height * 0.05f;
+ musicBarWidth = Math.max(displayContainer.width * 0.005f, 7);
+ musicBarHeight = displayContainer.height * 0.9f;
// initialize scoreboard star stream
- scoreboardStarStream = new StarStream(0, height * 2f / 3f, width / 4, 0, 0);
- scoreboardStarStream.setPositionSpread(height / 20f);
+ scoreboardStarStream = new StarStream(0, displayContainer.height * 2f / 3f, displayContainer.width / 4, 0, 0);
+ scoreboardStarStream.setPositionSpread(displayContainer.height / 20f);
scoreboardStarStream.setDirectionSpread(10f);
scoreboardStarStream.setDurationSpread(700, 100);
// create the associated GameData object
- data = new GameData(width, height);
+ data = new GameData(displayContainer.width, displayContainer.height);
+ }
+
+
+ public void loadCheckpoint(int checkpoint) {
+ restart = Restart.MANUAL;
+ checkpointLoaded = true;
+ skippedToCheckpoint = true;
+ enter();
+ if (isLeadIn()) {
+ leadInTime = 0;
+ epiImgTime = 0;
+ MusicController.resume();
+ }
+ // skip to checkpoint
+ MusicController.setPosition(checkpoint);
+ while (objectIndex < gameObjects.length && beatmap.objects[objectIndex].getTime() <= checkpoint) {
+ objectIndex++;
+ }
+ if (objectIndex > 0) {
+ objectIndex--;
+ }
+ if (Options.isMergingSliders()) {
+ int obj = objectIndex;
+ while (obj < gameObjects.length) {
+ if (gameObjects[obj] instanceof Slider) {
+ slidercurveFrom = slidercurveTo = ((Slider) gameObjects[obj]).baseSliderFrom;
+ break;
+ }
+ obj++;
+ }
+ spliceSliderCurve(-1, -1);
+ }
+ Dancer.instance.setObjectIndex(objectIndex);
+ storyboardOverlay.updateIndex(objectIndex);
+ lastReplayTime = beatmap.objects[objectIndex].getTime();
}
@Override
- public void render(GameContainer container, StateBasedGame game, Graphics g)
- throws SlickException {
- int width = container.getWidth();
- int height = container.getHeight();
+ public void render(Graphics g) {
+ int width = displayContainer.width;
+ int height = displayContainer.height;
+
int trackPosition = MusicController.getPosition();
if (isLeadIn()) {
trackPosition -= leadInTime - currentMapMusicOffset - Options.getMusicOffset();
@@ -453,38 +450,6 @@ public class Game extends BasicGameState {
if (GameMod.FLASHLIGHT.isActive())
Graphics.setCurrent(g);
- // "auto" and "autopilot" mods: move cursor automatically
- // TODO: this should really be in update(), not render()
- autoMousePosition.set(width / 2, height / 2);
- autoMousePressed = false;
- if (GameMod.AUTO.isActive() || GameMod.AUTOPILOT.isActive()) {
- Vec2f autoPoint;
- if (objectIndex < beatmap.objects.length - Dancer.instance.getPolyMoverFactoryMinBufferSize()) {
- Dancer d = Dancer.instance;
- d.update(trackPosition, objectIndex);
- autoPoint = new Vec2f(d.x, d.y);
- if (trackPosition < gameObjects[objectIndex].getTime()) {
- autoMousePressed = true;
- }
- } else {
- if (objectIndex < beatmap.objects.length) {
- autoPoint = gameObjects[objectIndex].getPointAt(trackPosition);
- } else {
- // last object
- autoPoint = gameObjects[objectIndex - 1].getPointAt(trackPosition);
- }
- }
-
- float[] sbPosition = sbOverlay.getPoint(trackPosition);
- if (sbPosition != null) {
- autoPoint.x = sbPosition[0];
- autoPoint.y = sbPosition[1];
- }
-
- // set mouse coordinates
- autoMousePosition.set(autoPoint.x, autoPoint.y);
- }
-
// "flashlight" mod: restricted view of hit objects around cursor
if (GameMod.FLASHLIGHT.isActive()) {
// render hit objects offscreen
@@ -510,8 +475,8 @@ public class Game extends BasicGameState {
mouseX = replayX;
mouseY = replayY;
} else {
- mouseX = input.getMouseX();
- mouseY = input.getMouseY();
+ mouseX = displayContainer.mouseX;
+ mouseY = displayContainer.mouseY;
}
int alphaRadius = flashlightRadius * 256 / 215;
int alphaX = mouseX - alphaRadius / 2;
@@ -686,7 +651,7 @@ public class Game extends BasicGameState {
float animation = AnimationEquation.IN_OUT_QUAD.calc(
Utils.clamp((trackPosition - lastRankUpdateTime) / SCOREBOARD_ANIMATION_TIME, 0f, 1f)
);
- int scoreboardPosition = 2 * container.getHeight() / 3;
+ int scoreboardPosition = 2 * displayContainer.height / 3;
// draw star stream behind the scores
scoreboardStarStream.draw();
@@ -727,8 +692,7 @@ public class Game extends BasicGameState {
// draw music position bar (for replay seeking)
if (isReplay && Options.isReplaySeekingEnabled()) {
- int mouseX = input.getMouseX(), mouseY = input.getMouseY();
- g.setColor((musicPositionBarContains(mouseX, mouseY)) ? MUSICBAR_HOVER : MUSICBAR_NORMAL);
+ g.setColor((musicPositionBarContains(displayContainer.mouseX, displayContainer.mouseY)) ? MUSICBAR_HOVER : MUSICBAR_NORMAL);
g.fillRoundRect(musicBarX, musicBarY, musicBarWidth, musicBarHeight, 4);
if (!isLeadIn()) {
g.setColor(MUSICBAR_FILL);
@@ -753,41 +717,40 @@ public class Game extends BasicGameState {
cursorCirclePulse.drawCentered(pausedMousePosition.x, pausedMousePosition.y);
}
- if (isReplay)
- UI.draw(g, replayX, replayY, replayKeyPressed);
- else if (GameMod.AUTO.isActive()) {
- UI.draw(g, (int) autoMousePosition.x, (int) autoMousePosition.y, autoMousePressed);
+ if (isReplay) {
+ displayContainer.cursor.draw(replayKeyPressed);
+ } else if (GameMod.AUTO.isActive()) {
+ displayContainer.cursor.draw(autoMousePressed);
if (Options.isMirror() && GameMod.AUTO.isActive()) {
- double dx = autoMousePosition.x - Options.width / 2d;
- double dy = autoMousePosition.y - Options.height / 2d;
- double d = Math.sqrt(dx * dx + dy * dy);
- double a = Math.atan2(dy, dx) + Math.PI;
- mirrorCursor.draw((int) (Math.cos(a) * d + Options.width / 2), (int) (Math.sin(a) * d + Options.height / 2), autoMousePressed);
+ mirrorCursor.draw(autoMousePressed);
}
+ } else if (GameMod.AUTOPILOT.isActive()) {
+ displayContainer.cursor.draw(Utils.isGameKeyPressed());
}
- else if (GameMod.AUTOPILOT.isActive())
- UI.draw(g, (int) autoMousePosition.x, (int) autoMousePosition.y, Utils.isGameKeyPressed());
- else
- UI.draw(g);
- sbOverlay.render(container, g);
+ UI.draw(g);
if (!Options.isHideWM()) {
Fonts.SMALL.drawString(0.3f, 0.3f, "opsu!dance " + Updater.get().getCurrentVersion() + " by robin_be | https://github.com/yugecin/opsu-dance");
}
+
+ super.render(g);
}
@Override
- public void update(GameContainer container, StateBasedGame game, int delta)
- throws SlickException {
+ public void preRenderUpdate() {
+ super.preRenderUpdate();
+
+ int delta = displayContainer.renderDelta;
+
UI.update(delta);
Pippi.update(delta);
if (epiImgTime > 0) {
epiImgTime -= delta;
}
yugecin.opsudance.spinners.Spinner.update(delta);
- int mouseX = input.getMouseX(), mouseY = input.getMouseY();
- sbOverlay.update(delta, mouseX, mouseY);
+ int mouseX = displayContainer.mouseX;
+ int mouseY = displayContainer.mouseY;
skipButton.hoverUpdate(delta, mouseX, mouseY);
if (isReplay || GameMod.AUTO.isActive())
playbackSpeed.getButton().hoverUpdate(delta, mouseX, mouseY);
@@ -805,8 +768,8 @@ public class Game extends BasicGameState {
}
// focus lost: go back to pause screen
- else if (!container.hasFocus()) {
- game.enterState(Opsu.STATE_GAMEPAUSEMENU);
+ else if (!Display.isActive()) {
+ displayContainer.switchStateNow(GamePauseMenu.class);
pausePulse = 0f;
}
@@ -918,10 +881,65 @@ public class Game extends BasicGameState {
// game finished: change state after timer expires
if (gameFinished && !gameFinishedTimer.update(delta)) {
- if (checkpointLoaded) // if checkpoint used, skip ranking screen
- game.closeRequested();
- else // go to ranking screen
- game.enterState(Opsu.STATE_GAMERANKING, new EasedFadeOutTransition(), new FadeInTransition());
+ if (checkpointLoaded) {
+ // if checkpoint used, skip ranking screen
+ onCloseRequest();
+ } else {
+ // go to ranking screen
+ displayContainer.switchState(GameRanking.class);
+ }
+ }
+ }
+
+ @Override
+ public void update() {
+ super.update();
+
+ int trackPosition = MusicController.getPosition();
+
+ // "auto" and "autopilot" mods: move cursor automatically
+ autoMousePressed = false;
+ if (GameMod.AUTO.isActive() || GameMod.AUTOPILOT.isActive()) {
+ Vec2f autoPoint;
+ if (objectIndex < beatmap.objects.length - Dancer.instance.getPolyMoverFactoryMinBufferSize()) {
+ Dancer d = Dancer.instance;
+ d.update(trackPosition, objectIndex);
+ autoPoint = new Vec2f(d.x, d.y);
+ if (trackPosition < gameObjects[objectIndex].getTime()) {
+ autoMousePressed = true;
+ }
+ } else {
+ if (objectIndex < beatmap.objects.length) {
+ autoPoint = gameObjects[objectIndex].getPointAt(trackPosition);
+ } else {
+ // last object
+ autoPoint = gameObjects[objectIndex - 1].getPointAt(trackPosition);
+ }
+ }
+
+ float[] sbPosition = moveStoryboardOverlay.getPoint(trackPosition);
+ if (sbPosition != null) {
+ autoPoint.x = sbPosition[0];
+ autoPoint.y = sbPosition[1];
+ }
+
+ // set mouse coordinates
+ autoMousePosition.set(autoPoint.x, autoPoint.y);
+ }
+
+ if (isReplay) {
+ displayContainer.cursor.setCursorPosition(displayContainer.delta, replayX, replayY);
+ } else if (GameMod.AUTO.isActive()) {
+ displayContainer.cursor.setCursorPosition(displayContainer.delta, (int) autoMousePosition.x, (int) autoMousePosition.y);
+ if (Options.isMirror() && GameMod.AUTO.isActive()) {
+ double dx = autoMousePosition.x - Options.width / 2d;
+ double dy = autoMousePosition.y - Options.height / 2d;
+ double d = Math.sqrt(dx * dx + dy * dy);
+ double a = Math.atan2(dy, dx) + Math.PI;
+ mirrorCursor.setCursorPosition(displayContainer.delta, (int) (Math.cos(a) * d + Options.width / 2), (int) (Math.sin(a) * d + Options.height / 2));
+ }
+ } else if (GameMod.AUTOPILOT.isActive()) {
+ displayContainer.cursor.setCursorPosition(displayContainer.delta, (int) autoMousePosition.x, (int) autoMousePosition.y);
}
}
@@ -949,7 +967,7 @@ public class Game extends BasicGameState {
// save score and replay
if (!checkpointLoaded) {
boolean unranked = (GameMod.AUTO.isActive() || GameMod.RELAX.isActive() || GameMod.AUTOPILOT.isActive());
- ((GameRanking) game.getState(Opsu.STATE_GAMERANKING)).setGameData(data);
+ instanceContainer.provide(GameRanking.class).setGameData(data);
if (isReplay)
data.setReplay(replay);
else if (replayFrames != null) {
@@ -1027,14 +1045,15 @@ public class Game extends BasicGameState {
}
// pause game if focus lost
- if (!container.hasFocus() && !GameMod.AUTO.isActive() && !isReplay) {
+ if (!Display.isActive() && !GameMod.AUTO.isActive() && !isReplay) {
if (pauseTime < 0) {
pausedMousePosition = new Vec2f(mouseX, mouseY);
pausePulse = 0f;
}
- if (MusicController.isPlaying() || isLeadIn())
+ if (MusicController.isPlaying() || isLeadIn()) {
pauseTime = trackPosition;
- game.enterState(Opsu.STATE_GAMEPAUSEMENU, new EmptyTransition(), new FadeInTransition());
+ }
+ displayContainer.switchStateNow(GamePauseMenu.class);
}
// drain health
@@ -1058,13 +1077,10 @@ public class Game extends BasicGameState {
failTrackTime = MusicController.getPosition();
MusicController.fadeOut(MUSIC_FADEOUT_TIME);
MusicController.pitchFadeOut(MUSIC_FADEOUT_TIME);
- rotations = new IdentityHashMap();
+ rotations = new IdentityHashMap<>();
SoundController.playSound(SoundEffect.FAIL);
- // fade to pause menu
- game.enterState(Opsu.STATE_GAMEPAUSEMENU,
- new DelayedFadeOutTransition(Color.black, MUSIC_FADEOUT_TIME, MUSIC_FADEOUT_TIME - LOSE_FADEOUT_TIME),
- new FadeInTransition());
+ displayContainer.switchState(GamePauseMenu.class, FadeOutTransitionState.class, MUSIC_FADEOUT_TIME - LOSE_FADEOUT_TIME, FadeInTransitionState.class, 300);
}
}
}
@@ -1079,16 +1095,11 @@ public class Game extends BasicGameState {
boolean overlap = (objectIndex + 1 < gameObjects.length &&
trackPosition > beatmap.objects[objectIndex + 1].getTime() - hitResultOffset[GameData.HIT_50]);
- if (skippedObject && (GameMod.AUTO.isActive() || GameMod.AUTOPILOT.isActive())) {
- Vec2f start = gameObjects[objectIndex - 1].start;
- UI.getCursor().setCursorPosition((int) start.x, (int) start.y);
- }
-
// update hit object and check completion status
if (gameObjects[objectIndex].update(overlap, delta, mouseX, mouseY, keyPressed, trackPosition)) {
skippedObject = true;
objectIndex++; // done, so increment object index
- sbOverlay.updateIndex(objectIndex);
+ storyboardOverlay.updateIndex(objectIndex);
if (objectIndex >= mirrorTo) {
Options.setMirror(false);
}
@@ -1099,20 +1110,25 @@ public class Game extends BasicGameState {
}
@Override
- public int getID() { return state; }
+ public boolean onCloseRequest() {
+ instanceContainer.provide(SongMenu.class).resetGameDataOnLoad();
+ displayContainer.switchState(SongMenu.class);
+ return false;
+ }
@Override
- public void keyPressed(int key, char c) {
- if (gameFinished)
- return;
+ public boolean keyPressed(int key, char c) {
+ if (super.keyPressed(key, c)) {
+ return true;
+ }
- if (sbOverlay.keyPressed(key, c)) {
- return;
+ if (gameFinished) {
+ return true;
}
int trackPosition = MusicController.getPosition();
- int mouseX = input.getMouseX();
- int mouseY = input.getMouseY();
+ int mouseX = displayContainer.mouseX;
+ int mouseY = displayContainer.mouseY;
// game keys
if (!Keyboard.isRepeatEvent()) {
@@ -1129,7 +1145,7 @@ public class Game extends BasicGameState {
case Input.KEY_ESCAPE:
// "auto" mod or watching replay: go back to song menu
if (GameMod.AUTO.isActive() || isReplay) {
- game.closeRequested();
+ onCloseRequest();
break;
}
@@ -1138,9 +1154,10 @@ public class Game extends BasicGameState {
pausedMousePosition = new Vec2f(mouseX, mouseY);
pausePulse = 0f;
}
- if (MusicController.isPlaying() || isLeadIn())
+ if (MusicController.isPlaying() || isLeadIn()) {
pauseTime = trackPosition;
- game.enterState(Opsu.STATE_GAMEPAUSEMENU, new EmptyTransition(), new FadeInTransition());
+ }
+ displayContainer.switchStateNow(GamePauseMenu.class);
break;
case Input.KEY_SPACE:
// skip intro
@@ -1148,23 +1165,21 @@ public class Game extends BasicGameState {
break;
case Input.KEY_R:
// restart
- if (input.isKeyDown(Input.KEY_RCONTROL) || input.isKeyDown(Input.KEY_LCONTROL)) {
- try {
- if (trackPosition < beatmap.objects[0].getTime())
- retries--; // don't count this retry (cancel out later increment)
- restart = Restart.MANUAL;
- enter(container, game);
- skipIntro();
- } catch (SlickException e) {
- ErrorHandler.error("Failed to restart game.", e, false);
+ if (displayContainer.input.isKeyDown(Input.KEY_RCONTROL) || displayContainer.input.isKeyDown(Input.KEY_LCONTROL)) {
+ if (trackPosition < beatmap.objects[0].getTime()) {
+ retries--; // don't count this retry (cancel out later increment)
}
+ restart = Restart.MANUAL;
+ enter();
+ skipIntro();
}
break;
case Input.KEY_S:
// save checkpoint
- if (input.isKeyDown(Input.KEY_RCONTROL) || input.isKeyDown(Input.KEY_LCONTROL)) {
- if (isLeadIn())
+ if (displayContainer.input.isKeyDown(Input.KEY_RCONTROL) || displayContainer.input.isKeyDown(Input.KEY_LCONTROL)) {
+ if (isLeadIn()) {
break;
+ }
int position = (pauseTime > -1) ? pauseTime : trackPosition;
if (Options.setCheckpoint(position / 1000)) {
@@ -1175,7 +1190,7 @@ public class Game extends BasicGameState {
break;
case Input.KEY_L:
// load checkpoint
- if (input.isKeyDown(Input.KEY_RCONTROL) || input.isKeyDown(Input.KEY_LCONTROL)) {
+ if (displayContainer.input.isKeyDown(Input.KEY_RCONTROL) || displayContainer.input.isKeyDown(Input.KEY_LCONTROL)) {
int checkpoint = Options.getCheckpoint();
if (checkpoint == 0 || checkpoint > beatmap.endTime)
break; // invalid checkpoint
@@ -1197,15 +1212,6 @@ public class Game extends BasicGameState {
case Input.KEY_DOWN:
UI.changeVolume(-1);
break;
- case Input.KEY_F7:
- Options.setNextFPS(container);
- break;
- case Input.KEY_F10:
- Options.toggleMouseDisabled();
- break;
- case Input.KEY_F12:
- Utils.takeScreenShot();
- break;
case Input.KEY_TAB:
if (!Options.isHideUI()) {
scoreboardVisible = !scoreboardVisible;
@@ -1216,7 +1222,7 @@ public class Game extends BasicGameState {
mirrorTo = objectIndex;
Options.setMirror(false);
} else {
- mirrorCursor.resetLocations();
+ mirrorCursor.resetLocations((int) autoMousePosition.x, (int) autoMousePosition.y);
mirrorFrom = objectIndex;
mirrorTo = gameObjects.length;
Options.setMirror(true);
@@ -1227,7 +1233,7 @@ public class Game extends BasicGameState {
mirrorTo = objectIndex;
Options.setMirror(false);
} else {
- mirrorCursor.resetLocations();
+ mirrorCursor.resetLocations((int) autoMousePosition.x, (int) autoMousePosition.y);
mirrorFrom = objectIndex;
mirrorTo = mirrorFrom + 1;
Options.setMirror(true);
@@ -1242,29 +1248,33 @@ public class Game extends BasicGameState {
currentMapMusicOffset -= 5;
UI.sendBarNotification("Current map offset: " + currentMapMusicOffset);
}
+
+ return true;
}
@Override
- public void mouseDragged(int oldx, int oldy, int newx, int newy) {
- if (sbOverlay.mouseDragged(oldx, oldy, newx, newy)) {
- //noinspection UnnecessaryReturnStatement
- return;
+ public boolean mouseDragged(int oldx, int oldy, int newx, int newy) {
+ if (super.mouseDragged(oldx, oldy, newx, newy)) {
+ return true;
}
+ return true;
}
@Override
- public void mousePressed(int button, int x, int y) {
- if (gameFinished)
- return;
+ public boolean mousePressed(int button, int x, int y) {
+ if (super.mousePressed(button, x, y)) {
+ return true;
+ }
- if (sbOverlay.mousePressed(button, x, y)) {
- return;
+ if (gameFinished) {
+ return true;
}
// watching replay
if (isReplay || GameMod.AUTO.isActive()) {
- if (button == Input.MOUSE_MIDDLE_BUTTON)
- return;
+ if (button == Input.MOUSE_MIDDLE_BUTTON) {
+ return true;
+ }
// skip button
if (skipButton.contains(x, y))
@@ -1283,11 +1293,12 @@ public class Game extends BasicGameState {
MusicController.setPosition((int) pos);
isSeeking = true;
}
- return;
+ return true;
}
- if (Options.isMouseDisabled())
- return;
+ if (Options.isMouseDisabled()) {
+ return true;
+ }
// mouse wheel: pause the game
if (button == Input.MOUSE_MIDDLE_BUTTON && !Options.isMouseWheelDisabled()) {
@@ -1296,10 +1307,11 @@ public class Game extends BasicGameState {
pausedMousePosition = new Vec2f(x, y);
pausePulse = 0f;
}
- if (MusicController.isPlaying() || isLeadIn())
+ if (MusicController.isPlaying() || isLeadIn()) {
pauseTime = trackPosition;
- game.enterState(Opsu.STATE_GAMEPAUSEMENU, new EmptyTransition(), new FadeInTransition());
- return;
+ }
+ displayContainer.switchStateNow(GamePauseMenu.class);
+ return true;
}
// game keys
@@ -1310,6 +1322,8 @@ public class Game extends BasicGameState {
keys = ReplayFrame.KEY_M2;
if (keys != ReplayFrame.KEY_NONE)
gameKeyPressed(keys, x, y, MusicController.getPosition());
+
+ return true;
}
/**
@@ -1352,19 +1366,22 @@ public class Game extends BasicGameState {
}
@Override
- public void mouseReleased(int button, int x, int y) {
- if (gameFinished)
- return;
-
- if (sbOverlay.mouseReleased(button, x, y)) {
- return;
+ public boolean mouseReleased(int button, int x, int y) {
+ if (super.mouseReleased(button, x, y)) {
+ return true;
}
- if (Options.isMouseDisabled())
- return;
+ if (gameFinished) {
+ return true;
+ }
- if (button == Input.MOUSE_MIDDLE_BUTTON)
- return;
+ if (Options.isMouseDisabled()) {
+ return true;
+ }
+
+ if (button == Input.MOUSE_MIDDLE_BUTTON) {
+ return true;
+ }
int keys = ReplayFrame.KEY_NONE;
if (button == Input.MOUSE_LEFT_BUTTON)
@@ -1373,12 +1390,19 @@ public class Game extends BasicGameState {
keys = ReplayFrame.KEY_M2;
if (keys != ReplayFrame.KEY_NONE)
gameKeyReleased(keys, x, y, MusicController.getPosition());
+
+ return true;
}
@Override
- public void keyReleased(int key, char c) {
- if (gameFinished)
- return;
+ public boolean keyReleased(int key, char c) {
+ if (super.keyReleased(key, c)) {
+ return true;
+ }
+
+ if (gameFinished) {
+ return true;
+ }
int keys = ReplayFrame.KEY_NONE;
if (key == Options.getGameKeyLeft())
@@ -1386,7 +1410,9 @@ public class Game extends BasicGameState {
else if (key == Options.getGameKeyRight())
keys = ReplayFrame.KEY_K2;
if (keys != ReplayFrame.KEY_NONE)
- gameKeyReleased(keys, input.getMouseX(), input.getMouseY(), MusicController.getPosition());
+ gameKeyReleased(keys, displayContainer.input.getMouseX(), displayContainer.input.getMouseY(), MusicController.getPosition());
+
+ return true;
}
/**
@@ -1404,26 +1430,43 @@ public class Game extends BasicGameState {
}
@Override
- public void mouseWheelMoved(int newValue) {
- if (sbOverlay.mouseWheelMoved(newValue)) {
- return;
+ public boolean mouseWheelMoved(int newValue) {
+ if (super.mouseWheelMoved(newValue)) {
+ return true;
+ }
+
+ if (Options.isMouseWheelDisabled()) {
+ return true;
}
- if (Options.isMouseWheelDisabled())
- return;
UI.changeVolume((newValue < 0) ? -1 : 1);
+ return true;
}
@Override
- public void enter(GameContainer container, StateBasedGame game)
- throws SlickException {
+ public void enter() {
+ super.enter();
+
+ displayContainer.drawCursor = false;
+
+ overlays.clear();
+ if (Options.isEnableSB()) {
+ overlays.add(optionsOverlay);
+ overlays.add(moveStoryboardOverlay);
+ overlays.add(storyboardOverlay);
+ storyboardOverlay.onEnter();
+ optionsOverlay.revalidate();
+ }
+
isInGame = true;
if (!skippedToCheckpoint) {
UI.enter();
}
- if (beatmap == null || beatmap.objects == null)
- throw new RuntimeException("Running game with no beatmap loaded.");
+ if (beatmap == null || beatmap.objects == null) {
+ displayContainer.eventBus.post(new BubbleNotificationEvent("Game was running without a beatmap", BubbleNotificationEvent.COMMONCOLOR_RED));
+ displayContainer.switchStateInstantly(SongMenu.class);
+ }
Dancer.instance.reset();
MoverDirection.reset(beatmap.beatmapID);
@@ -1450,10 +1493,10 @@ public class Game extends BasicGameState {
epiImgTime = Options.getEpilepsyWarningLength();
if (epiImgTime > 0) {
epiImg = GameImage.EPILEPSY_WARNING.getImage();
- float desWidth = container.getWidth() / 2;
+ float desWidth = displayContainer.width / 2;
epiImg = epiImg.getScaledCopy(desWidth / epiImg.getWidth());
- epiImgX = (container.getWidth() - epiImg.getWidth()) / 2;
- epiImgY = (container.getHeight() - epiImg.getHeight()) / 2;
+ epiImgX = (displayContainer.width - epiImg.getWidth()) / 2;
+ epiImgY = (displayContainer.height - epiImg.getHeight()) / 2;
}
// load mods
@@ -1521,9 +1564,9 @@ public class Game extends BasicGameState {
else if (hitObject.isSpinner())
gameObjects[i] = new Spinner(hitObject, this, data);
} catch (Exception e) {
- // try to handle the error gracefully: substitute in a dummy GameObject
- ErrorHandler.error(String.format("Failed to create %s at index %d:\n%s",
- hitObject.getTypeName(), i, hitObject.toString()), e, true);
+ String message = String.format("Failed to create %s at index %d:\n%s", hitObject.getTypeName(), i, hitObject.toString());
+ Log.error(message, e);
+ displayContainer.eventBus.post(new BubbleNotificationEvent(message, BubbleNotificationEvent.COMMONCOLOR_RED));
gameObjects[i] = new DummyObject(hitObject);
}
}
@@ -1543,14 +1586,15 @@ public class Game extends BasicGameState {
}
// unhide cursor for "auto" mod and replays
- if (GameMod.AUTO.isActive() || isReplay)
- UI.getCursor().show();
+ if (GameMod.AUTO.isActive() || isReplay) {
+ GLHelper.showNativeCursor();
+ }
// load replay frames
if (isReplay) {
// load initial data
- replayX = container.getWidth() / 2;
- replayY = container.getHeight() / 2;
+ replayX = displayContainer.width / 2;
+ replayY = displayContainer.height / 2;
replayKeyPressed = false;
replaySkipTime = -1;
for (replayIndex = 0; replayIndex < replay.frames.length; replayIndex++) {
@@ -1571,8 +1615,8 @@ public class Game extends BasicGameState {
else {
lastKeysPressed = ReplayFrame.KEY_NONE;
replaySkipTime = -1;
- replayFrames = new LinkedList();
- replayFrames.add(new ReplayFrame(0, 0, input.getMouseX(), input.getMouseY(), 0));
+ replayFrames = new LinkedList<>();
+ replayFrames.add(new ReplayFrame(0, 0, displayContainer.mouseX, displayContainer.mouseY, 0));
}
for (int i = 0; i < gameObjects.length; i++) {
@@ -1634,10 +1678,10 @@ public class Game extends BasicGameState {
slidercurveTo = 0;
Dancer.instance.setGameObjects(gameObjects);
- sbOverlay.setGameObjects(gameObjects);
+ storyboardOverlay.setGameObjects(gameObjects);
if (!skippedToCheckpoint) {
- sbOverlay.enter();
- sbOverlay.updateIndex(0);
+ storyboardOverlay.onEnter();
+ storyboardOverlay.updateIndex(0);
}
Pippi.reset();
@@ -1651,15 +1695,25 @@ public class Game extends BasicGameState {
}
@Override
- public void leave(GameContainer container, StateBasedGame game)
- throws SlickException {
+ public void leave() {
+ super.leave();
+
+ displayContainer.drawCursor = true;
+
+ MusicController.pause();
+ MusicController.setPitch(1f);
+ MusicController.resume();
+
+ if (Options.isEnableSB()) {
+ storyboardOverlay.onLeave();
+ }
+
isInGame = false;
// container.setMouseGrabbed(false);
skippedToCheckpoint = false;
knorkesliders = null;
- sbOverlay.leave();
Dancer.instance.setGameObjects(null);
Cursor.lastObjColor = Color.white;
@@ -1668,8 +1722,9 @@ public class Game extends BasicGameState {
Cursor.nextMirroredObjColor = Color.white;
// re-hide cursor
- if (GameMod.AUTO.isActive() || isReplay)
- UI.getCursor().hide();
+ if (GameMod.AUTO.isActive() || isReplay) {
+ GLHelper.hideNativeCursor();
+ }
// replays
if (isReplay)
@@ -1725,7 +1780,7 @@ public class Game extends BasicGameState {
trackPosition = failTrackTime + (int) (System.currentTimeMillis() - failTime);
// get hit objects in reverse order, or else overlapping objects are unreadable
- Stack stack = new Stack();
+ Stack stack = new Stack<>();
for (int index = objectIndex; index < gameObjects.length && beatmap.objects[index].getTime() < trackPosition + approachTime; index++) {
stack.add(index);
@@ -1738,7 +1793,7 @@ public class Game extends BasicGameState {
}
if (lastObjectIndex != -1 && !beatmap.objects[index].isNewCombo()) {
// calculate points
- final int followPointInterval = container.getHeight() / 14;
+ final int followPointInterval = displayContainer.height / 14;
int lastObjectEndTime = gameObjects[lastObjectIndex].getEndTime() + 1;
int objectStartTime = beatmap.objects[index].getTime();
Vec2f startPoint = gameObjects[lastObjectIndex].getPointAt(lastObjectEndTime);
@@ -1827,7 +1882,7 @@ public class Game extends BasicGameState {
g.pushTransform();
// translate and rotate the object
- g.translate(0, dt * dt * container.getHeight());
+ g.translate(0, dt * dt * displayContainer.height);
Vec2f rotationCenter = gameObj.getPointAt((beatmap.objects[idx].getTime() + beatmap.objects[idx].getEndTime()) / 2);
g.rotate(rotationCenter.x, rotationCenter.y, rotSpeed * dt);
gameObj.draw(g, trackPosition, false);
@@ -1846,7 +1901,7 @@ public class Game extends BasicGameState {
currentMapMusicOffset = 0;
}
this.beatmap = beatmap;
- Display.setTitle(String.format("%s - %s", game.getTitle(), beatmap.toString()));
+ Display.setTitle(String.format("opsu!dance - %s", beatmap.toString()));
if (beatmap.breaks == null)
BeatmapDB.load(beatmap, BeatmapDB.LOAD_ARRAY);
BeatmapParser.parseHitObjects(beatmap);
@@ -1857,7 +1912,9 @@ public class Game extends BasicGameState {
* Resets all game data and structures.
*/
public void resetGameData() {
- data.clear();
+ if (data != null) {
+ data.clear();
+ }
objectIndex = 0;
breakIndex = 0;
breakTime = 0;
@@ -1878,8 +1935,10 @@ public class Game extends BasicGameState {
lastReplayTime = 0;
autoMousePosition = new Vec2f();
autoMousePressed = false;
- flashlightRadius = container.getHeight() * 2 / 3;
- scoreboardStarStream.clear();
+ flashlightRadius = displayContainer.height * 2 / 3;
+ if (scoreboardStarStream != null) {
+ scoreboardStarStream.clear();
+ }
gameFinished = false;
gameFinishedTimer.setTime(0);
@@ -1916,9 +1975,6 @@ public class Game extends BasicGameState {
* Loads all game images.
*/
private void loadImages() {
- int width = container.getWidth();
- int height = container.getHeight();
-
// set images
File parent = beatmap.getFile().getParentFile();
for (GameImage img : GameImage.values()) {
@@ -1931,17 +1987,17 @@ public class Game extends BasicGameState {
// skip button
if (GameImage.SKIP.getImages() != null) {
Animation skip = GameImage.SKIP.getAnimation(120);
- skipButton = new MenuButton(skip, width - skip.getWidth() / 2f, height - (skip.getHeight() / 2f));
+ skipButton = new MenuButton(skip, displayContainer.width - skip.getWidth() / 2f, displayContainer.height - (skip.getHeight() / 2f));
} else {
Image skip = GameImage.SKIP.getImage();
- skipButton = new MenuButton(skip, width - skip.getWidth() / 2f, height - (skip.getHeight() / 2f));
+ skipButton = new MenuButton(skip, displayContainer.width - skip.getWidth() / 2f, displayContainer.height - (skip.getHeight() / 2f));
}
skipButton.setHoverAnimationDuration(350);
skipButton.setHoverAnimationEquation(AnimationEquation.IN_OUT_BACK);
skipButton.setHoverExpand(1.1f, MenuButton.Expand.UP_LEFT);
// load other images...
- ((GamePauseMenu) game.getState(Opsu.STATE_GAMEPAUSEMENU)).loadImages();
+ instanceContainer.provide(GamePauseMenu.class).loadImages();
data.loadImages();
}
@@ -1973,10 +2029,10 @@ public class Game extends BasicGameState {
HitObject.setStackOffset(diameter * STACK_OFFSET_MODIFIER);
// initialize objects
- Circle.init(container, diameter);
- Slider.init(container, diameter, beatmap);
- Spinner.init(container, overallDifficulty);
- Curve.init(container.getWidth(), container.getHeight(), diameter, (Options.isBeatmapSkinIgnored()) ?
+ Circle.init(diameter);
+ Slider.init(displayContainer, diameter, beatmap);
+ Spinner.init(displayContainer, overallDifficulty);
+ Curve.init(displayContainer.width, displayContainer.height, diameter, (Options.isBeatmapSkinIgnored()) ?
Options.getSkin().getSliderBorderColor() : beatmap.getSliderBorderColor());
// approachRate (hit object approach time)
@@ -2095,7 +2151,7 @@ public class Game extends BasicGameState {
this.replay = null;
} else {
if (replay.frames == null) {
- ErrorHandler.error("Attempting to set a replay with no frames.", null, false);
+ displayContainer.eventBus.post(new BubbleNotificationEvent("Attempting to set a replay with no frames.", BubbleNotificationEvent.COLOR_ORANGE));
return;
}
this.isReplay = true;
@@ -2190,30 +2246,29 @@ public class Game extends BasicGameState {
if (!GameMod.FLASHLIGHT.isActive())
return;
- int width = container.getWidth(), height = container.getHeight();
boolean firstObject = (objectIndex == 0 && trackPosition < beatmap.objects[0].getTime());
if (isLeadIn()) {
// lead-in: expand area
float progress = Math.max((float) (leadInTime - beatmap.audioLeadIn) / approachTime, 0f);
- flashlightRadius = width - (int) ((width - (height * 2 / 3)) * progress);
+ flashlightRadius = displayContainer.width - (int) ((displayContainer.width - (displayContainer.height * 2 / 3)) * progress);
} else if (firstObject) {
// before first object: shrink area
int timeDiff = beatmap.objects[0].getTime() - trackPosition;
- flashlightRadius = width;
+ flashlightRadius = displayContainer.width;
if (timeDiff < approachTime) {
float progress = (float) timeDiff / approachTime;
- flashlightRadius -= (width - (height * 2 / 3)) * (1 - progress);
+ flashlightRadius -= (displayContainer.width - (displayContainer.height * 2 / 3)) * (1 - progress);
}
} else {
// gameplay: size based on combo
int targetRadius;
int combo = data.getComboStreak();
if (combo < 100)
- targetRadius = height * 2 / 3;
+ targetRadius = displayContainer.height * 2 / 3;
else if (combo < 200)
- targetRadius = height / 2;
+ targetRadius = displayContainer.height / 2;
else
- targetRadius = height / 3;
+ targetRadius = displayContainer.height / 3;
if (beatmap.breaks != null && breakIndex < beatmap.breaks.size() && breakTime > 0) {
// breaks: expand at beginning, shrink at end
flashlightRadius = targetRadius;
@@ -2225,11 +2280,11 @@ public class Game extends BasicGameState {
progress = (float) (trackPosition - breakTime) / approachTime;
else if (endTime - trackPosition < approachTime)
progress = (float) (endTime - trackPosition) / approachTime;
- flashlightRadius += (width - flashlightRadius) * progress;
+ flashlightRadius += (displayContainer.width - flashlightRadius) * progress;
}
} else if (flashlightRadius != targetRadius) {
// radius size change
- float radiusDiff = height * delta / 2000f;
+ float radiusDiff = displayContainer.height * delta / 2000f;
if (flashlightRadius > targetRadius) {
flashlightRadius -= radiusDiff;
if (flashlightRadius < targetRadius)
diff --git a/src/itdelatrisu/opsu/states/GamePauseMenu.java b/src/itdelatrisu/opsu/states/GamePauseMenu.java
index c3c9dec1..642c958e 100644
--- a/src/itdelatrisu/opsu/states/GamePauseMenu.java
+++ b/src/itdelatrisu/opsu/states/GamePauseMenu.java
@@ -19,9 +19,7 @@
package itdelatrisu.opsu.states;
import itdelatrisu.opsu.GameImage;
-import itdelatrisu.opsu.Opsu;
import itdelatrisu.opsu.Options;
-import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.audio.MusicController;
import itdelatrisu.opsu.audio.SoundController;
import itdelatrisu.opsu.audio.SoundEffect;
@@ -31,14 +29,11 @@ import itdelatrisu.opsu.ui.animations.AnimationEquation;
import org.lwjgl.input.Keyboard;
import org.newdawn.slick.Color;
-import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
-import org.newdawn.slick.SlickException;
-import org.newdawn.slick.state.BasicGameState;
-import org.newdawn.slick.state.StateBasedGame;
-import org.newdawn.slick.state.transition.FadeInTransition;
-import org.newdawn.slick.state.transition.EasedFadeOutTransition;
+import yugecin.opsudance.core.DisplayContainer;
+import yugecin.opsudance.core.inject.InstanceContainer;
+import yugecin.opsudance.core.state.BaseOpsuState;
/**
* "Game Pause/Fail" state.
@@ -46,33 +41,22 @@ import org.newdawn.slick.state.transition.EasedFadeOutTransition;
* Players are able to continue the game (if applicable), retry the beatmap,
* or return to the song menu from this state.
*/
-public class GamePauseMenu extends BasicGameState {
- /** "Continue", "Retry", and "Back" buttons. */
+public class GamePauseMenu extends BaseOpsuState {
+
+ private final InstanceContainer instanceContainer;
+
private MenuButton continueButton, retryButton, backButton;
- // game-related variables
- private GameContainer container;
- private StateBasedGame game;
- private Input input;
- private final int state;
- private Game gameState;
+ private final Game gameState;
- public GamePauseMenu(int state) {
- this.state = state;
+ public GamePauseMenu(DisplayContainer displayContainer, InstanceContainer instanceContainer, Game gameState) {
+ super(displayContainer);
+ this.instanceContainer = instanceContainer;
+ this.gameState = gameState;
}
@Override
- public void init(GameContainer container, StateBasedGame game)
- throws SlickException {
- this.container = container;
- this.game = game;
- this.input = container.getInput();
- this.gameState = (Game) game.getState(Opsu.STATE_GAME);
- }
-
- @Override
- public void render(GameContainer container, StateBasedGame game, Graphics g)
- throws SlickException {
+ public void render(Graphics g) {
// get background image
GameImage bg = (gameState.getRestart() == Game.Restart.LOSE) ?
GameImage.FAIL_BACKGROUND : GameImage.PAUSE_OVERLAY;
@@ -97,102 +81,107 @@ public class GamePauseMenu extends BasicGameState {
}
@Override
- public void update(GameContainer container, StateBasedGame game, int delta)
- throws SlickException {
+ public void preRenderUpdate() {
+ int delta = displayContainer.renderDelta;
UI.update(delta);
- int mouseX = input.getMouseX(), mouseY = input.getMouseY();
- continueButton.hoverUpdate(delta, mouseX, mouseY);
- retryButton.hoverUpdate(delta, mouseX, mouseY);
- backButton.hoverUpdate(delta, mouseX, mouseY);
+ continueButton.hoverUpdate(delta, displayContainer.mouseX, displayContainer.mouseY);
+ retryButton.hoverUpdate(delta, displayContainer.mouseX, displayContainer.mouseY);
+ backButton.hoverUpdate(delta, displayContainer.mouseX, displayContainer.mouseY);
}
@Override
- public int getID() { return state; }
-
- @Override
- public void keyPressed(int key, char c) {
- // game keys
- if (!Keyboard.isRepeatEvent()) {
- if (key == Options.getGameKeyLeft())
- mousePressed(Input.MOUSE_LEFT_BUTTON, input.getMouseX(), input.getMouseY());
- else if (key == Options.getGameKeyRight())
- mousePressed(Input.MOUSE_RIGHT_BUTTON, input.getMouseX(), input.getMouseY());
+ public boolean keyPressed(int key, char c) {
+ if (super.keyPressed(key, c)) {
+ return true;
}
- switch (key) {
- case Input.KEY_ESCAPE:
+ // game keys
+ if (!Keyboard.isRepeatEvent()) {
+ if (key == Options.getGameKeyLeft()) {
+ mousePressed(Input.MOUSE_LEFT_BUTTON, displayContainer.mouseX, displayContainer.mouseY);
+ } else if (key == Options.getGameKeyRight()) {
+ mousePressed(Input.MOUSE_RIGHT_BUTTON, displayContainer.mouseX, displayContainer.mouseY);
+ }
+ }
+
+ if (key == Input.KEY_ESCAPE) {
// 'esc' will normally unpause, but will return to song menu if health is zero
if (gameState.getRestart() == Game.Restart.LOSE) {
SoundController.playSound(SoundEffect.MENUBACK);
- ((SongMenu) game.getState(Opsu.STATE_SONGMENU)).resetGameDataOnLoad();
+ instanceContainer.provide(SongMenu.class).resetGameDataOnLoad();
MusicController.playAt(MusicController.getBeatmap().previewTime, true);
- if (UI.getCursor().isBeatmapSkinned())
- UI.getCursor().reset();
- game.enterState(Opsu.STATE_SONGMENU, new EasedFadeOutTransition(), new FadeInTransition());
+ displayContainer.switchState(SongMenu.class);
} else {
SoundController.playSound(SoundEffect.MENUBACK);
gameState.setRestart(Game.Restart.FALSE);
- game.enterState(Opsu.STATE_GAME);
+ displayContainer.switchState(Game.class);
}
- break;
- case Input.KEY_R:
- // restart
- if (input.isKeyDown(Input.KEY_RCONTROL) || input.isKeyDown(Input.KEY_LCONTROL)) {
- gameState.setRestart(Game.Restart.MANUAL);
- game.enterState(Opsu.STATE_GAME);
- }
- break;
- case Input.KEY_F7:
- Options.setNextFPS(container);
- break;
- case Input.KEY_F10:
- Options.toggleMouseDisabled();
- break;
- case Input.KEY_F12:
- Utils.takeScreenShot();
- break;
+ return true;
}
+
+ if (key == Input.KEY_R && (displayContainer.input.isKeyDown(Input.KEY_RCONTROL) || displayContainer.input.isKeyDown(Input.KEY_LCONTROL))) {
+ gameState.setRestart(Game.Restart.MANUAL);
+ displayContainer.switchState(Game.class);
+ return true;
+ }
+
+ return false;
}
@Override
- public void mousePressed(int button, int x, int y) {
- if (button == Input.MOUSE_MIDDLE_BUTTON)
- return;
+ public boolean mousePressed(int button, int x, int y) {
+ if (super.mousePressed(button, x, y)) {
+ return true;
+ }
+
+ if (button == Input.MOUSE_MIDDLE_BUTTON) {
+ return true;
+ }
boolean loseState = (gameState.getRestart() == Game.Restart.LOSE);
if (continueButton.contains(x, y) && !loseState) {
SoundController.playSound(SoundEffect.MENUBACK);
gameState.setRestart(Game.Restart.FALSE);
- game.enterState(Opsu.STATE_GAME);
+ displayContainer.switchState(Game.class);
} else if (retryButton.contains(x, y)) {
SoundController.playSound(SoundEffect.MENUHIT);
gameState.setRestart(Game.Restart.MANUAL);
- game.enterState(Opsu.STATE_GAME);
+ displayContainer.switchState(Game.class);
} else if (backButton.contains(x, y)) {
SoundController.playSound(SoundEffect.MENUBACK);
- ((SongMenu) game.getState(Opsu.STATE_SONGMENU)).resetGameDataOnLoad();
+ instanceContainer.provide(SongMenu.class).resetGameDataOnLoad();
if (loseState)
MusicController.playAt(MusicController.getBeatmap().previewTime, true);
else
MusicController.resume();
- if (UI.getCursor().isBeatmapSkinned())
- UI.getCursor().reset();
+ if (displayContainer.cursor.isBeatmapSkinned()) {
+ displayContainer.resetCursor();
+ }
MusicController.setPitch(1.0f);
- game.enterState(Opsu.STATE_SONGMENU, new EasedFadeOutTransition(), new FadeInTransition());
+ displayContainer.switchState(SongMenu.class);
}
+
+ return true;
}
@Override
- public void mouseWheelMoved(int newValue) {
- if (Options.isMouseWheelDisabled())
- return;
+ public boolean mouseWheelMoved(int newValue) {
+ if (super.mouseWheelMoved(newValue)) {
+ return true;
+ }
+
+ if (Options.isMouseWheelDisabled()) {
+ return true;
+ }
UI.changeVolume((newValue < 0) ? -1 : 1);
+ return true;
}
@Override
- public void enter(GameContainer container, StateBasedGame game)
- throws SlickException {
+ public void enter() {
+ super.enter();
+
UI.enter();
MusicController.pause();
continueButton.resetHover();
@@ -200,17 +189,23 @@ public class GamePauseMenu extends BasicGameState {
backButton.resetHover();
}
+ @Override
+ public boolean onCloseRequest() {
+ SongMenu songmenu = instanceContainer.provide(SongMenu.class);
+ songmenu.resetTrackOnLoad();
+ songmenu.resetGameDataOnLoad();
+ displayContainer.switchState(SongMenu.class);
+ return false;
+ }
+
/**
* Loads all game pause/fail menu images.
*/
public void loadImages() {
- int width = container.getWidth();
- int height = container.getHeight();
-
// initialize buttons
- continueButton = new MenuButton(GameImage.PAUSE_CONTINUE.getImage(), width / 2f, height * 0.25f);
- retryButton = new MenuButton(GameImage.PAUSE_RETRY.getImage(), width / 2f, height * 0.5f);
- backButton = new MenuButton(GameImage.PAUSE_BACK.getImage(), width / 2f, height * 0.75f);
+ continueButton = new MenuButton(GameImage.PAUSE_CONTINUE.getImage(), displayContainer.width / 2f, displayContainer.height * 0.25f);
+ retryButton = new MenuButton(GameImage.PAUSE_RETRY.getImage(), displayContainer.width / 2f, displayContainer.height * 0.5f);
+ backButton = new MenuButton(GameImage.PAUSE_BACK.getImage(), displayContainer.width / 2f, displayContainer.height * 0.75f);
final int buttonAnimationDuration = 300;
continueButton.setHoverAnimationDuration(buttonAnimationDuration);
retryButton.setHoverAnimationDuration(buttonAnimationDuration);
@@ -223,4 +218,5 @@ public class GamePauseMenu extends BasicGameState {
retryButton.setHoverExpand();
backButton.setHoverExpand();
}
+
}
diff --git a/src/itdelatrisu/opsu/states/GameRanking.java b/src/itdelatrisu/opsu/states/GameRanking.java
index fe7450fd..300d6dee 100644
--- a/src/itdelatrisu/opsu/states/GameRanking.java
+++ b/src/itdelatrisu/opsu/states/GameRanking.java
@@ -21,9 +21,6 @@ package itdelatrisu.opsu.states;
import itdelatrisu.opsu.GameData;
import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.GameMod;
-import itdelatrisu.opsu.Opsu;
-import itdelatrisu.opsu.Options;
-import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.audio.MusicController;
import itdelatrisu.opsu.audio.SoundController;
import itdelatrisu.opsu.audio.SoundEffect;
@@ -35,17 +32,13 @@ import itdelatrisu.opsu.ui.UI;
import java.io.FileNotFoundException;
import java.io.IOException;
-import org.lwjgl.opengl.Display;
-import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.Input;
-import org.newdawn.slick.SlickException;
-import org.newdawn.slick.state.BasicGameState;
-import org.newdawn.slick.state.StateBasedGame;
-import org.newdawn.slick.state.transition.FadeInTransition;
-import org.newdawn.slick.state.transition.EasedFadeOutTransition;
import org.newdawn.slick.util.Log;
+import yugecin.opsudance.core.DisplayContainer;
+import yugecin.opsudance.core.inject.InstanceContainer;
+import yugecin.opsudance.core.state.BaseOpsuState;
/**
* "Game Ranking" (score card) state.
@@ -54,7 +47,10 @@ import org.newdawn.slick.util.Log;
* or watch a replay of the game from this state.
*
*/
-public class GameRanking extends BasicGameState {
+public class GameRanking extends BaseOpsuState {
+
+ private final InstanceContainer instanceContainer;
+
/** Associated GameData object. */
private GameData data;
@@ -64,48 +60,35 @@ public class GameRanking extends BasicGameState {
/** Button coordinates. */
private float retryY, replayY;
- // game-related variables
- private GameContainer container;
- private StateBasedGame game;
- private final int state;
- private Input input;
+ public GameRanking(DisplayContainer displayContainer, InstanceContainer instanceContainer) {
+ super(displayContainer);
+ this.instanceContainer = instanceContainer;
- public GameRanking(int state) {
- this.state = state;
}
@Override
- public void init(GameContainer container, StateBasedGame game)
- throws SlickException {
- this.container = container;
- this.game = game;
- this.input = container.getInput();
-
- int width = container.getWidth();
- int height = container.getHeight();
+ public void revalidate() {
+ super.revalidate();
// buttons
Image retry = GameImage.PAUSE_RETRY.getImage();
Image replay = GameImage.PAUSE_REPLAY.getImage();
- replayY = (height * 0.985f) - replay.getHeight() / 2f;
+ replayY = (displayContainer.height * 0.985f) - replay.getHeight() / 2f;
retryY = replayY - (replay.getHeight() / 2f) - (retry.getHeight() / 1.975f);
- retryButton = new MenuButton(retry, width - (retry.getWidth() / 2f), retryY);
- replayButton = new MenuButton(replay, width - (replay.getWidth() / 2f), replayY);
+ retryButton = new MenuButton(retry, displayContainer.width - (retry.getWidth() / 2f), retryY);
+ replayButton = new MenuButton(replay, displayContainer.width - (replay.getWidth() / 2f), replayY);
retryButton.setHoverFade();
replayButton.setHoverFade();
}
@Override
- public void render(GameContainer container, StateBasedGame game, Graphics g)
- throws SlickException {
- int width = container.getWidth();
- int height = container.getHeight();
-
+ public void render(Graphics g) {
Beatmap beatmap = MusicController.getBeatmap();
// background
- if (!beatmap.drawBackground(width, height, 0.7f, true))
- GameImage.PLAYFIELD.getImage().draw(0,0);
+ if (!beatmap.drawBackground(displayContainer.width, displayContainer.height, 0.7f, true)) {
+ GameImage.PLAYFIELD.getImage().draw(0, 0);
+ }
// ranking screen elements
data.drawRankingElements(g, beatmap);
@@ -117,62 +100,62 @@ public class GameRanking extends BasicGameState {
UI.getBackButton().draw();
UI.draw(g);
+
+ super.render(g);
}
@Override
- public void update(GameContainer container, StateBasedGame game, int delta)
- throws SlickException {
+ public void preRenderUpdate() {
+ int delta = displayContainer.renderDelta;
UI.update(delta);
- int mouseX = input.getMouseX(), mouseY = input.getMouseY();
- replayButton.hoverUpdate(delta, mouseX, mouseY);
- if (data.isGameplay())
- retryButton.hoverUpdate(delta, mouseX, mouseY);
- else
+ replayButton.hoverUpdate(delta, displayContainer.mouseX, displayContainer.mouseY);
+ if (data.isGameplay()) {
+ retryButton.hoverUpdate(delta, displayContainer.mouseX, displayContainer.mouseY);
+ } else {
MusicController.loopTrackIfEnded(true);
- UI.getBackButton().hoverUpdate(delta, mouseX, mouseY);
- }
-
- @Override
- public int getID() { return state; }
-
- @Override
- public void mouseWheelMoved(int newValue) {
- if (input.isKeyDown(Input.KEY_LALT) || input.isKeyDown(Input.KEY_RALT))
- UI.changeVolume((newValue < 0) ? -1 : 1);
- }
-
- @Override
- public void keyPressed(int key, char c) {
- switch (key) {
- case Input.KEY_ESCAPE:
- returnToSongMenu();
- break;
- case Input.KEY_F7:
- Options.setNextFPS(container);
- break;
- case Input.KEY_F10:
- Options.toggleMouseDisabled();
- break;
- case Input.KEY_F12:
- Utils.takeScreenShot();
- break;
}
+ UI.getBackButton().hoverUpdate(delta, displayContainer.mouseX, displayContainer.mouseY);
}
@Override
- public void mousePressed(int button, int x, int y) {
+ public boolean mouseWheelMoved(int newValue) {
+ if (displayContainer.input.isKeyDown(Input.KEY_LALT) || displayContainer.input.isKeyDown(Input.KEY_RALT)) {
+ UI.changeVolume((newValue < 0) ? -1 : 1);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean keyPressed(int key, char c) {
+ if (super.keyPressed(key, c)) {
+ return true;
+ }
+
+ if (key == Input.KEY_ESCAPE) {
+ returnToSongMenu();
+ }
+ return true;
+ }
+
+ @Override
+ public boolean mousePressed(int button, int x, int y) {
+ if (super.mousePressed(button, x, y)) {
+ return true;
+ }
+
// check mouse button
- if (button == Input.MOUSE_MIDDLE_BUTTON)
- return;
+ if (button == Input.MOUSE_MIDDLE_BUTTON) {
+ return false;
+ }
// back to menu
if (UI.getBackButton().contains(x, y)) {
returnToSongMenu();
- return;
+ return true;
}
// replay
- Game gameState = (Game) game.getState(Opsu.STATE_GAME);
+ Game gameState = instanceContainer.provide(Game.class);
boolean returnToGame = false;
boolean replayButtonPressed = replayButton.contains(x, y);
if (replayButtonPressed && !(data.isGameplay() && GameMod.AUTO.isActive())) {
@@ -206,16 +189,16 @@ public class GameRanking extends BasicGameState {
Beatmap beatmap = MusicController.getBeatmap();
gameState.loadBeatmap(beatmap);
SoundController.playSound(SoundEffect.MENUHIT);
- game.enterState(Opsu.STATE_GAME, new EasedFadeOutTransition(), new FadeInTransition());
- return;
+ // TODO d displayContainer.switchState(Game.class);
}
+ return true;
}
@Override
- public void enter(GameContainer container, StateBasedGame game)
- throws SlickException {
+ public void enter() {
+ super.enter();
+
UI.enter();
- Display.setTitle(game.getTitle());
if (!data.isGameplay()) {
if (!MusicController.isTrackDimmed())
MusicController.toggleTrackDimmed(0.5f);
@@ -229,11 +212,24 @@ public class GameRanking extends BasicGameState {
}
@Override
- public void leave(GameContainer container, StateBasedGame game)
- throws SlickException {
+ public void leave() {
+ super.leave();
+
this.data = null;
- if (MusicController.isTrackDimmed())
+ if (MusicController.isTrackDimmed()) {
MusicController.toggleTrackDimmed(1f);
+ }
+ }
+
+ @Override
+ public boolean onCloseRequest() {
+ SongMenu songmenu = instanceContainer.provide(SongMenu.class);
+ if (data != null && data.isGameplay()) {
+ songmenu.resetTrackOnLoad();
+ }
+ songmenu.resetGameDataOnLoad();
+ displayContainer.switchState(SongMenu.class);
+ return false;
}
/**
@@ -242,13 +238,15 @@ public class GameRanking extends BasicGameState {
private void returnToSongMenu() {
SoundController.muteSoundComponent();
SoundController.playSound(SoundEffect.MENUBACK);
- SongMenu songMenu = (SongMenu) game.getState(Opsu.STATE_SONGMENU);
- if (data.isGameplay())
+ SongMenu songMenu = instanceContainer.provide(SongMenu.class);
+ if (data.isGameplay()) {
songMenu.resetTrackOnLoad();
+ }
songMenu.resetGameDataOnLoad();
- if (UI.getCursor().isBeatmapSkinned())
- UI.getCursor().reset();
- game.enterState(Opsu.STATE_SONGMENU, new EasedFadeOutTransition(), new FadeInTransition());
+ if (displayContainer.cursor.isBeatmapSkinned()) {
+ displayContainer.resetCursor();
+ }
+ displayContainer.switchState(SongMenu.class);
}
/**
diff --git a/src/itdelatrisu/opsu/states/MainMenu.java b/src/itdelatrisu/opsu/states/MainMenu.java
index 93fd15e7..a099e037 100644
--- a/src/itdelatrisu/opsu/states/MainMenu.java
+++ b/src/itdelatrisu/opsu/states/MainMenu.java
@@ -18,9 +18,7 @@
package itdelatrisu.opsu.states;
-import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.GameImage;
-import itdelatrisu.opsu.Opsu;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.audio.MusicController;
@@ -29,7 +27,6 @@ import itdelatrisu.opsu.audio.SoundEffect;
import itdelatrisu.opsu.beatmap.Beatmap;
import itdelatrisu.opsu.beatmap.BeatmapSetList;
import itdelatrisu.opsu.beatmap.BeatmapSetNode;
-import itdelatrisu.opsu.beatmap.TimingPoint;
import itdelatrisu.opsu.downloads.Updater;
import itdelatrisu.opsu.states.ButtonMenu.MenuState;
import itdelatrisu.opsu.ui.*;
@@ -43,23 +40,28 @@ import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Stack;
+import org.lwjgl.opengl.Display;
import org.newdawn.slick.Color;
-import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.Input;
-import org.newdawn.slick.SlickException;
-import org.newdawn.slick.state.BasicGameState;
-import org.newdawn.slick.state.StateBasedGame;
-import org.newdawn.slick.state.transition.EasedFadeOutTransition;
-import org.newdawn.slick.state.transition.FadeInTransition;
+import org.newdawn.slick.util.Log;
+import yugecin.opsudance.core.DisplayContainer;
+import yugecin.opsudance.core.events.EventBus;
+import yugecin.opsudance.core.inject.InstanceContainer;
+import yugecin.opsudance.core.state.BaseOpsuState;
+import yugecin.opsudance.core.state.OpsuState;
+import yugecin.opsudance.events.BubbleNotificationEvent;
/**
* "Main Menu" state.
*
* Players are able to enter the song menu or downloads menu from this state.
*/
-public class MainMenu extends BasicGameState {
+public class MainMenu extends BaseOpsuState {
+
+ private final InstanceContainer instanceContainer;
+
/** Idle time, in milliseconds, before returning the logo to its original position. */
private static final short LOGO_IDLE_DELAY = 10000;
@@ -123,40 +125,27 @@ public class MainMenu extends BasicGameState {
/** The star fountain. */
private StarFountain starFountain;
- // game-related variables
- private GameContainer container;
- private StateBasedGame game;
- private Input input;
- private final int state;
-
- public MainMenu(int state) {
- this.state = state;
+ public MainMenu(DisplayContainer displayContainer, InstanceContainer instanceContainer) {
+ super(displayContainer);
+ this.instanceContainer = instanceContainer;
}
@Override
- public void init(GameContainer container, StateBasedGame game)
- throws SlickException {
- this.container = container;
- this.game = game;
- this.input = container.getInput();
-
+ protected void revalidate() {
programStartTime = System.currentTimeMillis();
- previous = new Stack();
-
- int width = container.getWidth();
- int height = container.getHeight();
+ previous = new Stack<>();
// initialize menu buttons
Image logoImg = GameImage.MENU_LOGO.getImage();
Image playImg = GameImage.MENU_PLAY.getImage();
Image exitImg = GameImage.MENU_EXIT.getImage();
float exitOffset = (playImg.getWidth() - exitImg.getWidth()) / 3f;
- logo = new MenuButton(logoImg, width / 2f, height / 2f);
+ logo = new MenuButton(logoImg, displayContainer.width / 2f, displayContainer.height / 2f);
playButton = new MenuButton(playImg,
- width * 0.75f, (height / 2) - (logoImg.getHeight() / 5f)
+ displayContainer.width * 0.75f, (displayContainer.height / 2) - (logoImg.getHeight() / 5f)
);
exitButton = new MenuButton(exitImg,
- width * 0.75f - exitOffset, (height / 2) + (exitImg.getHeight() / 2f)
+ displayContainer.width * 0.75f - exitOffset, (displayContainer.height / 2) + (exitImg.getHeight() / 2f)
);
final int logoAnimationDuration = 350;
logo.setHoverAnimationDuration(logoAnimationDuration);
@@ -174,30 +163,30 @@ public class MainMenu extends BasicGameState {
// initialize music buttons
int musicWidth = GameImage.MUSIC_PLAY.getImage().getWidth();
int musicHeight = GameImage.MUSIC_PLAY.getImage().getHeight();
- musicPlay = new MenuButton(GameImage.MUSIC_PLAY.getImage(), width - (2 * musicWidth), musicHeight / 1.5f);
- musicPause = new MenuButton(GameImage.MUSIC_PAUSE.getImage(), width - (2 * musicWidth), musicHeight / 1.5f);
- musicNext = new MenuButton(GameImage.MUSIC_NEXT.getImage(), width - musicWidth, musicHeight / 1.5f);
- musicPrevious = new MenuButton(GameImage.MUSIC_PREVIOUS.getImage(), width - (3 * musicWidth), musicHeight / 1.5f);
+ musicPlay = new MenuButton(GameImage.MUSIC_PLAY.getImage(), displayContainer.width - (2 * musicWidth), musicHeight / 1.5f);
+ musicPause = new MenuButton(GameImage.MUSIC_PAUSE.getImage(), displayContainer.width - (2 * musicWidth), musicHeight / 1.5f);
+ musicNext = new MenuButton(GameImage.MUSIC_NEXT.getImage(), displayContainer.width - musicWidth, musicHeight / 1.5f);
+ musicPrevious = new MenuButton(GameImage.MUSIC_PREVIOUS.getImage(), displayContainer.width - (3 * musicWidth), musicHeight / 1.5f);
musicPlay.setHoverExpand(1.5f);
musicPause.setHoverExpand(1.5f);
musicNext.setHoverExpand(1.5f);
musicPrevious.setHoverExpand(1.5f);
// initialize music position bar location
- musicBarX = width - musicWidth * 3.5f;
+ musicBarX = displayContainer.width - musicWidth * 3.5f;
musicBarY = musicHeight * 1.25f;
musicBarWidth = musicWidth * 3f;
musicBarHeight = musicHeight * 0.11f;
// initialize downloads button
Image dlImg = GameImage.DOWNLOADS.getImage();
- downloadsButton = new MenuButton(dlImg, width - dlImg.getWidth() / 2f, height / 2f);
+ downloadsButton = new MenuButton(dlImg, displayContainer.width - dlImg.getWidth() / 2f, displayContainer.height / 2f);
downloadsButton.setHoverAnimationDuration(350);
downloadsButton.setHoverAnimationEquation(AnimationEquation.IN_OUT_BACK);
downloadsButton.setHoverExpand(1.03f, Expand.LEFT);
// initialize repository button
- float startX = width * 0.997f, startY = height * 0.997f;
+ float startX = displayContainer.width * 0.997f, startY = displayContainer.height * 0.997f;
if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) { // only if a webpage can be opened
Image repoImg;
repoImg = GameImage.REPOSITORY.getImage();
@@ -217,7 +206,7 @@ public class MainMenu extends BasicGameState {
}
// initialize update buttons
- float updateX = width / 2f, updateY = height * 17 / 18f;
+ float updateX = displayContainer.width / 2f, updateY = displayContainer.height * 17 / 18f;
Image downloadImg = GameImage.DOWNLOAD.getImage();
updateButton = new MenuButton(downloadImg, updateX, updateY);
updateButton.setHoverAnimationDuration(400);
@@ -230,22 +219,19 @@ public class MainMenu extends BasicGameState {
restartButton.setHoverRotate(360);
// initialize star fountain
- starFountain = new StarFountain(width, height);
+ starFountain = new StarFountain(displayContainer.width, displayContainer.height);
// logo animations
- float centerOffsetX = width / 6.5f;
+ float centerOffsetX = displayContainer.width / 6.5f;
logoOpen = new AnimatedValue(100, 0, centerOffsetX, AnimationEquation.OUT_QUAD);
logoClose = new AnimatedValue(2200, centerOffsetX, 0, AnimationEquation.OUT_QUAD);
logoButtonAlpha = new AnimatedValue(200, 0f, 1f, AnimationEquation.LINEAR);
-
- reset();
}
@Override
- public void render(GameContainer container, StateBasedGame game, Graphics g)
- throws SlickException {
- int width = container.getWidth();
- int height = container.getHeight();
+ public void render(Graphics g) {
+ int width = displayContainer.width;
+ int height = displayContainer.height;
// draw background
Beatmap beatmap = MusicController.getBeatmap();
@@ -305,7 +291,8 @@ public class MainMenu extends BasicGameState {
musicPrevious.draw();
// draw music position bar
- int mouseX = input.getMouseX(), mouseY = input.getMouseY();
+ int mouseX = displayContainer.mouseX;
+ int mouseY = displayContainer.mouseY;
g.setColor((musicPositionBarContains(mouseX, mouseY)) ? Colors.BLACK_BG_HOVER : Colors.BLACK_BG_NORMAL);
g.fillRoundRect(musicBarX, musicBarY, musicBarWidth, musicBarHeight, 4);
g.setColor(Color.white);
@@ -366,12 +353,14 @@ public class MainMenu extends BasicGameState {
}
@Override
- public void update(GameContainer container, StateBasedGame game, int delta)
- throws SlickException {
+ public void preRenderUpdate() {
+ int delta = displayContainer.renderDelta;
+
UI.update(delta);
if (MusicController.trackEnded())
nextTrack(false); // end of track: go to next track
- int mouseX = input.getMouseX(), mouseY = input.getMouseY();
+ int mouseX = displayContainer.mouseX;
+ int mouseY = displayContainer.mouseY;
logo.hoverUpdate(delta, mouseX, mouseY, 0.25f);
playButton.hoverUpdate(delta, mouseX, mouseY, 0.25f);
exitButton.hoverUpdate(delta, mouseX, mouseY, 0.25f);
@@ -396,7 +385,7 @@ public class MainMenu extends BasicGameState {
// window focus change: increase/decrease theme song volume
if (MusicController.isThemePlaying() &&
- MusicController.isTrackDimmed() == container.hasFocus())
+ MusicController.isTrackDimmed() == Display.isActive())
MusicController.toggleTrackDimmed(0.33f);
// fade in background
@@ -413,7 +402,7 @@ public class MainMenu extends BasicGameState {
}
// buttons
- int centerX = container.getWidth() / 2;
+ int centerX = displayContainer.width / 2;
float currentLogoButtonAlpha;
switch (logoState) {
case DEFAULT:
@@ -468,11 +457,16 @@ public class MainMenu extends BasicGameState {
}
@Override
- public int getID() { return state; }
+ public void enter() {
+ super.enter();
+
+ logo.setX(displayContainer.width / 2);
+ logoOpen.setTime(0);
+ logoClose.setTime(0);
+ logoButtonAlpha.setTime(0);
+ logoTimer = 0;
+ logoState = LogoState.DEFAULT;
- @Override
- public void enter(GameContainer container, StateBasedGame game)
- throws SlickException {
UI.enter();
if (!enterNotification) {
if (Updater.get().getStatus() == Updater.Status.UPDATE_AVAILABLE) {
@@ -489,7 +483,8 @@ public class MainMenu extends BasicGameState {
starFountain.clear();
// reset button hover states if mouse is not currently hovering over the button
- int mouseX = input.getMouseX(), mouseY = input.getMouseY();
+ int mouseX = displayContainer.mouseX;
+ int mouseY = displayContainer.mouseY;
if (!logo.contains(mouseX, mouseY, 0.25f))
logo.resetHover();
if (!playButton.contains(mouseX, mouseY, 0.25f))
@@ -515,17 +510,17 @@ public class MainMenu extends BasicGameState {
}
@Override
- public void leave(GameContainer container, StateBasedGame game)
- throws SlickException {
+ public void leave() {
+ super.leave();
if (MusicController.isTrackDimmed())
MusicController.toggleTrackDimmed(1f);
}
@Override
- public void mousePressed(int button, int x, int y) {
+ public boolean mousePressed(int button, int x, int y) {
// check mouse button
if (button == Input.MOUSE_MIDDLE_BUTTON)
- return;
+ return false;
// music position bar
if (MusicController.isPlaying()) {
@@ -533,7 +528,7 @@ public class MainMenu extends BasicGameState {
lastMeasureProgress = 0f;
float pos = (x - musicBarX) / musicBarWidth;
MusicController.setPosition((int) (pos * MusicController.getDuration()));
- return;
+ return true;
}
}
@@ -546,29 +541,28 @@ public class MainMenu extends BasicGameState {
MusicController.resume();
UI.sendBarNotification("Play");
}
- return;
+ return true;
} else if (musicNext.contains(x, y)) {
nextTrack(true);
UI.sendBarNotification(">> Next");
- return;
+ return true;
} else if (musicPrevious.contains(x, y)) {
lastMeasureProgress = 0f;
if (!previous.isEmpty()) {
- SongMenu menu = (SongMenu) game.getState(Opsu.STATE_SONGMENU);
- menu.setFocus(BeatmapSetList.get().getBaseNode(previous.pop()), -1, true, false);
+ instanceContainer.provide(SongMenu.class).setFocus(BeatmapSetList.get().getBaseNode(previous.pop()), -1, true, false);
if (Options.isDynamicBackgroundEnabled())
bgAlpha.setTime(0);
} else
MusicController.setPosition(0);
UI.sendBarNotification("<< Previous");
- return;
+ return true;
}
// downloads button actions
if (downloadsButton.contains(x, y)) {
SoundController.playSound(SoundEffect.MENUHIT);
- game.enterState(Opsu.STATE_DOWNLOADSMENU, new EasedFadeOutTransition(), new FadeInTransition());
- return;
+ displayContainer.switchState(DownloadsMenu.class);
+ return true;
}
// repository button actions
@@ -578,9 +572,10 @@ public class MainMenu extends BasicGameState {
} catch (UnsupportedOperationException e) {
UI.sendBarNotification("The repository web page could not be opened.");
} catch (IOException e) {
- ErrorHandler.error("Could not browse to repository URI.", e, false);
+ Log.error("could not browse to repo", e);
+ displayContainer.eventBus.post(new BubbleNotificationEvent("Could not browse to repo", BubbleNotificationEvent.COLOR_ORANGE));
}
- return;
+ return true;
}
if (danceRepoButton != null && danceRepoButton.contains(x, y)) {
@@ -589,9 +584,10 @@ public class MainMenu extends BasicGameState {
} catch (UnsupportedOperationException e) {
UI.sendBarNotification("The repository web page could not be opened.");
} catch (IOException e) {
- ErrorHandler.error("Could not browse to repository URI.", e, false);
+ Log.error("could not browse to repo", e);
+ displayContainer.eventBus.post(new BubbleNotificationEvent("Could not browse to repo", BubbleNotificationEvent.COLOR_ORANGE));
}
- return;
+ return true;
}
// update button actions
@@ -604,13 +600,12 @@ public class MainMenu extends BasicGameState {
updateButton.setHoverAnimationDuration(800);
updateButton.setHoverAnimationEquation(AnimationEquation.IN_OUT_QUAD);
updateButton.setHoverFade(0.6f);
- return;
+ return true;
} else if (restartButton.contains(x, y) && status == Updater.Status.UPDATE_DOWNLOADED) {
SoundController.playSound(SoundEffect.MENUHIT);
Updater.get().prepareUpdate();
- container.setForceExit(false);
- container.exit();
- return;
+ displayContainer.exitRequested = true;
+ return true;
}
}
@@ -623,7 +618,7 @@ public class MainMenu extends BasicGameState {
playButton.getImage().setAlpha(0f);
exitButton.getImage().setAlpha(0f);
SoundController.playSound(SoundEffect.MENUHIT);
- return;
+ return true;
}
}
@@ -632,21 +627,27 @@ public class MainMenu extends BasicGameState {
if (logo.contains(x, y, 0.25f) || playButton.contains(x, y, 0.25f)) {
SoundController.playSound(SoundEffect.MENUHIT);
enterSongMenu();
- return;
+ return true;
} else if (exitButton.contains(x, y, 0.25f)) {
- container.exit();
- return;
+ displayContainer.exitRequested = true;
+ return true;
}
}
+ return false;
}
@Override
- public void mouseWheelMoved(int newValue) {
+ public boolean mouseWheelMoved(int newValue) {
UI.changeVolume((newValue < 0) ? -1 : 1);
+ return true;
}
@Override
- public void keyPressed(int key, char c) {
+ public boolean keyPressed(int key, char c) {
+ if (super.keyPressed(key, c)) {
+ return true;
+ }
+
switch (key) {
case Input.KEY_ESCAPE:
case Input.KEY_Q:
@@ -656,9 +657,9 @@ public class MainMenu extends BasicGameState {
logoTimer = 0;
break;
}
- ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).setMenuState(MenuState.EXIT);
- game.enterState(Opsu.STATE_BUTTONMENU);
- break;
+ instanceContainer.provide(ButtonMenu.class).setMenuState(MenuState.EXIT);
+ displayContainer.switchState(ButtonMenu.class);
+ return true;
case Input.KEY_P:
SoundController.playSound(SoundEffect.MENUHIT);
if (logoState == LogoState.DEFAULT || logoState == LogoState.CLOSING) {
@@ -669,30 +670,22 @@ public class MainMenu extends BasicGameState {
exitButton.getImage().setAlpha(0f);
} else
enterSongMenu();
- break;
+ return true;
case Input.KEY_D:
SoundController.playSound(SoundEffect.MENUHIT);
- game.enterState(Opsu.STATE_DOWNLOADSMENU, new EasedFadeOutTransition(), new FadeInTransition());
- break;
+ displayContainer.switchState(DownloadsMenu.class);
+ return true;
case Input.KEY_R:
nextTrack(true);
- break;
+ return true;
case Input.KEY_UP:
UI.changeVolume(1);
- break;
+ return true;
case Input.KEY_DOWN:
UI.changeVolume(-1);
- break;
- case Input.KEY_F7:
- Options.setNextFPS(container);
- break;
- case Input.KEY_F10:
- Options.toggleMouseDisabled();
- break;
- case Input.KEY_F12:
- Utils.takeScreenShot();
- break;
+ return true;
}
+ return false;
}
/**
@@ -705,34 +698,6 @@ public class MainMenu extends BasicGameState {
(cy > musicBarY && cy < musicBarY + musicBarHeight));
}
- /**
- * Resets the button states.
- */
- public void reset() {
- // reset logo
- logo.setX(container.getWidth() / 2);
- logoOpen.setTime(0);
- logoClose.setTime(0);
- logoButtonAlpha.setTime(0);
- logoTimer = 0;
- logoState = LogoState.DEFAULT;
-
- logo.resetHover();
- playButton.resetHover();
- exitButton.resetHover();
- musicPlay.resetHover();
- musicPause.resetHover();
- musicNext.resetHover();
- musicPrevious.resetHover();
- if (repoButton != null)
- repoButton.resetHover();
- if (danceRepoButton != null)
- danceRepoButton.resetHover();
- updateButton.resetHover();
- restartButton.resetHover();
- downloadsButton.resetHover();
- }
-
/**
* Plays the next track, and adds the previous one to the stack.
* @param user {@code true} if this was user-initiated, false otherwise (track end)
@@ -746,8 +711,7 @@ public class MainMenu extends BasicGameState {
MusicController.playAt(0, false);
return;
}
- SongMenu menu = (SongMenu) game.getState(Opsu.STATE_SONGMENU);
- BeatmapSetNode node = menu.setFocus(BeatmapSetList.get().getRandomNode(), -1, true, false);
+ BeatmapSetNode node = instanceContainer.provide(SongMenu.class).setFocus(BeatmapSetList.get().getRandomNode(), -1, true, false);
boolean sameAudio = false;
if (node != null) {
sameAudio = MusicController.getBeatmap().audioFilename.equals(node.getBeatmapSet().get(0).audioFilename);
@@ -762,11 +726,11 @@ public class MainMenu extends BasicGameState {
* Enters the song menu, or the downloads menu if no beatmaps are loaded.
*/
private void enterSongMenu() {
- int state = Opsu.STATE_SONGMENU;
+ Class extends OpsuState> state = SongMenu.class;
if (BeatmapSetList.get().getMapSetCount() == 0) {
- ((DownloadsMenu) game.getState(Opsu.STATE_DOWNLOADSMENU)).notifyOnLoad("Download some beatmaps to get started!");
- state = Opsu.STATE_DOWNLOADSMENU;
+ instanceContainer.provide(DownloadsMenu.class).notifyOnLoad("Download some beatmaps to get started!");
+ state = DownloadsMenu.class;
}
- game.enterState(state, new EasedFadeOutTransition(), new FadeInTransition());
+ displayContainer.switchState(state);
}
}
diff --git a/src/itdelatrisu/opsu/states/OptionsMenu.java b/src/itdelatrisu/opsu/states/OptionsMenu.java
index 39ffa7ca..4f2c22eb 100644
--- a/src/itdelatrisu/opsu/states/OptionsMenu.java
+++ b/src/itdelatrisu/opsu/states/OptionsMenu.java
@@ -18,35 +18,14 @@
package itdelatrisu.opsu.states;
-import itdelatrisu.opsu.GameImage;
-import itdelatrisu.opsu.Opsu;
-import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.Options.GameOption;
-import itdelatrisu.opsu.audio.MusicController;
-import itdelatrisu.opsu.audio.SoundController;
-import itdelatrisu.opsu.audio.SoundEffect;
-import itdelatrisu.opsu.ui.UI;
-import org.newdawn.slick.GameContainer;
-import org.newdawn.slick.Graphics;
-import org.newdawn.slick.Input;
-import org.newdawn.slick.SlickException;
-import org.newdawn.slick.state.BasicGameState;
-import org.newdawn.slick.state.StateBasedGame;
-import org.newdawn.slick.state.transition.FadeInTransition;
-import org.newdawn.slick.state.transition.EmptyTransition;
import yugecin.opsudance.ui.OptionsOverlay;
import yugecin.opsudance.ui.OptionsOverlay.OptionTab;
-/**
- * "Game Options" state.
- *
- * Players are able to view and change various game settings in this state.
- */
-public class OptionsMenu extends BasicGameState implements OptionsOverlay.Parent {
+public class OptionsMenu {
- /** Option tabs. */
- private static final OptionTab[] options = new OptionsOverlay.OptionTab[]{
+ public static final OptionTab[] normalOptions = new OptionsOverlay.OptionTab[]{
new OptionTab("Display", new GameOption[]{
GameOption.SCREEN_RESOLUTION,
GameOption.FULLSCREEN,
@@ -154,104 +133,63 @@ public class OptionsMenu extends BasicGameState implements OptionsOverlay.Parent
})
};
- private StateBasedGame game;
- private Input input;
- private final int state;
-
- private OptionsOverlay optionsOverlay;
-
- public OptionsMenu(int state) {
- this.state = state;
- }
-
- @Override
- public void init(GameContainer container, StateBasedGame game)
- throws SlickException {
- this.game = game;
- this.input = container.getInput();
-
- optionsOverlay = new OptionsOverlay(this, options, 5, container);
- }
-
- @Override
- public void render(GameContainer container, StateBasedGame game, Graphics g) throws SlickException {
- // background
- GameImage.OPTIONS_BG.getImage().draw();
-
- int mouseX = input.getMouseX(), mouseY = input.getMouseY();
- optionsOverlay.render(g, mouseX, mouseY);
- UI.draw(g);
- }
-
- @Override
- public void update(GameContainer container, StateBasedGame game, int delta) throws SlickException {
- UI.update(delta);
- MusicController.loopTrackIfEnded(false);
- optionsOverlay.update(delta, input.getMouseX(), input.getMouseY());
- }
-
- @Override
- public int getID() {
- return state;
- }
-
- @Override
- public void mouseReleased(int button, int x, int y) {
- optionsOverlay.mouseReleased(button, x, y);
- }
-
- @Override
- public void mousePressed(int button, int x, int y) {
- optionsOverlay.mousePressed(button, x, y);
- }
-
- @Override
- public void mouseDragged(int oldx, int oldy, int newx, int newy) {
- optionsOverlay.mouseDragged(oldx, oldy, newx, newy);
- }
-
- @Override
- public void mouseWheelMoved(int newValue) {
- optionsOverlay.mouseWheelMoved(newValue);
- }
-
- @Override
- public void keyPressed(int key, char c) {
- optionsOverlay.keyPressed(key, c);
- }
-
- /**
- * This string is built with option values when entering the options menu.
- * When leaving the options menu, this string is checked against the new optionstring with the same options.
- * If those do not match, it means some option has change which requires a restart
- */
- private String restartOptions;
-
- @Override
- public void enter(GameContainer container, StateBasedGame game)
- throws SlickException {
- UI.enter();
- restartOptions = "" + Options.getResolutionIdx() + Options.isFullscreen() + Options.allowLargeResolutions() + Options.getSkinName();
- }
-
- @Override
- public void leave(GameContainer container, StateBasedGame game) throws SlickException {
- if (!("" + Options.getResolutionIdx() + Options.isFullscreen() + Options.allowLargeResolutions() + Options.getSkinName()).equals(restartOptions)) {
- container.setForceExit(false);
- container.exit();
- return;
- }
- SoundController.playSound(SoundEffect.MENUBACK);
- }
-
- @Override
- public void onLeave() {
- game.enterState(Opsu.STATE_SONGMENU, new EmptyTransition(), new FadeInTransition());
- }
-
- @Override
- public void onSaveOption(GameOption option) {
-
- }
+ public static final OptionTab[] storyboardOptions = new OptionsOverlay.OptionTab[]{
+ new OptionTab("Gameplay", new GameOption[] {
+ GameOption.BACKGROUND_DIM,
+ GameOption.DANCE_REMOVE_BG,
+ GameOption.SNAKING_SLIDERS,
+ GameOption.SHRINKING_SLIDERS,
+ GameOption.SHOW_HIT_LIGHTING,
+ GameOption.SHOW_HIT_ANIMATIONS,
+ GameOption.SHOW_COMBO_BURSTS,
+ GameOption.SHOW_PERFECT_HIT,
+ GameOption.SHOW_FOLLOW_POINTS,
+ }),
+ new OptionTab("Input", new GameOption[] {
+ GameOption.CURSOR_SIZE,
+ GameOption.NEW_CURSOR,
+ GameOption.DISABLE_CURSOR
+ }),
+ new OptionTab("Dance", new GameOption[] {
+ GameOption.DANCE_MOVER,
+ GameOption.DANCE_EXGON_DELAY,
+ GameOption.DANCE_QUAD_BEZ_AGGRESSIVENESS,
+ GameOption.DANCE_QUAD_BEZ_SLIDER_AGGRESSIVENESS_FACTOR,
+ GameOption.DANCE_QUAD_BEZ_USE_CUBIC_ON_SLIDERS,
+ GameOption.DANCE_QUAD_BEZ_CUBIC_AGGRESSIVENESS_FACTOR,
+ GameOption.DANCE_MOVER_DIRECTION,
+ GameOption.DANCE_SLIDER_MOVER_TYPE,
+ GameOption.DANCE_SPINNER,
+ GameOption.DANCE_SPINNER_DELAY,
+ GameOption.DANCE_LAZY_SLIDERS,
+ GameOption.DANCE_CIRCLE_STREAMS,
+ GameOption.DANCE_ONLY_CIRCLE_STACKS,
+ GameOption.DANCE_CIRLCE_IN_SLOW_SLIDERS,
+ GameOption.DANCE_CIRLCE_IN_LAZY_SLIDERS,
+ GameOption.DANCE_MIRROR,
+ }),
+ new OptionTab("Dance display", new GameOption[] {
+ GameOption.DANCE_DRAW_APPROACH,
+ GameOption.DANCE_OBJECT_COLOR_OVERRIDE,
+ GameOption.DANCE_OBJECT_COLOR_OVERRIDE_MIRRORED,
+ GameOption.DANCE_RGB_OBJECT_INC,
+ GameOption.DANCE_CURSOR_COLOR_OVERRIDE,
+ GameOption.DANCE_CURSOR_MIRROR_COLOR_OVERRIDE,
+ GameOption.DANCE_CURSOR_ONLY_COLOR_TRAIL,
+ GameOption.DANCE_RGB_CURSOR_INC,
+ GameOption.DANCE_CURSOR_TRAIL_OVERRIDE,
+ GameOption.DANCE_HIDE_OBJECTS,
+ GameOption.DANCE_HIDE_UI,
+ GameOption.DANCE_HIDE_WATERMARK,
+ }),
+ new OptionTab ("Pippi", new GameOption[] {
+ GameOption.PIPPI_ENABLE,
+ GameOption.PIPPI_RADIUS_PERCENT,
+ GameOption.PIPPI_ANGLE_INC_MUL,
+ GameOption.PIPPI_ANGLE_INC_MUL_SLIDER,
+ GameOption.PIPPI_SLIDER_FOLLOW_EXPAND,
+ GameOption.PIPPI_PREVENT_WOBBLY_STREAMS,
+ })
+ };
}
diff --git a/src/itdelatrisu/opsu/states/SongMenu.java b/src/itdelatrisu/opsu/states/SongMenu.java
index a0328350..d1b98ac6 100644
--- a/src/itdelatrisu/opsu/states/SongMenu.java
+++ b/src/itdelatrisu/opsu/states/SongMenu.java
@@ -22,7 +22,6 @@ import itdelatrisu.opsu.GameData;
import itdelatrisu.opsu.GameData.Grade;
import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.GameMod;
-import itdelatrisu.opsu.Opsu;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.ScoreData;
import itdelatrisu.opsu.Utils;
@@ -62,21 +61,17 @@ import java.nio.file.WatchEvent.Kind;
import java.util.Map;
import java.util.Stack;
-import org.lwjgl.opengl.Display;
import org.newdawn.slick.Animation;
import org.newdawn.slick.Color;
-import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.Input;
-import org.newdawn.slick.SlickException;
import org.newdawn.slick.SpriteSheet;
import org.newdawn.slick.gui.TextField;
-import org.newdawn.slick.state.BasicGameState;
-import org.newdawn.slick.state.StateBasedGame;
-import org.newdawn.slick.state.transition.EasedFadeOutTransition;
-import org.newdawn.slick.state.transition.EmptyTransition;
-import org.newdawn.slick.state.transition.FadeInTransition;
+import yugecin.opsudance.core.DisplayContainer;
+import yugecin.opsudance.core.inject.InstanceContainer;
+import yugecin.opsudance.core.state.ComplexOpsuState;
+import yugecin.opsudance.ui.OptionsOverlay;
/**
* "Song Selection" state.
@@ -84,7 +79,10 @@ import org.newdawn.slick.state.transition.FadeInTransition;
* Players are able to select a beatmap to play, view previous scores, choose game mods,
* manage beatmaps, or change game options from this state.
*/
-public class SongMenu extends BasicGameState {
+public class SongMenu extends ComplexOpsuState {
+
+ private final InstanceContainer instanceContainer;
+
/** The max number of song buttons to be shown on each screen. */
public static final int MAX_SONG_BUTTONS = 6;
@@ -169,7 +167,7 @@ public class SongMenu extends BasicGameState {
private MenuButton selectModsButton, selectRandomButton, selectMapOptionsButton, selectOptionsButton;
/** The search textfield. */
- private TextField search;
+ private TextField searchTextField;
/**
* Delay timer, in milliseconds, before running another search.
@@ -230,7 +228,7 @@ public class SongMenu extends BasicGameState {
} finally {
finished = true;
}
- };
+ }
/** Reloads all beatmaps. */
private void reloadBeatmaps() {
@@ -323,45 +321,41 @@ public class SongMenu extends BasicGameState {
/** Sort order dropdown menu. */
private DropdownMenu sortMenu;
- // game-related variables
- private GameContainer container;
- private StateBasedGame game;
- private Input input;
- private final int state;
+ private final OptionsOverlay optionsOverlay;
- public SongMenu(int state) {
- this.state = state;
+ public SongMenu(final DisplayContainer displayContainer, InstanceContainer instanceContainer) {
+ super(displayContainer);
+ this.instanceContainer = instanceContainer;
+ optionsOverlay = new OptionsOverlay(displayContainer, OptionsMenu.normalOptions, 0);
+ overlays.add(optionsOverlay);
}
@Override
- public void init(GameContainer container, StateBasedGame game)
- throws SlickException {
- this.container = container;
- this.game = game;
- this.input = container.getInput();
+ public void revalidate() {
+ super.revalidate();
- int width = container.getWidth();
- int height = container.getHeight();
+ components.clear();
// header/footer coordinates
- headerY = height * 0.0075f + GameImage.MENU_MUSICNOTE.getImage().getHeight() +
+ headerY = displayContainer.height * 0.0075f + GameImage.MENU_MUSICNOTE.getImage().getHeight() +
Fonts.BOLD.getLineHeight() + Fonts.DEFAULT.getLineHeight() +
Fonts.SMALL.getLineHeight();
- footerY = height - GameImage.SELECTION_MODS.getImage().getHeight();
+ footerY = displayContainer.height - GameImage.SELECTION_MODS.getImage().getHeight();
// footer logo coordinates
- float footerHeight = height - footerY;
+ float footerHeight = displayContainer.height - footerY;
footerLogoSize = footerHeight * 3.25f;
Image logo = GameImage.MENU_LOGO.getImage();
logo = logo.getScaledCopy(footerLogoSize / logo.getWidth());
- footerLogoButton = new MenuButton(logo, width - footerHeight * 0.8f, height - footerHeight * 0.65f);
+ footerLogoButton = new MenuButton(logo, displayContainer.width - footerHeight * 0.8f, displayContainer.height - footerHeight * 0.65f);
footerLogoButton.setHoverAnimationDuration(1);
footerLogoButton.setHoverExpand(1.2f);
// initialize sorts
- int sortWidth = (int) (width * 0.12f);
- sortMenu = new DropdownMenu(container, BeatmapSortOrder.values(),
- width * 0.87f, headerY - GameImage.MENU_TAB.getImage().getHeight() * 2.25f, sortWidth) {
+ int sortWidth = (int) (displayContainer.width * 0.12f);
+ int posX = (int) (displayContainer.width * 0.87f);
+ int posY = (int) (headerY - GameImage.MENU_TAB.getImage().getHeight() * 2.25f);
+ sortMenu = new DropdownMenu(displayContainer, BeatmapSortOrder.values(), posX, posY, sortWidth) {
@Override
public void itemSelected(int index, BeatmapSortOrder item) {
BeatmapSortOrder.set(item);
@@ -375,7 +369,7 @@ public class SongMenu extends BasicGameState {
}
@Override
- public boolean menuClicked(int index) {
+ public boolean canSelect(int index) {
if (isInputBlocked())
return false;
@@ -386,36 +380,40 @@ public class SongMenu extends BasicGameState {
sortMenu.setBackgroundColor(Colors.BLACK_BG_HOVER);
sortMenu.setBorderColor(Colors.BLUE_DIVIDER);
sortMenu.setChevronRightColor(Color.white);
+ components.add(sortMenu);
// initialize group tabs
for (BeatmapGroup group : BeatmapGroup.values())
- group.init(width, headerY - DIVIDER_LINE_WIDTH / 2);
+ group.init(displayContainer.width, headerY - DIVIDER_LINE_WIDTH / 2);
// initialize score data buttons
- ScoreData.init(width, headerY + height * 0.01f);
+ ScoreData.init(displayContainer.width, headerY + displayContainer.height * 0.01f);
// song button background & graphics context
Image menuBackground = GameImage.MENU_BUTTON_BG.getImage();
// song button coordinates
- buttonX = width * 0.6f;
+ buttonX = displayContainer.width * 0.6f;
//buttonY = headerY;
buttonWidth = menuBackground.getWidth();
buttonHeight = menuBackground.getHeight();
buttonOffset = (footerY - headerY - DIVIDER_LINE_WIDTH) / MAX_SONG_BUTTONS;
// search
- int textFieldX = (int) (width * 0.7125f + Fonts.BOLD.getWidth("Search: "));
+ int textFieldX = (int) (displayContainer.width * 0.7125f + Fonts.BOLD.getWidth("Search: "));
int textFieldY = (int) (headerY + Fonts.BOLD.getLineHeight() / 2);
- search = new TextField(
- container, Fonts.BOLD, textFieldX, textFieldY,
- (int) (width * 0.99f) - textFieldX, Fonts.BOLD.getLineHeight()
- );
- search.setBackgroundColor(Color.transparent);
- search.setBorderColor(Color.transparent);
- search.setTextColor(Color.white);
- search.setConsumeEvents(false);
- search.setMaxLength(60);
+ searchTextField = new TextField(displayContainer, Fonts.BOLD, textFieldX, textFieldY, (int) (displayContainer.width * 0.99f) - textFieldX, Fonts.BOLD.getLineHeight()) {
+ @Override
+ public boolean isFocusable() {
+ return false;
+ }
+ };
+ searchTextField.setBackgroundColor(Color.transparent);
+ searchTextField.setBorderColor(Color.transparent);
+ searchTextField.setTextColor(Color.white);
+ searchTextField.setMaxLength(60);
+ searchTextField.setFocused(true);
+ components.add(searchTextField);
// selection buttons
Image selectionMods = GameImage.SELECTION_MODS.getImage();
@@ -427,8 +425,8 @@ public class SongMenu extends BasicGameState {
if (selectButtonsWidth < 20) {
selectButtonsWidth = 100;
}
- float selectX = width * 0.183f + selectButtonsWidth / 2f;
- float selectY = height - selectButtonsHeight / 2f;
+ float selectX = displayContainer.width * 0.183f + selectButtonsWidth / 2f;
+ float selectY = displayContainer.height - selectButtonsHeight / 2f;
float selectOffset = selectButtonsWidth * 1.05f;
selectModsButton = new MenuButton(GameImage.SELECTION_MODS_OVERLAY.getImage(),
selectX, selectY);
@@ -449,33 +447,32 @@ public class SongMenu extends BasicGameState {
loader = new Animation(spr, 50);
// beatmap watch service listener
- final StateBasedGame game_ = game;
BeatmapWatchService.addListener(new BeatmapWatchServiceListener() {
@Override
public void eventReceived(Kind> kind, Path child) {
if (!songFolderChanged && kind != StandardWatchEventKinds.ENTRY_MODIFY) {
songFolderChanged = true;
- if (game_.getCurrentStateID() == Opsu.STATE_SONGMENU)
+ if (displayContainer.isInState(SongMenu.class)) {
UI.sendBarNotification("Changes in Songs folder detected. Hit F5 to refresh.");
+ }
}
}
});
// star stream
- starStream = new StarStream(width, (height - GameImage.STAR.getImage().getHeight()) / 2, -width, 0, MAX_STREAM_STARS);
- starStream.setPositionSpread(height / 20f);
+ starStream = new StarStream(displayContainer.width, (displayContainer.height - GameImage.STAR.getImage().getHeight()) / 2, -displayContainer.width, 0, MAX_STREAM_STARS);
+ starStream.setPositionSpread(displayContainer.height / 20f);
starStream.setDirectionSpread(10f);
}
@Override
- public void render(GameContainer container, StateBasedGame game, Graphics g)
- throws SlickException {
+ public void render(Graphics g) {
g.setBackground(Color.black);
- int width = container.getWidth();
- int height = container.getHeight();
- int mouseX = input.getMouseX(), mouseY = input.getMouseY();
- boolean inDropdownMenu = sortMenu.contains(mouseX, mouseY);
+ int width = displayContainer.width;
+ int height = displayContainer.height;
+ int mouseX = displayContainer.mouseX;
+ int mouseY = displayContainer.mouseY;
// background
if (focusNode != null) {
@@ -547,8 +544,9 @@ public class SongMenu extends BasicGameState {
g.clearClip();
// scroll bar
- if (focusScores.length > MAX_SCORE_BUTTONS && ScoreData.areaContains(mouseX, mouseY) && !inDropdownMenu)
+ if (focusScores.length > MAX_SCORE_BUTTONS && ScoreData.areaContains(mouseX, mouseY) && !isAnyComponentFocused()) {
ScoreData.drawScrollbar(g, startScorePos.getPosition(), focusScores.length * ScoreData.getButtonOffset());
+ }
}
// top/bottom bars
@@ -565,7 +563,7 @@ public class SongMenu extends BasicGameState {
Float position = MusicController.getBeatProgress();
if (position == null) // default to 60bpm
position = System.currentTimeMillis() % 1000 / 1000f;
- if (footerLogoButton.contains(mouseX, mouseY, 0.25f) && !inDropdownMenu) {
+ if (footerLogoButton.contains(mouseX, mouseY, 0.25f)) {
// hovering over logo: stop pulsing
footerLogoButton.draw();
} else {
@@ -658,7 +656,7 @@ public class SongMenu extends BasicGameState {
// group tabs
BeatmapGroup currentGroup = BeatmapGroup.current();
BeatmapGroup hoverGroup = null;
- if (!inDropdownMenu) {
+ if (!isAnyComponentFocused()) {
for (BeatmapGroup group : BeatmapGroup.values()) {
if (group.contains(mouseX, mouseY)) {
hoverGroup = group;
@@ -673,8 +671,9 @@ public class SongMenu extends BasicGameState {
currentGroup.draw(true, false);
// search
- boolean searchEmpty = search.getText().isEmpty();
- int searchX = search.getX(), searchY = search.getY();
+ boolean searchEmpty = searchTextField.getText().isEmpty();
+ int searchX = searchTextField.x;
+ int searchY = searchTextField.y;
float searchBaseX = width * 0.7f;
float searchTextX = width * 0.7125f;
float searchRectHeight = Fonts.BOLD.getLineHeight() * 2;
@@ -693,20 +692,15 @@ public class SongMenu extends BasicGameState {
g.fillRect(searchBaseX, headerY + DIVIDER_LINE_WIDTH / 2, width - searchBaseX, searchRectHeight);
Colors.BLACK_ALPHA.a = oldAlpha;
Fonts.BOLD.drawString(searchTextX, searchY, "Search:", Colors.GREEN_SEARCH);
- if (searchEmpty)
+ if (searchEmpty) {
Fonts.BOLD.drawString(searchX, searchY, "Type to search!", Color.white);
- else {
+ } else {
g.setColor(Color.white);
- // TODO: why is this needed to correctly position the TextField?
- search.setLocation(searchX - 3, searchY - 1);
- search.render(container, g);
- search.setLocation(searchX, searchY);
- Fonts.DEFAULT.drawString(searchTextX, searchY + Fonts.BOLD.getLineHeight(),
- (searchResultString == null) ? "Searching..." : searchResultString, Color.white);
+ searchTextField.render(g);
+ Fonts.DEFAULT.drawString(searchTextX, searchY + Fonts.BOLD.getLineHeight(), (searchResultString == null) ? "Searching..." : searchResultString, Color.white);
}
- // sorting options
- sortMenu.render(container, g);
+ sortMenu.render(g);
// reloading beatmaps
if (reloadThread != null) {
@@ -722,11 +716,15 @@ public class SongMenu extends BasicGameState {
UI.getBackButton().draw();
UI.draw(g);
+
+ super.render(g);
}
@Override
- public void update(GameContainer container, StateBasedGame game, int delta)
- throws SlickException {
+ public void preRenderUpdate() {
+ super.preRenderUpdate();
+
+ int delta = displayContainer.renderDelta;
UI.update(delta);
if (reloadThread == null)
MusicController.loopTrackIfEnded(true);
@@ -742,8 +740,8 @@ public class SongMenu extends BasicGameState {
MusicController.playThemeSong();
reloadThread = null;
}
- int mouseX = input.getMouseX(), mouseY = input.getMouseY();
- boolean inDropdownMenu = sortMenu.contains(mouseX, mouseY);
+ int mouseX = displayContainer.mouseX;
+ int mouseY = displayContainer.mouseY;
UI.getBackButton().hoverUpdate(delta, mouseX, mouseY);
selectModsButton.hoverUpdate(delta, mouseX, mouseY);
selectRandomButton.hoverUpdate(delta, mouseX, mouseY);
@@ -759,8 +757,8 @@ public class SongMenu extends BasicGameState {
if (focusNode != null) {
MenuState state = focusNode.getBeatmapSet().isFavorite() ?
MenuState.BEATMAP_FAVORITE : MenuState.BEATMAP;
- ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).setMenuState(state, focusNode);
- game.enterState(Opsu.STATE_BUTTONMENU);
+ instanceContainer.provide(ButtonMenu.class).setMenuState(state, focusNode);
+ displayContainer.switchState(ButtonMenu.class);
}
return;
}
@@ -782,7 +780,6 @@ public class SongMenu extends BasicGameState {
starStream.update(delta);
// search
- search.setFocus(true);
searchTimer += delta;
if (searchTimer >= SEARCH_DELAY && reloadThread == null && beatmapMenuTimer == -1) {
searchTimer = 0;
@@ -791,12 +788,12 @@ public class SongMenu extends BasicGameState {
if (focusNode != null)
oldFocusNode = new SongNode(BeatmapSetList.get().getBaseNode(focusNode.index), focusNode.beatmapIndex);
- if (BeatmapSetList.get().search(search.getText())) {
+ if (BeatmapSetList.get().search(searchTextField.getText())) {
// reset song stack
- randomStack = new Stack();
+ randomStack = new Stack<>();
// empty search
- if (search.getText().isEmpty())
+ if (searchTextField.getText().isEmpty())
searchResultString = null;
// search produced new list: re-initialize it
@@ -805,7 +802,7 @@ public class SongMenu extends BasicGameState {
focusScores = null;
if (BeatmapSetList.get().size() > 0) {
BeatmapSetList.get().init();
- if (search.getText().isEmpty()) { // cleared search
+ if (searchTextField.getText().isEmpty()) { // cleared search
// use previous start/focus if possible
if (oldFocusNode != null)
setFocus(oldFocusNode.getNode(), oldFocusNode.getIndex(), true, true);
@@ -818,7 +815,7 @@ public class SongMenu extends BasicGameState {
setFocus(BeatmapSetList.get().getRandomNode(), -1, true, true);
}
oldFocusNode = null;
- } else if (!search.getText().isEmpty())
+ } else if (!searchTextField.getText().isEmpty())
searchResultString = "No matches found. Hit ESC to reset.";
}
}
@@ -848,7 +845,7 @@ public class SongMenu extends BasicGameState {
// mouse hover
BeatmapSetNode node = getNodeAtPosition(mouseX, mouseY);
- if (node != null && !inDropdownMenu) {
+ if (node != null && !isAnyComponentFocused()) {
if (node == hoverIndex)
hoverOffset.update(delta);
else {
@@ -880,66 +877,65 @@ public class SongMenu extends BasicGameState {
}
@Override
- public int getID() { return state; }
+ public boolean mousePressed(int button, int x, int y) {
+ if (super.mousePressed(button, x, y)) {
+ return true;
+ }
- @Override
- public void mousePressed(int button, int x, int y) {
- // check mouse button
- if (button == Input.MOUSE_MIDDLE_BUTTON)
- return;
+ if (button == Input.MOUSE_MIDDLE_BUTTON) {
+ return false;
+ }
- if (isScrollingToFocusNode)
- return;
+ if (isScrollingToFocusNode) {
+ return true;
+ }
songScrolling.pressed();
startScorePos.pressed();
+ return true;
}
@Override
- public void mouseReleased(int button, int x, int y) {
- // check mouse button
- if (button == Input.MOUSE_MIDDLE_BUTTON)
- return;
+ public boolean mouseReleased(int button, int x, int y) {
+ if (super.mouseReleased(button, x, y)) {
+ return true;
+ }
- if (isScrollingToFocusNode)
- return;
+ if (button == Input.MOUSE_MIDDLE_BUTTON) {
+ return false;
+ }
+
+ if (isScrollingToFocusNode) {
+ return true;
+ }
songScrolling.released();
startScorePos.released();
- }
- @Override
- public void mouseClicked(int button, int x, int y, int clickCount) {
- // check mouse button
- if (button == Input.MOUSE_MIDDLE_BUTTON)
- return;
+ if (isInputBlocked()) {
+ return true;
+ }
- // block input
- if (isInputBlocked())
- return;
-
- // back
if (UI.getBackButton().contains(x, y)) {
SoundController.playSound(SoundEffect.MENUBACK);
- ((MainMenu) game.getState(Opsu.STATE_MAINMENU)).reset();
- game.enterState(Opsu.STATE_MAINMENU, new EasedFadeOutTransition(), new FadeInTransition());
- return;
+ displayContainer.switchState(MainMenu.class);
+ return true;
}
// selection buttons
if (selectModsButton.contains(x, y)) {
this.keyPressed(Input.KEY_F1, '\0');
- return;
+ return true;
} else if (selectRandomButton.contains(x, y)) {
this.keyPressed(Input.KEY_F2, '\0');
- return;
+ return true;
} else if (selectMapOptionsButton.contains(x, y)) {
this.keyPressed(Input.KEY_F3, '\0');
- return;
+ return true;
} else if (selectOptionsButton.contains(x, y)) {
SoundController.playSound(SoundEffect.MENUHIT);
- game.enterState(Opsu.STATE_OPTIONSMENU, new EmptyTransition(), new FadeInTransition());
- return;
+ optionsOverlay.show();
+ return true;
}
// group tabs
@@ -954,7 +950,7 @@ public class SongMenu extends BasicGameState {
songInfo = null;
scoreMap = null;
focusScores = null;
- search.setText("");
+ searchTextField.setText("");
searchTimer = SEARCH_DELAY;
searchTransitionTimer = SEARCH_TRANSITION_TIME;
searchResultString = null;
@@ -965,17 +961,18 @@ public class SongMenu extends BasicGameState {
if (BeatmapSetList.get().size() < 1 && group.getEmptyMessage() != null)
UI.sendBarNotification(group.getEmptyMessage());
}
- return;
+ return true;
}
}
- if (focusNode == null)
- return;
+ if (focusNode == null) {
+ return false;
+ }
// logo: start game
if (footerLogoButton.contains(x, y, 0.25f)) {
startGame();
- return;
+ return true;
}
// song buttons
@@ -1014,7 +1011,7 @@ public class SongMenu extends BasicGameState {
if (button == Input.MOUSE_RIGHT_BUTTON)
beatmapMenuTimer = (node.index == expandedIndex) ? BEATMAP_MENU_DELAY * 4 / 5 : 0;
- return;
+ return true;
}
// score buttons
@@ -1027,49 +1024,55 @@ public class SongMenu extends BasicGameState {
SoundController.playSound(SoundEffect.MENUHIT);
if (button != Input.MOUSE_RIGHT_BUTTON) {
// view score
- GameData data = new GameData(focusScores[rank], container.getWidth(), container.getHeight());
- ((GameRanking) game.getState(Opsu.STATE_GAMERANKING)).setGameData(data);
- game.enterState(Opsu.STATE_GAMERANKING, new EasedFadeOutTransition(), new FadeInTransition());
+ instanceContainer.provide(GameRanking.class).setGameData(new GameData(focusScores[rank], displayContainer.width, displayContainer.height));
+ displayContainer.switchState(GameRanking.class);
} else {
// score management
- ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).setMenuState(MenuState.SCORE, focusScores[rank]);
- game.enterState(Opsu.STATE_BUTTONMENU);
+ instanceContainer.provide(ButtonMenu.class).setMenuState(MenuState.SCORE, focusScores[rank]);
+ displayContainer.switchState(ButtonMenu.class);
}
- return;
+ return true;
}
}
}
+ return true;
}
@Override
- public void keyPressed(int key, char c) {
+ public boolean keyPressed(int key, char c) {
+ if (super.keyPressed(key, c)) {
+ return true;
+ }
+
// block input
- if ((reloadThread != null && !(key == Input.KEY_ESCAPE || key == Input.KEY_F12)) || beatmapMenuTimer > -1 || isScrollingToFocusNode)
- return;
+ if ((reloadThread != null && key != Input.KEY_ESCAPE) || beatmapMenuTimer > -1 || isScrollingToFocusNode) {
+ return true;
+ }
+
+ Input input = displayContainer.input;
switch (key) {
case Input.KEY_ESCAPE:
if (reloadThread != null) {
// beatmap reloading: stop parsing beatmaps by sending interrupt to BeatmapParser
reloadThread.interrupt();
- } else if (!search.getText().isEmpty()) {
+ } else if (!searchTextField.getText().isEmpty()) {
// clear search text
- search.setText("");
+ searchTextField.setText("");
searchTimer = SEARCH_DELAY;
searchTransitionTimer = 0;
searchResultString = null;
} else {
// return to main menu
SoundController.playSound(SoundEffect.MENUBACK);
- ((MainMenu) game.getState(Opsu.STATE_MAINMENU)).reset();
- game.enterState(Opsu.STATE_MAINMENU, new EasedFadeOutTransition(), new FadeInTransition());
+ displayContainer.switchState(MainMenu.class);
}
- break;
+ return true;
case Input.KEY_F1:
SoundController.playSound(SoundEffect.MENUHIT);
- ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).setMenuState(MenuState.MODS);
- game.enterState(Opsu.STATE_BUTTONMENU);
- break;
+ instanceContainer.provide(ButtonMenu.class).setMenuState(MenuState.MODS);
+ displayContainer.switchState(ButtonMenu.class);
+ return true;
case Input.KEY_F2:
if (focusNode == null)
break;
@@ -1089,25 +1092,25 @@ public class SongMenu extends BasicGameState {
randomStack.push(new SongNode(BeatmapSetList.get().getBaseNode(focusNode.index), focusNode.beatmapIndex));
setFocus(BeatmapSetList.get().getRandomNode(), -1, true, true);
}
- break;
+ return true;
case Input.KEY_F3:
if (focusNode == null)
break;
SoundController.playSound(SoundEffect.MENUHIT);
MenuState state = focusNode.getBeatmapSet().isFavorite() ?
MenuState.BEATMAP_FAVORITE : MenuState.BEATMAP;
- ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).setMenuState(state, focusNode);
- game.enterState(Opsu.STATE_BUTTONMENU);
- break;
+ instanceContainer.provide(ButtonMenu.class).setMenuState(state, focusNode);
+ displayContainer.switchState(ButtonMenu.class);
+ return true;
case Input.KEY_F5:
SoundController.playSound(SoundEffect.MENUHIT);
if (songFolderChanged)
reloadBeatmaps(false);
else {
- ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).setMenuState(MenuState.RELOAD);
- game.enterState(Opsu.STATE_BUTTONMENU);
+ instanceContainer.provide(ButtonMenu.class).setMenuState(MenuState.RELOAD);
+ displayContainer.switchState(ButtonMenu.class);
}
- break;
+ return true;
case Input.KEY_DELETE:
if (focusNode == null)
break;
@@ -1115,30 +1118,21 @@ public class SongMenu extends BasicGameState {
SoundController.playSound(SoundEffect.MENUHIT);
MenuState ms = (focusNode.beatmapIndex == -1 || focusNode.getBeatmapSet().size() == 1) ?
MenuState.BEATMAP_DELETE_CONFIRM : MenuState.BEATMAP_DELETE_SELECT;
- ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).setMenuState(ms, focusNode);
- game.enterState(Opsu.STATE_BUTTONMENU);
+ instanceContainer.provide(ButtonMenu.class).setMenuState(ms, focusNode);
+ displayContainer.switchState(ButtonMenu.class);
}
- break;
- case Input.KEY_F7:
- Options.setNextFPS(container);
- break;
- case Input.KEY_F10:
- Options.toggleMouseDisabled();
- break;
- case Input.KEY_F12:
- Utils.takeScreenShot();
- break;
+ return true;
case Input.KEY_ENTER:
if (focusNode == null)
break;
startGame();
- break;
+ return true;
case Input.KEY_DOWN:
changeIndex(1);
- break;
+ return true;
case Input.KEY_UP:
changeIndex(-1);
- break;
+ return true;
case Input.KEY_RIGHT:
if (focusNode == null)
break;
@@ -1154,7 +1148,7 @@ public class SongMenu extends BasicGameState {
hoverIndex = oldHoverIndex;
}
}
- break;
+ return true;
case Input.KEY_LEFT:
if (focusNode == null)
break;
@@ -1170,24 +1164,25 @@ public class SongMenu extends BasicGameState {
hoverIndex = oldHoverIndex;
}
}
- break;
+ return true;
case Input.KEY_NEXT:
changeIndex(MAX_SONG_BUTTONS);
- break;
+ return true;
case Input.KEY_PRIOR:
changeIndex(-MAX_SONG_BUTTONS);
- break;
+ return true;
case Input.KEY_O:
if (input.isKeyDown(Input.KEY_LCONTROL) || input.isKeyDown(Input.KEY_RCONTROL)) {
- game.enterState(Opsu.STATE_OPTIONSMENU, new EmptyTransition(), new FadeInTransition());
+ optionsOverlay.show();
}
- break;
+ return true;
default:
// wait for user to finish typing
// TODO: accept all characters (current conditions are from TextField class)
if ((c > 31 && c < 127) || key == Input.KEY_BACK) {
searchTimer = 0;
- int textLength = search.getText().length();
+ searchTextField.keyPressed(key, c);
+ int textLength = searchTextField.getText().length();
if (lastSearchTextLength != textLength) {
if (key == Input.KEY_BACK) {
if (textLength == 0)
@@ -1197,49 +1192,60 @@ public class SongMenu extends BasicGameState {
lastSearchTextLength = textLength;
}
}
- break;
+ return true;
}
+ return true;
}
@Override
- public void mouseDragged(int oldx, int oldy, int newx, int newy) {
- // block input
- if (isInputBlocked())
- return;
+ public boolean mouseDragged(int oldx, int oldy, int newx, int newy) {
+ if (super.mouseDragged(oldx, oldy, newx, newy)) {
+ return true;
+ }
+
+ if (isInputBlocked()) {
+ return true;
+ }
int diff = newy - oldy;
- if (diff == 0)
- return;
+ if (diff == 0) {
+ return false;
+ }
// check mouse button (right click scrolls faster on songs)
int multiplier;
- if (input.isMouseButtonDown(Input.MOUSE_RIGHT_BUTTON))
+ if (displayContainer.input.isMouseButtonDown(Input.MOUSE_RIGHT_BUTTON)) {
multiplier = 10;
- else if (input.isMouseButtonDown(Input.MOUSE_LEFT_BUTTON))
+ } else if (displayContainer.input.isMouseButtonDown(Input.MOUSE_LEFT_BUTTON)) {
multiplier = 1;
- else
- return;
+ } else {
+ return false;
+ }
- // score buttons
- if (focusScores != null && focusScores.length >= MAX_SCORE_BUTTONS && ScoreData.areaContains(oldx, oldy))
+ if (focusScores != null && focusScores.length >= MAX_SCORE_BUTTONS && ScoreData.areaContains(oldx, oldy)) {
startScorePos.dragged(-diff * multiplier);
-
- // song buttons
- else
+ } else {
songScrolling.dragged(-diff * multiplier);
+ }
+ return true;
}
@Override
- public void mouseWheelMoved(int newValue) {
- // change volume
- if (input.isKeyDown(Input.KEY_LALT) || input.isKeyDown(Input.KEY_RALT)) {
- UI.changeVolume((newValue < 0) ? -1 : 1);
- return;
+ public boolean mouseWheelMoved(int newValue) {
+ if (super.mouseWheelMoved(newValue)) {
+ return true;
}
- // block input
- if (isInputBlocked())
- return;
+ Input input = displayContainer.input;
+
+ if (input.isKeyDown(Input.KEY_LALT) || input.isKeyDown(Input.KEY_RALT)) {
+ UI.changeVolume((newValue < 0) ? -1 : 1);
+ return true;
+ }
+
+ if (isInputBlocked()) {
+ return true;
+ }
int shift = (newValue < 0) ? 1 : -1;
int mouseX = input.getMouseX(), mouseY = input.getMouseY();
@@ -1251,13 +1257,14 @@ public class SongMenu extends BasicGameState {
// song buttons
else
changeIndex(shift);
+ return false;
}
@Override
- public void enter(GameContainer container, StateBasedGame game)
- throws SlickException {
+ public void enter() {
+ super.enter();
+
UI.enter();
- Display.setTitle(game.getTitle());
selectModsButton.resetHover();
selectRandomButton.resetHover();
selectMapOptionsButton.resetHover();
@@ -1275,11 +1282,10 @@ public class SongMenu extends BasicGameState {
songChangeTimer.setTime(songChangeTimer.getDuration());
musicIconBounceTimer.setTime(musicIconBounceTimer.getDuration());
starStream.clear();
- sortMenu.activate();
sortMenu.reset();
// reset song stack
- randomStack = new Stack();
+ randomStack = new Stack<>();
// reload beatmaps if song folder changed
if (songFolderChanged && stateAction != MenuState.RELOAD)
@@ -1307,7 +1313,7 @@ public class SongMenu extends BasicGameState {
// reset game data
if (resetGame) {
- ((Game) game.getState(Opsu.STATE_GAME)).resetGameData();
+ instanceContainer.provide(Game.class).resetGameData();
// destroy extra Clips
MultiClip.destroyExtraClips();
@@ -1439,13 +1445,6 @@ public class SongMenu extends BasicGameState {
}
}
- @Override
- public void leave(GameContainer container, StateBasedGame game)
- throws SlickException {
- search.setFocus(false);
- sortMenu.deactivate();
- }
-
/**
* Shifts the startNode forward (+) or backwards (-) by a given number of nodes.
* Initiates sliding "animation" by shifting the button Y position.
@@ -1568,9 +1567,9 @@ public class SongMenu extends BasicGameState {
// change the focus node
if (changeStartNode || (startNode.index == 0 && startNode.beatmapIndex == -1 && startNode.prev == null)) {
- if (startNode == null || game.getCurrentStateID() != Opsu.STATE_SONGMENU)
+ if (startNode == null || displayContainer.isInState(SongMenu.class)) {
songScrolling.setPosition((node.index - 1) * buttonOffset);
- else {
+ } else {
isScrollingToFocusNode = true;
songScrolling.setSpeedMultiplier(2f);
songScrolling.released();
@@ -1703,7 +1702,7 @@ public class SongMenu extends BasicGameState {
songInfo = null;
hoverOffset.setTime(0);
hoverIndex = null;
- search.setText("");
+ searchTextField.setText("");
searchTimer = SEARCH_DELAY;
searchTransitionTimer = SEARCH_TRANSITION_TIME;
searchResultString = null;
@@ -1784,17 +1783,17 @@ public class SongMenu extends BasicGameState {
}
// turn on "auto" mod if holding "ctrl" key
- if (input.isKeyDown(Input.KEY_RCONTROL) || input.isKeyDown(Input.KEY_LCONTROL)) {
+ if (displayContainer.input.isKeyDown(Input.KEY_RCONTROL) || displayContainer.input.isKeyDown(Input.KEY_LCONTROL)) {
if (!GameMod.AUTO.isActive())
GameMod.AUTO.toggle(true);
}
SoundController.playSound(SoundEffect.MENUHIT);
MultiClip.destroyExtraClips();
- Game gameState = (Game) game.getState(Opsu.STATE_GAME);
+ Game gameState = instanceContainer.provide(Game.class);
gameState.loadBeatmap(beatmap);
gameState.setRestart(Game.Restart.NEW);
gameState.setReplay(null);
- game.enterState(Opsu.STATE_GAME, new EasedFadeOutTransition(), new FadeInTransition());
+ displayContainer.switchState(Game.class);
}
}
diff --git a/src/itdelatrisu/opsu/states/Splash.java b/src/itdelatrisu/opsu/states/Splash.java
index a0ea9963..c832408f 100644
--- a/src/itdelatrisu/opsu/states/Splash.java
+++ b/src/itdelatrisu/opsu/states/Splash.java
@@ -19,7 +19,6 @@
package itdelatrisu.opsu.states;
import itdelatrisu.opsu.GameImage;
-import itdelatrisu.opsu.Opsu;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.audio.MusicController;
@@ -36,19 +35,22 @@ import itdelatrisu.opsu.ui.animations.AnimationEquation;
import java.io.File;
import org.newdawn.slick.Color;
-import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
-import org.newdawn.slick.SlickException;
-import org.newdawn.slick.state.BasicGameState;
-import org.newdawn.slick.state.StateBasedGame;
+import org.newdawn.slick.util.Log;
+import yugecin.opsudance.core.DisplayContainer;
+import yugecin.opsudance.core.inject.InstanceContainer;
+import yugecin.opsudance.core.state.BaseOpsuState;
/**
* "Splash Screen" state.
*
* Loads game resources and enters "Main Menu" state.
*/
-public class Splash extends BasicGameState {
+public class Splash extends BaseOpsuState {
+
+ private final InstanceContainer instanceContainer;
+
/** Minimum time, in milliseconds, to display the splash screen (and fade in the logo). */
private static final int MIN_SPLASH_TIME = 400;
@@ -71,18 +73,16 @@ public class Splash extends BasicGameState {
private AnimatedValue logoAlpha;
// game-related variables
- private final int state;
- private GameContainer container;
private boolean init = false;
- public Splash(int state) {
- this.state = state;
+ public Splash(DisplayContainer displayContainer, InstanceContainer instanceContainer) {
+ super(displayContainer);
+ this.instanceContainer = instanceContainer;
}
@Override
- public void init(GameContainer container, StateBasedGame game)
- throws SlickException {
- this.container = container;
+ protected void revalidate() {
+ super.revalidate();
// check if skin changed
if (Options.getSkin() != null)
@@ -92,7 +92,7 @@ public class Splash extends BasicGameState {
this.watchServiceChange = Options.isWatchServiceEnabled() && BeatmapWatchService.get() == null;
// load Utils class first (needed in other 'init' methods)
- Utils.init(container, game);
+ Utils.init(displayContainer);
// fade in logo
this.logoAlpha = new AnimatedValue(MIN_SPLASH_TIME, 0f, 1f, AnimationEquation.LINEAR);
@@ -100,16 +100,14 @@ public class Splash extends BasicGameState {
}
@Override
- public void render(GameContainer container, StateBasedGame game, Graphics g)
- throws SlickException {
+ public void render(Graphics g) {
g.setBackground(Color.black);
- GameImage.MENU_LOGO.getImage().drawCentered(container.getWidth() / 2, container.getHeight() / 2);
+ GameImage.MENU_LOGO.getImage().drawCentered(displayContainer.width / 2, displayContainer.height / 2);
UI.drawLoadingProgress(g);
}
@Override
- public void update(GameContainer container, StateBasedGame game, int delta)
- throws SlickException {
+ public void preRenderUpdate() {
if (!init) {
init = true;
@@ -165,7 +163,7 @@ public class Splash extends BasicGameState {
}
// fade in logo
- if (logoAlpha.update(delta))
+ if (logoAlpha.update(displayContainer.renderDelta))
GameImage.MENU_LOGO.getImage().setAlpha(logoAlpha.getValue());
// change states when loading complete
@@ -173,33 +171,41 @@ public class Splash extends BasicGameState {
// initialize song list
if (BeatmapSetList.get().size() > 0) {
BeatmapSetList.get().init();
- if (Options.isThemeSongEnabled())
+ if (Options.isThemeSongEnabled()) {
MusicController.playThemeSong();
- else
- ((SongMenu) game.getState(Opsu.STATE_SONGMENU)).setFocus(BeatmapSetList.get().getRandomNode(), -1, true, true);
- }
-
- // play the theme song
- else
+ } else {
+ instanceContainer.provide(SongMenu.class).setFocus(BeatmapSetList.get().getRandomNode(), -1, true, true);
+ }
+ } else {
MusicController.playThemeSong();
-
- game.enterState(Opsu.STATE_MAINMENU);
+ }
+ displayContainer.switchState(MainMenu.class);
}
}
@Override
- public int getID() { return state; }
+ public boolean onCloseRequest() {
+ if (thread != null && thread.isAlive()) {
+ thread.interrupt();
+ try {
+ thread.join();
+ } catch (InterruptedException e) {
+ Log.warn("InterruptedException while waiting for splash thread to die", e);
+ }
+ }
+ return true;
+ }
@Override
- public void keyPressed(int key, char c) {
- if (key == Input.KEY_ESCAPE) {
- // close program
- if (++escapeCount >= 3)
- container.exit();
-
- // stop parsing beatmaps by sending interrupt to BeatmapParser
- else if (thread != null)
- thread.interrupt();
+ public boolean keyPressed(int key, char c) {
+ if (key != Input.KEY_ESCAPE) {
+ return false;
}
+ if (++escapeCount >= 3) {
+ displayContainer.exitRequested = true;
+ } else if (thread != null) {
+ thread.interrupt();
+ }
+ return true;
}
}
diff --git a/src/itdelatrisu/opsu/ui/Cursor.java b/src/itdelatrisu/opsu/ui/Cursor.java
index 7ad8171d..f5ad23bf 100644
--- a/src/itdelatrisu/opsu/ui/Cursor.java
+++ b/src/itdelatrisu/opsu/ui/Cursor.java
@@ -18,31 +18,22 @@
package itdelatrisu.opsu.ui;
-import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.GameImage;
-import itdelatrisu.opsu.Opsu;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.Utils;
-import itdelatrisu.opsu.audio.MusicController;
import itdelatrisu.opsu.skins.Skin;
import itdelatrisu.opsu.ui.animations.AnimationEquation;
import java.awt.Point;
-import java.nio.IntBuffer;
import java.util.LinkedList;
-import org.lwjgl.BufferUtils;
-import org.lwjgl.LWJGLException;
import org.newdawn.slick.*;
-import org.newdawn.slick.state.StateBasedGame;
import yugecin.opsudance.Dancer;
/**
* Updates and draws the cursor.
*/
public class Cursor {
- /** Empty cursor. */
- private static org.lwjgl.input.Cursor emptyCursor;
/** Last cursor coordinates. */
private Point lastPosition;
@@ -63,15 +54,10 @@ public class Cursor {
private static final float CURSOR_SCALE_TIME = 125;
/** Stores all previous cursor locations to display a trail. */
- private LinkedList trail = new LinkedList();
+ private LinkedList trail = new LinkedList<>();
private boolean newStyle;
- // game-related variables
- private static GameContainer container;
- private static StateBasedGame game;
- private static Input input;
-
public static Color lastObjColor = Color.white;
public static Color lastMirroredObjColor = Color.white;
public static Color nextObjColor = Color.white;
@@ -80,26 +66,6 @@ public class Cursor {
private boolean isMirrored;
- /**
- * Initializes the class.
- * @param container the game container
- * @param game the game object
- */
- public static void init(GameContainer container, StateBasedGame game) {
- Cursor.container = container;
- Cursor.game = game;
- Cursor.input = container.getInput();
-
- // create empty cursor to simulate hiding the cursor
- try {
- int min = org.lwjgl.input.Cursor.getMinCursorSize();
- IntBuffer tmp = BufferUtils.createIntBuffer(min * min);
- emptyCursor = new org.lwjgl.input.Cursor(min, min, min/2, min/2, 1, tmp, null);
- } catch (LWJGLException e) {
- ErrorHandler.error("Failed to create hidden cursor.", e, true);
- }
- }
-
/**
* Constructor.
*/
@@ -108,29 +74,15 @@ public class Cursor {
}
public Cursor(boolean isMirrored) {
- resetLocations();
+ resetLocations(0, 0);
this.isMirrored = isMirrored;
}
/**
* Draws the cursor.
- */
- public void draw() {
- int state = game.getCurrentStateID();
- boolean mousePressed =
- (((state == Opsu.STATE_GAME || state == Opsu.STATE_GAMEPAUSEMENU) && Utils.isGameKeyPressed()) ||
- ((input.isMouseButtonDown(Input.MOUSE_LEFT_BUTTON) || input.isMouseButtonDown(Input.MOUSE_RIGHT_BUTTON)) &&
- !(state == Opsu.STATE_GAME && Options.isMouseDisabled())));
- draw(input.getMouseX(), input.getMouseY(), mousePressed);
- }
-
- /**
- * Draws the cursor.
- * @param mouseX the mouse x coordinate
- * @param mouseY the mouse y coordinate
* @param mousePressed whether or not the mouse button is pressed
*/
- public void draw(int mouseX, int mouseY, boolean mousePressed) {
+ public void draw(boolean mousePressed) {
if (Options.isCursorDisabled())
return;
@@ -172,8 +124,6 @@ public class Cursor {
cursorTrail = cursorTrail.getScaledCopy(cursorScale);
}
- setCursorPosition(mouseX, mouseY);
-
Color filter;
if (isMirrored) {
filter = Dancer.cursorColorMirrorOverride.getMirrorColor();
@@ -195,16 +145,16 @@ public class Cursor {
cursorTrailWidth, cursorTrailHeight, cursorTrailRotation);
}
cursorTrail.drawEmbedded(
- mouseX - (cursorTrailWidth / 2f), mouseY - (cursorTrailHeight / 2f),
+ lastPosition.x - (cursorTrailWidth / 2f), lastPosition.y - (cursorTrailHeight / 2f),
cursorTrailWidth, cursorTrailHeight, cursorTrailRotation);
cursorTrail.endUse();
// draw the other components
if (newStyle && skin.isCursorRotated())
cursor.setRotation(cursorAngle);
- cursor.drawCentered(mouseX, mouseY, Options.isCursorOnlyColorTrail() ? Color.white : filter);
+ cursor.drawCentered(lastPosition.x, lastPosition.y, Options.isCursorOnlyColorTrail() ? Color.white : filter);
if (hasMiddle)
- cursorMiddle.drawCentered(mouseX, mouseY, Options.isCursorOnlyColorTrail() ? Color.white : filter);
+ cursorMiddle.drawCentered(lastPosition.x, lastPosition.y, Options.isCursorOnlyColorTrail() ? Color.white : filter);
}
/**
@@ -212,10 +162,10 @@ public class Cursor {
* @param mouseX x coordinate to set position to
* @param mouseY y coordinate to set position to
*/
- public void setCursorPosition(int mouseX, int mouseY) {
+ public void setCursorPosition(int delta, int mouseX, int mouseY) {
// TODO: use an image buffer
int removeCount = 0;
- float FPSmod = Math.max(container.getFPS(), 1) / 30f;
+ float FPSmod = Math.max(1000 / Math.max(delta, 1), 1) / 30f; // TODO
if (newStyle) {
// new style: add all points between cursor movements
if ((lastPosition.x == 0 && lastPosition.y == 0) || !addCursorPoints(lastPosition.x, lastPosition.y, mouseX, mouseY)) {
@@ -301,7 +251,7 @@ public class Cursor {
* If the old style cursor is being used, this will do nothing.
* @param delta the delta interval since the last call
*/
- public void update(int delta) {
+ public void updateAngle(int delta) {
cursorAngle += delta / 40f;
cursorAngle %= 360;
}
@@ -309,14 +259,14 @@ public class Cursor {
/**
* Resets all cursor data and beatmap skins.
*/
- public void reset() {
+ public void reset(int mouseX, int mouseY) {
// destroy skin images
GameImage.CURSOR.destroyBeatmapSkinImage();
GameImage.CURSOR_MIDDLE.destroyBeatmapSkinImage();
GameImage.CURSOR_TRAIL.destroyBeatmapSkinImage();
// reset locations
- resetLocations();
+ resetLocations(mouseX, mouseY);
// reset angles
cursorAngle = 0f;
@@ -325,14 +275,12 @@ public class Cursor {
/**
* Resets all cursor location data.
*/
- public void resetLocations() {
+ public void resetLocations(int mouseX, int mouseY) {
trail.clear();
- if (lastPosition != null) {
- for (int i = 0; i < 50; i++) {
- trail.add(new Point(lastPosition));
- }
+ lastPosition = new Point(mouseX, mouseY);
+ for (int i = 0; i < 50; i++) {
+ trail.add(new Point(lastPosition));
}
- lastPosition = new Point(0, 0);
}
/**
@@ -344,23 +292,4 @@ public class Cursor {
GameImage.CURSOR_TRAIL.hasBeatmapSkinImage());
}
- /**
- * Hides the cursor, if possible.
- */
- public void hide() {
- if (emptyCursor != null) {
- try {
- container.setMouseCursor(emptyCursor, 0, 0);
- } catch (SlickException e) {
- ErrorHandler.error("Failed to hide the cursor.", e, true);
- }
- }
- }
-
- /**
- * Unhides the cursor.
- */
- public void show() {
- container.setDefaultMouseCursor();
- }
}
diff --git a/src/itdelatrisu/opsu/ui/DropdownMenu.java b/src/itdelatrisu/opsu/ui/DropdownMenu.java
index 5204c257..095ead77 100644
--- a/src/itdelatrisu/opsu/ui/DropdownMenu.java
+++ b/src/itdelatrisu/opsu/ui/DropdownMenu.java
@@ -27,152 +27,62 @@ import org.newdawn.slick.Font;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.Input;
-import org.newdawn.slick.SlickException;
import org.newdawn.slick.UnicodeFont;
-import org.newdawn.slick.gui.AbstractComponent;
-import org.newdawn.slick.gui.GUIContext;
+import yugecin.opsudance.core.DisplayContainer;
+import yugecin.opsudance.core.components.Component;
+
+public class DropdownMenu extends Component {
-/**
- * Simple dropdown menu.
- *
- * Basic usage:
- *
- * - Override {@link #menuClicked(int)} to perform actions when the menu is clicked
- * (e.g. play a sound effect, block input under certain conditions).
- *
- Override {@link #itemSelected(int, Object)} to perform actions when a new item is selected.
- *
- Call {@link #activate()}/{@link #deactivate()} whenever the component is needed
- * (e.g. in a state's {@code enter} and {@code leave} events.
- *
- *
- * @param the type of the elements in the menu
- */
-public class DropdownMenu extends AbstractComponent {
- /** Padding ratios for drawing. */
private static final float PADDING_Y = 0.1f, CHEVRON_X = 0.03f;
- /** Whether this component is active. */
- private boolean active;
+ private final DisplayContainer displayContainer;
- /** The menu items. */
private E[] items;
-
- /** The menu item names. */
private String[] itemNames;
+ private int selectedItemIndex = 0;
+ private boolean expanded;
- /** The index of the selected item. */
- private int itemIndex = 0;
-
- /** Whether the menu is expanded. */
- private boolean expanded = false;
-
- /** The expanding animation progress. */
private AnimatedValue expandProgress = new AnimatedValue(300, 0f, 1f, AnimationEquation.LINEAR);
- /** The last update time, in milliseconds. */
- private long lastUpdateTime;
-
- /** The top-left coordinates. */
- private float x, y;
-
- /** The width and height of the dropdown menu. */
- private int width, height;
-
- /** The height of the base item. */
private int baseHeight;
-
- /** The vertical offset between items. */
private float offsetY;
- /** The colors to use. */
- private Color
- textColor = Color.white, backgroundColor = Color.black,
- highlightColor = Colors.BLUE_DIVIDER, borderColor = Colors.BLUE_DIVIDER,
- chevronDownColor = textColor, chevronRightColor = backgroundColor;
+ private Color textColor = Color.white;
+ private Color backgroundColor = Color.black;
+ private Color highlightColor = Colors.BLUE_DIVIDER;
+ private Color borderColor = Colors.BLUE_DIVIDER;
+ private Color chevronDownColor = textColor;
+ private Color chevronRightColor = backgroundColor;
- /** The fonts to use. */
- private UnicodeFont fontNormal = Fonts.MEDIUM, fontSelected = Fonts.MEDIUMBOLD;
+ private UnicodeFont fontNormal = Fonts.MEDIUM;
+ private UnicodeFont fontSelected = Fonts.MEDIUMBOLD;
- /** The chevron images. */
- private Image chevronDown, chevronRight;
+ private Image chevronDown;
+ private Image chevronRight;
- /** Should the next click be blocked? */
- private boolean blockClick = false;
-
- /**
- * Creates a new dropdown menu.
- * @param container the container rendering this menu
- * @param items the list of items (with names given as their {@code toString()} methods)
- * @param x the top-left x coordinate
- * @param y the top-left y coordinate
- */
- public DropdownMenu(GUIContext container, E[] items, float x, float y) {
- this(container, items, x, y, 0);
- }
-
- /**
- * Creates a new dropdown menu with the given fonts.
- * @param container the container rendering this menu
- * @param items the list of items (with names given as their {@code toString()} methods)
- * @param x the top-left x coordinate
- * @param y the top-left y coordinate
- * @param normal the normal font
- * @param selected the font for the selected item
- */
- public DropdownMenu(GUIContext container, E[] items, float x, float y, UnicodeFont normal, UnicodeFont selected) {
- this(container, items, x, y, 0, normal, selected);
- }
-
- /**
- * Creates a new dropdown menu with the given width.
- * @param container the container rendering this menu
- * @param items the list of items (with names given as their {@code toString()} methods)
- * @param x the top-left x coordinate
- * @param y the top-left y coordinate
- * @param width the menu width
- */
- public DropdownMenu(GUIContext container, E[] items, float x, float y, int width) {
- super(container);
+ public DropdownMenu(DisplayContainer displayContainer, E[] items, int x, int y, int width) {
+ this.displayContainer = displayContainer;
init(items, x, y, width);
}
- /**
- * Creates a new dropdown menu with the given width and fonts.
- * @param container the container rendering this menu
- * @param items the list of items (with names given as their {@code toString()} methods)
- * @param x the top-left x coordinate
- * @param y the top-left y coordinate
- * @param width the menu width
- * @param normal the normal font
- * @param selected the font for the selected item
- */
- public DropdownMenu(GUIContext container, E[] items, float x, float y, int width, UnicodeFont normal, UnicodeFont selected) {
- super(container);
- this.fontNormal = normal;
- this.fontSelected = selected;
- init(items, x, y, width);
- }
-
- /**
- * Returns the maximum item width from the list.
- */
private int getMaxItemWidth() {
int maxWidth = 0;
- for (int i = 0; i < itemNames.length; i++) {
- int w = fontSelected.getWidth(itemNames[i]);
- if (w > maxWidth)
+ for (String itemName : itemNames) {
+ int w = fontSelected.getWidth(itemName);
+ if (w > maxWidth) {
maxWidth = w;
+ }
}
return maxWidth;
}
- /**
- * Initializes the component.
- */
- private void init(E[] items, float x, float y, int width) {
+ @SuppressWarnings("SuspiciousNameCombination")
+ private void init(E[] items, int x, int y, int width) {
this.items = items;
this.itemNames = new String[items.length];
- for (int i = 0; i < itemNames.length; i++)
+ for (int i = 0; i < itemNames.length; i++) {
itemNames[i] = items[i].toString();
+ }
this.x = x;
this.y = y;
this.baseHeight = fontNormal.getLineHeight();
@@ -188,77 +98,27 @@ public class DropdownMenu extends AbstractComponent {
}
@Override
- public void setLocation(int x, int y) {
- this.x = x;
- this.y = y;
+ public void updateHover(int x, int y) {
+ this.hovered = this.x <= x && x <= this.x + width && this.y <= y && y <= this.y + (expanded ? height : baseHeight);
+ }
+
+ public boolean baseContains(int x, int y) {
+ return (x > this.x && x < this.x + width && y > this.y && y < this.y + baseHeight);
}
@Override
- public int getX() { return (int) x; }
+ public void render(Graphics g) {
+ int delta = displayContainer.renderDelta;
- @Override
- public int getY() { return (int) y; }
-
- @Override
- public int getWidth() { return width; }
-
- @Override
- public int getHeight() { return (expanded) ? height : baseHeight; }
-
- /** Activates the component. */
- public void activate() { this.active = true; }
-
- /** Deactivates the component. */
- public void deactivate() { this.active = false; }
-
- /**
- * Returns whether the dropdown menu is currently open.
- * @return true if open, false otherwise
- */
- public boolean isOpen() { return expanded; }
-
- /**
- * Opens or closes the dropdown menu.
- * @param flag true to open, false to close
- */
- public void open(boolean flag) { this.expanded = flag; }
-
- /**
- * Returns true if the coordinates are within the menu bounds.
- * @param cx the x coordinate
- * @param cy the y coordinate
- */
- public boolean contains(float cx, float cy) {
- return (cx > x && cx < x + width && (
- (cy > y && cy < y + baseHeight) ||
- (expanded && cy > y + offsetY && cy < y + height)));
- }
-
- /**
- * Returns true if the coordinates are within the base item bounds.
- * @param cx the x coordinate
- * @param cy the y coordinate
- */
- public boolean baseContains(float cx, float cy) {
- return (cx > x && cx < x + width && cy > y && cy < y + baseHeight);
- }
-
- @Override
- public void render(GUIContext container, Graphics g) throws SlickException {
// update animation
- long time = container.getTime();
- if (lastUpdateTime > 0) {
- int delta = (int) (time - lastUpdateTime);
- expandProgress.update((expanded) ? delta : -delta * 2);
- }
- this.lastUpdateTime = time;
+ expandProgress.update((expanded) ? delta : -delta * 2);
// get parameters
- Input input = container.getInput();
- int idx = getIndexAt(input.getMouseX(), input.getMouseY());
+ int idx = getIndexAt(displayContainer.mouseY);
float t = expandProgress.getValue();
- if (expanded)
+ if (expanded) {
t = AnimationEquation.OUT_CUBIC.calc(t);
+ }
// background and border
Color oldGColor = g.getColor();
@@ -293,12 +153,12 @@ public class DropdownMenu extends AbstractComponent {
// text
chevronDown.draw(x + width - chevronDown.getWidth() - width * CHEVRON_X, y + (baseHeight - chevronDown.getHeight()) / 2f, chevronDownColor);
- fontNormal.drawString(x + (width * 0.03f), y + (fontNormal.getPaddingTop() + fontNormal.getPaddingBottom()) / 2f, itemNames[itemIndex], textColor);
+ fontNormal.drawString(x + (width * 0.03f), y + (fontNormal.getPaddingTop() + fontNormal.getPaddingBottom()) / 2f, itemNames[selectedItemIndex], textColor);
float oldTextAlpha = textColor.a;
textColor.a *= t;
if (expanded || t >= 0.0001) {
for (int i = 0; i < itemNames.length; i++) {
- Font f = (i == itemIndex) ? fontSelected : fontNormal;
+ Font f = (i == selectedItemIndex) ? fontSelected : fontNormal;
if (i == idx && t >= 0.999)
chevronRight.draw(x, y + offsetY + (offsetY * i) + (offsetY - chevronRight.getHeight()) / 2f, chevronRightColor);
f.drawString(x + chevronRight.getWidth(), y + offsetY + (offsetY * i * t), itemNames[i], textColor);
@@ -310,131 +170,89 @@ public class DropdownMenu extends AbstractComponent {
/**
* Returns the index of the item at the given location, -1 for the base item,
* and -2 if there is no item at the location.
- * @param cx the x coordinate
- * @param cy the y coordinate
+ * @param y the y coordinate
*/
- private int getIndexAt(float cx, float cy) {
- if (!contains(cx, cy))
+ private int getIndexAt(int y) {
+ if (!hovered) {
return -2;
- if (cy <= y + baseHeight)
+ }
+ if (y <= this.y + baseHeight) {
return -1;
- if (!expanded)
+ }
+ if (!expanded) {
return -2;
- return (int) ((cy - (y + offsetY)) / offsetY);
+ }
+ return (int) ((y - (this.y + offsetY)) / offsetY);
}
- /**
- * Resets the menu state.
- */
public void reset() {
this.expanded = false;
- this.lastUpdateTime = 0;
expandProgress.setTime(0);
- blockClick = false;
+ }
+
+
+ @Override
+ public void setFocused(boolean focused) {
+ super.setFocused(focused);
+ expanded = focused;
}
@Override
- public void mousePressed(int button, int x, int y) {
- if (!active)
- return;
+ public boolean isFocusable() {
+ return true;
+ }
- if (button == Input.MOUSE_MIDDLE_BUTTON)
- return;
+ @Override
+ public void mouseReleased(int button) {
+ super.mouseReleased(button);
- int idx = getIndexAt(x, y);
+ if (button == Input.MOUSE_MIDDLE_BUTTON) {
+ return;
+ }
+
+ int idx = getIndexAt(displayContainer.mouseY);
if (idx == -2) {
this.expanded = false;
return;
}
- if (!menuClicked(idx))
+ if (!canSelect(selectedItemIndex)) {
return;
- this.expanded = (idx == -1) ? !expanded : false;
- if (idx >= 0 && itemIndex != idx) {
- this.itemIndex = idx;
- itemSelected(idx, items[idx]);
}
- blockClick = true;
- consumeEvent();
- }
-
- @Override
- public void mouseClicked(int button, int x, int y, int clickCount) {
- if (!active)
- return;
-
- if (blockClick) {
- blockClick = false;
- consumeEvent();
+ this.expanded = (idx == -1) && !expanded;
+ if (idx >= 0 && selectedItemIndex != idx) {
+ this.selectedItemIndex = idx;
+ itemSelected(idx, items[selectedItemIndex]);
}
}
- /**
- * Notification that a new item was selected (via override).
- * @param index the index of the item selected
- * @param item the item selected
- */
- public void itemSelected(int index, E item) {}
-
- /**
- * Notification that the menu was clicked (via override).
- * @param index the index of the item clicked, or -1 for the base item
- * @return true to process the click, or false to block/intercept it
- */
- public boolean menuClicked(int index) { return true; }
-
- @Override
- public void setFocus(boolean focus) { /* does not currently use the "focus" concept */ }
-
- @Override
- public void mouseReleased(int button, int x, int y) { /* does not currently use the "focus" concept */ }
-
- /**
- * Selects the item at the given index.
- * @param index the list item index
- * @throws IllegalArgumentException if {@code index} is negative or greater than or equal to size
- */
- public void setSelectedIndex(int index) {
- if (index < 0 || index >= items.length)
- throw new IllegalArgumentException();
- this.itemIndex = index;
+ protected boolean canSelect(int index) {
+ return true;
}
- /**
- * Returns the index of the selected item.
- */
- public int getSelectedIndex() { return itemIndex; }
+ protected void itemSelected(int index, E item) {
+ }
- /**
- * Returns the selected item.
- */
- public E getSelectedItem() { return items[itemIndex]; }
+ public E getSelectedItem() {
+ return items[selectedItemIndex];
+ }
- /**
- * Returns the item at the given index.
- * @param index the list item index
- */
- public E getItemAt(int index) { return items[index]; }
+ public void setBackgroundColor(Color c) {
+ this.backgroundColor = c;
+ }
- /**
- * Returns the number of items in the list.
- */
- public int getItemCount() { return items.length; }
+ public void setHighlightColor(Color c) {
+ this.highlightColor = c;
+ }
- /** Sets the text color. */
- public void setTextColor(Color c) { this.textColor = c; }
+ public void setBorderColor(Color c) {
+ this.borderColor = c;
+ }
- /** Sets the background color. */
- public void setBackgroundColor(Color c) { this.backgroundColor = c; }
+ public void setChevronDownColor(Color c) {
+ this.chevronDownColor = c;
+ }
- /** Sets the highlight color. */
- public void setHighlightColor(Color c) { this.highlightColor = c; }
-
- /** Sets the border color. */
- public void setBorderColor(Color c) { this.borderColor = c; }
-
- /** Sets the down chevron color. */
- public void setChevronDownColor(Color c) { this.chevronDownColor = c; }
-
- /** Sets the right chevron color. */
- public void setChevronRightColor(Color c) { this.chevronRightColor = c; }
+ public void setChevronRightColor(Color c) {
+ this.chevronRightColor = c;
+ }
}
diff --git a/src/itdelatrisu/opsu/ui/UI.java b/src/itdelatrisu/opsu/ui/UI.java
index b58b7002..f2d7f65d 100644
--- a/src/itdelatrisu/opsu/ui/UI.java
+++ b/src/itdelatrisu/opsu/ui/UI.java
@@ -18,7 +18,6 @@
package itdelatrisu.opsu.ui;
-import itdelatrisu.opsu.ErrorHandler;
import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.Utils;
@@ -29,23 +28,16 @@ import itdelatrisu.opsu.replay.ReplayImporter;
import itdelatrisu.opsu.ui.animations.AnimatedValue;
import itdelatrisu.opsu.ui.animations.AnimationEquation;
-import javax.swing.JOptionPane;
-import javax.swing.UIManager;
-
import org.newdawn.slick.Animation;
import org.newdawn.slick.Color;
-import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
-import org.newdawn.slick.Input;
-import org.newdawn.slick.state.StateBasedGame;
+import yugecin.opsudance.core.DisplayContainer;
/**
* Draws common UI components.
*/
public class UI {
- /** Cursor. */
- private static Cursor cursor = new Cursor();
/** Back button. */
private static MenuButton backButton;
@@ -75,32 +67,24 @@ public class UI {
private static AnimatedValue tooltipAlpha = new AnimatedValue(200, 0f, 1f, AnimationEquation.LINEAR);
// game-related variables
- private static GameContainer container;
- private static Input input;
+ private static DisplayContainer displayContainer;
// This class should not be instantiated.
private UI() {}
/**
* Initializes UI data.
- * @param container the game container
- * @param game the game object
*/
- public static void init(GameContainer container, StateBasedGame game) {
- UI.container = container;
- UI.input = container.getInput();
-
- // initialize cursor
- Cursor.init(container, game);
- cursor.hide();
+ public static void init(DisplayContainer displayContainer) {
+ UI.displayContainer = displayContainer;
// back button
if (GameImage.MENU_BACK.getImages() != null) {
Animation back = GameImage.MENU_BACK.getAnimation(120);
- backButton = new MenuButton(back, back.getWidth() / 2f, container.getHeight() - (back.getHeight() / 2f));
+ backButton = new MenuButton(back, back.getWidth() / 2f, displayContainer.height - (back.getHeight() / 2f));
} else {
Image back = GameImage.MENU_BACK.getImage();
- backButton = new MenuButton(back, back.getWidth() / 2f, container.getHeight() - (back.getHeight() / 2f));
+ backButton = new MenuButton(back, back.getWidth() / 2f, displayContainer.height - (back.getHeight() / 2f));
}
backButton.setHoverAnimationDuration(350);
backButton.setHoverAnimationEquation(AnimationEquation.IN_OUT_BACK);
@@ -112,7 +96,6 @@ public class UI {
* @param delta the delta interval since the last call.
*/
public static void update(int delta) {
- cursor.update(delta);
updateVolumeDisplay(delta);
updateBarNotification(delta);
tooltipAlpha.update(-delta);
@@ -125,24 +108,6 @@ public class UI {
public static void draw(Graphics g) {
drawBarNotification(g);
drawVolume(g);
- drawFPS();
- cursor.draw();
- drawTooltip(g);
- }
-
- /**
- * Draws the global UI components: cursor, FPS, volume bar, tooltips, bar notifications.
- * @param g the graphics context
- * @param mouseX the mouse x coordinate
- * @param mouseY the mouse y coordinate
- * @param mousePressed whether or not the mouse button is pressed
- */
- public static void draw(Graphics g, int mouseX, int mouseY, boolean mousePressed) {
- drawBarNotification(g);
- drawVolume(g);
- drawFPS();
- cursor.draw(mouseX, mouseY, mousePressed);
- drawTooltip(g);
}
/**
@@ -150,16 +115,10 @@ public class UI {
*/
public static void enter() {
backButton.resetHover();
- cursor.resetLocations();
resetBarNotification();
resetTooltip();
}
- /**
- * Returns the game cursor.
- */
- public static Cursor getCursor() { return cursor; }
-
/**
* Returns the 'menu-back' MenuButton.
*/
@@ -189,27 +148,6 @@ public class UI {
Fonts.MEDIUM.drawString(tabTextX, tabTextY, text, textColor);
}
- /**
- * Draws the FPS at the bottom-right corner of the game container.
- * If the option is not activated, this will do nothing.
- */
- public static void drawFPS() {
- if (!Options.isFPSCounterEnabled())
- return;
-
- String fps = String.format("%dFPS", container.getFPS());
- Fonts.BOLD.drawString(
- container.getWidth() * 0.997f - Fonts.BOLD.getWidth(fps),
- container.getHeight() * 0.997f - Fonts.BOLD.getHeight(fps),
- Integer.toString(container.getFPS()), Color.white
- );
- Fonts.DEFAULT.drawString(
- container.getWidth() * 0.997f - Fonts.BOLD.getWidth("FPS"),
- container.getHeight() * 0.997f - Fonts.BOLD.getHeight("FPS"),
- "FPS", Color.white
- );
- }
-
/**
* Draws the volume bar on the middle right-hand side of the game container.
* Only draws if the volume has recently been changed using with {@link #changeVolume(int)}.
@@ -219,7 +157,6 @@ public class UI {
if (volumeDisplay == -1)
return;
- int width = container.getWidth(), height = container.getHeight();
Image img = GameImage.VOLUME.getImage();
// move image in/out
@@ -230,13 +167,13 @@ public class UI {
else if (ratio >= 0.9f)
xOffset = img.getWidth() * (1 - ((1 - ratio) * 10f));
- img.drawCentered(width - img.getWidth() / 2f + xOffset, height / 2f);
+ img.drawCentered(displayContainer.width - img.getWidth() / 2f + xOffset, displayContainer.height / 2f);
float barHeight = img.getHeight() * 0.9f;
float volume = Options.getMasterVolume();
g.setColor(Color.white);
g.fillRoundRect(
- width - (img.getWidth() * 0.368f) + xOffset,
- (height / 2f) - (img.getHeight() * 0.47f) + (barHeight * (1 - volume)),
+ displayContainer.width - (img.getWidth() * 0.368f) + xOffset,
+ (displayContainer.height / 2f) - (img.getHeight() * 0.47f) + (barHeight * (1 - volume)),
img.getWidth() * 0.15f, barHeight * volume, 3
);
}
@@ -260,7 +197,7 @@ public class UI {
*/
public static void changeVolume(int units) {
final float UNIT_OFFSET = 0.05f;
- Options.setMasterVolume(container, Utils.clamp(Options.getMasterVolume() + (UNIT_OFFSET * units), 0f, 1f));
+ Options.setMasterVolume(Utils.clamp(Options.getMasterVolume() + (UNIT_OFFSET * units), 0f, 1f));
if (volumeDisplay == -1)
volumeDisplay = 0;
else if (volumeDisplay >= VOLUME_DISPLAY_TIME / 10)
@@ -294,8 +231,8 @@ public class UI {
return;
// draw loading info
- float marginX = container.getWidth() * 0.02f, marginY = container.getHeight() * 0.02f;
- float lineY = container.getHeight() - marginY;
+ float marginX = displayContainer.width * 0.02f, marginY = displayContainer.height * 0.02f;
+ float lineY = displayContainer.height - marginY;
int lineOffsetY = Fonts.MEDIUM.getLineHeight();
if (Options.isLoadVerbose()) {
// verbose: display percentages and file names
@@ -308,7 +245,7 @@ public class UI {
Fonts.MEDIUM.drawString(marginX, lineY - (lineOffsetY * 2), text, Color.white);
g.setColor(Color.white);
g.fillRoundRect(marginX, lineY - (lineOffsetY / 2f),
- (container.getWidth() - (marginX * 2f)) * progress / 100f, lineOffsetY / 4f, 4
+ (displayContainer.width - (marginX * 2f)) * progress / 100f, lineOffsetY / 4f, 4
);
}
}
@@ -332,7 +269,7 @@ public class UI {
float unitBaseX, float unitBaseY, float unitWidth, float scrollAreaHeight,
Color bgColor, Color scrollbarColor, boolean right
) {
- float scrollbarWidth = container.getWidth() * 0.00347f;
+ float scrollbarWidth = displayContainer.width * 0.00347f;
float scrollbarHeight = scrollAreaHeight * lengthShown / totalLength;
float offsetY = (scrollAreaHeight - scrollbarHeight) * (position / (totalLength - lengthShown));
float scrollbarX = unitBaseX + unitWidth - ((right) ? scrollbarWidth : 0);
@@ -368,8 +305,7 @@ public class UI {
if (tooltipAlpha.getTime() == 0 || tooltip == null)
return;
- int containerWidth = container.getWidth(), containerHeight = container.getHeight();
- int margin = containerWidth / 100, textMarginX = 2;
+ int margin = displayContainer.width / 100, textMarginX = 2;
int offset = GameImage.CURSOR_MIDDLE.getImage().getWidth() / 2;
int lineHeight = Fonts.SMALL.getLineHeight();
int textWidth = textMarginX * 2, textHeight = lineHeight;
@@ -387,13 +323,14 @@ public class UI {
textWidth += Fonts.SMALL.getWidth(tooltip);
// get drawing coordinates
- int x = input.getMouseX() + offset, y = input.getMouseY() + offset;
- if (x + textWidth > containerWidth - margin)
- x = containerWidth - margin - textWidth;
+ int x = displayContainer.mouseX + offset;
+ int y = displayContainer.mouseY + offset;
+ if (x + textWidth > displayContainer.width - margin)
+ x = displayContainer.width - margin - textWidth;
else if (x < margin)
x = margin;
- if (y + textHeight > containerHeight - margin)
- y = containerHeight - margin - textHeight;
+ if (y + textHeight > displayContainer.height - margin)
+ y = displayContainer.height - margin - textHeight;
else if (y < margin)
y = margin;
@@ -467,13 +404,13 @@ public class UI {
float alpha = 1f;
if (barNotifTimer >= BAR_NOTIFICATION_TIME * 0.9f)
alpha -= 1 - ((BAR_NOTIFICATION_TIME - barNotifTimer) / (BAR_NOTIFICATION_TIME * 0.1f));
- int midX = container.getWidth() / 2, midY = container.getHeight() / 2;
+ int midX = displayContainer.width / 2, midY = displayContainer.height / 2;
float barHeight = Fonts.LARGE.getLineHeight() * (1f + 0.6f * Math.min(barNotifTimer * 15f / BAR_NOTIFICATION_TIME, 1f));
float oldAlphaB = Colors.BLACK_ALPHA.a, oldAlphaW = Colors.WHITE_ALPHA.a;
Colors.BLACK_ALPHA.a *= alpha;
Colors.WHITE_ALPHA.a = alpha;
g.setColor(Colors.BLACK_ALPHA);
- g.fillRect(0, midY - barHeight / 2f, container.getWidth(), barHeight);
+ g.fillRect(0, midY - barHeight / 2f, displayContainer.width, barHeight);
Fonts.LARGE.drawString(
midX - Fonts.LARGE.getWidth(barNotif) / 2f,
midY - Fonts.LARGE.getLineHeight() / 2.2f,
@@ -482,19 +419,4 @@ public class UI {
Colors.WHITE_ALPHA.a = oldAlphaW;
}
- /**
- * Shows a confirmation dialog (used before exiting the game).
- * @param message the message to display
- * @return true if user selects "yes", false otherwise
- */
- public static boolean showExitConfirmation(String message) {
- try {
- UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
- } catch (Exception e) {
- ErrorHandler.error("Could not set system look and feel for exit confirmation.", e, true);
- }
- int n = JOptionPane.showConfirmDialog(null, message, "Warning",
- JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
- return (n != JOptionPane.YES_OPTION);
- }
}
diff --git a/src/org/newdawn/slick/GameContainer.java b/src/org/newdawn/slick/GameContainer.java
deleted file mode 100644
index 01c7604f..00000000
--- a/src/org/newdawn/slick/GameContainer.java
+++ /dev/null
@@ -1,907 +0,0 @@
-/*
- * Copyright (c) 2013, Slick2D
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * - Neither the name of the Slick2D nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-package org.newdawn.slick;
-
-import java.io.IOException;
-import java.util.Properties;
-
-import org.lwjgl.LWJGLException;
-import org.lwjgl.Sys;
-import org.lwjgl.input.Cursor;
-import org.lwjgl.opengl.Display;
-import org.lwjgl.opengl.Drawable;
-import org.lwjgl.opengl.Pbuffer;
-import org.lwjgl.opengl.PixelFormat;
-import org.newdawn.slick.gui.GUIContext;
-import org.newdawn.slick.openal.SoundStore;
-import org.newdawn.slick.opengl.CursorLoader;
-import org.newdawn.slick.opengl.ImageData;
-import org.newdawn.slick.opengl.renderer.Renderer;
-import org.newdawn.slick.opengl.renderer.SGL;
-import org.newdawn.slick.util.Log;
-import org.newdawn.slick.util.ResourceLoader;
-
-/**
- * A generic game container that handles the game loop, fps recording and
- * managing the input system
- *
- * @author kevin
- */
-public abstract class GameContainer implements GUIContext {
- /** The renderer to use for all GL operations */
- protected static SGL GL = Renderer.get();
- /** The shared drawable if any */
- protected static Drawable SHARED_DRAWABLE;
-
- /** The time the last frame was rendered */
- protected long lastFrame;
- /** The last time the FPS recorded */
- protected long lastFPS;
- /** The last recorded FPS */
- protected int recordedFPS;
- /** The current count of FPS */
- protected int fps;
- /** True if we're currently running the game loop */
- protected boolean running = true;
-
- /** The width of the display */
- protected int width;
- /** The height of the display */
- protected int height;
- /** The game being managed */
- protected Game game;
-
- /** The default font to use in the graphics context */
- private Font defaultFont;
- /** The graphics context to be passed to the game */
- private Graphics graphics;
-
- /** The input system to pass to the game */
- protected Input input;
- /** The FPS we want to lock to */
- protected int targetFPS = -1;
- /** True if we should show the fps */
- private boolean showFPS = true;
- /** The minimum logic update interval */
- protected long minimumLogicInterval = 1;
- /** The stored delta */
- protected long storedDelta;
- /** The maximum logic update interval */
- protected long maximumLogicInterval = 0;
- /** The last game started */
- protected Game lastGame;
- /** True if we should clear the screen each frame */
- protected boolean clearEachFrame = true;
-
- /** True if the game is paused */
- protected boolean paused;
- /** True if we should force exit */
- protected boolean forceExit = true;
- /** True if vsync has been requested */
- protected boolean vsync;
- /** Smoothed deltas requested */
- protected boolean smoothDeltas;
- /** The number of samples we'll attempt through hardware */
- protected int samples;
-
- /** True if this context supports multisample */
- protected boolean supportsMultiSample;
-
- /** True if we should render when not focused */
- protected boolean alwaysRender;
- /** True if we require stencil bits */
- protected static boolean stencil;
-
- /**
- * Create a new game container wrapping a given game
- *
- * @param game The game to be wrapped
- */
- protected GameContainer(Game game) {
- this.game = game;
- lastFrame = getTime();
-
- getBuildVersion();
- Log.checkVerboseLogSetting();
- }
-
- public static void enableStencil() {
- stencil = true;
- }
-
- /**
- * Set the default font that will be intialised in the graphics held in this container
- *
- * @param font The font to use as default
- */
- public void setDefaultFont(Font font) {
- if (font != null) {
- this.defaultFont = font;
- } else {
- Log.warn("Please provide a non null font");
- }
- }
-
- /**
- * Indicate whether we want to try to use fullscreen multisampling. This will
- * give antialiasing across the whole scene using a hardware feature.
- *
- * @param samples The number of samples to attempt (2 is safe)
- */
- public void setMultiSample(int samples) {
- this.samples = samples;
- }
-
- /**
- * Check if this hardware can support multi-sampling
- *
- * @return True if the hardware supports multi-sampling
- */
- public boolean supportsMultiSample() {
- return supportsMultiSample;
- }
-
- /**
- * The number of samples we're attempting to performing using
- * hardware multisampling
- *
- * @return The number of samples requested
- */
- public int getSamples() {
- return samples;
- }
-
- /**
- * Indicate if we should force exitting the VM at the end
- * of the game (default = true)
- *
- * @param forceExit True if we should force the VM exit
- */
- public void setForceExit(boolean forceExit) {
- this.forceExit = forceExit;
- }
-
- /**
- * Indicate if we want to smooth deltas. This feature will report
- * a delta based on the FPS not the time passed. This works well with
- * vsync.
- *
- * @param smoothDeltas True if we should report smooth deltas
- */
- public void setSmoothDeltas(boolean smoothDeltas) {
- this.smoothDeltas = smoothDeltas;
- }
-
- /**
- * Check if the display is in fullscreen mode
- *
- * @return True if the display is in fullscreen mode
- */
- public boolean isFullscreen() {
- return false;
- }
-
- /**
- * Get the aspect ratio of the screen
- *
- * @return The aspect ratio of the display
- */
- public float getAspectRatio() {
- return getWidth() / getHeight();
- }
-
- /**
- * Indicate whether we want to be in fullscreen mode. Note that the current
- * display mode must be valid as a fullscreen mode for this to work
- *
- * @param fullscreen True if we want to be in fullscreen mode
- * @throws SlickException Indicates we failed to change the display mode
- */
- public void setFullscreen(boolean fullscreen) throws SlickException {
- }
-
- /**
- * Enable shared OpenGL context. After calling this all containers created
- * will shared a single parent context
- *
- * @throws SlickException Indicates a failure to create the shared drawable
- */
- public static void enableSharedContext() throws SlickException {
- try {
- SHARED_DRAWABLE = new Pbuffer(64, 64, new PixelFormat(8, 0, 0), null);
- } catch (LWJGLException e) {
- throw new SlickException("Unable to create the pbuffer used for shard context, buffers not supported", e);
- }
- }
-
- /**
- * Get the context shared by all containers
- *
- * @return The context shared by all the containers or null if shared context isn't enabled
- */
- public static Drawable getSharedContext() {
- return SHARED_DRAWABLE;
- }
-
- /**
- * Indicate if we should clear the screen at the beginning of each frame. If you're
- * rendering to the whole screen each frame then setting this to false can give
- * some performance improvements
- *
- * @param clear True if the the screen should be cleared each frame
- */
- public void setClearEachFrame(boolean clear) {
- this.clearEachFrame = clear;
- }
-
- /**
- * Renitialise the game and the context in which it's being rendered
- *
- * @throws SlickException Indicates a failure rerun initialisation routines
- */
- public void reinit() throws SlickException {
- }
-
- /**
- * Pause the game - i.e. suspend updates
- */
- public void pause()
- {
- setPaused(true);
- }
-
- /**
- * Resumt the game - i.e. continue updates
- */
- public void resume()
- {
- setPaused(false);
- }
-
- /**
- * Check if the container is currently paused.
- *
- * @return True if the container is paused
- */
- public boolean isPaused() {
- return paused;
- }
-
- /**
- * Indicates if the game should be paused, i.e. if updates
- * should be propogated through to the game.
- *
- * @param paused True if the game should be paused
- */
- public void setPaused(boolean paused)
- {
- this.paused = paused;
- }
-
- /**
- * True if this container should render when it has focus
- *
- * @return True if this container should render when it has focus
- */
- public boolean getAlwaysRender () {
- return alwaysRender;
- }
-
- /**
- * Indicate whether we want this container to render when it has focus
- *
- * @param alwaysRender True if this container should render when it has focus
- */
- public void setAlwaysRender (boolean alwaysRender) {
- this.alwaysRender = alwaysRender;
- }
-
- /**
- * Get the build number of slick
- *
- * @return The build number of slick
- */
- public static int getBuildVersion() {
- try {
- Properties props = new Properties();
- props.load(ResourceLoader.getResourceAsStream("version"));
-
- int build = Integer.parseInt(props.getProperty("build"));
- Log.info("Slick Build #"+build);
-
- return build;
- } catch (Exception e) {
- Log.info("Unable to determine Slick build number");
- return -1;
- }
- }
-
- /**
- * Get the default system font
- *
- * @return The default system font
- */
- @Override
- public Font getDefaultFont() {
- return defaultFont;
- }
-
- /**
- * Check if sound effects are enabled
- *
- * @return True if sound effects are enabled
- */
- public boolean isSoundOn() {
- return SoundStore.get().soundsOn();
- }
-
- /**
- * Check if music is enabled
- *
- * @return True if music is enabled
- */
- public boolean isMusicOn() {
- return SoundStore.get().musicOn();
- }
-
- /**
- * Indicate whether music should be enabled
- *
- * @param on True if music should be enabled
- */
- public void setMusicOn(boolean on) {
- SoundStore.get().setMusicOn(on);
- }
-
- /**
- * Indicate whether sound effects should be enabled
- *
- * @param on True if sound effects should be enabled
- */
- public void setSoundOn(boolean on) {
- SoundStore.get().setSoundsOn(on);
- }
-
- /**
- * Retrieve the current default volume for music
- * @return the current default volume for music
- */
- public float getMusicVolume() {
- return SoundStore.get().getMusicVolume();
- }
-
- /**
- * Retrieve the current default volume for sound fx
- * @return the current default volume for sound fx
- */
- public float getSoundVolume() {
- return SoundStore.get().getSoundVolume();
- }
-
- /**
- * Set the default volume for sound fx
- * @param volume the new default value for sound fx volume
- */
- public void setSoundVolume(float volume) {
- SoundStore.get().setSoundVolume(volume);
- }
-
- /**
- * Set the default volume for music
- * @param volume the new default value for music volume
- */
- public void setMusicVolume(float volume) {
- SoundStore.get().setMusicVolume(volume);
- }
-
- /**
- * Get the width of the standard screen resolution
- *
- * @return The screen width
- */
- @Override
- public abstract int getScreenWidth();
-
- /**
- * Get the height of the standard screen resolution
- *
- * @return The screen height
- */
- @Override
- public abstract int getScreenHeight();
-
- /**
- * Get the width of the game canvas
- *
- * @return The width of the game canvas
- */
- @Override
- public int getWidth() {
- return width;
- }
-
- /**
- * Get the height of the game canvas
- *
- * @return The height of the game canvas
- */
- @Override
- public int getHeight() {
- return height;
- }
-
- /**
- * Set the icon to be displayed if possible in this type of
- * container
- *
- * @param ref The reference to the icon to be displayed
- * @throws SlickException Indicates a failure to load the icon
- */
- public abstract void setIcon(String ref) throws SlickException;
-
- /**
- * Set the icons to be used for this application. Note that the size of the icon
- * defines how it will be used. Important ones to note
- *
- * Windows window icon must be 16x16
- * Windows alt-tab icon must be 24x24 or 32x32 depending on Windows version (XP=32)
- *
- * @param refs The reference to the icon to be displayed
- * @throws SlickException Indicates a failure to load the icon
- */
- public abstract void setIcons(String[] refs) throws SlickException;
-
- /**
- * Get the accurate system time
- *
- * @return The system time in milliseconds
- */
- @Override
- public long getTime() {
- return (Sys.getTime() * 1000) / Sys.getTimerResolution();
- }
-
- /**
- * Sleep for a given period
- *
- * @param milliseconds The period to sleep for in milliseconds
- */
- public void sleep(int milliseconds) {
- long target = getTime()+milliseconds;
- while (getTime() < target) {
- try { Thread.sleep(1); } catch (Exception e) {}
- }
- }
-
- /**
- * Set the mouse cursor to be displayed - this is a hardware cursor and hence
- * shouldn't have any impact on FPS.
- *
- * @param ref The location of the image to be loaded for the cursor
- * @param hotSpotX The x coordinate of the hotspot within the cursor image
- * @param hotSpotY The y coordinate of the hotspot within the cursor image
- * @throws SlickException Indicates a failure to load the cursor image or create the hardware cursor
- */
- @Override
- public abstract void setMouseCursor(String ref, int hotSpotX, int hotSpotY) throws SlickException;
-
- /**
- * Set the mouse cursor to be displayed - this is a hardware cursor and hence
- * shouldn't have any impact on FPS.
- *
- * @param data The image data from which the cursor can be construted
- * @param hotSpotX The x coordinate of the hotspot within the cursor image
- * @param hotSpotY The y coordinate of the hotspot within the cursor image
- * @throws SlickException Indicates a failure to load the cursor image or create the hardware cursor
- */
- @Override
- public abstract void setMouseCursor(ImageData data, int hotSpotX, int hotSpotY) throws SlickException;
-
- /**
- * Set the mouse cursor based on the contents of the image. Note that this will not take
- * account of render state type changes to images (rotation and such). If these effects
- * are required it is recommended that an offscreen buffer be used to produce an appropriate
- * image. An offscreen buffer will always be used to produce the new cursor and as such
- * this operation an be very expensive
- *
- * @param image The image to use as the cursor
- * @param hotSpotX The x coordinate of the hotspot within the cursor image
- * @param hotSpotY The y coordinate of the hotspot within the cursor image
- * @throws SlickException Indicates a failure to load the cursor image or create the hardware cursor
- */
- public abstract void setMouseCursor(Image image, int hotSpotX, int hotSpotY) throws SlickException;
-
- /**
- * Set the mouse cursor to be displayed - this is a hardware cursor and hence
- * shouldn't have any impact on FPS.
- *
- * @param cursor The cursor to use
- * @param hotSpotX The x coordinate of the hotspot within the cursor image
- * @param hotSpotY The y coordinate of the hotspot within the cursor image
- * @throws SlickException Indicates a failure to load the cursor image or create the hardware cursor
- */
- @Override
- public abstract void setMouseCursor(Cursor cursor, int hotSpotX, int hotSpotY) throws SlickException;
-
- /**
- * Get a cursor based on a image reference on the classpath. The image
- * is assumed to be a set/strip of cursor animation frames running from top to
- * bottom.
- *
- * @param ref The reference to the image to be loaded
- * @param x The x-coordinate of the cursor hotspot (left {@literal ->} right)
- * @param y The y-coordinate of the cursor hotspot (bottom {@literal ->} top)
- * @param width The x width of the cursor
- * @param height The y height of the cursor
- * @param cursorDelays image delays between changing frames in animation
- *
- * @throws SlickException Indicates a failure to load the image or a failure to create the hardware cursor
- */
- public void setAnimatedMouseCursor(String ref, int x, int y, int width, int height, int[] cursorDelays) throws SlickException
- {
- try {
- Cursor cursor;
- cursor = CursorLoader.get().getAnimatedCursor(ref, x, y, width, height, cursorDelays);
- setMouseCursor(cursor, x, y);
- } catch (IOException e) {
- throw new SlickException("Failed to set mouse cursor", e);
- } catch (LWJGLException e) {
- throw new SlickException("Failed to set mouse cursor", e);
- }
- }
-
- /**
- * Set the default mouse cursor - i.e. the original cursor before any native
- * cursor was set
- */
- @Override
- public abstract void setDefaultMouseCursor();
-
- /**
- * Get the input system
- *
- * @return The input system available to this game container
- */
- @Override
- public Input getInput() {
- return input;
- }
-
- /**
- * Get the current recorded FPS (frames per second)
- *
- * @return The current FPS
- */
- public int getFPS() {
- return recordedFPS;
- }
-
- /**
- * Indicate whether mouse cursor should be grabbed or not
- *
- * @param grabbed True if mouse cursor should be grabbed
- */
- public abstract void setMouseGrabbed(boolean grabbed);
-
- /**
- * Check if the mouse cursor is current grabbed. This will cause it not
- * to be seen.
- *
- * @return True if the mouse is currently grabbed
- */
- public abstract boolean isMouseGrabbed();
-
- /**
- * Retrieve the time taken to render the last frame, i.e. the change in time - delta.
- *
- * @return The time taken to render the last frame
- */
- protected int getDelta() {
- long time = getTime();
- int delta = (int) (time - lastFrame);
- lastFrame = time;
-
- return delta;
- }
-
- /**
- * Updated the FPS counter
- */
- protected void updateFPS() {
- if (getTime() - lastFPS > 1000) {
- lastFPS = getTime();
- recordedFPS = fps;
- fps = 0;
- }
- fps++;
- }
-
- /**
- * Set the minimum amount of time in milliseonds that has to
- * pass before update() is called on the container game. This gives
- * a way to limit logic updates compared to renders.
- *
- * @param interval The minimum interval between logic updates
- */
- public void setMinimumLogicUpdateInterval(int interval) {
- minimumLogicInterval = interval;
- }
-
- /**
- * Set the maximum amount of time in milliseconds that can passed
- * into the update method. Useful for collision detection without
- * sweeping.
- *
- * @param interval The maximum interval between logic updates
- */
- public void setMaximumLogicUpdateInterval(int interval) {
- maximumLogicInterval = interval;
- }
-
- /**
- * Update and render the game
- *
- * @param delta The change in time since last update and render
- * @throws SlickException Indicates an internal fault to the game.
- */
- protected void updateAndRender(int delta) throws SlickException {
- if (smoothDeltas) {
- if (getFPS() != 0) {
- delta = 1000 / getFPS();
- }
- }
-
- input.poll(width, height);
-
- Music.poll(delta);
- if (!paused) {
- storedDelta += delta;
-
- if (storedDelta >= minimumLogicInterval) {
- try {
- if (maximumLogicInterval != 0) {
- long cycles = storedDelta / maximumLogicInterval;
- for (int i=0;i minimumLogicInterval) {
- game.update(this, (int) (remainder % maximumLogicInterval));
- storedDelta = 0;
- } else {
- storedDelta = remainder;
- }
- } else {
- game.update(this, (int) storedDelta);
- storedDelta = 0;
- }
-
- } catch (Throwable e) {
-// Log.error(e);
- throw new SlickException("Game.update() failure.", e);
- }
- }
- } else {
- game.update(this, 0);
- }
-
- if (hasFocus() || getAlwaysRender()) {
- if (clearEachFrame) {
- GL.glClear(SGL.GL_COLOR_BUFFER_BIT | SGL.GL_DEPTH_BUFFER_BIT);
- }
-
- GL.glLoadIdentity();
-
- graphics.resetTransform();
- graphics.resetFont();
- graphics.resetLineWidth();
- graphics.setAntiAlias(false);
- try {
- game.render(this, graphics);
- } catch (Throwable e) {
-// Log.error(e);
- throw new SlickException("Game.render() failure.", e);
- }
- graphics.resetTransform();
-
- if (showFPS) {
- defaultFont.drawString(10, 10, "FPS: "+recordedFPS);
- }
-
- GL.flush();
- }
-
- if (targetFPS != -1) {
- Display.sync(targetFPS);
- }
- }
-
- /**
- * Indicate if the display should update only when the game is visible
- * (the default is true)
- *
- * @param updateOnlyWhenVisible True if we should updated only when the display is visible
- */
- public void setUpdateOnlyWhenVisible(boolean updateOnlyWhenVisible) {
- }
-
- /**
- * Check if this game is only updating when visible to the user (default = true)
- *
- * @return True if the game is only updated when the display is visible
- */
- public boolean isUpdatingOnlyWhenVisible() {
- return true;
- }
-
- /**
- * Initialise the GL context
- */
- protected void initGL() {
- Log.info("Starting display "+width+"x"+height);
- GL.initDisplay(width, height);
-
- if (input == null) {
- input = new Input(height);
- }
- input.init(height);
- // no need to remove listeners?
- //input.removeAllListeners();
- if (game instanceof InputListener) {
- input.removeListener((InputListener) game);
- input.addListener((InputListener) game);
- }
-
- if (graphics != null) {
- graphics.setDimensions(getWidth(), getHeight());
- }
- lastGame = game;
- }
-
- /**
- * Initialise the system components, OpenGL and OpenAL.
- *
- * @throws SlickException Indicates a failure to create a native handler
- */
- protected void initSystem() throws SlickException {
- initGL();
- setMusicVolume(1.0f);
- setSoundVolume(1.0f);
-
- graphics = new Graphics(width, height);
- defaultFont = graphics.getFont();
- }
-
- /**
- * Enter the orthographic mode
- */
- protected void enterOrtho() {
- enterOrtho(width, height);
- }
-
- /**
- * Indicate whether the container should show the FPS
- *
- * @param show True if the container should show the FPS
- */
- public void setShowFPS(boolean show) {
- showFPS = show;
- }
-
- /**
- * Check if the FPS is currently showing
- *
- * @return True if the FPS is showing
- */
- public boolean isShowingFPS() {
- return showFPS;
- }
-
- /**
- * Set the target fps we're hoping to get
- *
- * @param fps The target fps we're hoping to get
- */
- public void setTargetFrameRate(int fps) {
- targetFPS = fps;
- }
-
- /**
- * Indicate whether the display should be synced to the
- * vertical refresh (stops tearing)
- *
- * @param vsync True if we want to sync to vertical refresh
- */
- public void setVSync(boolean vsync) {
- this.vsync = vsync;
- Display.setVSyncEnabled(vsync);
- }
-
- /**
- * True if vsync is requested
- *
- * @return True if vsync is requested
- */
- public boolean isVSyncRequested() {
- return vsync;
- }
-
- /**
- * True if the game is running
- *
- * @return True if the game is running
- */
- protected boolean running() {
- return running;
- }
-
- /**
- * Inidcate we want verbose logging
- *
- * @param verbose True if we want verbose logging (INFO and DEBUG)
- */
- public void setVerbose(boolean verbose) {
- Log.setVerbose(verbose);
- }
-
- /**
- * Cause the game to exit and shutdown cleanly
- */
- public void exit() {
- running = false;
- }
-
- /**
- * Check if the game currently has focus
- *
- * @return True if the game currently has focus
- */
- public abstract boolean hasFocus();
-
- /**
- * Get the graphics context used by this container. Note that this
- * value may vary over the life time of the game.
- *
- * @return The graphics context used by this container
- */
- public Graphics getGraphics() {
- return graphics;
- }
-
- /**
- * Enter the orthographic mode
- *
- * @param xsize The size of the panel being used
- * @param ysize The size of the panel being used
- */
- protected void enterOrtho(int xsize, int ysize) {
- GL.enterOrtho(xsize, ysize);
- }
-}
diff --git a/src/org/newdawn/slick/gui/TextField.java b/src/org/newdawn/slick/gui/TextField.java
index 6696ff9f..a989d2c4 100644
--- a/src/org/newdawn/slick/gui/TextField.java
+++ b/src/org/newdawn/slick/gui/TextField.java
@@ -34,232 +34,70 @@ import org.newdawn.slick.Font;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import org.newdawn.slick.geom.Rectangle;
+import yugecin.opsudance.core.DisplayContainer;
+import yugecin.opsudance.core.components.ActionListener;
+import yugecin.opsudance.core.components.Component;
/**
* A single text field supporting text entry
*
* @author kevin
*/
-@SuppressWarnings("unused")
-public class TextField extends AbstractComponent {
- /** The key repeat interval */
+public class TextField extends Component {
+
private static final int INITIAL_KEY_REPEAT_INTERVAL = 400;
- /** The key repeat interval */
private static final int KEY_REPEAT_INTERVAL = 50;
+
+ private final DisplayContainer displayContainer;
- /** The width of the field */
- private int width;
-
- /** The height of the field */
- private int height;
-
- /** The location in the X coordinate */
- protected int x;
-
- /** The location in the Y coordinate */
- protected int y;
-
- /** The maximum number of characters allowed to be input */
+ private String value = "";
+ private Font font;
private int maxCharacter = 10000;
- /** The value stored in the text field */
- private String value = "";
+ private Color borderCol = Color.white;
+ private Color textCol = Color.white;
+ private Color backgroundCol = new Color(0, 0, 0, 0.5f);
- /** The font used to render text in the field */
- private Font font;
-
- /** The border color - null if no border */
- private Color border = Color.white;
-
- /** The text color */
- private Color text = Color.white;
-
- /** The background color - null if no background */
- private Color background = new Color(0, 0, 0, 0.5f);
-
- /** The current cursor position */
private int cursorPos;
-
- /** True if the cursor should be visible */
- private boolean visibleCursor = true;
-
- /** The last key pressed */
private int lastKey = -1;
-
- /** The last character pressed */
private char lastChar = 0;
-
- /** The time since last key repeat */
private long repeatTimer;
-
- /** The text before the paste in */
- private String oldText;
-
- /** The cursor position before the paste */
- private int oldCursorPos;
-
- /** True if events should be consumed by the field */
- private boolean consume = true;
-
- /**
- * Create a new text field
- *
- * @param container
- * The container rendering this field
- * @param font
- * The font to use in the text field
- * @param x
- * The x coordinate of the top left corner of the text field
- * @param y
- * The y coordinate of the top left corner of the text field
- * @param width
- * The width of the text field
- * @param height
- * The height of the text field
- * @param listener
- * The listener to add to the text field
- */
- public TextField(GUIContext container, Font font, int x, int y, int width,
- int height, ComponentListener listener) {
- this(container,font,x,y,width,height);
- addListener(listener);
- }
-
- /**
- * Create a new text field
- *
- * @param container
- * The container rendering this field
- * @param font
- * The font to use in the text field
- * @param x
- * The x coordinate of the top left corner of the text field
- * @param y
- * The y coordinate of the top left corner of the text field
- * @param width
- * The width of the text field
- * @param height
- * The height of the text field
- */
- public TextField(GUIContext container, Font font, int x, int y, int width,
- int height) {
- super(container);
+ private ActionListener listener;
+
+ public TextField(DisplayContainer displayContainer, Font font, int x, int y, int width, int height) {
+ this.displayContainer = displayContainer;
this.font = font;
-
- setLocation(x, y);
+ this.x = x;
+ this.y = y;
this.width = width;
this.height = height;
}
- /**
- * Indicate if the input events should be consumed by this field
- *
- * @param consume True if events should be consumed by this field
- */
- public void setConsumeEvents(boolean consume) {
- this.consume = consume;
+ public void setListener(ActionListener listener) {
+ this.listener = listener;
}
-
- /**
- * Deactivate the key input handling for this field
- */
- public void deactivate() {
- setFocus(false);
+
+ public void setBorderColor(Color border) {
+ this.borderCol = border;
}
-
- /**
- * Moves the component.
- *
- * @param x
- * X coordinate
- * @param y
- * Y coordinate
- */
+
+ public void setTextColor(Color text) {
+ this.textCol = text;
+ }
+
+ public void setBackgroundColor(Color background) {
+ this.backgroundCol = background;
+ }
+
@Override
- public void setLocation(int x, int y) {
- this.x = x;
- this.y = y;
+ public boolean isFocusable() {
+ return true;
}
- /**
- * Returns the position in the X coordinate
- *
- * @return x
- */
- @Override
- public int getX() {
- return x;
- }
-
- /**
- * Returns the position in the Y coordinate
- *
- * @return y
- */
- @Override
- public int getY() {
- return y;
- }
-
- /**
- * Get the width of the component
- *
- * @return The width of the component
- */
- @Override
- public int getWidth() {
- return width;
- }
-
- /**
- * Get the height of the component
- *
- * @return The height of the component
- */
- @Override
- public int getHeight() {
- return height;
- }
-
- /**
- * Set the background color. Set to null to disable the background
- *
- * @param color
- * The color to use for the background
- */
- public void setBackgroundColor(Color color) {
- background = color;
- }
-
- /**
- * Set the border color. Set to null to disable the border
- *
- * @param color
- * The color to use for the border
- */
- public void setBorderColor(Color color) {
- border = color;
- }
-
- /**
- * Set the text color.
- *
- * @param color
- * The color to use for the text
- */
- public void setTextColor(Color color) {
- text = color;
- }
-
- /**
- * @see org.newdawn.slick.gui.AbstractComponent#render(org.newdawn.slick.gui.GUIContext,
- * org.newdawn.slick.Graphics)
- */
- @Override
- public void render(GUIContext container, Graphics g) {
+ public void render(Graphics g) {
if (lastKey != -1) {
- if (input.isKeyDown(lastKey)) {
+ if (displayContainer.input.isKeyDown(lastKey)) {
if (repeatTimer < System.currentTimeMillis()) {
repeatTimer = System.currentTimeMillis() + KEY_REPEAT_INTERVAL;
keyPressed(lastKey, lastChar);
@@ -274,11 +112,11 @@ public class TextField extends AbstractComponent {
// Someone could have set a color for me to blend...
Color clr = g.getColor();
- if (background != null) {
- g.setColor(background.multiply(clr));
+ if (backgroundCol != null) {
+ g.setColor(backgroundCol.multiply(clr));
g.fillRect(x, y, width, height);
}
- g.setColor(text.multiply(clr));
+ g.setColor(textCol.multiply(clr));
Font temp = g.getFont();
int cpos = font.getWidth(value.substring(0, cursorPos));
@@ -291,14 +129,14 @@ public class TextField extends AbstractComponent {
g.setFont(font);
g.drawString(value, x + 1, y + 1);
- if (hasFocus() && visibleCursor) {
- g.drawString("_", x + 1 + cpos + 2, y + 1);
+ if (focused) {
+ g.drawString("|", x + 1 + cpos + 2, y + 1);
}
g.translate(-tx - 2, 0);
- if (border != null) {
- g.setColor(border.multiply(clr));
+ if (borderCol != null) {
+ g.setColor(borderCol.multiply(clr));
g.drawRect(x, y, width, height);
}
g.setColor(clr);
@@ -307,21 +145,10 @@ public class TextField extends AbstractComponent {
g.setClip(oldClip);
}
- /**
- * Get the value in the text field
- *
- * @return The value in the text field
- */
public String getText() {
return value;
}
- /**
- * Set the value to be displayed in the text field
- *
- * @param value
- * The value to be displayed in the text field
- */
public void setText(String value) {
this.value = value;
if (cursorPos > value.length()) {
@@ -329,35 +156,6 @@ public class TextField extends AbstractComponent {
}
}
- /**
- * Set the position of the cursor
- *
- * @param pos
- * The new position of the cursor
- */
- public void setCursorPos(int pos) {
- cursorPos = pos;
- if (cursorPos > value.length()) {
- cursorPos = value.length();
- }
- }
-
- /**
- * Indicate whether the mouse cursor should be visible or not
- *
- * @param visibleCursor
- * True if the mouse cursor should be visible
- */
- public void setCursorVisible(boolean visibleCursor) {
- this.visibleCursor = visibleCursor;
- }
-
- /**
- * Set the length of the allowed input
- *
- * @param length
- * The length of the allowed input
- */
public void setMaxLength(int length) {
maxCharacter = length;
if (value.length() > maxCharacter) {
@@ -365,173 +163,101 @@ public class TextField extends AbstractComponent {
}
}
- /**
- * Do the paste into the field, overrideable for custom behaviour
- *
- * @param text The text to be pasted in
- */
protected void doPaste(String text) {
- recordOldPosition();
-
for (int i=0;i 0) {
+ cursorPos--;
+ }
+ // Nobody more will be notified
+ if (consume) {
+ container.getInput().consumeEvent();
+ }
+ */ } else if (key == Input.KEY_RIGHT) { /*
+ if (cursorPos < value.length()) {
+ cursorPos++;
+ }
+ // Nobody more will be notified
+ if (consume) {
+ container.getInput().consumeEvent();
+ }
+ */ } else if (key == Input.KEY_BACK) {
+ if ((cursorPos > 0) && (value.length() > 0)) {
+ if (displayContainer.input.isKeyDown(Input.KEY_LCONTROL) || displayContainer.input.isKeyDown(Input.KEY_RCONTROL)) {
+ int sp = 0;
+ boolean startSpace = Character.isWhitespace(value.charAt(cursorPos - 1));
+ boolean charSeen = false;
+ for (int i = cursorPos - 1; i >= 0; i--) {
+ boolean isSpace = Character.isWhitespace(value.charAt(i));
+ if (!startSpace && isSpace) {
+ sp = i;
+ break;
+ } else if (startSpace) {
+ if (charSeen && isSpace) {
+ sp = i + 1;
+ break;
+ } else if (!charSeen && !isSpace)
+ charSeen = true;
+ }
+ }
+ if (cursorPos < value.length())
+ value = value.substring(0, sp) + value.substring(cursorPos);
+ else
+ value = value.substring(0, sp);
+ cursorPos = sp;
+ } else {
+ if (cursorPos < value.length()) {
+ value = value.substring(0, cursorPos - 1)
+ + value.substring(cursorPos);
+ } else {
+ value = value.substring(0, cursorPos - 1);
}
- return;
- } */
-
- // alt and control keys don't come through here
- /* if (input.isKeyDown(Input.KEY_LCONTROL) || input.isKeyDown(Input.KEY_RCONTROL)) {
- return;
- } */
- if (input.isKeyDown(Input.KEY_LALT) || input.isKeyDown(Input.KEY_RALT)) {
- return;
- }
- }
-
- if (lastKey != key) {
- lastKey = key;
- repeatTimer = System.currentTimeMillis() + INITIAL_KEY_REPEAT_INTERVAL;
- } else {
- repeatTimer = System.currentTimeMillis() + KEY_REPEAT_INTERVAL;
- }
- lastChar = c;
-
- if (key == Input.KEY_LEFT) { /*
- if (cursorPos > 0) {
cursorPos--;
}
- // Nobody more will be notified
- if (consume) {
- container.getInput().consumeEvent();
- }
- */ } else if (key == Input.KEY_RIGHT) { /*
- if (cursorPos < value.length()) {
- cursorPos++;
- }
- // Nobody more will be notified
- if (consume) {
- container.getInput().consumeEvent();
- }
- */ } else if (key == Input.KEY_BACK) {
- if ((cursorPos > 0) && (value.length() > 0)) {
- if (input.isKeyDown(Input.KEY_LCONTROL) || input.isKeyDown(Input.KEY_RCONTROL)) {
- int sp = 0;
- boolean startSpace = Character.isWhitespace(value.charAt(cursorPos - 1));
- boolean charSeen = false;
- for (int i = cursorPos - 1; i >= 0; i--) {
- boolean isSpace = Character.isWhitespace(value.charAt(i));
- if (!startSpace && isSpace) {
- sp = i;
- break;
- } else if (startSpace) {
- if (charSeen && isSpace) {
- sp = i + 1;
- break;
- } else if (!charSeen && !isSpace)
- charSeen = true;
- }
- }
- if (cursorPos < value.length())
- value = value.substring(0, sp) + value.substring(cursorPos);
- else
- value = value.substring(0, sp);
- cursorPos = sp;
- } else {
- if (cursorPos < value.length()) {
- value = value.substring(0, cursorPos - 1)
- + value.substring(cursorPos);
- } else {
- value = value.substring(0, cursorPos - 1);
- }
- cursorPos--;
- }
- }
- // Nobody more will be notified
- if (consume) {
- container.getInput().consumeEvent();
- }
- } else if (key == Input.KEY_DELETE) {
- if (value.length() > cursorPos) {
- value = value.substring(0,cursorPos) + value.substring(cursorPos+1);
- }
- // Nobody more will be notified
- if (consume) {
- container.getInput().consumeEvent();
- }
- } else if ((c < 127) && (c > 31) && (value.length() < maxCharacter)) {
- if (cursorPos < value.length()) {
- value = value.substring(0, cursorPos) + c
- + value.substring(cursorPos);
- } else {
- value = value.substring(0, cursorPos) + c;
- }
- cursorPos++;
- // Nobody more will be notified
- if (consume) {
- container.getInput().consumeEvent();
- }
- } else if (key == Input.KEY_RETURN) {
- notifyListeners();
- // Nobody more will be notified
- if (consume) {
- container.getInput().consumeEvent();
- }
}
-
+ } else if (key == Input.KEY_DELETE) {
+ if (value.length() > cursorPos) {
+ value = value.substring(0,cursorPos) + value.substring(cursorPos+1);
+ }
+ } else if ((c < 127) && (c > 31) && (value.length() < maxCharacter)) {
+ if (cursorPos < value.length()) {
+ value = value.substring(0, cursorPos) + c
+ + value.substring(cursorPos);
+ } else {
+ value = value.substring(0, cursorPos) + c;
+ }
+ cursorPos++;
+ } else if (key == Input.KEY_RETURN) {
+ if (listener != null) {
+ listener.onAction();
+ }
}
+
}
- /**
- * @see org.newdawn.slick.gui.AbstractComponent#setFocus(boolean)
- */
- @Override
- public void setFocus(boolean focus) {
- lastKey = -1;
-
- super.setFocus(focus);
- }
}
diff --git a/src/yugecin/opsudance/OpsuDance.java b/src/yugecin/opsudance/OpsuDance.java
index d0a9da61..2fa43c60 100644
--- a/src/yugecin/opsudance/OpsuDance.java
+++ b/src/yugecin/opsudance/OpsuDance.java
@@ -19,9 +19,11 @@ package yugecin.opsudance;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.Utils;
+import itdelatrisu.opsu.beatmap.BeatmapWatchService;
import itdelatrisu.opsu.db.DBController;
import itdelatrisu.opsu.downloads.DownloadList;
import itdelatrisu.opsu.downloads.Updater;
+import itdelatrisu.opsu.states.Splash;
import org.newdawn.slick.util.Log;
import yugecin.opsudance.core.DisplayContainer;
import yugecin.opsudance.core.errorhandling.ErrorHandler;
@@ -61,23 +63,32 @@ public class OpsuDance {
initUpdater(args);
sout("database & updater initialized");
- container.init(EmptyState.class);
+ //container.init(EmptyState.class);
+ container.init(Splash.class);
} catch (Exception e) {
errorAndExit("startup failure", e);
}
while (rungame());
+ container.teardownAL();
+ Options.saveOptions();
closeSingleInstanceSocket();
DBController.closeConnections();
DownloadList.get().cancelAllDownloads();
+ Utils.deleteDirectory(Options.TEMP_DIR);
+ if (!Options.isWatchServiceEnabled()) {
+ BeatmapWatchService.destroy();
+ }
}
private boolean rungame() {
try {
container.setup();
+ container.resume();
} catch (Exception e) {
- errorAndExit("could not initialize GL", e);
+ ErrorHandler.error("could not initialize GL", e).allowTerminate().preventContinue().show();
+ return false;
}
Exception caughtException = null;
try {
@@ -86,7 +97,8 @@ public class OpsuDance {
caughtException = e;
}
container.teardown();
- return caughtException != null && ErrorHandler.error("update/render error", caughtException).show().shouldIgnoreAndContinue();
+ container.pause();
+ return caughtException != null && ErrorHandler.error("update/render error", caughtException).allowTerminate().show().shouldIgnoreAndContinue();
}
private void initDatabase() {
@@ -160,7 +172,7 @@ public class OpsuDance {
}
private void errorAndExit(String errstr) {
- ErrorHandler.error(errstr, new Throwable()).preventContinue().show();
+ ErrorHandler.error(errstr, new Throwable()).allowTerminate().preventContinue().show();
System.exit(1);
}
diff --git a/src/yugecin/opsudance/core/DisplayContainer.java b/src/yugecin/opsudance/core/DisplayContainer.java
index f1480557..35a47aba 100644
--- a/src/yugecin/opsudance/core/DisplayContainer.java
+++ b/src/yugecin/opsudance/core/DisplayContainer.java
@@ -17,18 +17,23 @@
*/
package yugecin.opsudance.core;
+import itdelatrisu.opsu.GameData;
import itdelatrisu.opsu.GameImage;
+import itdelatrisu.opsu.Options;
+import itdelatrisu.opsu.audio.MusicController;
+import itdelatrisu.opsu.beatmap.Beatmap;
+import itdelatrisu.opsu.downloads.DownloadList;
+import itdelatrisu.opsu.downloads.Updater;
+import itdelatrisu.opsu.render.CurveRenderState;
+import itdelatrisu.opsu.ui.Cursor;
import itdelatrisu.opsu.ui.Fonts;
-import org.lwjgl.LWJGLException;
+import itdelatrisu.opsu.ui.UI;
import org.lwjgl.Sys;
import org.lwjgl.openal.AL;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
-import org.newdawn.slick.Graphics;
-import org.newdawn.slick.Input;
-import org.newdawn.slick.KeyListener;
-import org.newdawn.slick.MouseListener;
+import org.newdawn.slick.*;
import org.newdawn.slick.opengl.InternalTextureLoader;
import org.newdawn.slick.opengl.renderer.Renderer;
import org.newdawn.slick.opengl.renderer.SGL;
@@ -41,6 +46,7 @@ import yugecin.opsudance.core.state.specialstates.BarNotificationState;
import yugecin.opsudance.core.state.specialstates.BubbleNotificationState;
import yugecin.opsudance.core.state.specialstates.FpsRenderState;
import yugecin.opsudance.core.state.transitions.*;
+import yugecin.opsudance.events.BubbleNotificationEvent;
import yugecin.opsudance.events.ResolutionChangedEvent;
import yugecin.opsudance.utils.GLHelper;
@@ -70,10 +76,10 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
private OpsuState state;
- private final DisplayMode nativeDisplayMode;
+ public final DisplayMode nativeDisplayMode;
private Graphics graphics;
- private Input input;
+ public Input input;
public int width;
public int height;
@@ -90,16 +96,27 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
public int renderDelta;
public int delta;
+ public boolean exitRequested;
+
public int timeSinceLastRender;
private long lastFrame;
+ private boolean wasMusicPlaying;
+
private String glVersion;
private String glVendor;
+ private long exitconfirmation;
+
+ public final Cursor cursor;
+ public boolean drawCursor;
+
public DisplayContainer(InstanceContainer instanceContainer, EventBus eventBus) {
this.instanceContainer = instanceContainer;
this.eventBus = eventBus;
+ this.cursor = new Cursor();
+ drawCursor = true;
outTransitionListener = new TransitionFinishedListener() {
@Override
@@ -149,16 +166,21 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
}
- public void run() throws LWJGLException {
- while(!(Display.isCloseRequested() && state.onCloseRequest())) {
+ public void run() throws Exception {
+ while(!exitRequested && !(Display.isCloseRequested() && state.onCloseRequest()) || !confirmExit()) {
delta = getDelta();
timeSinceLastRender += delta;
input.poll(width, height);
+ Music.poll(delta);
mouseX = input.getMouseX();
mouseY = input.getMouseY();
+
state.update();
+ if (drawCursor) {
+ cursor.setCursorPosition(delta, mouseX, mouseY);
+ }
int maxRenderInterval;
if (Display.isVisible() && Display.isActive()) {
@@ -185,6 +207,12 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
bubNotifState.render(graphics);
barNotifState.render(graphics);
+ cursor.updateAngle(renderDelta);
+ if (drawCursor) {
+ cursor.draw(input.isMouseButtonDown(Input.MOUSE_LEFT_BUTTON) || input.isMouseButtonDown(Input.MOUSE_RIGHT_BUTTON));
+ }
+ UI.drawTooltip(graphics);
+
timeSinceLastRender = 0;
Display.update(false);
@@ -193,28 +221,66 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
Display.processMessages();
Display.sync(targetUpdatesPerSecond);
}
- teardown();
}
public void setup() throws Exception {
width = height = -1;
Input.disableControllers();
Display.setTitle("opsu!dance");
- // temp displaymode to not flash the screen with a 1ms black window
- Display.setDisplayMode(new DisplayMode(100, 100));
+ Options.setDisplayMode(this);
Display.create();
GLHelper.setIcons(new String[] { "icon16.png", "icon32.png" });
- setDisplayMode(800, 600, false);
- sout("GL ready");
+ initGL();
glVersion = GL11.glGetString(GL11.GL_VERSION);
glVendor = GL11.glGetString(GL11.GL_VENDOR);
+ GLHelper.hideNativeCursor();
}
public void teardown() {
+ InternalTextureLoader.get().clear();
+ GameImage.destroyImages();
+ GameData.Grade.destroyImages();
+ Beatmap.destroyBackgroundImageCache();
+ CurveRenderState.shutdown();
Display.destroy();
+ }
+
+ public void teardownAL() {
AL.destroy();
}
+ public void pause() {
+ wasMusicPlaying = MusicController.isPlaying();
+ if (wasMusicPlaying) {
+ MusicController.pause();
+ }
+ }
+
+ public void resume() {
+ if (wasMusicPlaying) {
+ MusicController.resume();
+ }
+ }
+
+ private boolean confirmExit() {
+ if (System.currentTimeMillis() - exitconfirmation < 10000) {
+ return true;
+ }
+ if (DownloadList.get().hasActiveDownloads()) {
+ eventBus.post(new BubbleNotificationEvent(DownloadList.EXIT_CONFIRMATION, BubbleNotificationEvent.COMMONCOLOR_PURPLE));
+ exitRequested = false;
+ exitconfirmation = System.currentTimeMillis();
+ return false;
+ }
+ if (Updater.get().getStatus() == Updater.Status.UPDATE_DOWNLOADING) {
+ eventBus.post(new BubbleNotificationEvent(Updater.EXIT_CONFIRMATION, BubbleNotificationEvent.COMMONCOLOR_PURPLE));
+ exitRequested = false;
+ exitconfirmation = System.currentTimeMillis();
+ return false;
+ }
+ return true;
+ }
+
public void setDisplayMode(int width, int height, boolean fullscreen) throws Exception {
if (this.width == width && this.height == height) {
Display.setFullscreen(fullscreen);
@@ -231,6 +297,7 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
if (fullscreen) {
fullscreen = false;
Log.warn("could not find fullscreen displaymode for " + width + "x" + height);
+ eventBus.post(new BubbleNotificationEvent("Fullscreen mode is not supported for " + width + "x" + height, BubbleNotificationEvent.COLOR_ORANGE));
}
}
@@ -240,9 +307,9 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
Display.setDisplayMode(displayMode);
Display.setFullscreen(fullscreen);
- initGL();
-
- eventBus.post(new ResolutionChangedEvent(this.width, this.height));
+ if (Display.isCreated()) {
+ initGL();
+ }
if (displayMode.getBitsPerPixel() == 16) {
InternalTextureLoader.get().set16BitMode();
@@ -257,11 +324,20 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
graphics.setAntiAlias(false);
input = new Input(height);
+ input.enableKeyRepeat();
input.addKeyListener(this);
input.addMouseListener(this);
+ sout("GL ready");
+
GameImage.init(width, height);
Fonts.init();
+
+ eventBus.post(new ResolutionChangedEvent(this.width, this.height));
+ }
+
+ public void resetCursor() {
+ cursor.reset(mouseX, mouseY);
}
private int getDelta() {
@@ -292,6 +368,10 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
state.writeErrorDump(dump);
}
+ public boolean isInState(Class extends OpsuState> state) {
+ return state.isInstance(state);
+ }
+
public boolean isTransitioning() {
return state instanceof TransitionState;
}
@@ -301,7 +381,13 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
}
public void switchStateNow(Class extends OpsuState> newState) {
- switchState(newState, EmptyTransitionState.class, 0, EmptyTransitionState.class, 0);
+ switchState(newState, EmptyTransitionState.class, 0, FadeInTransitionState.class, 300);
+ }
+
+ public void switchStateInstantly(Class extends OpsuState> newState) {
+ state.leave();
+ state = instanceContainer.provide(newState);
+ state.enter();
}
public void switchState(Class extends OpsuState> newState, Class extends TransitionState> outTransition, int outTime, Class extends TransitionState> inTransition, int inTime) {
@@ -353,7 +439,9 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
public void mouseMoved(int oldx, int oldy, int newx, int newy) { }
@Override
- public void mouseDragged(int oldx, int oldy, int newx, int newy) { }
+ public void mouseDragged(int oldx, int oldy, int newx, int newy) {
+ state.mouseDragged(oldx, oldy, newx, newy);
+ }
@Override
public void setInput(Input input) { }
diff --git a/src/yugecin/opsudance/core/Entrypoint.java b/src/yugecin/opsudance/core/Entrypoint.java
index 88225e8c..dfba2245 100644
--- a/src/yugecin/opsudance/core/Entrypoint.java
+++ b/src/yugecin/opsudance/core/Entrypoint.java
@@ -17,6 +17,7 @@
*/
package yugecin.opsudance.core;
+import itdelatrisu.opsu.downloads.Updater;
import yugecin.opsudance.OpsuDance;
import yugecin.opsudance.core.inject.OpsuDanceInjector;
@@ -27,6 +28,10 @@ public class Entrypoint {
public static void main(String[] args) {
sout("launched");
(new OpsuDanceInjector()).provide(OpsuDance.class).start(args);
+
+ if (Updater.get().getStatus() == Updater.Status.UPDATE_FINAL) {
+ Updater.get().runUpdate();
+ }
}
public static long runtime() {
diff --git a/src/yugecin/opsudance/core/components/ActionListener.java b/src/yugecin/opsudance/core/components/ActionListener.java
new file mode 100644
index 00000000..b1e05733
--- /dev/null
+++ b/src/yugecin/opsudance/core/components/ActionListener.java
@@ -0,0 +1,24 @@
+/*
+ * opsu!dance - fork of opsu! with cursordance auto
+ * Copyright (C) 2017 yugecin
+ *
+ * opsu!dance is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * opsu!dance is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with opsu!dance. If not, see .
+ */
+package yugecin.opsudance.core.components;
+
+public interface ActionListener {
+
+ void onAction();
+
+}
diff --git a/src/yugecin/opsudance/core/components/Component.java b/src/yugecin/opsudance/core/components/Component.java
new file mode 100644
index 00000000..20e4f777
--- /dev/null
+++ b/src/yugecin/opsudance/core/components/Component.java
@@ -0,0 +1,60 @@
+/*
+ * opsu!dance - fork of opsu! with cursordance auto
+ * Copyright (C) 2017 yugecin
+ *
+ * opsu!dance is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * opsu!dance is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with opsu!dance. If not, see .
+ */
+package yugecin.opsudance.core.components;
+
+import org.newdawn.slick.Graphics;
+
+public abstract class Component {
+
+ public int width;
+ public int height;
+ public int x;
+ public int y;
+
+ protected boolean focused;
+ protected boolean hovered;
+
+ public abstract boolean isFocusable();
+
+ public boolean isHovered() {
+ return hovered;
+ }
+
+ public void updateHover(int x, int y) {
+ this.hovered = this.x <= x && x <= this.x + width && this.y <= y && y <= this.y + height;
+ }
+
+ public void mouseReleased(int button) {
+ }
+
+ public void preRenderUpdate() {
+ }
+
+ public abstract void render(Graphics g);
+
+ public void keyPressed(int key, char c) {
+ }
+
+ public void keyReleased(int key, char c) {
+ }
+
+ public void setFocused(boolean focused) {
+ this.focused = focused;
+ }
+
+}
diff --git a/src/yugecin/opsudance/core/errorhandling/ErrorHandler.java b/src/yugecin/opsudance/core/errorhandling/ErrorHandler.java
index 163a1940..99321ba4 100644
--- a/src/yugecin/opsudance/core/errorhandling/ErrorHandler.java
+++ b/src/yugecin/opsudance/core/errorhandling/ErrorHandler.java
@@ -52,6 +52,7 @@ public class ErrorHandler {
private boolean preventContinue;
private boolean preventReport;
private boolean ignoreAndContinue;
+ private boolean allowTerminate;
public ErrorHandler(DisplayContainer displayContainer) {
this.displayContainer = displayContainer;
@@ -95,6 +96,11 @@ public class ErrorHandler {
return this;
}
+ public ErrorHandler allowTerminate() {
+ allowTerminate = true;
+ return this;
+ }
+
public ErrorHandler preventContinue() {
preventContinue = true;
return this;
@@ -127,7 +133,9 @@ public class ErrorHandler {
Object[] messageComponents = new Object[] { message, new JScrollPane(textArea), createViewLogButton(), createReportButton() };
String[] buttons;
- if (preventContinue) {
+ if (!allowTerminate && !preventContinue) {
+ buttons = new String[] { "Ignore & continue" };
+ } else if (preventContinue) {
buttons = new String[] { "Terminate" };
} else {
buttons = new String[] { "Terminate", "Ignore & continue" };
@@ -145,7 +153,7 @@ public class ErrorHandler {
null,
buttons,
buttons[buttons.length - 1]);
- ignoreAndContinue = result == 1;
+ ignoreAndContinue = !allowTerminate || result == 1;
frame.dispose();
return this;
diff --git a/src/yugecin/opsudance/core/events/EventBus.java b/src/yugecin/opsudance/core/events/EventBus.java
index 51f142a3..5bdf6c98 100644
--- a/src/yugecin/opsudance/core/events/EventBus.java
+++ b/src/yugecin/opsudance/core/events/EventBus.java
@@ -22,10 +22,14 @@ import java.util.*;
@SuppressWarnings("unchecked")
public class EventBus {
+ @Deprecated
+ public static EventBus instance; // TODO get rid of this
+
private final List subscribers;
public EventBus() {
subscribers = new LinkedList<>();
+ instance = this;
}
public void subscribe(Class eventType, EventListener eventListener) {
diff --git a/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java b/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java
index 0617463c..13f72a50 100644
--- a/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java
+++ b/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java
@@ -17,6 +17,7 @@
*/
package yugecin.opsudance.core.inject;
+import itdelatrisu.opsu.states.*;
import yugecin.opsudance.PreStartupInitializer;
import yugecin.opsudance.core.DisplayContainer;
import yugecin.opsudance.core.events.EventBus;
@@ -50,6 +51,15 @@ public class OpsuDanceInjector extends Injector {
bind(EmptyRedState.class).asEagerSingleton();
bind(EmptyState.class).asEagerSingleton();
+
+ bind(Splash.class).asEagerSingleton();
+ bind(MainMenu.class).asEagerSingleton();
+ bind(ButtonMenu.class).asEagerSingleton();
+ bind(SongMenu.class).asEagerSingleton();
+ bind(DownloadsMenu.class).asEagerSingleton();
+ bind(Game.class).asEagerSingleton();
+ bind(GameRanking.class).asEagerSingleton();
+ bind(GamePauseMenu.class).asEagerSingleton();
}
}
diff --git a/src/yugecin/opsudance/core/state/BaseOpsuState.java b/src/yugecin/opsudance/core/state/BaseOpsuState.java
index 3777ba3e..86bdfb9c 100644
--- a/src/yugecin/opsudance/core/state/BaseOpsuState.java
+++ b/src/yugecin/opsudance/core/state/BaseOpsuState.java
@@ -17,6 +17,10 @@
*/
package yugecin.opsudance.core.state;
+import itdelatrisu.opsu.Options;
+import itdelatrisu.opsu.Utils;
+import org.newdawn.slick.Graphics;
+import org.newdawn.slick.Input;
import yugecin.opsudance.core.DisplayContainer;
import yugecin.opsudance.core.events.EventListener;
import yugecin.opsudance.events.ResolutionChangedEvent;
@@ -41,6 +45,18 @@ public abstract class BaseOpsuState implements OpsuState, EventListener BaseOpsuState dump\n");
diff --git a/src/yugecin/opsudance/core/state/ComplexOpsuState.java b/src/yugecin/opsudance/core/state/ComplexOpsuState.java
new file mode 100644
index 00000000..d0dc544e
--- /dev/null
+++ b/src/yugecin/opsudance/core/state/ComplexOpsuState.java
@@ -0,0 +1,194 @@
+/*
+ * opsu!dance - fork of opsu! with cursordance auto
+ * Copyright (C) 2017 yugecin
+ *
+ * opsu!dance is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * opsu!dance is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with opsu!dance. If not, see .
+ */
+package yugecin.opsudance.core.state;
+
+import org.newdawn.slick.Graphics;
+import org.newdawn.slick.Input;
+import yugecin.opsudance.core.DisplayContainer;
+import yugecin.opsudance.core.components.Component;
+
+import java.util.LinkedList;
+
+public abstract class ComplexOpsuState extends BaseOpsuState {
+
+ protected final LinkedList components;
+ protected final LinkedList overlays;
+
+ private Component focusedComponent;
+
+ public ComplexOpsuState(DisplayContainer displayContainer) {
+ super(displayContainer);
+ this.components = new LinkedList<>();
+ this.overlays = new LinkedList<>();
+ }
+
+ public final void focusComponent(Component component) {
+ if (!component.isFocusable()) {
+ return;
+ }
+ if (focusedComponent != null) {
+ focusedComponent.setFocused(false);
+ }
+ focusedComponent = component;
+ component.setFocused(true);
+ }
+
+ public boolean isAnyComponentFocused() {
+ return focusedComponent != null || isAnyOverlayActive();
+ }
+
+ public boolean isAnyOverlayActive() {
+ for (OverlayOpsuState overlay : overlays) {
+ if (overlay.active) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean mouseWheelMoved(int delta) {
+ for (OverlayOpsuState overlay : overlays) {
+ if (overlay.mouseWheelMoved(delta)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean mousePressed(int button, int x, int y) {
+ for (OverlayOpsuState overlay : overlays) {
+ if (overlay.mousePressed(button, x, y)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean mouseDragged(int oldx, int oldy, int newx, int newy) {
+ for (OverlayOpsuState overlay : overlays) {
+ if (overlay.mouseDragged(oldx, oldy, newx, newy)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean mouseReleased(int button, int x, int y) {
+ for (OverlayOpsuState overlay : overlays) {
+ if (overlay.mouseReleased(button, x, y)) {
+ return true;
+ }
+ }
+ if (focusedComponent == null) {
+ for (Component component : components) {
+ if (!component.isFocusable()) {
+ continue;
+ }
+ component.updateHover(x, y);
+ if (component.isHovered()) {
+ focusedComponent = component;
+ focusedComponent.setFocused(true);
+ return true;
+ }
+ }
+ return false;
+ }
+ focusedComponent.updateHover(x, y);
+ if (focusedComponent.isHovered()) {
+ focusedComponent.mouseReleased(button);
+ return true;
+ }
+ focusedComponent.setFocused(false);
+ focusedComponent = null;
+ return true;
+ }
+
+ @Override
+ public void preRenderUpdate() {
+ super.preRenderUpdate();
+ for (Component component : components) {
+ component.updateHover(displayContainer.mouseX, displayContainer.mouseY);
+ component.preRenderUpdate();
+ }
+ for (OverlayOpsuState overlay : overlays) {
+ overlay.preRenderUpdate();
+ }
+ }
+
+ @Override
+ protected void revalidate() {
+ super.revalidate();
+ for (OverlayOpsuState overlay : overlays) {
+ overlay.revalidate();
+ }
+ }
+
+ @Override
+ public void render(Graphics g) {
+ for (OverlayOpsuState overlay : overlays) {
+ overlay.render(g);
+ }
+ super.render(g);
+ }
+
+ @Override
+ public boolean keyReleased(int key, char c) {
+ if (super.keyReleased(key, c)) {
+ return true;
+ }
+ for (OverlayOpsuState overlay : overlays) {
+ if (overlay.keyReleased(key, c)) {
+ return true;
+ }
+ }
+ if (focusedComponent != null) {
+ if (key == Input.KEY_ESCAPE) {
+ focusedComponent.setFocused(false);
+ focusedComponent = null;
+ return true;
+ }
+ focusedComponent.keyReleased(key, c);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean keyPressed(int key, char c) {
+ for (OverlayOpsuState overlay : overlays) {
+ if (overlay.keyPressed(key, c)) {
+ return true;
+ }
+ }
+ if (focusedComponent != null) {
+ if (key == Input.KEY_ESCAPE) {
+ focusedComponent.setFocused(false);
+ focusedComponent = null;
+ return true;
+ }
+ focusedComponent.keyPressed(key, c);
+ return true;
+ }
+ return false;
+ }
+
+}
diff --git a/src/yugecin/opsudance/core/state/OpsuState.java b/src/yugecin/opsudance/core/state/OpsuState.java
index 37902c0b..0a0a65ca 100644
--- a/src/yugecin/opsudance/core/state/OpsuState.java
+++ b/src/yugecin/opsudance/core/state/OpsuState.java
@@ -58,4 +58,9 @@ public interface OpsuState extends ErrorDumpable {
*/
boolean mouseReleased(int button, int x, int y);
+ /**
+ * @return false to stop event bubbling
+ */
+ boolean mouseDragged(int oldx, int oldy, int newx, int newy);
+
}
diff --git a/src/yugecin/opsudance/core/state/OverlayOpsuState.java b/src/yugecin/opsudance/core/state/OverlayOpsuState.java
new file mode 100644
index 00000000..849b4567
--- /dev/null
+++ b/src/yugecin/opsudance/core/state/OverlayOpsuState.java
@@ -0,0 +1,122 @@
+/*
+ * opsu!dance - fork of opsu! with cursordance auto
+ * Copyright (C) 2017 yugecin
+ *
+ * opsu!dance is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * opsu!dance is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with opsu!dance. If not, see .
+ */
+package yugecin.opsudance.core.state;
+
+import org.newdawn.slick.Graphics;
+
+import java.io.StringWriter;
+
+public abstract class OverlayOpsuState implements OpsuState {
+
+ protected boolean active;
+ protected boolean acceptInput;
+
+ public void hide() {
+ acceptInput = active = false;
+ }
+
+ public void show() {
+ acceptInput = active = true;
+ }
+
+ @Override
+ public final void update() {
+ }
+
+ public void revalidate() {
+ }
+
+ protected abstract void onPreRenderUpdate();
+
+ @Override
+ public final void preRenderUpdate() {
+ if (active) {
+ onPreRenderUpdate();
+ }
+ }
+
+ protected abstract void onRender(Graphics g);
+
+ @Override
+ public final void render(Graphics g) {
+ if (active) {
+ onRender(g);
+ }
+ }
+
+ @Override
+ public final void enter() {
+ }
+
+ @Override
+ public final void leave() {
+ }
+
+ @Override
+ public final boolean onCloseRequest() {
+ return true;
+ }
+
+ protected abstract boolean onKeyPressed(int key, char c);
+
+ @Override
+ public final boolean keyPressed(int key, char c) {
+ return acceptInput && onKeyPressed(key, c);
+ }
+
+ protected abstract boolean onKeyReleased(int key, char c);
+
+ @Override
+ public final boolean keyReleased(int key, char c) {
+ return acceptInput && onKeyReleased(key, c);
+ }
+
+ protected abstract boolean onMouseWheelMoved(int delta);
+
+ @Override
+ public final boolean mouseWheelMoved(int delta) {
+ return acceptInput && onMouseWheelMoved(delta);
+ }
+
+ protected abstract boolean onMousePressed(int button, int x, int y);
+
+ @Override
+ public final boolean mousePressed(int button, int x, int y) {
+ return acceptInput && onMousePressed(button, x, y);
+ }
+
+ protected abstract boolean onMouseReleased(int button, int x, int y);
+
+ @Override
+ public final boolean mouseReleased(int button, int x, int y) {
+ return acceptInput && onMouseReleased(button, x, y);
+ }
+
+ protected abstract boolean onMouseDragged(int oldx, int oldy, int newx, int newy);
+
+ @Override
+ public final boolean mouseDragged(int oldx, int oldy, int newx, int newy) {
+ return acceptInput && onMouseDragged(oldx, oldy, newx, newy);
+ }
+
+ @Override
+ public void writeErrorDump(StringWriter dump) {
+ dump.append("> OverlayOpsuState dump\n");
+ dump.append("accepts input: ").append(String.valueOf(acceptInput)).append(" is active: ").append(String.valueOf(active));
+ }
+}
diff --git a/src/yugecin/opsudance/core/state/specialstates/FpsRenderState.java b/src/yugecin/opsudance/core/state/specialstates/FpsRenderState.java
index 89055d22..d8a52f37 100644
--- a/src/yugecin/opsudance/core/state/specialstates/FpsRenderState.java
+++ b/src/yugecin/opsudance/core/state/specialstates/FpsRenderState.java
@@ -43,16 +43,16 @@ public class FpsRenderState implements EventListener {
public void render(Graphics g) {
int x = this.x;
- int target = displayContainer.targetRenderInterval - (displayContainer.targetUpdateInterval % displayContainer.targetRenderInterval);
+ int target = displayContainer.targetRenderInterval + (displayContainer.targetUpdateInterval % displayContainer.targetRenderInterval);
x = drawText(g, getColor(target, displayContainer.renderDelta), (1000 / displayContainer.renderDelta) + " fps", x, this.y);
drawText(g, getColor(displayContainer.targetUpdateInterval, displayContainer.delta), (1000 / displayContainer.delta) + " ups", x, this.y);
}
private Color getColor(int targetValue, int realValue) {
- if (realValue >= targetValue) {
+ if (realValue <= targetValue) {
return GREEN;
}
- if (realValue >= targetValue * 0.9f) {
+ if (realValue <= targetValue * 1.15f) {
return ORANGE;
}
return DARKORANGE;
diff --git a/src/yugecin/opsudance/events/BubbleNotificationEvent.java b/src/yugecin/opsudance/events/BubbleNotificationEvent.java
index caf5b736..8ae2b1de 100644
--- a/src/yugecin/opsudance/events/BubbleNotificationEvent.java
+++ b/src/yugecin/opsudance/events/BubbleNotificationEvent.java
@@ -21,10 +21,11 @@ import org.newdawn.slick.Color;
public class BubbleNotificationEvent {
- public static final Color COMMONCOLOR_RED = new Color(138, 72, 51);
public static final Color COMMONCOLOR_GREEN = new Color(98, 131, 59);
public static final Color COMMONCOLOR_WHITE = new Color(220, 220, 220);
public static final Color COMMONCOLOR_PURPLE = new Color(94, 46, 149);
+ public static final Color COMMONCOLOR_RED = new Color(141, 49, 16);
+ public static final Color COLOR_ORANGE = new Color(138, 72, 51);
public final String message;
public final Color borderColor;
diff --git a/src/yugecin/opsudance/sbv2/MoveStoryboard.java b/src/yugecin/opsudance/sbv2/MoveStoryboard.java
index b6119d86..aa4e95c8 100644
--- a/src/yugecin/opsudance/sbv2/MoveStoryboard.java
+++ b/src/yugecin/opsudance/sbv2/MoveStoryboard.java
@@ -25,6 +25,8 @@ import itdelatrisu.opsu.ui.animations.AnimationEquation;
import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
+import yugecin.opsudance.core.DisplayContainer;
+import yugecin.opsudance.core.state.OverlayOpsuState;
import yugecin.opsudance.sbv2.movers.CubicStoryboardMover;
import yugecin.opsudance.sbv2.movers.LinearStoryboardMover;
import yugecin.opsudance.sbv2.movers.QuadraticStoryboardMover;
@@ -34,20 +36,20 @@ import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
-public class MoveStoryboard {
+public class MoveStoryboard extends OverlayOpsuState{
- private final SimpleButton btnAddLinear;
- private final SimpleButton btnAddQuadratic;
- private final SimpleButton btnAddCubic;
+ private final DisplayContainer displayContainer;
- private final SimpleButton btnAnimLin;
- private final SimpleButton btnAnimMid;
- private final SimpleButton btnAnimCub;
+ private SimpleButton btnAddLinear;
+ private SimpleButton btnAddQuadratic;
+ private SimpleButton btnAddCubic;
+
+ private SimpleButton btnAnimLin;
+ private SimpleButton btnAnimMid;
+ private SimpleButton btnAnimCub;
private final StoryboardMove dummyMove;
- private int width;
-
private StoryboardMove[] moves;
private GameObject[] gameObjects;
@@ -55,14 +57,8 @@ public class MoveStoryboard {
private int trackPosition;
- public MoveStoryboard(GameContainer container) {
- this.width = container.getWidth();
- btnAddLinear = new SimpleButton(width - 205, 50, 200, 25, Fonts.SMALL, "add linear", Colors.BLUE_BUTTON, Colors.WHITE_FADE, Colors.WHITE_FADE, Colors.ORANGE_BUTTON);
- btnAddQuadratic = new SimpleButton(width - 205, 80, 200, 25, Fonts.SMALL, "add quadratic", Colors.BLUE_BUTTON, Colors.WHITE_FADE, Colors.WHITE_FADE, Colors.ORANGE_BUTTON);
- btnAddCubic = new SimpleButton(width - 205, 110, 200, 25, Fonts.SMALL, "add cubic", Colors.BLUE_BUTTON, Colors.WHITE_FADE, Colors.WHITE_FADE, Colors.ORANGE_BUTTON);
- btnAnimLin = new SimpleButton(width - 250, 50, 40, 25, Fonts.SMALL, "lin", Color.blue, Color.white, Color.white, Color.orange);
- btnAnimMid = new SimpleButton(width - 250, 80, 40, 25, Fonts.SMALL, "mid", Color.blue, Color.white, Color.white, Color.orange);
- btnAnimCub = new SimpleButton(width - 250, 110, 40, 25, Fonts.SMALL, "cub", Color.blue, Color.white, Color.white, Color.orange);
+ public MoveStoryboard(DisplayContainer displayContainer) {
+ this.displayContainer = displayContainer;
dummyMove = (StoryboardMove) Proxy.newProxyInstance(StoryboardMove.class.getClassLoader(), new Class>[]{StoryboardMove.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
@@ -71,6 +67,16 @@ public class MoveStoryboard {
});
}
+ @Override
+ public void revalidate() {
+ btnAddLinear = new SimpleButton(displayContainer.width - 205, 50, 200, 25, Fonts.SMALL, "add linear", Colors.BLUE_BUTTON, Colors.WHITE_FADE, Colors.WHITE_FADE, Colors.ORANGE_BUTTON);
+ btnAddQuadratic = new SimpleButton(displayContainer.width - 205, 80, 200, 25, Fonts.SMALL, "add quadratic", Colors.BLUE_BUTTON, Colors.WHITE_FADE, Colors.WHITE_FADE, Colors.ORANGE_BUTTON);
+ btnAddCubic = new SimpleButton(displayContainer.width - 205, 110, 200, 25, Fonts.SMALL, "add cubic", Colors.BLUE_BUTTON, Colors.WHITE_FADE, Colors.WHITE_FADE, Colors.ORANGE_BUTTON);
+ btnAnimLin = new SimpleButton(displayContainer.width - 250, 50, 40, 25, Fonts.SMALL, "lin", Color.blue, Color.white, Color.white, Color.orange);
+ btnAnimMid = new SimpleButton(displayContainer.width - 250, 80, 40, 25, Fonts.SMALL, "mid", Color.blue, Color.white, Color.white, Color.orange);
+ btnAnimCub = new SimpleButton(displayContainer.width - 250, 110, 40, 25, Fonts.SMALL, "cub", Color.blue, Color.white, Color.white, Color.orange);
+ }
+
/**
* Get the point at the current time
* @param trackPosition current time in ms
@@ -88,7 +94,33 @@ public class MoveStoryboard {
return moves[objectIndex].getPointAt(t);
}
- public void render(Graphics g) {
+ @Override
+ public void hide() {
+
+ }
+
+ @Override
+ public void show() {
+
+ }
+
+ @Override
+ protected void onPreRenderUpdate() {
+ int x = displayContainer.mouseX;
+ int y = displayContainer.mouseY;
+ btnAddLinear.update(x, y);
+ btnAddQuadratic.update(x, y);
+ btnAddCubic.update(x, y);
+ btnAnimLin.update(x, y);
+ btnAnimMid.update(x, y);
+ btnAnimCub.update(x, y);
+ if (moves[objectIndex] != null) {
+ moves[objectIndex].update(displayContainer.renderDelta, x, y);
+ }
+ }
+
+ @Override
+ protected void onRender(Graphics g) {
btnAddLinear.render(g);
btnAddQuadratic.render(g);
btnAddCubic.render(g);
@@ -100,13 +132,31 @@ public class MoveStoryboard {
}
}
- public void mousePressed(int x, int y) {
+ @Override
+ protected boolean onKeyPressed(int key, char c) {
+ return false;
+ }
+
+ @Override
+ protected boolean onKeyReleased(int key, char c) {
+ return false;
+ }
+
+ @Override
+ protected boolean onMouseWheelMoved(int delta) {
+ return false;
+ }
+
+ @Override
+ protected boolean onMousePressed(int button, int x, int y) {
if (moves[objectIndex] != null) {
moves[objectIndex].mousePressed(x, y);
}
+ return true;
}
- public void mouseReleased(int x, int y) {
+ @Override
+ protected boolean onMouseReleased(int button, int x, int y) {
if (moves[objectIndex] != null) {
moves[objectIndex].mouseReleased(x, y);
if (moves[objectIndex].getAmountOfMovers() == 0) {
@@ -114,7 +164,7 @@ public class MoveStoryboard {
}
}
if (objectIndex == 0) {
- return;
+ return true;
}
if (btnAddLinear.isHovered()) {
getCurrentMoveOrCreateNew().add(new LinearStoryboardMover());
@@ -134,6 +184,12 @@ public class MoveStoryboard {
if (btnAnimCub.isHovered()) {
getCurrentMoveOrDummy().setAnimationEquation(AnimationEquation.IN_OUT_EASE_MIDDLE);
}
+ return true;
+ }
+
+ @Override
+ protected boolean onMouseDragged(int oldx, int oldy, int newx, int newy) {
+ return false;
}
private StoryboardMove getCurrentMoveOrCreateNew() {
@@ -142,7 +198,7 @@ public class MoveStoryboard {
return dummyMove;
}
if (moves[objectIndex] == null) {
- return moves[objectIndex] = new StoryboardMoveImpl(gameObjects[objectIndex - 1].end, gameObjects[objectIndex].start, width);
+ return moves[objectIndex] = new StoryboardMoveImpl(gameObjects[objectIndex - 1].end, gameObjects[objectIndex].start, displayContainer.width);
}
return moves[objectIndex];
}
@@ -154,18 +210,6 @@ public class MoveStoryboard {
return moves[objectIndex];
}
- public void update(int delta, int x, int y) {
- btnAddLinear.update(x, y);
- btnAddQuadratic.update(x, y);
- btnAddCubic.update(x, y);
- btnAnimLin.update(x, y);
- btnAnimMid.update(x, y);
- btnAnimCub.update(x, y);
- if (moves[objectIndex] != null) {
- moves[objectIndex].update(delta, x, y);
- }
- }
-
public void setGameObjects(GameObject[] gameObjects) {
this.gameObjects = gameObjects;
this.moves = new StoryboardMove[gameObjects.length];
diff --git a/src/yugecin/opsudance/states/EmptyRedState.java b/src/yugecin/opsudance/states/EmptyRedState.java
index fcf52029..95c6427c 100644
--- a/src/yugecin/opsudance/states/EmptyRedState.java
+++ b/src/yugecin/opsudance/states/EmptyRedState.java
@@ -100,6 +100,11 @@ public class EmptyRedState implements OpsuState {
return false;
}
+ @Override
+ public boolean mouseDragged(int oldx, int oldy, int newx, int newy) {
+ return false;
+ }
+
@Override
public void writeErrorDump(StringWriter dump) {
dump.append("> EmptyRedState dump\n");
diff --git a/src/yugecin/opsudance/states/EmptyState.java b/src/yugecin/opsudance/states/EmptyState.java
index 28703a57..6a75f783 100644
--- a/src/yugecin/opsudance/states/EmptyState.java
+++ b/src/yugecin/opsudance/states/EmptyState.java
@@ -92,6 +92,11 @@ public class EmptyState implements OpsuState {
return false;
}
+ @Override
+ public boolean mouseDragged(int oldx, int oldy, int newx, int newy) {
+ return false;
+ }
+
@Override
public void writeErrorDump(StringWriter dump) {
dump.append("> EmptyState dump\n");
diff --git a/src/yugecin/opsudance/ui/OptionsOverlay.java b/src/yugecin/opsudance/ui/OptionsOverlay.java
index fdff1e3f..0aae9e08 100644
--- a/src/yugecin/opsudance/ui/OptionsOverlay.java
+++ b/src/yugecin/opsudance/ui/OptionsOverlay.java
@@ -29,16 +29,18 @@ import itdelatrisu.opsu.ui.Fonts;
import itdelatrisu.opsu.ui.MenuButton;
import itdelatrisu.opsu.ui.UI;
import org.newdawn.slick.*;
+import yugecin.opsudance.core.DisplayContainer;
+import yugecin.opsudance.core.state.OverlayOpsuState;
-@SuppressWarnings("UnusedParameters")
-public class OptionsOverlay {
+public class OptionsOverlay extends OverlayOpsuState {
- private Parent parent;
- private GameContainer container;
+ private final DisplayContainer displayContainer;
- private final Image sliderBallImg;
- private final Image checkOnImg;
- private final Image checkOffImg;
+ private Listener listener;
+
+ private Image sliderBallImg;
+ private Image checkOnImg;
+ private Image checkOffImg;
private OptionTab[] tabs;
private int selectedTab;
@@ -79,21 +81,29 @@ public class OptionsOverlay {
private int sliderSoundDelay;
- public OptionsOverlay(Parent parent, OptionTab[] tabs, int defaultSelectedTabIndex, GameContainer container) {
- this.parent = parent;
- this.container = container;
+ public OptionsOverlay(DisplayContainer displayContainer, OptionTab[] tabs, int defaultSelectedTabIndex) {
+ this.displayContainer = displayContainer;
this.tabs = tabs;
selectedTab = defaultSelectedTabIndex;
listHoverIndex = -1;
+ }
+
+ public void setListener(Listener listener) {
+ this.listener = listener;
+ }
+
+ @Override
+ public void revalidate() {
+ super.revalidate();
sliderBallImg = GameImage.CONTROL_SLIDER_BALL.getImage().getScaledCopy(20, 20);
checkOnImg = GameImage.CONTROL_CHECK_ON.getImage().getScaledCopy(20, 20);
checkOffImg = GameImage.CONTROL_CHECK_OFF.getImage().getScaledCopy(20, 20);
- width = container.getWidth();
- height = container.getHeight();
+ width = displayContainer.width;
+ height = displayContainer.height;
// calculate positions
optionWidth = width / 2;
@@ -109,10 +119,12 @@ public class OptionsOverlay {
maxScrollOffset = Fonts.MEDIUM.getLineHeight() * 2 * tabs.length;
scrollOffset = 0;
for (OptionTab tab : tabs) {
+ /*
if (defaultSelectedTabIndex-- > 0) {
scrollOffset += Fonts.MEDIUM.getLineHeight() * 2;
scrollOffset += tab.options.length * optionHeight;
}
+ */
maxScrollOffset += tab.options.length * optionHeight;
tab.button = new MenuButton(tabImage, tabX, tabY);
tabX += tabOffset;
@@ -127,7 +139,8 @@ public class OptionsOverlay {
optionStartY = (int) (tabY + tabImage.getHeight() / 2 + 2); // +2 for the separator line
}
- public void render(Graphics g, int mouseX, int mouseY) {
+ @Override
+ public void onRender(Graphics g) {
// bg
g.setColor(Colors.BLACK_ALPHA_75);
g.fillRect(0, 0, width, height);
@@ -136,7 +149,7 @@ public class OptionsOverlay {
renderTitle();
// option tabs
- renderTabs(mouseX, mouseY);
+ renderTabs();
// line separator
g.setColor(Color.white);
@@ -159,7 +172,7 @@ public class OptionsOverlay {
UI.getBackButton().draw();
// tooltip
- renderTooltip(g, mouseX, mouseY);
+ renderTooltip(g);
// key input options
if (keyEntryLeft || keyEntryRight) {
@@ -175,15 +188,10 @@ public class OptionsOverlay {
Fonts.LARGE.drawString((width - Fonts.LARGE.getWidth(prompt)) / 2, (height - Fonts.LARGE.getLineHeight()) / 2, prompt);
}
- private void renderTooltip(Graphics g, int mouseX, int mouseY) {
+ private void renderTooltip(Graphics g) {
if (hoverOption != null) {
- String optionDescription = hoverOption.getDescription();
- float textWidth = Fonts.SMALL.getWidth(optionDescription);
- Color.black.a = 0.7f;
- g.setColor(Color.black);
- g.fillRoundRect(mouseX + 10, mouseY + 10, 10 + textWidth, 10 + Fonts.SMALL.getLineHeight(), 4);
- Fonts.SMALL.drawString(mouseX + 15, mouseY + 15, optionDescription, Color.white);
- Color.black.a = 1f;
+ UI.updateTooltip(displayContainer.renderDelta, hoverOption.getDescription(), false);
+ UI.drawTooltip(g);
}
}
@@ -322,10 +330,10 @@ public class OptionsOverlay {
Fonts.MEDIUM.drawString(optionStartX + optionWidth - valueLen, y, value, Colors.BLUE_BACKGROUND);
}
- public void renderTabs(int mouseX, int mouseY) {
+ public void renderTabs() {
for (int i = 0; i < tabs.length; i++) {
OptionTab tab = tabs[i];
- boolean hovering = tab.button.contains(mouseX, mouseY);
+ boolean hovering = tab.button.contains(displayContainer.mouseX, displayContainer.mouseY);
UI.drawTab(tab.button.getX(), tab.button.getY(), tab.name, i == selectedTab, hovering);
}
}
@@ -339,7 +347,25 @@ public class OptionsOverlay {
Fonts.DEFAULT.drawString(marginX, marginY, "Change the way opsu! behaves", Color.white);
}
- public void update(int delta, int mouseX, int mouseY) {
+ @Override
+ public void hide() {
+ acceptInput = false;
+ SoundController.playSound(SoundEffect.MENUBACK);
+ active = false;
+ }
+
+ @Override
+ public void show() {
+ acceptInput = true;
+ active = true;
+ }
+
+ @Override
+ public void onPreRenderUpdate() {
+ int mouseX = displayContainer.mouseX;
+ int mouseY = displayContainer.mouseY;
+ int delta = displayContainer.renderDelta;
+
if (sliderSoundDelay > 0) {
sliderSoundDelay -= delta;
}
@@ -352,7 +378,7 @@ public class OptionsOverlay {
UI.getBackButton().hoverUpdate(delta, mouseX, mouseY);
if (isAdjustingSlider) {
int sliderValue = hoverOption.getIntegerValue();
- updateSliderOption(mouseX, mouseY);
+ updateSliderOption();
if (hoverOption.getIntegerValue() - sliderValue != 0 && sliderSoundDelay <= 0) {
sliderSoundDelay = 90;
SoundController.playSound(SoundEffect.MENUHIT);
@@ -366,22 +392,27 @@ public class OptionsOverlay {
}
}
- public void mousePressed(int button, int x, int y) {
+ @Override
+ public boolean onMousePressed(int button, int x, int y) {
if (keyEntryLeft || keyEntryRight) {
keyEntryLeft = keyEntryRight = false;
- return;
+ return true;
}
if (isListOptionOpen) {
if (y > optionStartY && listStartX <= x && x < listStartX + listWidth && listStartY <= y && y < listStartY + listHeight) {
- hoverOption.clickListItem(listHoverIndex);
- parent.onSaveOption(hoverOption);
+ if (0 <= listHoverIndex && listHoverIndex < hoverOption.getListItems().length) {
+ hoverOption.clickListItem(listHoverIndex);
+ if (listener != null) {
+ listener.onSaveOption(hoverOption);
+ }
+ }
SoundController.playSound(SoundEffect.MENUCLICK);
}
isListOptionOpen = false;
listHoverIndex = -1;
updateHoverOption(x, y);
- return;
+ return true;
}
mousePressY = y;
@@ -393,35 +424,39 @@ public class OptionsOverlay {
} else if (hoverOption.getType() == OptionType.NUMERIC) {
isAdjustingSlider = sliderOptionStartX <= x && x < sliderOptionStartX + sliderOptionLength;
if (isAdjustingSlider) {
- updateSliderOption(x, y);
+ updateSliderOption();
}
}
}
if (UI.getBackButton().contains(x, y)) {
- parent.onLeave();
+ hide();
}
+ return true;
}
- public void mouseReleased(int button, int x, int y) {
+ @Override
+ public boolean onMouseReleased(int button, int x, int y) {
selectedOption = null;
- if (isAdjustingSlider) {
- parent.onSaveOption(hoverOption);
+ if (isAdjustingSlider && listener != null) {
+ listener.onSaveOption(hoverOption);
}
isAdjustingSlider = false;
sliderOptionLength = 0;
// check if clicked, not dragged
if (Math.abs(y - mousePressY) >= 5) {
- return;
+ return true;
}
if (hoverOption != null) {
if (hoverOption.getType() == OptionType.BOOLEAN) {
- hoverOption.click(container);
- parent.onSaveOption(hoverOption);
+ hoverOption.click();
+ if (listener != null) {
+ listener.onSaveOption(hoverOption);
+ }
SoundController.playSound(SoundEffect.MENUHIT);
- return;
+ return true;
} else if (hoverOption == GameOption.KEY_LEFT) {
keyEntryLeft = true;
} else if (hoverOption == GameOption.KEY_RIGHT) {
@@ -435,27 +470,38 @@ public class OptionsOverlay {
if (tab.button.contains(x, y)) {
scrollOffset = tScrollOffset;
SoundController.playSound(SoundEffect.MENUCLICK);
- return;
+ return true;
}
tScrollOffset += Fonts.MEDIUM.getLineHeight() * 2;
tScrollOffset += tab.options.length * optionHeight;
}
+
+ if (UI.getBackButton().contains(x, y) && listener != null) {
+ listener.onLeaveOptionsMenu();
+ }
+
+ return true;
}
- public void mouseDragged(int oldx, int oldy, int newx, int newy) {
+ @Override
+ public boolean onMouseDragged(int oldx, int oldy, int newx, int newy) {
if (!isAdjustingSlider) {
scrollOffset = Utils.clamp(scrollOffset + oldy - newy, 0, maxScrollOffset);
}
+ return true;
}
- public void mouseWheelMoved(int delta) {
+ @Override
+ public boolean onMouseWheelMoved(int delta) {
if (!isAdjustingSlider) {
scrollOffset = Utils.clamp(scrollOffset - delta, 0, maxScrollOffset);
}
updateHoverOption(prevMouseX, prevMouseY);
+ return true;
}
- public boolean keyPressed(int key, char c) {
+ @Override
+ public boolean onKeyPressed(int key, char c) {
if (keyEntryRight) {
Options.setGameKeyRight(key);
keyEntryRight = false;
@@ -468,23 +514,31 @@ public class OptionsOverlay {
return true;
}
- switch (key) {
- case Input.KEY_ESCAPE:
- if (isListOptionOpen) {
- isListOptionOpen = false;
- listHoverIndex = -1;
- return true;
- }
- parent.onLeave();
+ if (key == Input.KEY_ESCAPE) {
+ if (isListOptionOpen) {
+ isListOptionOpen = false;
+ listHoverIndex = -1;
return true;
+ }
+ hide();
+ if (listener != null) {
+ listener.onLeaveOptionsMenu();
+ }
+ return true;
}
+
return false;
}
- private void updateSliderOption(int mouseX, int mouseY) {
+ @Override
+ public boolean onKeyReleased(int key, char c) {
+ return false;
+ }
+
+ private void updateSliderOption() {
int min = hoverOption.getMinValue();
int max = hoverOption.getMaxValue();
- int value = min + Math.round((float) (max - min) * (mouseX - sliderOptionStartX) / (sliderOptionLength));
+ int value = min + Math.round((float) (max - min) * (displayContainer.mouseX - sliderOptionStartX) / (sliderOptionLength));
hoverOption.setValue(Utils.clamp(value, min, max));
}
@@ -533,10 +587,9 @@ public class OptionsOverlay {
}
- public interface Parent {
-
- void onLeave();
+ public interface Listener {
+ void onLeaveOptionsMenu();
void onSaveOption(GameOption option);
}
diff --git a/src/yugecin/opsudance/ui/SBOverlay.java b/src/yugecin/opsudance/ui/StoryboardOverlay.java
similarity index 59%
rename from src/yugecin/opsudance/ui/SBOverlay.java
rename to src/yugecin/opsudance/ui/StoryboardOverlay.java
index bd03da4d..725dc107 100644
--- a/src/yugecin/opsudance/ui/SBOverlay.java
+++ b/src/yugecin/opsudance/ui/StoryboardOverlay.java
@@ -22,86 +22,27 @@ import itdelatrisu.opsu.Options.GameOption;
import itdelatrisu.opsu.audio.MusicController;
import itdelatrisu.opsu.objects.GameObject;
import itdelatrisu.opsu.states.Game;
+import itdelatrisu.opsu.states.OptionsMenu;
import itdelatrisu.opsu.ui.Fonts;
import org.newdawn.slick.Color;
-import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import yugecin.opsudance.ObjectColorOverrides;
+import yugecin.opsudance.core.DisplayContainer;
+import yugecin.opsudance.core.state.OverlayOpsuState;
import yugecin.opsudance.sbv2.MoveStoryboard;
import yugecin.opsudance.ui.OptionsOverlay.OptionTab;
import java.util.*;
@SuppressWarnings("unchecked")
-public class SBOverlay implements OptionsOverlay.Parent {
-
- private static final OptionTab[] options = new OptionsOverlay.OptionTab[]{
- new OptionTab("Gameplay", new GameOption[] {
- GameOption.BACKGROUND_DIM,
- GameOption.DANCE_REMOVE_BG,
- GameOption.SNAKING_SLIDERS,
- GameOption.SHRINKING_SLIDERS,
- GameOption.SHOW_HIT_LIGHTING,
- GameOption.SHOW_HIT_ANIMATIONS,
- GameOption.SHOW_COMBO_BURSTS,
- GameOption.SHOW_PERFECT_HIT,
- GameOption.SHOW_FOLLOW_POINTS,
- }),
- new OptionTab("Input", new GameOption[] {
- GameOption.CURSOR_SIZE,
- GameOption.NEW_CURSOR,
- GameOption.DISABLE_CURSOR
- }),
- new OptionTab("Dance", new GameOption[] {
- GameOption.DANCE_MOVER,
- GameOption.DANCE_EXGON_DELAY,
- GameOption.DANCE_QUAD_BEZ_AGGRESSIVENESS,
- GameOption.DANCE_QUAD_BEZ_SLIDER_AGGRESSIVENESS_FACTOR,
- GameOption.DANCE_QUAD_BEZ_USE_CUBIC_ON_SLIDERS,
- GameOption.DANCE_QUAD_BEZ_CUBIC_AGGRESSIVENESS_FACTOR,
- GameOption.DANCE_MOVER_DIRECTION,
- GameOption.DANCE_SLIDER_MOVER_TYPE,
- GameOption.DANCE_SPINNER,
- GameOption.DANCE_SPINNER_DELAY,
- GameOption.DANCE_LAZY_SLIDERS,
- GameOption.DANCE_CIRCLE_STREAMS,
- GameOption.DANCE_ONLY_CIRCLE_STACKS,
- GameOption.DANCE_CIRLCE_IN_SLOW_SLIDERS,
- GameOption.DANCE_CIRLCE_IN_LAZY_SLIDERS,
- GameOption.DANCE_MIRROR,
- }),
- new OptionTab("Dance display", new GameOption[] {
- GameOption.DANCE_DRAW_APPROACH,
- GameOption.DANCE_OBJECT_COLOR_OVERRIDE,
- GameOption.DANCE_OBJECT_COLOR_OVERRIDE_MIRRORED,
- GameOption.DANCE_RGB_OBJECT_INC,
- GameOption.DANCE_CURSOR_COLOR_OVERRIDE,
- GameOption.DANCE_CURSOR_MIRROR_COLOR_OVERRIDE,
- GameOption.DANCE_CURSOR_ONLY_COLOR_TRAIL,
- GameOption.DANCE_RGB_CURSOR_INC,
- GameOption.DANCE_CURSOR_TRAIL_OVERRIDE,
- GameOption.DANCE_HIDE_OBJECTS,
- GameOption.DANCE_HIDE_UI,
- GameOption.DANCE_HIDE_WATERMARK,
- }),
- new OptionTab ("Pippi", new GameOption[] {
- GameOption.PIPPI_ENABLE,
- GameOption.PIPPI_RADIUS_PERCENT,
- GameOption.PIPPI_ANGLE_INC_MUL,
- GameOption.PIPPI_ANGLE_INC_MUL_SLIDER,
- GameOption.PIPPI_SLIDER_FOLLOW_EXPAND,
- GameOption.PIPPI_PREVENT_WOBBLY_STREAMS,
- })
- };
+public class StoryboardOverlay extends OverlayOpsuState implements OptionsOverlay.Listener {
private final static List optionList = new ArrayList<>();
- private boolean hide;
- private boolean menu;
+ private final DisplayContainer displayContainer;
- private int width;
- private int height;
+ private boolean hide;
private int speed;
private GameObject[] gameObjects;
@@ -112,43 +53,42 @@ public class SBOverlay implements OptionsOverlay.Parent {
private final Game game;
private final MoveStoryboard msb;
- private final OptionsOverlay overlay;
+ private final OptionsOverlay optionsOverlay;
static {
- for (OptionTab tab : options) {
+ for (OptionTab tab : OptionsMenu.storyboardOptions) {
optionList.addAll(Arrays.asList(tab.options));
}
}
- public SBOverlay(Game game, MoveStoryboard msb, GameContainer container) {
- this.game = game;
+ public StoryboardOverlay(DisplayContainer displayContainer, MoveStoryboard msb, OptionsOverlay optionsOverlay, Game game) {
+ this.displayContainer = displayContainer;
this.msb = msb;
+ this.optionsOverlay = optionsOverlay;
+ this.game = game;
initialOptions = new HashMap<>();
- overlay = new OptionsOverlay(this, options, 2, container);
- this.width = container.getWidth();
- this.height = container.getHeight();
speed = 10;
gameObjects = new GameObject[0];
}
- public void render(GameContainer container, Graphics g) {
+ @Override
+ public void onRender(Graphics g) {
if (!Options.isEnableSB() || hide) {
return;
}
- msb.render(g);
int lh = Fonts.SMALL.getLineHeight();
- Fonts.SMALL.drawString(10, height - 50 + lh, "save position: ctrl+s, load position: ctrl+l", Color.cyan);
- Fonts.SMALL.drawString(10, height - 50, "speed: C " + (speed / 10f) + " V", Color.cyan);
- Fonts.SMALL.drawString(10, height - 50 - lh, "Menu: N", Color.cyan);
- Fonts.SMALL.drawString(10, height - 50 - lh * 2, "HIDE: H", Color.cyan);
- Fonts.SMALL.drawString(10, height - 50 - lh * 3, "obj: J " + index + " K", Color.cyan);
+ Fonts.SMALL.drawString(10, displayContainer.height - 50 + lh, "save position: ctrl+s, load position: ctrl+l", Color.cyan);
+ Fonts.SMALL.drawString(10, displayContainer.height - 50, "speed: C " + (speed / 10f) + " V", Color.cyan);
+ Fonts.SMALL.drawString(10, displayContainer.height - 50 - lh, "Menu: N", Color.cyan);
+ Fonts.SMALL.drawString(10, displayContainer.height - 50 - lh * 2, "HIDE: H", Color.cyan);
+ Fonts.SMALL.drawString(10, displayContainer.height - 50 - lh * 3, "obj: J " + index + " K", Color.cyan);
g.setColor(Color.red);
if (index < optionsMap.length && optionsMap[index] != null) {
int i = 0;
for (Object o : optionsMap[index].entrySet()) {
Map.Entry option = (Map.Entry) o;
Fonts.SMALL.drawString(10, 50 + i * lh, option.getKey().getName(), Color.cyan);
- Fonts.SMALL.drawString(width / 5, 50 + i * lh, option.getKey().getValueString(), Color.cyan);
+ Fonts.SMALL.drawString(displayContainer.width / 5, 50 + i * lh, option.getKey().getValueString(), Color.cyan);
g.fillRect(0, 50 + i * lh + lh / 4, 10, 10);
i++;
}
@@ -157,27 +97,16 @@ public class SBOverlay implements OptionsOverlay.Parent {
int start = gameObjects[0].getTime();
int end = gameObjects[gameObjects.length - 1].getEndTime();
float curtime = (float) (MusicController.getPosition() - start) / (end - start);
- g.fillRect(curtime * width, height - 10f, 10f, 10f);
- }
- if (menu) {
- overlay.render(g, container.getInput().getMouseX(), container.getInput().getMouseY());
+ g.fillRect(curtime * displayContainer.width, displayContainer.height - 10f, 10f, 10f);
}
}
- public void update(int delta, int mouseX, int mouseY) {
- if (Options.isEnableSB() && menu) {
- overlay.update(delta, mouseX, mouseY);
- }
- msb.update(delta, mouseX, mouseY);
+ @Override
+ public void onPreRenderUpdate() {
}
- public boolean keyPressed(int key, char c) {
- if (!Options.isEnableSB()) {
- return false;
- }
- if (menu && overlay.keyPressed(key, c)) {
- return true;
- }
+ @Override
+ public boolean onKeyPressed(int key, char c) {
if (key == Input.KEY_C) {
if (speed > 0) {
speed -= 1;
@@ -196,11 +125,9 @@ public class SBOverlay implements OptionsOverlay.Parent {
} else if (key == Input.KEY_H) {
hide = !hide;
} else if (key == Input.KEY_N) {
- menu = !menu;
- if (menu && speed != 0) {
+ optionsOverlay.show();
+ if (speed != 0) {
MusicController.pause();
- } else if (!menu && speed != 0) {
- MusicController.resume();
}
} else if (key == Input.KEY_J && index > 0) {
index--;
@@ -214,6 +141,11 @@ public class SBOverlay implements OptionsOverlay.Parent {
return false;
}
+ @Override
+ protected boolean onKeyReleased(int key, char c) {
+ return false;
+ }
+
private void goBackOneSBIndex() {
if (index + 1 < optionsMap.length) {
// new options on previous index, so to revert then we have to reload them all to this point..
@@ -252,20 +184,13 @@ public class SBOverlay implements OptionsOverlay.Parent {
this.gameObjects = gameObjects;
}
- public boolean mousePressed(int button, int x, int y) {
- msb.mousePressed(x, y);
- if (!menu) {
- return false;
- }
- overlay.mousePressed(button, x, y);
+ @Override
+ public boolean onMousePressed(int button, int x, int y) {
return true;
}
- public boolean mouseDragged(int oldx, int oldy, int newx, int newy) {
- if (!menu) {
- return false;
- }
- overlay.mouseDragged(oldx, oldy, newx, newy);
+ @Override
+ public boolean onMouseDragged(int oldx, int oldy, int newx, int newy) {
return true;
}
@@ -293,12 +218,8 @@ public class SBOverlay implements OptionsOverlay.Parent {
this.index--;
}
- public boolean mouseReleased(int button, int x, int y) {
- if (menu) {
- overlay.mouseReleased(button, x, y);
- return true;
- }
- msb.mouseReleased(x, y);
+ @Override
+ public boolean onMouseReleased(int button, int x, int y) {
if (x > 10 || index >= optionsMap.length || optionsMap[index] == null) {
return false;
}
@@ -318,15 +239,12 @@ public class SBOverlay implements OptionsOverlay.Parent {
return true;
}
- public boolean mouseWheelMoved(int delta) {
- if (!menu) {
- return false;
- }
- overlay.mouseWheelMoved(delta);
+ @Override
+ public boolean onMouseWheelMoved(int delta) {
return true;
}
- public void enter() {
+ public void onEnter() {
// enter, save current settings
for (Options.GameOption o : optionList) {
initialOptions.put(o, o.write());
@@ -334,7 +252,7 @@ public class SBOverlay implements OptionsOverlay.Parent {
speed = 10;
}
- public void leave() {
+ public void onLeave() {
// leave, revert the settings saved before entering
for (Options.GameOption o : optionList) {
if (initialOptions.containsKey(o)) {
@@ -358,13 +276,8 @@ public class SBOverlay implements OptionsOverlay.Parent {
}
}
- public float[] getPoint(int trackPosition) {
- return msb.getPoint(trackPosition);
- }
-
@Override
- public void onLeave() {
- menu = false;
+ public void onLeaveOptionsMenu() {
if (speed != 0) {
MusicController.resume();
}
diff --git a/src/yugecin/opsudance/utils/GLHelper.java b/src/yugecin/opsudance/utils/GLHelper.java
index b1d4a965..66db778b 100644
--- a/src/yugecin/opsudance/utils/GLHelper.java
+++ b/src/yugecin/opsudance/utils/GLHelper.java
@@ -17,7 +17,10 @@
*/
package yugecin.opsudance.utils;
+import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
+import org.lwjgl.input.Cursor;
+import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.newdawn.slick.opengl.ImageIOImageData;
@@ -25,8 +28,10 @@ import org.newdawn.slick.opengl.LoadableImageData;
import org.newdawn.slick.opengl.TGAImageData;
import org.newdawn.slick.util.Log;
import org.newdawn.slick.util.ResourceLoader;
+import yugecin.opsudance.core.errorhandling.ErrorHandler;
import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
public class GLHelper {
@@ -85,4 +90,22 @@ public class GLHelper {
Display.setIcon(bufs);
}
+ public static void hideNativeCursor() {
+ try {
+ int min = Cursor.getMinCursorSize();
+ IntBuffer tmp = BufferUtils.createIntBuffer(min * min);
+ Mouse.setNativeCursor(new Cursor(min, min, min / 2, min / 2, 1, tmp, null));
+ } catch (LWJGLException e) {
+ ErrorHandler.error("Cannot hide native cursor", e).show();
+ }
+ }
+
+ public static void showNativeCursor() {
+ try {
+ Mouse.setNativeCursor(null);
+ } catch (LWJGLException e) {
+ ErrorHandler.error("Cannot show native cursor", e).show();
+ }
+ }
+
}
diff --git a/src/yugecin/opsudance/utils/SlickUtil.java b/src/yugecin/opsudance/utils/SlickUtil.java
new file mode 100644
index 00000000..1123caf0
--- /dev/null
+++ b/src/yugecin/opsudance/utils/SlickUtil.java
@@ -0,0 +1,44 @@
+/*
+ * opsu!dance - fork of opsu! with cursordance auto
+ * Copyright (C) 2017 yugecin
+ *
+ * opsu!dance is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * opsu!dance is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with opsu!dance. If not, see .
+ */
+package yugecin.opsudance.utils;
+
+import org.newdawn.slick.Image;
+import org.newdawn.slick.SlickException;
+
+public class SlickUtil {
+
+ public static void destroyImages(Image[] imgs) {
+ if (imgs == null) {
+ return;
+ }
+ for (Image i : imgs) {
+ destroyImage(i);
+ }
+ }
+
+ public static void destroyImage(Image image) {
+ if (image == null) {
+ return;
+ }
+ try {
+ image.destroy();
+ } catch (SlickException ignored) {
+ }
+ }
+
+}