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:
@@ -171,7 +171,8 @@ public class GameRanking extends BasicGameState {
|
||||
throws SlickException {
|
||||
Display.setTitle(game.getTitle());
|
||||
Utils.getBackButton().setScale(1f);
|
||||
SoundController.playSound(SoundEffect.APPLAUSE);
|
||||
if (data.isGameplay())
|
||||
SoundController.playSound(SoundEffect.APPLAUSE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
package itdelatrisu.opsu.states;
|
||||
|
||||
import itdelatrisu.opsu.GameData;
|
||||
import itdelatrisu.opsu.GameData.Grade;
|
||||
import itdelatrisu.opsu.GameImage;
|
||||
import itdelatrisu.opsu.GameMod;
|
||||
import itdelatrisu.opsu.MenuButton;
|
||||
@@ -29,7 +31,6 @@ import itdelatrisu.opsu.OsuGroupNode;
|
||||
import itdelatrisu.opsu.OsuParser;
|
||||
import itdelatrisu.opsu.OszUnpacker;
|
||||
import itdelatrisu.opsu.Scores;
|
||||
import itdelatrisu.opsu.GameData.Grade;
|
||||
import itdelatrisu.opsu.Scores.ScoreData;
|
||||
import itdelatrisu.opsu.SongSort;
|
||||
import itdelatrisu.opsu.Utils;
|
||||
@@ -66,8 +67,11 @@ import org.newdawn.slick.state.transition.FadeOutTransition;
|
||||
* </ul>
|
||||
*/
|
||||
public class SongMenu extends BasicGameState {
|
||||
/** The number of buttons to be shown on each screen. */
|
||||
private static final int MAX_BUTTONS = 6;
|
||||
/** The max number of song buttons to be shown on each screen. */
|
||||
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. */
|
||||
private static final int SEARCH_DELAY = 500;
|
||||
@@ -160,6 +164,12 @@ public class SongMenu extends BasicGameState {
|
||||
/** Current map of scores (Version, ScoreData[]). */
|
||||
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
|
||||
private GameContainer container;
|
||||
private StateBasedGame game;
|
||||
@@ -188,7 +198,7 @@ public class SongMenu extends BasicGameState {
|
||||
buttonY = height * 0.16f;
|
||||
buttonWidth = menuBackground.getWidth();
|
||||
buttonHeight = menuBackground.getHeight();
|
||||
buttonOffset = (height * 0.8f) / MAX_BUTTONS;
|
||||
buttonOffset = (height * 0.8f) / MAX_SONG_BUTTONS;
|
||||
|
||||
// search
|
||||
searchTimer = 0;
|
||||
@@ -267,7 +277,7 @@ public class SongMenu extends BasicGameState {
|
||||
|
||||
// song buttons
|
||||
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
|
||||
float offset = (i == hoverIndex) ? hoverOffset : 0f;
|
||||
ScoreData[] scores = getScoreDataForNode(node);
|
||||
@@ -281,6 +291,22 @@ public class SongMenu extends BasicGameState {
|
||||
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
|
||||
optionsButton.draw();
|
||||
|
||||
@@ -403,7 +429,7 @@ public class SongMenu extends BasicGameState {
|
||||
// mouse hover
|
||||
OsuGroupNode node = startNode;
|
||||
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;
|
||||
if ((mouseX > cx && mouseX < cx + buttonWidth) &&
|
||||
(mouseY > buttonY + (i * buttonOffset) && mouseY < buttonY + (i * buttonOffset) + buttonHeight)) {
|
||||
@@ -477,7 +503,7 @@ public class SongMenu extends BasicGameState {
|
||||
// song buttons
|
||||
int expandedIndex = OsuGroupList.get().getExpandedIndex();
|
||||
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?
|
||||
float cx = (node.index == expandedIndex) ? buttonX * 0.9f : buttonX;
|
||||
if ((x > cx && x < cx + buttonWidth) &&
|
||||
@@ -508,7 +534,23 @@ public class SongMenu extends BasicGameState {
|
||||
hoverOffset = oldHoverOffset;
|
||||
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;
|
||||
case Input.KEY_NEXT:
|
||||
changeIndex(MAX_BUTTONS);
|
||||
changeIndex(MAX_SONG_BUTTONS);
|
||||
break;
|
||||
case Input.KEY_PRIOR:
|
||||
changeIndex(-MAX_BUTTONS);
|
||||
changeIndex(-MAX_SONG_BUTTONS);
|
||||
break;
|
||||
default:
|
||||
// wait for user to finish typing
|
||||
@@ -663,7 +705,12 @@ public class SongMenu extends BasicGameState {
|
||||
if (reloadThread != null)
|
||||
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;
|
||||
if (input.isMouseButtonDown(Input.MOUSE_RIGHT_BUTTON))
|
||||
multiplier = 4;
|
||||
@@ -672,11 +719,16 @@ public class SongMenu extends BasicGameState {
|
||||
else
|
||||
return;
|
||||
|
||||
int diff = newy - oldy;
|
||||
if (diff != 0) {
|
||||
diff = ((diff < 0) ? 1 : -1) * multiplier;
|
||||
changeIndex(diff);
|
||||
// score buttons
|
||||
if (focusScores != null && focusScores.length >= MAX_SCORE_BUTTONS && ScoreData.areaContains(oldx, oldy)) {
|
||||
int newStartScore = startScore + shift;
|
||||
if (newStartScore >= 0 && newStartScore + MAX_SCORE_BUTTONS <= focusScores.length)
|
||||
startScore = newStartScore;
|
||||
}
|
||||
|
||||
// song buttons
|
||||
else
|
||||
changeIndex(shift * multiplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -685,7 +737,19 @@ public class SongMenu extends BasicGameState {
|
||||
if (reloadThread != null)
|
||||
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
|
||||
@@ -696,6 +760,7 @@ public class SongMenu extends BasicGameState {
|
||||
optionsButton.setScale(1f);
|
||||
hoverOffset = 0f;
|
||||
hoverIndex = -1;
|
||||
startScore = 0;
|
||||
|
||||
// stop playing the theme song
|
||||
if (MusicController.isThemePlaying() && focusNode != null)
|
||||
@@ -726,8 +791,10 @@ public class SongMenu extends BasicGameState {
|
||||
}
|
||||
|
||||
// reload scores
|
||||
if (focusNode != null)
|
||||
if (focusNode != null) {
|
||||
scoreMap = Scores.getMapSetScores(focusNode.osuFiles.get(focusNode.osuFileIndex));
|
||||
focusScores = getScoreDataForNode(focusNode);
|
||||
}
|
||||
|
||||
resetGame = false;
|
||||
}
|
||||
@@ -763,7 +830,7 @@ public class SongMenu extends BasicGameState {
|
||||
n++;
|
||||
shifted = true;
|
||||
} 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;
|
||||
buttonY -= buttonOffset / 4;
|
||||
if (buttonY < height * 0.14f)
|
||||
@@ -821,13 +888,15 @@ public class SongMenu extends BasicGameState {
|
||||
|
||||
// load scores
|
||||
scoreMap = Scores.getMapSetScores(osu);
|
||||
focusScores = getScoreDataForNode(focusNode);
|
||||
startScore = 0;
|
||||
|
||||
// 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;
|
||||
|
||||
// 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
|
||||
changeIndex(val);
|
||||
else { // above screen
|
||||
@@ -866,7 +935,7 @@ public class SongMenu extends BasicGameState {
|
||||
* @return the ScoreData array
|
||||
*/
|
||||
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;
|
||||
|
||||
OsuFile osu = node.osuFiles.get(node.osuFileIndex);
|
||||
|
||||
Reference in New Issue
Block a user