Merge branch 'switch-base' into reorganise
This commit is contained in:
commit
dd731592aa
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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, "", ""));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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.
|
||||
* <p>
|
||||
* 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);
|
||||
}
|
||||
}
|
|
@ -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).
|
||||
* <p>
|
||||
* 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 {
|
|||
* <p>
|
||||
* 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Beatmap> {
|
|||
*/
|
||||
public static void clearBackgroundImageCache() { bgImageCache.clear(); }
|
||||
|
||||
public static void destroyBackgroundImageCache() {
|
||||
Collection<ImageLoader> values = bgImageCache.values();
|
||||
for (ImageLoader value : values) {
|
||||
value.destroy();
|
||||
}
|
||||
bgImageCache.clear();
|
||||
}
|
||||
|
||||
/** The OSU File object associated with this beatmap. */
|
||||
private File file;
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -96,7 +96,7 @@ public class CurveRenderState {
|
|||
*/
|
||||
public static void shutdown() {
|
||||
staticState.shutdown();
|
||||
FrameBufferCache.shutdown();
|
||||
//FrameBufferCache.shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -128,6 +128,7 @@ public class FrameBufferCache {
|
|||
* <p>
|
||||
* 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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
* <p>
|
||||
* 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>();
|
||||
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<String> list = Fonts.wrap(Fonts.LARGE, title[i], maxLineWidth, false);
|
||||
if (Fonts.LARGE.getWidth(aTitle) > maxLineWidth) {
|
||||
List<String> 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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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<DownloadServer>(container, SERVERS,
|
||||
baseX + searchWidth + buttonMarginX * 3f + resetButtonWidth + rankedButtonWidth, searchY, serverWidth) {
|
||||
int x = baseX + searchWidth + buttonMarginX * 3 + resetButtonWidth + rankedButtonWidth;
|
||||
serverMenu = new DropdownMenu<DownloadServer>(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();
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
* </ul>
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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.
|
||||
* <p>
|
||||
* 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<Integer>();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
* <p>
|
||||
* 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,
|
||||
})
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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<BeatmapSortOrder> 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<BeatmapSortOrder>(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<BeatmapSortOrder>(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<SongNode>();
|
||||
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<SongNode>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
* <p>
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Point> trail = new LinkedList<Point>();
|
||||
private LinkedList<Point> 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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<E> extends Component {
|
||||
|
||||
/**
|
||||
* Simple dropdown menu.
|
||||
* <p>
|
||||
* Basic usage:
|
||||
* <ul>
|
||||
* <li>Override {@link #menuClicked(int)} to perform actions when the menu is clicked
|
||||
* (e.g. play a sound effect, block input under certain conditions).
|
||||
* <li>Override {@link #itemSelected(int, Object)} to perform actions when a new item is selected.
|
||||
* <li>Call {@link #activate()}/{@link #deactivate()} whenever the component is needed
|
||||
* (e.g. in a state's {@code enter} and {@code leave} events.
|
||||
* </ul>
|
||||
*
|
||||
* @param <E> the type of the elements in the menu
|
||||
*/
|
||||
public class DropdownMenu<E> 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<E> 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<E> 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<E> 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<cycles;i++) {
|
||||
game.update(this, (int) maximumLogicInterval);
|
||||
}
|
||||
|
||||
int remainder = (int) (storedDelta % maximumLogicInterval);
|
||||
if (remainder > 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);
|
||||
}
|
||||
}
|
|
@ -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<text.length();i++) {
|
||||
keyPressed(-1, text.charAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Record the old position and content
|
||||
*/
|
||||
protected void recordOldPosition() {
|
||||
oldText = getText();
|
||||
oldCursorPos = cursorPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the undo of the paste, overrideable for custom behaviour
|
||||
*
|
||||
* @param oldCursorPos before the paste
|
||||
* @param oldText The text before the last paste
|
||||
*/
|
||||
protected void doUndo(int oldCursorPos, String oldText) {
|
||||
if (oldText != null) {
|
||||
setText(oldText);
|
||||
setCursorPos(oldCursorPos);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.newdawn.slick.gui.AbstractComponent#keyPressed(int, char)
|
||||
*/
|
||||
@Override
|
||||
|
||||
public void keyPressed(int key, char c) {
|
||||
if (hasFocus()) {
|
||||
if (key != -1)
|
||||
{
|
||||
if ((key == Input.KEY_V) &&
|
||||
((input.isKeyDown(Input.KEY_LCONTROL)) || (input.isKeyDown(Input.KEY_RCONTROL)))) {
|
||||
String text = Sys.getClipboard();
|
||||
if (text != null) {
|
||||
doPaste(text);
|
||||
}
|
||||
return;
|
||||
if (key != -1)
|
||||
{
|
||||
if ((key == Input.KEY_V) &&
|
||||
((displayContainer.input.isKeyDown(Input.KEY_LCONTROL)) || (displayContainer.input.isKeyDown(Input.KEY_RCONTROL)))) {
|
||||
String text = Sys.getClipboard();
|
||||
if (text != null) {
|
||||
doPaste(text);
|
||||
}
|
||||
/* if ((key == Input.KEY_Z) &&
|
||||
((input.isKeyDown(Input.KEY_LCONTROL)) || (input.isKeyDown(Input.KEY_RCONTROL)))) {
|
||||
if (oldText != null) {
|
||||
doUndo(oldCursorPos, oldText);
|
||||
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 (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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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) { }
|
||||
|
|
|
@ -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() {
|
||||
|
|
24
src/yugecin/opsudance/core/components/ActionListener.java
Normal file
24
src/yugecin/opsudance/core/components/ActionListener.java
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package yugecin.opsudance.core.components;
|
||||
|
||||
public interface ActionListener {
|
||||
|
||||
void onAction();
|
||||
|
||||
}
|
60
src/yugecin/opsudance/core/components/Component.java
Normal file
60
src/yugecin/opsudance/core/components/Component.java
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* opsu!dance - fork of opsu! with cursordance auto
|
||||
* Copyright (C) 2017 yugecin
|
||||
*
|
||||
* opsu!dance is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* opsu!dance is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package yugecin.opsudance.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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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<Subscriber> subscribers;
|
||||
|
||||
public EventBus() {
|
||||
subscribers = new LinkedList<>();
|
||||
instance = this;
|
||||
}
|
||||
|
||||
public <T> void subscribe(Class<T> eventType, EventListener<T> eventListener) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<Resoluti
|
|||
protected void revalidate() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preRenderUpdate() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Graphics g) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(ResolutionChangedEvent event) {
|
||||
if (isCurrentState) {
|
||||
|
@ -76,6 +92,18 @@ public abstract class BaseOpsuState implements OpsuState, EventListener<Resoluti
|
|||
|
||||
@Override
|
||||
public boolean keyReleased(int key, char c) {
|
||||
if (key == Input.KEY_F7) {
|
||||
Options.setNextFPS(displayContainer);
|
||||
return true;
|
||||
}
|
||||
if (key == Input.KEY_F10) {
|
||||
Options.toggleMouseDisabled();
|
||||
return true;
|
||||
}
|
||||
if (key == Input.KEY_F12) {
|
||||
Utils.takeScreenShot();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -94,6 +122,11 @@ public abstract class BaseOpsuState implements OpsuState, EventListener<Resoluti
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseDragged(int oldx, int oldy, int newx, int newy) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeErrorDump(StringWriter dump) {
|
||||
dump.append("> BaseOpsuState dump\n");
|
||||
|
|
194
src/yugecin/opsudance/core/state/ComplexOpsuState.java
Normal file
194
src/yugecin/opsudance/core/state/ComplexOpsuState.java
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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<Component> components;
|
||||
protected final LinkedList<OverlayOpsuState> 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
122
src/yugecin/opsudance/core/state/OverlayOpsuState.java
Normal file
122
src/yugecin/opsudance/core/state/OverlayOpsuState.java
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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));
|
||||
}
|
||||
}
|
|
@ -43,16 +43,16 @@ public class FpsRenderState implements EventListener<ResolutionChangedEvent> {
|
|||
|
||||
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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
@ -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<GameOption> 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<Options.GameOption, String> option = (Map.Entry<Options.GameOption, String>) 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();
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
44
src/yugecin/opsudance/utils/SlickUtil.java
Normal file
44
src/yugecin/opsudance/utils/SlickUtil.java
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user