Added score-viewing components to the song menu. [Completes 0bd72e7
]
Added a scrollable score history area in the song menu. Clicking on any score button will open the ranking screen. Details: - All drawing is performed by ScoreData. - Store scores for the current focus node, and display up to "MAX_SCORE_BUTTONS" at a time; "startScore" is the starting index. - When hovered over the score area, show scroll bar if needed. When hovered over individual score buttons, change colors and show the rank. - Scrolling with the mouse in the score area overrides song scrolling. - Store scaled grade images as a Grade field. Signed-off-by: Jeffrey Han <itdelatrisu@gmail.com>
This commit is contained in:
parent
0bd72e731a
commit
ce15f25ca1
|
@ -90,6 +90,7 @@ public class Container extends AppGameContainer {
|
||||||
|
|
||||||
// reset image references
|
// reset image references
|
||||||
GameImage.clearReferences();
|
GameImage.clearReferences();
|
||||||
|
GameData.Grade.clearReferences();
|
||||||
OsuFile.resetImageCache();
|
OsuFile.resetImageCache();
|
||||||
|
|
||||||
// prevent loading tracks from re-initializing OpenAL
|
// prevent loading tracks from re-initializing OpenAL
|
||||||
|
|
|
@ -55,6 +55,18 @@ public class GameData {
|
||||||
/** GameImages associated with this grade (large and small sizes). */
|
/** GameImages associated with this grade (large and small sizes). */
|
||||||
private GameImage large, small;
|
private GameImage large, small;
|
||||||
|
|
||||||
|
/** Large-size image scaled for use in song menu. */
|
||||||
|
private Image menuImage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears all image references.
|
||||||
|
* This does NOT destroy images, so be careful of memory leaks!
|
||||||
|
*/
|
||||||
|
public static void clearReferences() {
|
||||||
|
for (Grade grade : Grade.values())
|
||||||
|
grade.menuImage = null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
* @param large the large size image
|
* @param large the large size image
|
||||||
|
@ -74,6 +86,20 @@ public class GameData {
|
||||||
* Returns the small size grade image.
|
* Returns the small size grade image.
|
||||||
*/
|
*/
|
||||||
public Image getSmallImage() { return small.getImage(); }
|
public Image getSmallImage() { return small.getImage(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the large size grade image scaled for song menu use.
|
||||||
|
*/
|
||||||
|
public Image getMenuImage() {
|
||||||
|
if (menuImage != null)
|
||||||
|
return menuImage;
|
||||||
|
|
||||||
|
Image img = getSmallImage();
|
||||||
|
img = img.getScaledCopy((GameImage.MENU_BUTTON_BG.getImage().getHeight() * 0.45f) / img.getHeight());
|
||||||
|
if (!small.hasSkinImage()) // save default image only
|
||||||
|
this.menuImage = img;
|
||||||
|
return img;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Hit result types. */
|
/** Hit result types. */
|
||||||
|
|
|
@ -81,8 +81,7 @@ public class OsuGroupNode {
|
||||||
float cy = y + (bg.getHeight() * 0.2f) - 3;
|
float cy = y + (bg.getHeight() * 0.2f) - 3;
|
||||||
|
|
||||||
if (grade != Grade.NULL) {
|
if (grade != Grade.NULL) {
|
||||||
Image gradeImg = grade.getSmallImage();
|
Image gradeImg = grade.getMenuImage();
|
||||||
gradeImg = gradeImg.getScaledCopy((bg.getHeight() * 0.45f) / gradeImg.getHeight());
|
|
||||||
gradeImg.drawCentered(cx - bg.getWidth() * 0.01f + gradeImg.getWidth() / 2f, y + bg.getHeight() / 2.2f);
|
gradeImg.drawCentered(cx - bg.getWidth() * 0.01f + gradeImg.getWidth() / 2f, y + bg.getHeight() / 2.2f);
|
||||||
cx += gradeImg.getWidth();
|
cx += gradeImg.getWidth();
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
package itdelatrisu.opsu;
|
package itdelatrisu.opsu;
|
||||||
|
|
||||||
import itdelatrisu.opsu.GameData.Grade;
|
import itdelatrisu.opsu.GameData.Grade;
|
||||||
|
import itdelatrisu.opsu.states.SongMenu;
|
||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.DriverManager;
|
import java.sql.DriverManager;
|
||||||
|
@ -26,6 +27,7 @@ import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
|
import java.text.NumberFormat;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
@ -35,6 +37,10 @@ import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.newdawn.slick.Color;
|
||||||
|
import org.newdawn.slick.Graphics;
|
||||||
|
import org.newdawn.slick.Image;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles game score data.
|
* Handles game score data.
|
||||||
*/
|
*/
|
||||||
|
@ -65,6 +71,80 @@ public class Scores {
|
||||||
/** Game mod bitmask. */
|
/** Game mod bitmask. */
|
||||||
public int mods;
|
public int mods;
|
||||||
|
|
||||||
|
/** The grade. */
|
||||||
|
private Grade grade;
|
||||||
|
|
||||||
|
/** The score percent. */
|
||||||
|
private float scorePercent = -1f;
|
||||||
|
|
||||||
|
/** Drawing values. */
|
||||||
|
private static float baseX, baseY, buttonWidth, buttonHeight, buttonOffset;
|
||||||
|
|
||||||
|
/** Container dimensions. */
|
||||||
|
private static int containerWidth, containerHeight;
|
||||||
|
|
||||||
|
/** Button background colors. */
|
||||||
|
private static final Color
|
||||||
|
BG_NORMAL = new Color(0, 0, 0, 0.25f),
|
||||||
|
BG_FOCUS = new Color(0, 0, 0, 0.75f);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the base coordinates for drawing.
|
||||||
|
* @param width the container width
|
||||||
|
* @param height the container height
|
||||||
|
*/
|
||||||
|
public static void init(int width, int height) {
|
||||||
|
containerWidth = width;
|
||||||
|
containerHeight = height;
|
||||||
|
|
||||||
|
baseX = width * 0.01f;
|
||||||
|
baseY = height * 0.16f;
|
||||||
|
buttonWidth = width * 0.4f;
|
||||||
|
float gradeHeight = GameImage.MENU_BUTTON_BG.getImage().getHeight() * 0.45f;
|
||||||
|
buttonHeight = Math.max(gradeHeight, Utils.FONT_DEFAULT.getLineHeight() * 3.03f);
|
||||||
|
buttonOffset = buttonHeight + gradeHeight / 10f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the coordinates are within the bounds of the
|
||||||
|
* button at the given index.
|
||||||
|
* @param cx the x coordinate
|
||||||
|
* @param cy the y coordinate
|
||||||
|
* @param index the index (to offset the button from the topmost button)
|
||||||
|
*/
|
||||||
|
public static boolean buttonContains(float cx, float cy, int index) {
|
||||||
|
float y = baseY + (index * buttonOffset);
|
||||||
|
return ((cx >= 0 && cx < baseX + buttonWidth) &&
|
||||||
|
(cy > y && cy < y + buttonHeight));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the coordinates are within the bounds of the
|
||||||
|
* score button area.
|
||||||
|
* @param cx the x coordinate
|
||||||
|
* @param cy the y coordinate
|
||||||
|
*/
|
||||||
|
public static boolean areaContains(float cx, float cy) {
|
||||||
|
return ((cx >= 0 && cx < baseX + buttonWidth) &&
|
||||||
|
(cy > baseY && cy < baseY + buttonOffset * SongMenu.MAX_SCORE_BUTTONS));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws the scroll bar for the score buttons.
|
||||||
|
* @param g the graphics context
|
||||||
|
* @param index the start button index
|
||||||
|
* @param total the total number of buttons
|
||||||
|
*/
|
||||||
|
public static void drawScrollbar(Graphics g, int index, int total) {
|
||||||
|
float scorebarWidth = containerWidth * 0.00347f;
|
||||||
|
float heightRatio = 0.0016f * (total * total) - 0.0705f * total + 0.9965f;
|
||||||
|
float scorebarHeight = containerHeight * heightRatio;
|
||||||
|
float heightDiff = buttonHeight + buttonOffset * (SongMenu.MAX_SCORE_BUTTONS - 1) - scorebarHeight;
|
||||||
|
float offsetY = heightDiff * ((float) index / (total - SongMenu.MAX_SCORE_BUTTONS));
|
||||||
|
g.setColor(Color.white);
|
||||||
|
g.fillRect(0, baseY + offsetY, scorebarWidth, scorebarHeight);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Empty constructor.
|
* Empty constructor.
|
||||||
*/
|
*/
|
||||||
|
@ -102,13 +182,105 @@ public class Scores {
|
||||||
return new SimpleDateFormat("M/d/yyyy h:mm:ss a").format(new Date(timestamp * 1000L));
|
return new SimpleDateFormat("M/d/yyyy h:mm:ss a").format(new Date(timestamp * 1000L));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the raw score percentage based on score data.
|
||||||
|
* @see GameData#getScorePercent(int, int, int, int)
|
||||||
|
*/
|
||||||
|
private float getScorePercent() {
|
||||||
|
if (scorePercent < 0f)
|
||||||
|
scorePercent = GameData.getScorePercent(hit300, hit100, hit50, miss);
|
||||||
|
return scorePercent;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns letter grade based on score data,
|
* Returns letter grade based on score data,
|
||||||
* or Grade.NULL if no objects have been processed.
|
* or Grade.NULL if no objects have been processed.
|
||||||
* @see GameData#getGrade(int, int, int, int)
|
* @see GameData#getGrade(int, int, int, int)
|
||||||
*/
|
*/
|
||||||
public Grade getGrade() {
|
public Grade getGrade() {
|
||||||
return GameData.getGrade(hit300, hit100, hit50, miss);
|
if (grade == null)
|
||||||
|
grade = GameData.getGrade(hit300, hit100, hit50, miss);
|
||||||
|
return grade;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws the score data as a rectangular button.
|
||||||
|
* @param g the graphics context
|
||||||
|
* @param index the index (to offset the button from the topmost button)
|
||||||
|
* @param rank the score rank
|
||||||
|
* @param prevScore the previous (lower) score, or -1 if none
|
||||||
|
* @param focus whether the button is focused
|
||||||
|
*/
|
||||||
|
public void draw(Graphics g, int index, int rank, long prevScore, boolean focus) {
|
||||||
|
Image img = getGrade().getMenuImage();
|
||||||
|
float y = baseY + index * (buttonOffset);
|
||||||
|
float textX = baseX + buttonWidth * 0.24f, edgeX = baseX + buttonWidth * 0.98f;
|
||||||
|
float marginY = Utils.FONT_DEFAULT.getLineHeight() * 0.01f;
|
||||||
|
|
||||||
|
// rectangle outline
|
||||||
|
g.setColor((focus) ? BG_FOCUS : BG_NORMAL);
|
||||||
|
g.fillRect(baseX, y, buttonWidth, buttonHeight);
|
||||||
|
|
||||||
|
// rank
|
||||||
|
if (focus) {
|
||||||
|
Utils.FONT_LARGE.drawString(
|
||||||
|
baseX + buttonWidth * 0.04f,
|
||||||
|
y + (buttonHeight - Utils.FONT_LARGE.getLineHeight()) / 2f,
|
||||||
|
Integer.toString(rank + 1), Color.white
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// grade image
|
||||||
|
img.drawCentered(baseX + buttonWidth * 0.15f, y + buttonHeight / 2f);
|
||||||
|
|
||||||
|
// score
|
||||||
|
float textOffset = (buttonHeight - Utils.FONT_MEDIUM.getLineHeight() - Utils.FONT_SMALL.getLineHeight()) / 2f;
|
||||||
|
Utils.FONT_MEDIUM.drawString(
|
||||||
|
textX, y + textOffset,
|
||||||
|
String.format("Score: %s (%dx)", NumberFormat.getNumberInstance().format(score), combo),
|
||||||
|
Color.white
|
||||||
|
);
|
||||||
|
|
||||||
|
// hit counts (custom: osu! shows user instead, above score)
|
||||||
|
Utils.FONT_SMALL.drawString(
|
||||||
|
textX, y + textOffset + Utils.FONT_MEDIUM.getLineHeight(),
|
||||||
|
String.format("300:%d 100:%d 50:%d Miss:%d", hit300, hit100, hit50, miss),
|
||||||
|
Color.white
|
||||||
|
);
|
||||||
|
|
||||||
|
// mods
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (GameMod mod : GameMod.values()) {
|
||||||
|
if ((mod.getBit() & mods) > 0) {
|
||||||
|
sb.append(mod.getAbbreviation());
|
||||||
|
sb.append(',');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sb.length() > 0) {
|
||||||
|
sb.setLength(sb.length() - 1);
|
||||||
|
String modString = sb.toString();
|
||||||
|
Utils.FONT_DEFAULT.drawString(
|
||||||
|
edgeX - Utils.FONT_DEFAULT.getWidth(modString),
|
||||||
|
y + marginY, modString, Color.white
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// accuracy
|
||||||
|
String accuracy = String.format("%.2f%%", getScorePercent());
|
||||||
|
Utils.FONT_DEFAULT.drawString(
|
||||||
|
edgeX - Utils.FONT_DEFAULT.getWidth(accuracy),
|
||||||
|
y + marginY + Utils.FONT_DEFAULT.getLineHeight(),
|
||||||
|
accuracy, Color.white
|
||||||
|
);
|
||||||
|
|
||||||
|
// score difference
|
||||||
|
String diff = (prevScore < 0 || score < prevScore) ?
|
||||||
|
"-" : String.format("+%s", NumberFormat.getNumberInstance().format(score - prevScore));
|
||||||
|
Utils.FONT_DEFAULT.drawString(
|
||||||
|
edgeX - Utils.FONT_DEFAULT.getWidth(diff),
|
||||||
|
y + marginY + Utils.FONT_DEFAULT.getLineHeight() * 2,
|
||||||
|
diff, Color.white
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
package itdelatrisu.opsu;
|
package itdelatrisu.opsu;
|
||||||
|
|
||||||
|
import itdelatrisu.opsu.Scores.ScoreData;
|
||||||
import itdelatrisu.opsu.audio.SoundController;
|
import itdelatrisu.opsu.audio.SoundController;
|
||||||
import itdelatrisu.opsu.audio.SoundEffect;
|
import itdelatrisu.opsu.audio.SoundEffect;
|
||||||
|
|
||||||
|
@ -198,6 +199,9 @@ public class Utils {
|
||||||
// initialize hit objects
|
// initialize hit objects
|
||||||
OsuHitObject.init(width, height);
|
OsuHitObject.init(width, height);
|
||||||
|
|
||||||
|
// initialize score data buttons
|
||||||
|
ScoreData.init(width, height);
|
||||||
|
|
||||||
// back button
|
// back button
|
||||||
Image back = GameImage.MENU_BACK.getImage();
|
Image back = GameImage.MENU_BACK.getImage();
|
||||||
backButton = new MenuButton(back,
|
backButton = new MenuButton(back,
|
||||||
|
|
|
@ -171,7 +171,8 @@ public class GameRanking extends BasicGameState {
|
||||||
throws SlickException {
|
throws SlickException {
|
||||||
Display.setTitle(game.getTitle());
|
Display.setTitle(game.getTitle());
|
||||||
Utils.getBackButton().setScale(1f);
|
Utils.getBackButton().setScale(1f);
|
||||||
SoundController.playSound(SoundEffect.APPLAUSE);
|
if (data.isGameplay())
|
||||||
|
SoundController.playSound(SoundEffect.APPLAUSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
|
|
||||||
package itdelatrisu.opsu.states;
|
package itdelatrisu.opsu.states;
|
||||||
|
|
||||||
|
import itdelatrisu.opsu.GameData;
|
||||||
|
import itdelatrisu.opsu.GameData.Grade;
|
||||||
import itdelatrisu.opsu.GameImage;
|
import itdelatrisu.opsu.GameImage;
|
||||||
import itdelatrisu.opsu.GameMod;
|
import itdelatrisu.opsu.GameMod;
|
||||||
import itdelatrisu.opsu.MenuButton;
|
import itdelatrisu.opsu.MenuButton;
|
||||||
|
@ -29,7 +31,6 @@ import itdelatrisu.opsu.OsuGroupNode;
|
||||||
import itdelatrisu.opsu.OsuParser;
|
import itdelatrisu.opsu.OsuParser;
|
||||||
import itdelatrisu.opsu.OszUnpacker;
|
import itdelatrisu.opsu.OszUnpacker;
|
||||||
import itdelatrisu.opsu.Scores;
|
import itdelatrisu.opsu.Scores;
|
||||||
import itdelatrisu.opsu.GameData.Grade;
|
|
||||||
import itdelatrisu.opsu.Scores.ScoreData;
|
import itdelatrisu.opsu.Scores.ScoreData;
|
||||||
import itdelatrisu.opsu.SongSort;
|
import itdelatrisu.opsu.SongSort;
|
||||||
import itdelatrisu.opsu.Utils;
|
import itdelatrisu.opsu.Utils;
|
||||||
|
@ -66,8 +67,11 @@ import org.newdawn.slick.state.transition.FadeOutTransition;
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
public class SongMenu extends BasicGameState {
|
public class SongMenu extends BasicGameState {
|
||||||
/** The number of buttons to be shown on each screen. */
|
/** The max number of song buttons to be shown on each screen. */
|
||||||
private static final int MAX_BUTTONS = 6;
|
private static final int MAX_SONG_BUTTONS = 6;
|
||||||
|
|
||||||
|
/** The max number of score buttons to be shown at a time. */
|
||||||
|
public static final int MAX_SCORE_BUTTONS = 7;
|
||||||
|
|
||||||
/** Delay time, in milliseconds, between each search. */
|
/** Delay time, in milliseconds, between each search. */
|
||||||
private static final int SEARCH_DELAY = 500;
|
private static final int SEARCH_DELAY = 500;
|
||||||
|
@ -160,6 +164,12 @@ public class SongMenu extends BasicGameState {
|
||||||
/** Current map of scores (Version, ScoreData[]). */
|
/** Current map of scores (Version, ScoreData[]). */
|
||||||
private Map<String, ScoreData[]> scoreMap;
|
private Map<String, ScoreData[]> scoreMap;
|
||||||
|
|
||||||
|
/** Scores for the current focus node. */
|
||||||
|
private ScoreData[] focusScores;
|
||||||
|
|
||||||
|
/** Current start score (topmost score entry). */
|
||||||
|
private int startScore = 0;
|
||||||
|
|
||||||
// game-related variables
|
// game-related variables
|
||||||
private GameContainer container;
|
private GameContainer container;
|
||||||
private StateBasedGame game;
|
private StateBasedGame game;
|
||||||
|
@ -188,7 +198,7 @@ public class SongMenu extends BasicGameState {
|
||||||
buttonY = height * 0.16f;
|
buttonY = height * 0.16f;
|
||||||
buttonWidth = menuBackground.getWidth();
|
buttonWidth = menuBackground.getWidth();
|
||||||
buttonHeight = menuBackground.getHeight();
|
buttonHeight = menuBackground.getHeight();
|
||||||
buttonOffset = (height * 0.8f) / MAX_BUTTONS;
|
buttonOffset = (height * 0.8f) / MAX_SONG_BUTTONS;
|
||||||
|
|
||||||
// search
|
// search
|
||||||
searchTimer = 0;
|
searchTimer = 0;
|
||||||
|
@ -267,7 +277,7 @@ public class SongMenu extends BasicGameState {
|
||||||
|
|
||||||
// song buttons
|
// song buttons
|
||||||
OsuGroupNode node = startNode;
|
OsuGroupNode node = startNode;
|
||||||
for (int i = 0; i < MAX_BUTTONS && node != null; i++, node = node.next) {
|
for (int i = 0; i < MAX_SONG_BUTTONS && node != null; i++, node = node.next) {
|
||||||
// draw the node
|
// draw the node
|
||||||
float offset = (i == hoverIndex) ? hoverOffset : 0f;
|
float offset = (i == hoverIndex) ? hoverOffset : 0f;
|
||||||
ScoreData[] scores = getScoreDataForNode(node);
|
ScoreData[] scores = getScoreDataForNode(node);
|
||||||
|
@ -281,6 +291,22 @@ public class SongMenu extends BasicGameState {
|
||||||
Utils.loadGlyphs(node.osuFiles.get(0));
|
Utils.loadGlyphs(node.osuFiles.get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// score buttons
|
||||||
|
if (focusScores != null) {
|
||||||
|
for (int i = 0; i < MAX_SCORE_BUTTONS; i++) {
|
||||||
|
int rank = startScore + i;
|
||||||
|
if (rank >= focusScores.length)
|
||||||
|
break;
|
||||||
|
long prevScore = (rank + 1 < focusScores.length) ?
|
||||||
|
focusScores[rank + 1].score : -1;
|
||||||
|
focusScores[rank].draw(g, i, rank, prevScore, ScoreData.buttonContains(mouseX, mouseY, i));
|
||||||
|
}
|
||||||
|
|
||||||
|
// scroll bar
|
||||||
|
if (focusScores.length > MAX_SCORE_BUTTONS && ScoreData.areaContains(mouseX, mouseY))
|
||||||
|
ScoreData.drawScrollbar(g, startScore, focusScores.length);
|
||||||
|
}
|
||||||
|
|
||||||
// options button
|
// options button
|
||||||
optionsButton.draw();
|
optionsButton.draw();
|
||||||
|
|
||||||
|
@ -403,7 +429,7 @@ public class SongMenu extends BasicGameState {
|
||||||
// mouse hover
|
// mouse hover
|
||||||
OsuGroupNode node = startNode;
|
OsuGroupNode node = startNode;
|
||||||
boolean isHover = false;
|
boolean isHover = false;
|
||||||
for (int i = 0; i < MAX_BUTTONS && node != null; i++, node = node.next) {
|
for (int i = 0; i < MAX_SONG_BUTTONS && node != null; i++, node = node.next) {
|
||||||
float cx = (node.index == OsuGroupList.get().getExpandedIndex()) ? buttonX * 0.9f : buttonX;
|
float cx = (node.index == OsuGroupList.get().getExpandedIndex()) ? buttonX * 0.9f : buttonX;
|
||||||
if ((mouseX > cx && mouseX < cx + buttonWidth) &&
|
if ((mouseX > cx && mouseX < cx + buttonWidth) &&
|
||||||
(mouseY > buttonY + (i * buttonOffset) && mouseY < buttonY + (i * buttonOffset) + buttonHeight)) {
|
(mouseY > buttonY + (i * buttonOffset) && mouseY < buttonY + (i * buttonOffset) + buttonHeight)) {
|
||||||
|
@ -477,7 +503,7 @@ public class SongMenu extends BasicGameState {
|
||||||
// song buttons
|
// song buttons
|
||||||
int expandedIndex = OsuGroupList.get().getExpandedIndex();
|
int expandedIndex = OsuGroupList.get().getExpandedIndex();
|
||||||
OsuGroupNode node = startNode;
|
OsuGroupNode node = startNode;
|
||||||
for (int i = 0; i < MAX_BUTTONS && node != null; i++, node = node.next) {
|
for (int i = 0; i < MAX_SONG_BUTTONS && node != null; i++, node = node.next) {
|
||||||
// is button at this index clicked?
|
// is button at this index clicked?
|
||||||
float cx = (node.index == expandedIndex) ? buttonX * 0.9f : buttonX;
|
float cx = (node.index == expandedIndex) ? buttonX * 0.9f : buttonX;
|
||||||
if ((x > cx && x < cx + buttonWidth) &&
|
if ((x > cx && x < cx + buttonWidth) &&
|
||||||
|
@ -508,7 +534,23 @@ public class SongMenu extends BasicGameState {
|
||||||
hoverOffset = oldHoverOffset;
|
hoverOffset = oldHoverOffset;
|
||||||
hoverIndex = oldHoverIndex;
|
hoverIndex = oldHoverIndex;
|
||||||
|
|
||||||
break;
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// score buttons
|
||||||
|
if (focusScores != null && ScoreData.areaContains(x, y)) {
|
||||||
|
for (int i = 0; i < MAX_SCORE_BUTTONS; i++) {
|
||||||
|
int rank = startScore + i;
|
||||||
|
if (rank >= focusScores.length)
|
||||||
|
break;
|
||||||
|
if (ScoreData.buttonContains(x, y, i)) {
|
||||||
|
// 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 FadeOutTransition(Color.black), new FadeInTransition(Color.black));
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -644,10 +686,10 @@ public class SongMenu extends BasicGameState {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Input.KEY_NEXT:
|
case Input.KEY_NEXT:
|
||||||
changeIndex(MAX_BUTTONS);
|
changeIndex(MAX_SONG_BUTTONS);
|
||||||
break;
|
break;
|
||||||
case Input.KEY_PRIOR:
|
case Input.KEY_PRIOR:
|
||||||
changeIndex(-MAX_BUTTONS);
|
changeIndex(-MAX_SONG_BUTTONS);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// wait for user to finish typing
|
// wait for user to finish typing
|
||||||
|
@ -663,7 +705,12 @@ public class SongMenu extends BasicGameState {
|
||||||
if (reloadThread != null)
|
if (reloadThread != null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// check mouse button (right click scrolls faster)
|
int diff = newy - oldy;
|
||||||
|
if (diff == 0)
|
||||||
|
return;
|
||||||
|
int shift = (diff < 0) ? 1 : -1;
|
||||||
|
|
||||||
|
// check mouse button (right click scrolls faster on songs)
|
||||||
int multiplier;
|
int multiplier;
|
||||||
if (input.isMouseButtonDown(Input.MOUSE_RIGHT_BUTTON))
|
if (input.isMouseButtonDown(Input.MOUSE_RIGHT_BUTTON))
|
||||||
multiplier = 4;
|
multiplier = 4;
|
||||||
|
@ -672,11 +719,16 @@ public class SongMenu extends BasicGameState {
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int diff = newy - oldy;
|
// score buttons
|
||||||
if (diff != 0) {
|
if (focusScores != null && focusScores.length >= MAX_SCORE_BUTTONS && ScoreData.areaContains(oldx, oldy)) {
|
||||||
diff = ((diff < 0) ? 1 : -1) * multiplier;
|
int newStartScore = startScore + shift;
|
||||||
changeIndex(diff);
|
if (newStartScore >= 0 && newStartScore + MAX_SCORE_BUTTONS <= focusScores.length)
|
||||||
|
startScore = newStartScore;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// song buttons
|
||||||
|
else
|
||||||
|
changeIndex(shift * multiplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -685,7 +737,19 @@ public class SongMenu extends BasicGameState {
|
||||||
if (reloadThread != null)
|
if (reloadThread != null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
changeIndex((newValue < 0) ? 1 : -1);
|
int shift = (newValue < 0) ? 1 : -1;
|
||||||
|
int mouseX = input.getMouseX(), mouseY = input.getMouseY();
|
||||||
|
|
||||||
|
// score buttons
|
||||||
|
if (focusScores != null && focusScores.length >= MAX_SCORE_BUTTONS && ScoreData.areaContains(mouseX, mouseY)) {
|
||||||
|
int newStartScore = startScore + shift;
|
||||||
|
if (newStartScore >= 0 && newStartScore + MAX_SCORE_BUTTONS <= focusScores.length)
|
||||||
|
startScore = newStartScore;
|
||||||
|
}
|
||||||
|
|
||||||
|
// song buttons
|
||||||
|
else
|
||||||
|
changeIndex(shift);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -696,6 +760,7 @@ public class SongMenu extends BasicGameState {
|
||||||
optionsButton.setScale(1f);
|
optionsButton.setScale(1f);
|
||||||
hoverOffset = 0f;
|
hoverOffset = 0f;
|
||||||
hoverIndex = -1;
|
hoverIndex = -1;
|
||||||
|
startScore = 0;
|
||||||
|
|
||||||
// stop playing the theme song
|
// stop playing the theme song
|
||||||
if (MusicController.isThemePlaying() && focusNode != null)
|
if (MusicController.isThemePlaying() && focusNode != null)
|
||||||
|
@ -726,8 +791,10 @@ public class SongMenu extends BasicGameState {
|
||||||
}
|
}
|
||||||
|
|
||||||
// reload scores
|
// reload scores
|
||||||
if (focusNode != null)
|
if (focusNode != null) {
|
||||||
scoreMap = Scores.getMapSetScores(focusNode.osuFiles.get(focusNode.osuFileIndex));
|
scoreMap = Scores.getMapSetScores(focusNode.osuFiles.get(focusNode.osuFileIndex));
|
||||||
|
focusScores = getScoreDataForNode(focusNode);
|
||||||
|
}
|
||||||
|
|
||||||
resetGame = false;
|
resetGame = false;
|
||||||
}
|
}
|
||||||
|
@ -763,7 +830,7 @@ public class SongMenu extends BasicGameState {
|
||||||
n++;
|
n++;
|
||||||
shifted = true;
|
shifted = true;
|
||||||
} else if (n > 0 && startNode.next != null &&
|
} else if (n > 0 && startNode.next != null &&
|
||||||
OsuGroupList.get().getNode(startNode, MAX_BUTTONS) != null) {
|
OsuGroupList.get().getNode(startNode, MAX_SONG_BUTTONS) != null) {
|
||||||
startNode = startNode.next;
|
startNode = startNode.next;
|
||||||
buttonY -= buttonOffset / 4;
|
buttonY -= buttonOffset / 4;
|
||||||
if (buttonY < height * 0.14f)
|
if (buttonY < height * 0.14f)
|
||||||
|
@ -821,13 +888,15 @@ public class SongMenu extends BasicGameState {
|
||||||
|
|
||||||
// load scores
|
// load scores
|
||||||
scoreMap = Scores.getMapSetScores(osu);
|
scoreMap = Scores.getMapSetScores(osu);
|
||||||
|
focusScores = getScoreDataForNode(focusNode);
|
||||||
|
startScore = 0;
|
||||||
|
|
||||||
// check startNode bounds
|
// check startNode bounds
|
||||||
while (startNode.index >= OsuGroupList.get().size() + length - MAX_BUTTONS && startNode.prev != null)
|
while (startNode.index >= OsuGroupList.get().size() + length - MAX_SONG_BUTTONS && startNode.prev != null)
|
||||||
startNode = startNode.prev;
|
startNode = startNode.prev;
|
||||||
|
|
||||||
// make sure focusNode is on the screen (TODO: cleanup...)
|
// make sure focusNode is on the screen (TODO: cleanup...)
|
||||||
int val = focusNode.index + focusNode.osuFileIndex - (startNode.index + MAX_BUTTONS) + 1;
|
int val = focusNode.index + focusNode.osuFileIndex - (startNode.index + MAX_SONG_BUTTONS) + 1;
|
||||||
if (val > 0) // below screen
|
if (val > 0) // below screen
|
||||||
changeIndex(val);
|
changeIndex(val);
|
||||||
else { // above screen
|
else { // above screen
|
||||||
|
@ -866,7 +935,7 @@ public class SongMenu extends BasicGameState {
|
||||||
* @return the ScoreData array
|
* @return the ScoreData array
|
||||||
*/
|
*/
|
||||||
private ScoreData[] getScoreDataForNode(OsuGroupNode node) {
|
private ScoreData[] getScoreDataForNode(OsuGroupNode node) {
|
||||||
if (scoreMap == null || node.osuFileIndex == -1) // node not expanded
|
if (scoreMap == null || scoreMap.isEmpty() || node.osuFileIndex == -1) // node not expanded
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
OsuFile osu = node.osuFiles.get(node.osuFileIndex);
|
OsuFile osu = node.osuFiles.get(node.osuFileIndex);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user