diff --git a/CREDITS.md b/CREDITS.md index 94d8aca3..be12ed80 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -17,6 +17,7 @@ The images included in opsu! belong to their respective authors. * pictuga - "osu! web" * sherrie__fay * kouyang +* teinecthel Projects -------- diff --git a/res/cursor.png b/res/cursor.png index 79c21510..f8438108 100644 Binary files a/res/cursor.png and b/res/cursor.png differ diff --git a/res/cursor2.png b/res/cursor2.png new file mode 100644 index 00000000..5fef2fd7 Binary files /dev/null and b/res/cursor2.png differ diff --git a/res/cursormiddle.png b/res/cursormiddle.png new file mode 100644 index 00000000..5a1e1b5b Binary files /dev/null and b/res/cursormiddle.png differ diff --git a/res/cursortrail.png b/res/cursortrail.png new file mode 100644 index 00000000..6379fedd Binary files /dev/null and b/res/cursortrail.png differ diff --git a/res/cursortrail2.png b/res/cursortrail2.png new file mode 100644 index 00000000..9b644d0a Binary files /dev/null and b/res/cursortrail2.png differ diff --git a/src/itdelatrisu/opsu/GameScore.java b/src/itdelatrisu/opsu/GameScore.java index 5b4e69fd..7ef362cb 100644 --- a/src/itdelatrisu/opsu/GameScore.java +++ b/src/itdelatrisu/opsu/GameScore.java @@ -509,7 +509,7 @@ public class GameScore { // header & "Ranking" text float rankingHeight = (rankingImage.getHeight() * 0.75f) + 3; - g.setColor(Options.COLOR_BLACK_ALPHA); + g.setColor(Utils.COLOR_BLACK_ALPHA); g.fillRect(0, 0, width, rankingHeight); rankingImage.draw((width * 0.97f) - rankingImage.getWidth(), 0); diff --git a/src/itdelatrisu/opsu/OsuGroupNode.java b/src/itdelatrisu/opsu/OsuGroupNode.java index a9d3c9d4..83c67a13 100644 --- a/src/itdelatrisu/opsu/OsuGroupNode.java +++ b/src/itdelatrisu/opsu/OsuGroupNode.java @@ -18,8 +18,6 @@ package itdelatrisu.opsu; -import itdelatrisu.opsu.states.Options; - import java.util.ArrayList; import java.util.Comparator; @@ -128,21 +126,21 @@ public class OsuGroupNode implements Comparable { textColor = Color.white; } else { xOffset = bg.getWidth() * 0.05f; - bg.draw(x + xOffset, y, Options.COLOR_BLUE_BUTTON); + bg.draw(x + xOffset, y, Utils.COLOR_BLUE_BUTTON); } osu = osuFiles.get(osuFileIndex); } else { - bg.draw(x, y, Options.COLOR_ORANGE_BUTTON); + bg.draw(x, y, Utils.COLOR_ORANGE_BUTTON); osu = osuFiles.get(0); } float cx = x + (bg.getWidth() * 0.05f) + xOffset; float cy = y + (bg.getHeight() * 0.2f) - 3; - Options.FONT_MEDIUM.drawString(cx, cy, osu.title, textColor); - Options.FONT_DEFAULT.drawString(cx, cy + Options.FONT_MEDIUM.getLineHeight() - 4, String.format("%s // %s", osu.artist, osu.creator), textColor); + Utils.FONT_MEDIUM.drawString(cx, cy, osu.title, textColor); + Utils.FONT_DEFAULT.drawString(cx, cy + Utils.FONT_MEDIUM.getLineHeight() - 4, String.format("%s // %s", osu.artist, osu.creator), textColor); if (expanded) - Options.FONT_BOLD.drawString(cx, cy + Options.FONT_MEDIUM.getLineHeight() + Options.FONT_DEFAULT.getLineHeight() - 8, osu.version, textColor); + Utils.FONT_BOLD.drawString(cx, cy + Utils.FONT_MEDIUM.getLineHeight() + Utils.FONT_DEFAULT.getLineHeight() - 8, osu.version, textColor); } /** diff --git a/src/itdelatrisu/opsu/OsuParser.java b/src/itdelatrisu/opsu/OsuParser.java index 6ff0f07b..89c2fddb 100644 --- a/src/itdelatrisu/opsu/OsuParser.java +++ b/src/itdelatrisu/opsu/OsuParser.java @@ -18,15 +18,12 @@ package itdelatrisu.opsu; -import itdelatrisu.opsu.states.Options; - import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.FilenameFilter; import java.io.IOException; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; @@ -104,8 +101,6 @@ public class OsuParser { try (BufferedReader in = new BufferedReader(new FileReader(file))) { - // copy the default combo colors - osu.combo = Arrays.copyOf(Options.DEFAULT_COMBO, Options.DEFAULT_COMBO.length); // initialize timing point list osu.timingPoints = new ArrayList(); @@ -403,7 +398,7 @@ public class OsuParser { // if no custom colors, use the default color scheme if (osu.combo == null) - osu.combo = Options.DEFAULT_COMBO; + osu.combo = Utils.DEFAULT_COMBO; // add tags if (!tags.isEmpty()) { diff --git a/src/itdelatrisu/opsu/Utils.java b/src/itdelatrisu/opsu/Utils.java new file mode 100644 index 00000000..4417187c --- /dev/null +++ b/src/itdelatrisu/opsu/Utils.java @@ -0,0 +1,369 @@ +/* + * opsu! - an open-source osu! client + * Copyright (C) 2014 Jeffrey Han + * + * opsu! is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * opsu! is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with opsu!. If not, see . + */ + +package itdelatrisu.opsu; + +import itdelatrisu.opsu.states.Options; + +import java.awt.Font; +import java.io.File; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Iterator; +import java.util.LinkedList; + +import org.lwjgl.BufferUtils; +import org.lwjgl.LWJGLException; +import org.lwjgl.input.Cursor; +import org.newdawn.slick.Animation; +import org.newdawn.slick.Color; +import org.newdawn.slick.GameContainer; +import org.newdawn.slick.Image; +import org.newdawn.slick.Input; +import org.newdawn.slick.SlickException; +import org.newdawn.slick.TrueTypeFont; +import org.newdawn.slick.imageout.ImageOut; +import org.newdawn.slick.state.StateBasedGame; +import org.newdawn.slick.util.Log; + +/** + * Contains miscellaneous utilities. + */ +public class Utils { + /** + * Game colors. + */ + public static final Color + COLOR_BLACK_ALPHA = new Color(0, 0, 0, 0.5f), + COLOR_BLUE_DIVIDER = new Color(49, 94, 237), + COLOR_BLUE_BACKGROUND = new Color(74, 130, 255), + COLOR_BLUE_BUTTON = new Color(50, 189, 237), + COLOR_ORANGE_BUTTON = new Color(230, 151, 87), + COLOR_GREEN_OBJECT = new Color(26, 207, 26), + COLOR_BLUE_OBJECT = new Color(46, 136, 248), + COLOR_RED_OBJECT = new Color(243, 48, 77), + COLOR_ORANGE_OBJECT = new Color(255, 200, 32); + + /** + * The default map colors, used when a map does not provide custom colors. + */ + public static final Color[] DEFAULT_COMBO = { + COLOR_GREEN_OBJECT, COLOR_BLUE_OBJECT, + COLOR_RED_OBJECT, COLOR_ORANGE_OBJECT + }; + + /** + * Game fonts. + */ + public static TrueTypeFont + FONT_DEFAULT, FONT_BOLD, + FONT_XLARGE, FONT_LARGE, FONT_MEDIUM, FONT_SMALL; + + /** + * Back button (shared by other states). + */ + private static GUIMenuButton backButton; + + /** + * Cursor image and trail. + */ + private static Image cursor, cursorTrail, cursorMiddle; + + /** + * Last cursor coordinates. + */ + private static int lastX = -1, lastY = -1; + + /** + * Stores all previous cursor locations to display a trail. + */ + private static LinkedList + cursorX = new LinkedList(), + cursorY = new LinkedList(); + + // game-related variables + private static GameContainer container; +// private static StateBasedGame game; + 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 + * @throws SlickException + */ + public static void init(GameContainer container, StateBasedGame game) + throws SlickException { + Utils.container = container; +// Utils.game = game; + Utils.input = container.getInput(); + + // game settings + container.setTargetFrameRate(Options.getTargetFPS()); + container.setMusicVolume(Options.getMusicVolume()); + container.setShowFPS(false); + container.getInput().enableKeyRepeat(); + container.setAlwaysRender(true); + + // hide the cursor + try { + Cursor emptyCursor = new Cursor(1, 1, 0, 0, 1, BufferUtils.createIntBuffer(1), null); + container.setMouseCursor(emptyCursor, 0, 0); + } catch (LWJGLException e) { + Log.error("Failed to set the cursor.", e); + } + + // load cursor images + if (Options.isNewCursorEnabled()) { + // load new cursor type + try { + cursorMiddle = new Image("cursormiddle.png"); + cursor = new Image("cursor.png"); + cursorTrail = new Image("cursortrail.png"); + } catch (Exception e) { + // optional + } + } + if (cursorMiddle == null) { + // load old cursor type + cursor = new Image("cursor2.png"); + cursorTrail = new Image("cursortrail2.png"); + } + + // create fonts + int height = container.getHeight(); + float fontBase; + if (height <= 600) + fontBase = 9f; + else if (height < 800) + fontBase = 10f; + else if (height <= 900) + fontBase = 12f; + else + fontBase = 14f; + + Font font = new Font("Lucida Sans Unicode", Font.PLAIN, (int) (fontBase * 4 / 3)); + FONT_DEFAULT = new TrueTypeFont(font, false); + FONT_BOLD = new TrueTypeFont(font.deriveFont(Font.BOLD), false); + FONT_XLARGE = new TrueTypeFont(font.deriveFont(fontBase * 4), false); + FONT_LARGE = new TrueTypeFont(font.deriveFont(fontBase * 2), false); + FONT_MEDIUM = new TrueTypeFont(font.deriveFont(fontBase * 3 / 2), false); + FONT_SMALL = new TrueTypeFont(font.deriveFont(fontBase), false); + + // back button + Image back = new Image("menu-back.png"); + float scale = (height * 0.1f) / back.getHeight(); + back = back.getScaledCopy(scale); + backButton = new GUIMenuButton(back, + back.getWidth() / 2f, + height - (back.getHeight() / 2f)); + } + + /** + * Returns the 'back' GUIMenuButton. + */ + public static GUIMenuButton getBackButton() { return backButton; } + + /** + * Draws an image based on its center with a color filter. + * @param img the image to draw + * @param x the center x coordinate + * @param y the center y coordinate + * @param color the color filter to apply + */ + public static void drawCentered(Image img, float x, float y, Color color) { + img.draw(x - (img.getWidth() / 2f), y - (img.getHeight() / 2f), color); + } + + /** + * Draws an animation based on its center. + * @param anim the animation to draw + * @param x the center x coordinate + * @param y the center y coordinate + */ + public static void drawCentered(Animation anim, float x, float y) { + anim.draw(x - (anim.getWidth() / 2f), y - (anim.getHeight() / 2f)); + } + + /** + * Draws the cursor. + */ + public static void drawCursor() { + // TODO: use an image buffer + + int x = input.getMouseX(); + int y = input.getMouseY(); + + int removeCount = 0; + int FPSmod = (Options.getTargetFPS() / 60); + + // if middle exists, add all points between cursor movements + if (cursorMiddle != null) { + if (lastX < 0) { + lastX = x; + lastY = y; + return; + } + addCursorPoints(lastX, lastY, x, y); + lastX = x; + lastY = y; + + removeCount = (cursorX.size() / (6 * FPSmod)) + 1; + } + + // else, sample one point at a time + else { + cursorX.add(x); + cursorY.add(y); + + int max = 10 * FPSmod; + if (cursorX.size() > max) + removeCount = cursorX.size() - max; + } + + // remove points from the lists + for (int i = 0; i < removeCount && !cursorX.isEmpty(); i++) { + cursorX.remove(); + cursorY.remove(); + } + + // draw a fading trail + float alpha = 0f; + float t = 2f / cursorX.size(); + Iterator iterX = cursorX.iterator(); + Iterator iterY = cursorY.iterator(); + while (iterX.hasNext()) { + int cx = iterX.next(); + int cy = iterY.next(); + alpha += t; + cursorTrail.setAlpha(alpha); +// if (cx != x || cy != y) + cursorTrail.drawCentered(cx, cy); + } + cursorTrail.drawCentered(x, y); + + // draw the other components + cursor.drawCentered(x, y); + if (cursorMiddle != null) + cursorMiddle.drawCentered(x, y); + } + + /** + * Adds all points between (x1, y1) and (x2, y2) to the cursor point lists. + * @author http://rosettacode.org/wiki/Bitmap/Bresenham's_line_algorithm#Java + */ + private static void addCursorPoints(int x1, int y1, int x2, int y2) { + // delta of exact value and rounded value of the dependent variable + int d = 0; + int dy = Math.abs(y2 - y1); + int dx = Math.abs(x2 - x1); + + int dy2 = (dy << 1); // slope scaling factors to avoid floating + int dx2 = (dx << 1); // point + int ix = x1 < x2 ? 1 : -1; // increment direction + int iy = y1 < y2 ? 1 : -1; + + int k = 5; // sample size + if (dy <= dx) { + for (int i = 0; ; i++) { + if (i == k) { + cursorX.add(x1); + cursorY.add(y1); + i = 0; + } + if (x1 == x2) + break; + x1 += ix; + d += dy2; + if (d > dx) { + y1 += iy; + d -= dx2; + } + } + } else { + for (int i = 0; ; i++) { + if (i == k) { + cursorX.add(x1); + cursorY.add(y1); + i = 0; + } + if (y1 == y2) + break; + y1 += iy; + d += dx2; + if (d > dy) { + x1 += ix; + d -= dy2; + } + } + } + } + + /** + * 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("FPS: %d", container.getFPS()); + FONT_DEFAULT.drawString( + container.getWidth() - 15 - FONT_DEFAULT.getWidth(fps), + container.getHeight() - 15 - FONT_DEFAULT.getHeight(fps), + fps, Color.white + ); + } + + /** + * Takes a screenshot. + * @return true if successful + */ + public static boolean takeScreenShot() { + // TODO: should this be threaded? + try { + // create the screenshot directory + if (!Options.SCREENSHOT_DIR.isDirectory()) { + if (!Options.SCREENSHOT_DIR.mkdir()) + return false; + } + + // create file name + SimpleDateFormat date = new SimpleDateFormat("yyyyMMdd_HHmmss"); + String file = date.format(new Date()); + + SoundController.playSound(SoundController.SOUND_SHUTTER); + + // copy the screen + Image screen = new Image(container.getWidth(), container.getHeight()); + container.getGraphics().copyArea(screen, 0, 0); + ImageOut.write(screen, String.format("%s%sscreenshot_%s.%s", + Options.SCREENSHOT_DIR.getName(), File.separator, + file, Options.getScreenshotFormat()), false + ); + screen.destroy(); + } catch (SlickException e) { + Log.warn("Failed to take a screenshot.", e); + return false; + } + return true; + } +} \ No newline at end of file diff --git a/src/itdelatrisu/opsu/objects/Circle.java b/src/itdelatrisu/opsu/objects/Circle.java index a90616c8..167426e0 100644 --- a/src/itdelatrisu/opsu/objects/Circle.java +++ b/src/itdelatrisu/opsu/objects/Circle.java @@ -21,6 +21,7 @@ package itdelatrisu.opsu.objects; import itdelatrisu.opsu.GameScore; import itdelatrisu.opsu.MusicController; import itdelatrisu.opsu.OsuHitObject; +import itdelatrisu.opsu.Utils; import itdelatrisu.opsu.states.Game; import itdelatrisu.opsu.states.Options; @@ -120,21 +121,14 @@ public class Circle { if (timeDiff >= 0) { float approachScale = 1 + (timeDiff * 2f / game.getApproachTime()); - drawCentered(approachCircle.getScaledCopy(approachScale), hitObject.x, hitObject.y, color); - drawCentered(hitCircleOverlay, hitObject.x, hitObject.y, Color.white); - drawCentered(hitCircle, hitObject.x, hitObject.y, color); + Utils.drawCentered(approachCircle.getScaledCopy(approachScale), hitObject.x, hitObject.y, color); + Utils.drawCentered(hitCircleOverlay, hitObject.x, hitObject.y, Color.white); + Utils.drawCentered(hitCircle, hitObject.x, hitObject.y, color); score.drawSymbolNumber(hitObject.comboNumber, hitObject.x, hitObject.y, hitCircle.getWidth() * 0.40f / score.getDefaultSymbolImage(0).getHeight()); } } - /** - * Draws an image based on its center with a color filter. - */ - private void drawCentered(Image img, float x, float y, Color color) { - img.draw(x - (img.getWidth() / 2f), y - (img.getHeight() / 2f), color); - } - /** * Calculates the circle hit result. * @param time the hit object time (difference between track time) diff --git a/src/itdelatrisu/opsu/objects/Slider.java b/src/itdelatrisu/opsu/objects/Slider.java index 1503650f..6a110483 100644 --- a/src/itdelatrisu/opsu/objects/Slider.java +++ b/src/itdelatrisu/opsu/objects/Slider.java @@ -22,6 +22,7 @@ import itdelatrisu.opsu.GameScore; import itdelatrisu.opsu.MusicController; import itdelatrisu.opsu.OsuFile; import itdelatrisu.opsu.OsuHitObject; +import itdelatrisu.opsu.Utils; import itdelatrisu.opsu.states.Game; import itdelatrisu.opsu.states.Options; @@ -240,9 +241,9 @@ public class Slider { // draw overlay and hit circle for (int i = curveX.length - 1; i >= 0; i--) - drawCentered(hitCircleOverlay, curveX[i], curveY[i], Color.white); + Utils.drawCentered(hitCircleOverlay, curveX[i], curveY[i], Color.white); for (int i = curveX.length - 1; i >= 0; i--) - drawCentered(hitCircle, curveX[i], curveY[i], color); + Utils.drawCentered(hitCircle, curveX[i], curveY[i], color); } } @@ -312,12 +313,12 @@ public class Slider { // end circle int lastIndex = hitObject.sliderX.length - 1; - drawCentered(hitCircleOverlay, hitObject.sliderX[lastIndex], hitObject.sliderY[lastIndex], Color.white); - drawCentered(hitCircle, hitObject.sliderX[lastIndex], hitObject.sliderY[lastIndex], color); + Utils.drawCentered(hitCircleOverlay, hitObject.sliderX[lastIndex], hitObject.sliderY[lastIndex], Color.white); + Utils.drawCentered(hitCircle, hitObject.sliderX[lastIndex], hitObject.sliderY[lastIndex], color); // start circle - drawCentered(hitCircleOverlay, hitObject.x, hitObject.y, Color.white); - drawCentered(hitCircle, hitObject.x, hitObject.y, color); + Utils.drawCentered(hitCircleOverlay, hitObject.x, hitObject.y, Color.white); + Utils.drawCentered(hitCircle, hitObject.x, hitObject.y, color); if (sliderClicked) ; // don't draw current combo number if already clicked else @@ -335,12 +336,13 @@ public class Slider { if (timeDiff >= 0) { // approach circle float approachScale = 1 + (timeDiff * 2f / game.getApproachTime()); - drawCentered(Circle.getApproachCircle().getScaledCopy(approachScale), hitObject.x, hitObject.y, color); + Utils.drawCentered(Circle.getApproachCircle().getScaledCopy(approachScale), + hitObject.x, hitObject.y, color); } else { float[] c = bezier.pointAt(getT(trackPosition, false)); // slider ball - drawCentered(sliderBall, c[0], c[1]); + Utils.drawCentered(sliderBall, c[0], c[1]); // follow circle if (followCircleActive) @@ -348,20 +350,6 @@ public class Slider { } } - /** - * Draws an image based on its center with a color filter. - */ - private void drawCentered(Image img, float x, float y, Color color) { - img.draw(x - (img.getWidth() / 2f), y - (img.getHeight() / 2f), color); - } - - /** - * Draws an animation based on its center with a color filter. - */ - private static void drawCentered(Animation anim, float x, float y) { - anim.draw(x - (anim.getWidth() / 2f), y - (anim.getHeight() / 2f)); - } - /** * Calculates the slider hit result. * @param time the hit object time (difference between track time) diff --git a/src/itdelatrisu/opsu/objects/Spinner.java b/src/itdelatrisu/opsu/objects/Spinner.java index 5086cff4..f982ea49 100644 --- a/src/itdelatrisu/opsu/objects/Spinner.java +++ b/src/itdelatrisu/opsu/objects/Spinner.java @@ -22,6 +22,7 @@ import itdelatrisu.opsu.GameScore; import itdelatrisu.opsu.MusicController; import itdelatrisu.opsu.OsuHitObject; import itdelatrisu.opsu.SoundController; +import itdelatrisu.opsu.Utils; import itdelatrisu.opsu.states.Game; import itdelatrisu.opsu.states.Options; @@ -127,7 +128,7 @@ public class Spinner { //spinnerOsuImage.drawCentered(width / 2, height / 4); // darken screen - g.setColor(Options.COLOR_BLACK_ALPHA); + g.setColor(Utils.COLOR_BLACK_ALPHA); g.fillRect(0, 0, width, height); if (timeDiff > 0) diff --git a/src/itdelatrisu/opsu/states/Game.java b/src/itdelatrisu/opsu/states/Game.java index f758aeaf..d3a4c766 100644 --- a/src/itdelatrisu/opsu/states/Game.java +++ b/src/itdelatrisu/opsu/states/Game.java @@ -26,6 +26,7 @@ import itdelatrisu.opsu.OsuFile; import itdelatrisu.opsu.OsuHitObject; import itdelatrisu.opsu.OsuTimingPoint; import itdelatrisu.opsu.SoundController; +import itdelatrisu.opsu.Utils; import itdelatrisu.opsu.objects.Circle; import itdelatrisu.opsu.objects.Slider; import itdelatrisu.opsu.objects.Spinner; @@ -264,8 +265,6 @@ public class Game extends BasicGameState { if (!osu.drawBG(width, height, 0.7f)) g.setBackground(Color.black); - Options.drawFPS(); - int trackPosition = MusicController.getPosition(); if (pauseTime > -1) // returning from pause screen trackPosition = pauseTime; @@ -313,6 +312,9 @@ public class Game extends BasicGameState { warningArrowL.draw(width * 0.75f, height * 0.75f); } } + + Utils.drawFPS(); + Utils.drawCursor(); return; } } @@ -413,7 +415,7 @@ public class Game extends BasicGameState { // returning from pause screen if (pauseTime > -1 && pausedMouseX > -1 && pausedMouseY > -1) { // darken the screen - g.setColor(Options.COLOR_BLACK_ALPHA); + g.setColor(Utils.COLOR_BLACK_ALPHA); g.fillRect(0, 0, width, height); // draw glowing hit select circle and pulse effect @@ -425,6 +427,9 @@ public class Game extends BasicGameState { cursorCirclePulse.setAlpha(1f - pausePulse); cursorCirclePulse.drawCentered(pausedMouseX, pausedMouseY); } + + Utils.drawFPS(); + Utils.drawCursor(); } @Override @@ -589,7 +594,7 @@ public class Game extends BasicGameState { mousePressed(Input.MOUSE_RIGHT_BUTTON, input.getMouseX(), input.getMouseY()); break; case Input.KEY_F12: - Options.takeScreenShot(); + Utils.takeScreenShot(); break; } } @@ -647,6 +652,9 @@ public class Game extends BasicGameState { if (osu == null || osu.objects == null) throw new RuntimeException("Running game with no OsuFile loaded."); + // grab the mouse + container.setMouseGrabbed(true); + // restart the game if (restart != RESTART_FALSE) { // new game @@ -720,6 +728,12 @@ public class Game extends BasicGameState { } } + @Override + public void leave(GameContainer container, StateBasedGame game) + throws SlickException { + container.setMouseGrabbed(false); + } + /** * Skips the beginning of a track. * @return true if skipped, false otherwise diff --git a/src/itdelatrisu/opsu/states/GamePauseMenu.java b/src/itdelatrisu/opsu/states/GamePauseMenu.java index e49463c9..dc5e183a 100644 --- a/src/itdelatrisu/opsu/states/GamePauseMenu.java +++ b/src/itdelatrisu/opsu/states/GamePauseMenu.java @@ -22,6 +22,7 @@ import itdelatrisu.opsu.GUIMenuButton; import itdelatrisu.opsu.MusicController; import itdelatrisu.opsu.Opsu; import itdelatrisu.opsu.SoundController; +import itdelatrisu.opsu.Utils; import org.newdawn.slick.Color; import org.newdawn.slick.GameContainer; @@ -117,13 +118,14 @@ public class GamePauseMenu extends BasicGameState { else g.setBackground(Color.black); - Options.drawFPS(); - // draw buttons if (Game.getRestart() != Game.RESTART_LOSE) continueButton.draw(); retryButton.draw(); backButton.draw(); + + Utils.drawFPS(); + Utils.drawCursor(); } @Override @@ -149,7 +151,7 @@ public class GamePauseMenu extends BasicGameState { unPause(Game.RESTART_FALSE); break; case Input.KEY_F12: - Options.takeScreenShot(); + Utils.takeScreenShot(); break; } } diff --git a/src/itdelatrisu/opsu/states/GameRanking.java b/src/itdelatrisu/opsu/states/GameRanking.java index cab08835..1c7ae4f6 100644 --- a/src/itdelatrisu/opsu/states/GameRanking.java +++ b/src/itdelatrisu/opsu/states/GameRanking.java @@ -24,6 +24,7 @@ import itdelatrisu.opsu.MusicController; import itdelatrisu.opsu.Opsu; import itdelatrisu.opsu.OsuFile; import itdelatrisu.opsu.SoundController; +import itdelatrisu.opsu.Utils; import org.lwjgl.opengl.Display; import org.newdawn.slick.Color; @@ -100,7 +101,7 @@ public class GameRanking extends BasicGameState { // background if (!osu.drawBG(width, height, 0.7f)) - g.setBackground(Options.COLOR_BLACK_ALPHA); + g.setBackground(Utils.COLOR_BLACK_ALPHA); // ranking screen elements score.drawRankingElements(g, width, height); @@ -118,17 +119,18 @@ public class GameRanking extends BasicGameState { // header text g.setColor(Color.white); - Options.FONT_LARGE.drawString(10, 0, + Utils.FONT_LARGE.drawString(10, 0, String.format("%s - %s [%s]", osu.artist, osu.title, osu.version)); - Options.FONT_MEDIUM.drawString(10, Options.FONT_LARGE.getLineHeight() - 6, + Utils.FONT_MEDIUM.drawString(10, Utils.FONT_LARGE.getLineHeight() - 6, String.format("Beatmap by %s", osu.creator)); // buttons retryButton.draw(); exitButton.draw(); - Options.getBackButton().draw(); + Utils.getBackButton().draw(); - Options.drawFPS(); + Utils.drawFPS(); + Utils.drawCursor(); } @Override @@ -150,7 +152,7 @@ public class GameRanking extends BasicGameState { game.enterState(Opsu.STATE_SONGMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black)); break; case Input.KEY_F12: - Options.takeScreenShot(); + Utils.takeScreenShot(); break; } } @@ -170,7 +172,7 @@ public class GameRanking extends BasicGameState { } else if (exitButton.contains(x, y)) { SoundController.playSound(SoundController.SOUND_MENUBACK); game.enterState(Opsu.STATE_MAINMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black)); - } else if (Options.getBackButton().contains(x, y)) { + } else if (Utils.getBackButton().contains(x, y)) { MusicController.pause(); MusicController.playAt(Game.getOsuFile().previewTime, true); SoundController.playSound(SoundController.SOUND_MENUBACK); diff --git a/src/itdelatrisu/opsu/states/MainMenu.java b/src/itdelatrisu/opsu/states/MainMenu.java index 30bd7600..95d81715 100644 --- a/src/itdelatrisu/opsu/states/MainMenu.java +++ b/src/itdelatrisu/opsu/states/MainMenu.java @@ -23,6 +23,7 @@ import itdelatrisu.opsu.MusicController; import itdelatrisu.opsu.Opsu; import itdelatrisu.opsu.OsuGroupNode; import itdelatrisu.opsu.SoundController; +import itdelatrisu.opsu.Utils; import java.text.SimpleDateFormat; import java.util.Date; @@ -153,8 +154,8 @@ public class MainMenu extends BasicGameState { if (backgroundImage != null) backgroundImage.draw(); else - g.setBackground(Options.COLOR_BLUE_BACKGROUND); - g.setFont(Options.FONT_MEDIUM); + g.setBackground(Utils.COLOR_BLUE_BACKGROUND); + g.setFont(Utils.FONT_MEDIUM); int width = container.getWidth(); int height = container.getHeight(); @@ -173,7 +174,7 @@ public class MainMenu extends BasicGameState { musicPlay.draw(); musicNext.draw(); musicPrevious.draw(); - g.setColor(Options.COLOR_BLACK_ALPHA); + g.setColor(Utils.COLOR_BLACK_ALPHA); g.fillRoundRect(width - 168, 54, 148, 5, 4); g.setColor(Color.white); if (!MusicController.isConverting()) @@ -181,7 +182,7 @@ public class MainMenu extends BasicGameState { 148f * MusicController.getPosition() / MusicController.getTrackLength(), 5, 4); // draw text - int lineHeight = Options.FONT_MEDIUM.getLineHeight(); + int lineHeight = Utils.FONT_MEDIUM.getLineHeight(); g.drawString(String.format("Loaded %d songs and %d beatmaps.", Opsu.groups.size(), Opsu.groups.getMapCount()), 25, 25); if (MusicController.isConverting()) @@ -203,7 +204,8 @@ public class MainMenu extends BasicGameState { new SimpleDateFormat("h:mm a").format(new Date())), 25, height - 25 - lineHeight); - Options.drawFPS(); + Utils.drawFPS(); + Utils.drawCursor(); } @Override @@ -317,7 +319,7 @@ public class MainMenu extends BasicGameState { game.enterState(Opsu.STATE_MAINMENUEXIT); break; case Input.KEY_F12: - Options.takeScreenShot(); + Utils.takeScreenShot(); break; } diff --git a/src/itdelatrisu/opsu/states/MainMenuExit.java b/src/itdelatrisu/opsu/states/MainMenuExit.java index d01c9ee7..2988cb15 100644 --- a/src/itdelatrisu/opsu/states/MainMenuExit.java +++ b/src/itdelatrisu/opsu/states/MainMenuExit.java @@ -20,6 +20,7 @@ package itdelatrisu.opsu.states; import itdelatrisu.opsu.GUIMenuButton; import itdelatrisu.opsu.Opsu; +import itdelatrisu.opsu.Utils; import org.newdawn.slick.Color; import org.newdawn.slick.GameContainer; @@ -90,22 +91,23 @@ public class MainMenuExit extends BasicGameState { // draw text float c = container.getWidth() * 0.02f; - Options.FONT_LARGE.drawString(c, c, "Are you sure you want to exit opsu!?"); + Utils.FONT_LARGE.drawString(c, c, "Are you sure you want to exit opsu!?"); // draw buttons yesButton.draw(Color.green); noButton.draw(Color.red); - g.setFont(Options.FONT_XLARGE); + g.setFont(Utils.FONT_XLARGE); g.drawString("1. Yes", - yesButton.getX() - (Options.FONT_XLARGE.getWidth("1. Yes") / 2f), - yesButton.getY() - (Options.FONT_XLARGE.getHeight() / 2f) + yesButton.getX() - (Utils.FONT_XLARGE.getWidth("1. Yes") / 2f), + yesButton.getY() - (Utils.FONT_XLARGE.getHeight() / 2f) ); g.drawString("2. No", - noButton.getX() - (Options.FONT_XLARGE.getWidth("2. No") / 2f), - noButton.getY() - (Options.FONT_XLARGE.getHeight() / 2f) + noButton.getX() - (Utils.FONT_XLARGE.getWidth("2. No") / 2f), + noButton.getY() - (Utils.FONT_XLARGE.getHeight() / 2f) ); - Options.drawFPS(); + Utils.drawFPS(); + Utils.drawCursor(); } @Override @@ -150,7 +152,7 @@ public class MainMenuExit extends BasicGameState { game.enterState(Opsu.STATE_MAINMENU, new EmptyTransition(), new FadeInTransition(Color.black)); break; case Input.KEY_F12: - Options.takeScreenShot(); + Utils.takeScreenShot(); break; } } diff --git a/src/itdelatrisu/opsu/states/Options.java b/src/itdelatrisu/opsu/states/Options.java index 37d67a9c..bcbcf89c 100644 --- a/src/itdelatrisu/opsu/states/Options.java +++ b/src/itdelatrisu/opsu/states/Options.java @@ -20,9 +20,8 @@ package itdelatrisu.opsu.states; import itdelatrisu.opsu.GUIMenuButton; import itdelatrisu.opsu.Opsu; -import itdelatrisu.opsu.SoundController; +import itdelatrisu.opsu.Utils; -import java.awt.Font; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; @@ -39,8 +38,6 @@ import org.newdawn.slick.Graphics; import org.newdawn.slick.Image; import org.newdawn.slick.Input; import org.newdawn.slick.SlickException; -import org.newdawn.slick.TrueTypeFont; -import org.newdawn.slick.imageout.ImageOut; import org.newdawn.slick.state.BasicGameState; import org.newdawn.slick.state.StateBasedGame; import org.newdawn.slick.state.transition.EmptyTransition; @@ -85,41 +82,6 @@ public class Options extends BasicGameState { */ private static final String OPTIONS_FILE = ".opsu.cfg"; - /** - * Whether or not any changes were made to options. - * If false, the options file will not be modified. - */ - private static boolean optionsChanged = false; - - /** - * Game colors. - */ - public static final Color - COLOR_BLACK_ALPHA = new Color(0, 0, 0, 0.5f), - COLOR_BLUE_DIVIDER = new Color(49, 94, 237), - COLOR_BLUE_BACKGROUND = new Color(74, 130, 255), - COLOR_BLUE_BUTTON = new Color(50, 189, 237), - COLOR_ORANGE_BUTTON = new Color(230, 151, 87), - COLOR_GREEN_OBJECT = new Color(26, 207, 26), - COLOR_BLUE_OBJECT = new Color(46, 136, 248), - COLOR_RED_OBJECT = new Color(243, 48, 77), - COLOR_ORANGE_OBJECT = new Color(255, 200, 32); - - /** - * The default map colors, used when a map does not provide custom colors. - */ - public static final Color[] DEFAULT_COMBO = { - COLOR_GREEN_OBJECT, COLOR_BLUE_OBJECT, - COLOR_RED_OBJECT, COLOR_ORANGE_OBJECT - }; - - /** - * Game fonts. - */ - public static TrueTypeFont - FONT_DEFAULT, FONT_BOLD, - FONT_XLARGE, FONT_LARGE, FONT_MEDIUM, FONT_SMALL; - /** * Game mods. */ @@ -235,12 +197,12 @@ public class Options extends BasicGameState { /** * Port binding. */ - private static int port = 0; + private static int port = 49250; /** - * Back button (shared by other states). + * Whether or not to use the new cursor type. */ - private static GUIMenuButton backButton; + private static boolean newCursor = true; /** * Game option coordinate modifiers (for drawing). @@ -248,8 +210,8 @@ public class Options extends BasicGameState { private int textY, offsetY; // game-related variables - private static GameContainer container; - private static StateBasedGame game; + private GameContainer container; + private StateBasedGame game; private Input input; private int state; private boolean init = false; @@ -261,42 +223,17 @@ public class Options extends BasicGameState { @Override public void init(GameContainer container, StateBasedGame game) throws SlickException { - Options.container = container; - Options.game = game; + this.container = container; + this.game = game; this.input = container.getInput(); - // game settings - container.setTargetFrameRate(targetFPS[targetFPSindex]); - container.setMouseCursor("cursor.png", 16, 16); - container.setMusicVolume(getMusicVolume()); - container.setShowFPS(false); - container.getInput().enableKeyRepeat(); - container.setAlwaysRender(true); - - // create fonts - float fontBase; - if (container.getHeight() <= 600) - fontBase = 9f; - else if (container.getHeight() < 800) - fontBase = 10f; - else if (container.getHeight() <= 900) - fontBase = 12f; - else - fontBase = 14f; - - Font font = new Font("Lucida Sans Unicode", Font.PLAIN, (int) (fontBase * 4 / 3)); - FONT_DEFAULT = new TrueTypeFont(font, false); - FONT_BOLD = new TrueTypeFont(font.deriveFont(Font.BOLD), false); - FONT_XLARGE = new TrueTypeFont(font.deriveFont(fontBase * 4), false); - FONT_LARGE = new TrueTypeFont(font.deriveFont(fontBase * 2), false); - FONT_MEDIUM = new TrueTypeFont(font.deriveFont(fontBase * 3 / 2), false); - FONT_SMALL = new TrueTypeFont(font.deriveFont(fontBase), false); + Utils.init(container, game); int width = container.getWidth(); int height = container.getHeight(); // game option coordinate modifiers - textY = 10 + (FONT_XLARGE.getLineHeight() * 3 / 2); + textY = 10 + (Utils.FONT_XLARGE.getLineHeight() * 3 / 2); offsetY = (int) (((height * 0.8f) - textY) / OPTIONS_MAX); // game mods @@ -330,14 +267,6 @@ public class Options extends BasicGameState { for (int i = 0; i < modButtons.length; i++) modButtons[i].getImage().setAlpha(0.5f); - // back button - Image back = new Image("menu-back.png"); - float scale = (height * 0.1f) / back.getHeight(); - back = back.getScaledCopy(scale); - backButton = new GUIMenuButton(back, - back.getWidth() / 2f, - height - (back.getHeight() / 2f)); - game.enterState(Opsu.STATE_MAINMENU, new EmptyTransition(), new FadeInTransition(Color.black)); } @@ -347,25 +276,25 @@ public class Options extends BasicGameState { if (!init) return; - g.setBackground(COLOR_BLACK_ALPHA); + g.setBackground(Utils.COLOR_BLACK_ALPHA); g.setColor(Color.white); int width = container.getWidth(); int height = container.getHeight(); // title - FONT_XLARGE.drawString( - (width / 2) - (FONT_XLARGE.getWidth("GAME OPTIONS") / 2), + Utils.FONT_XLARGE.drawString( + (width / 2) - (Utils.FONT_XLARGE.getWidth("GAME OPTIONS") / 2), 10, "GAME OPTIONS" ); - FONT_DEFAULT.drawString( - (width / 2) - (FONT_DEFAULT.getWidth("Click or drag an option to change it.") / 2), - 10 + FONT_XLARGE.getHeight(), "Click or drag an option to change it." + Utils.FONT_DEFAULT.drawString( + (width / 2) - (Utils.FONT_DEFAULT.getWidth("Click or drag an option to change it.") / 2), + 10 + Utils.FONT_XLARGE.getHeight(), "Click or drag an option to change it." ); // game options g.setLineWidth(1f); - g.setFont(FONT_LARGE); + g.setFont(Utils.FONT_LARGE); this.drawOption(g, OPTIONS_SCREEN_RESOLUTION, "Screen Resolution", String.format("%dx%d", resolutions[resolutionIndex][0], resolutions[resolutionIndex][1]), "Restart to apply resolution changes." @@ -375,7 +304,7 @@ public class Options extends BasicGameState { // "Restart to apply changes." // ); this.drawOption(g, OPTIONS_TARGET_FPS, "Frame Limiter", - String.format("%dfps", targetFPS[targetFPSindex]), + String.format("%dfps", getTargetFPS()), "Higher values may cause high CPU usage." ); this.drawOption(g, OPTIONS_MUSIC_VOLUME, "Music Volume", @@ -408,13 +337,14 @@ public class Options extends BasicGameState { ); // game mods - FONT_LARGE.drawString(width * 0.02f, height * 0.8f, "Game Mods:", Color.white); + Utils.FONT_LARGE.drawString(width * 0.02f, height * 0.8f, "Game Mods:", Color.white); for (int i = 0; i < modButtons.length; i++) modButtons[i].draw(); - backButton.draw(); + Utils.getBackButton().draw(); - drawFPS(); + Utils.drawFPS(); + Utils.drawCursor(); } @Override @@ -433,7 +363,7 @@ public class Options extends BasicGameState { return; // back - if (backButton.contains(x, y)) { + if (Utils.getBackButton().contains(x, y)) { game.enterState(Opsu.STATE_SONGMENU, new EmptyTransition(), new FadeInTransition(Color.black)); return; } @@ -472,7 +402,7 @@ public class Options extends BasicGameState { // } if (isOptionClicked(OPTIONS_TARGET_FPS, y)) { targetFPSindex = (targetFPSindex + 1) % targetFPS.length; - container.setTargetFrameRate(targetFPS[targetFPSindex]); + container.setTargetFrameRate(getTargetFPS()); return; } if (isOptionClicked(OPTIONS_SCREENSHOT_FORMAT, y)) { @@ -545,7 +475,7 @@ public class Options extends BasicGameState { game.enterState(Opsu.STATE_SONGMENU, new EmptyTransition(), new FadeInTransition(Color.black)); break; case Input.KEY_F12: - Options.takeScreenShot(); + Utils.takeScreenShot(); break; } } @@ -560,14 +490,14 @@ public class Options extends BasicGameState { */ private void drawOption(Graphics g, int pos, String label, String value, String notes) { int width = container.getWidth(); - int textHeight = FONT_LARGE.getHeight(); + int textHeight = Utils.FONT_LARGE.getHeight(); float y = textY + (pos * offsetY); g.drawString(label, width / 50, y); g.drawString(value, width / 2, y); g.drawLine(0, y + textHeight, width, y + textHeight); if (notes != null) - FONT_SMALL.drawString(width / 50, y + textHeight, notes); + Utils.FONT_SMALL.drawString(width / 50, y + textHeight, notes); } /** @@ -577,12 +507,8 @@ public class Options extends BasicGameState { * @return true if clicked */ private boolean isOptionClicked(int pos, int y) { - if (y > textY + (offsetY * pos) - FONT_LARGE.getHeight() && - y < textY + (offsetY * pos) + FONT_LARGE.getHeight()) { - optionsChanged = true; - return true; - } - return false; + return (y > textY + (offsetY * pos) - Utils.FONT_LARGE.getHeight() && + y < textY + (offsetY * pos) + Utils.FONT_LARGE.getHeight()); } /** @@ -610,9 +536,10 @@ public class Options extends BasicGameState { public static Image getModImage(int mod) { return modButtons[mod].getImage(); } /** - * Returns the 'back' GUIMenuButton. + * Returns the target frame rate. + * @return the target FPS */ - public static GUIMenuButton getBackButton() { return backButton; } + public static int getTargetFPS() { return targetFPS[targetFPSindex]; } /** * Returns the default music volume. @@ -633,53 +560,10 @@ public class Options extends BasicGameState { public static int getMusicOffset() { return musicOffset; } /** - * Draws the FPS at the bottom-right corner of the game container. - * If the option is not activated, this will do nothing. + * Returns the screenshot file format. + * @return the file extension ("png", "jpg", "bmp") */ - public static void drawFPS() { - if (showFPS) { - String fps = String.format("FPS: %d", container.getFPS()); - FONT_DEFAULT.drawString( - container.getWidth() - 15 - FONT_DEFAULT.getWidth(fps), - container.getHeight() - 15 - FONT_DEFAULT.getHeight(fps), - fps, Color.white - ); - } - } - - /** - * Takes a screenshot. - * @return true if successful - */ - public static boolean takeScreenShot() { - // TODO: should this be threaded? - try { - // create the screenshot directory - if (!SCREENSHOT_DIR.isDirectory()) { - if (!SCREENSHOT_DIR.mkdir()) - return false; - } - - // create file name - SimpleDateFormat date = new SimpleDateFormat("yyyyMMdd_HHmmss"); - String file = date.format(new Date()); - - SoundController.playSound(SoundController.SOUND_SHUTTER); - - // copy the screen - Image screen = new Image(container.getWidth(), container.getHeight()); - container.getGraphics().copyArea(screen, 0, 0); - ImageOut.write(screen, String.format("%s%sscreenshot_%s.%s", - SCREENSHOT_DIR.getName(), File.separator, - file, screenshotFormat[screenshotFormatIndex]), false - ); - screen.destroy(); - } catch (SlickException e) { - Log.warn("Failed to take a screenshot.", e); - return false; - } - return true; - } + public static String getScreenshotFormat() { return screenshotFormat[screenshotFormatIndex]; } /** * Returns the screen resolution. @@ -693,6 +577,12 @@ public class Options extends BasicGameState { // */ // public static boolean isFullscreen() { return fullscreen; } + /** + * Returns whether or not the FPS counter display is enabled. + * @return true if enabled + */ + public static boolean isFPSCounterEnabled() { return showFPS; } + /** * Returns whether or not hit lighting effects are enabled. * @return true if enabled @@ -709,14 +599,13 @@ public class Options extends BasicGameState { * Returns the port number to bind to. * @return the port */ - public static int getPort() { - if (port == 0) { - // choose a random port - port = 49250; - optionsChanged = true; // force file creation - } - return port; - } + public static int getPort() { return port; } + + /** + * Returns whether or not the new cursor type is enabled. + * @return true if enabled + */ + public static boolean isNewCursorEnabled() { return newCursor; } /** * Returns the current beatmap directory. @@ -730,15 +619,14 @@ public class Options extends BasicGameState { // search for directory for (int i = 0; i < BEATMAP_DIRS.length; i++) { beatmapDir = new File(BEATMAP_DIRS[i]); - if (beatmapDir.isDirectory()) { - optionsChanged = true; // force config file creation + if (beatmapDir.isDirectory()) return beatmapDir; - } } beatmapDir.mkdir(); // none found, create new directory return beatmapDir; } + /** * Reads user options from the options file, if it exists. */ @@ -746,9 +634,7 @@ public class Options extends BasicGameState { // if no config file, use default settings File file = new File(OPTIONS_FILE); if (!file.isFile()) { - optionsChanged = true; // force file creation saveOptions(); - optionsChanged = false; return; } @@ -816,6 +702,9 @@ public class Options extends BasicGameState { if (i > 0 && i <= 65535) port = i; break; + case "NewCursor": // custom + newCursor = Boolean.parseBoolean(value); + break; } } } catch (IOException e) { @@ -830,10 +719,6 @@ public class Options extends BasicGameState { * (Over)writes user options to a file. */ public static void saveOptions() { - // only overwrite when needed - if (!optionsChanged) - return; - try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter( new FileOutputStream(OPTIONS_FILE), "utf-8"))) { // header @@ -873,6 +758,8 @@ public class Options extends BasicGameState { writer.newLine(); writer.write(String.format("Port = %d", port)); writer.newLine(); + writer.write(String.format("NewCursor = %b", newCursor)); // custom + writer.newLine(); writer.close(); } catch (IOException e) { Log.error(String.format("Failed to write to file '%s'.", OPTIONS_FILE), e); diff --git a/src/itdelatrisu/opsu/states/SongMenu.java b/src/itdelatrisu/opsu/states/SongMenu.java index 271473e8..a05b2f5e 100644 --- a/src/itdelatrisu/opsu/states/SongMenu.java +++ b/src/itdelatrisu/opsu/states/SongMenu.java @@ -26,6 +26,7 @@ import itdelatrisu.opsu.OsuGroupList; import itdelatrisu.opsu.OsuGroupNode; import itdelatrisu.opsu.OsuParser; import itdelatrisu.opsu.SoundController; +import itdelatrisu.opsu.Utils; import org.lwjgl.opengl.Display; import org.newdawn.slick.Color; @@ -170,13 +171,13 @@ public class SongMenu extends BasicGameState { searchResultString = "Type to search!"; searchIcon = new Image("search.png"); - float iconScale = Options.FONT_BOLD.getLineHeight() * 2f / searchIcon.getHeight(); + float iconScale = Utils.FONT_BOLD.getLineHeight() * 2f / searchIcon.getHeight(); searchIcon = searchIcon.getScaledCopy(iconScale); search = new TextField( - container, Options.FONT_DEFAULT, + container, Utils.FONT_DEFAULT, (int) tabX + searchIcon.getWidth(), (int) ((height * 0.15f) - (tab.getHeight() * 5 / 2f)), - (int) (buttonWidth / 2), Options.FONT_DEFAULT.getHeight() + (int) (buttonWidth / 2), Utils.FONT_DEFAULT.getHeight() ); search.setBackgroundColor(Color.transparent); search.setBorderColor(Color.transparent); @@ -205,9 +206,9 @@ public class SongMenu extends BasicGameState { // header setup float lowerBound = height * 0.15f; - g.setColor(Options.COLOR_BLACK_ALPHA); + g.setColor(Utils.COLOR_BLACK_ALPHA); g.fillRect(0, 0, width, lowerBound); - g.setColor(Options.COLOR_BLUE_DIVIDER); + g.setColor(Utils.COLOR_BLUE_DIVIDER); g.setLineWidth(2f); g.drawLine(0, lowerBound, width, lowerBound); g.resetLineWidth(); @@ -220,17 +221,17 @@ public class SongMenu extends BasicGameState { String[] info = focusNode.getInfo(); g.setColor(Color.white); - Options.FONT_LARGE.drawString( + Utils.FONT_LARGE.drawString( musicNoteWidth + 5, -3, info[0]); - float y1 = -3 + Options.FONT_LARGE.getHeight() * 0.75f; - Options.FONT_DEFAULT.drawString( + float y1 = -3 + Utils.FONT_LARGE.getHeight() * 0.75f; + Utils.FONT_DEFAULT.drawString( musicNoteWidth + 5, y1, info[1]); - Options.FONT_BOLD.drawString( + Utils.FONT_BOLD.drawString( 5, Math.max(y1 + 4, musicNoteHeight - 3), info[2]); - Options.FONT_DEFAULT.drawString( - 5, musicNoteHeight + Options.FONT_BOLD.getLineHeight() - 9, info[3]); - Options.FONT_SMALL.drawString( - 5, musicNoteHeight + Options.FONT_BOLD.getLineHeight() + Options.FONT_DEFAULT.getLineHeight() - 13, info[4]); + Utils.FONT_DEFAULT.drawString( + 5, musicNoteHeight + Utils.FONT_BOLD.getLineHeight() - 9, info[3]); + Utils.FONT_SMALL.drawString( + 5, musicNoteHeight + Utils.FONT_BOLD.getLineHeight() + Utils.FONT_DEFAULT.getLineHeight() - 13, info[4]); } // song buttons @@ -248,17 +249,17 @@ public class SongMenu extends BasicGameState { for (int i = sortTabs.length - 1; i >= 0; i--) { sortTabs[i].getImage().setAlpha((i == currentSort) ? 1.0f : 0.7f); sortTabs[i].draw(); - float tabTextX = sortTabs[i].getX() - (Options.FONT_MEDIUM.getWidth(OsuGroupList.SORT_NAMES[i]) / 2); - Options.FONT_MEDIUM.drawString(tabTextX, tabTextY, OsuGroupList.SORT_NAMES[i], Color.white); + float tabTextX = sortTabs[i].getX() - (Utils.FONT_MEDIUM.getWidth(OsuGroupList.SORT_NAMES[i]) / 2); + Utils.FONT_MEDIUM.drawString(tabTextX, tabTextY, OsuGroupList.SORT_NAMES[i], Color.white); } // search - Options.FONT_BOLD.drawString( - search.getX(), search.getY() - Options.FONT_BOLD.getLineHeight(), + Utils.FONT_BOLD.drawString( + search.getX(), search.getY() - Utils.FONT_BOLD.getLineHeight(), searchResultString, Color.white ); searchIcon.draw(search.getX() - searchIcon.getWidth(), - search.getY() - Options.FONT_DEFAULT.getLineHeight()); + search.getY() - Utils.FONT_DEFAULT.getLineHeight()); g.setColor(Color.white); search.render(container, g); @@ -266,16 +267,17 @@ public class SongMenu extends BasicGameState { if (focusNode != null) { float scrollStartY = height * 0.16f; float scrollEndY = height * 0.82f; - g.setColor(Options.COLOR_BLACK_ALPHA); + g.setColor(Utils.COLOR_BLACK_ALPHA); g.fillRoundRect(width - 10, scrollStartY, 5, scrollEndY, 4); g.setColor(Color.white); g.fillRoundRect(width - 10, scrollStartY + (scrollEndY * startNode.index / Opsu.groups.size()), 5, 20, 4); } // back button - Options.getBackButton().draw(); + Utils.getBackButton().draw(); - Options.drawFPS(); + Utils.drawFPS(); + Utils.drawCursor(); } @Override @@ -343,7 +345,7 @@ public class SongMenu extends BasicGameState { return; // back - if (Options.getBackButton().contains(x, y)) { + if (Utils.getBackButton().contains(x, y)) { SoundController.playSound(SoundController.SOUND_MENUBACK); game.enterState(Opsu.STATE_MAINMENU, new FadeOutTransition(Color.black), new FadeInTransition(Color.black)); return; @@ -436,7 +438,7 @@ public class SongMenu extends BasicGameState { setFocus(Opsu.groups.getRandomNode(), -1, true); break; case Input.KEY_F12: - Options.takeScreenShot(); + Utils.takeScreenShot(); break; case Input.KEY_ENTER: if (focusNode != null)