diff --git a/src/itdelatrisu/opsu/GameMod.java b/src/itdelatrisu/opsu/GameMod.java index 473366f7..dc7b1146 100644 --- a/src/itdelatrisu/opsu/GameMod.java +++ b/src/itdelatrisu/opsu/GameMod.java @@ -30,33 +30,33 @@ import org.newdawn.slick.Input; */ public enum GameMod { EASY (Category.EASY, 0, GameImage.MOD_EASY, "EZ", 2, Input.KEY_Q, 0.5f, - "Reduces overall difficulty - larger circles, more forgiving HP drain, less accuracy required."), + "Easy", "Reduces overall difficulty - larger circles, more forgiving HP drain, less accuracy required."), NO_FAIL (Category.EASY, 1, GameImage.MOD_NO_FAIL, "NF", 1, Input.KEY_W, 0.5f, - "You can't fail. No matter what."), + "NoFail", "You can't fail. No matter what."), HALF_TIME (Category.EASY, 2, GameImage.MOD_HALF_TIME, "HT", 256, Input.KEY_E, 0.3f, false, - "Less zoom."), + "HalfTime", "Less zoom."), HARD_ROCK (Category.HARD, 0, GameImage.MOD_HARD_ROCK, "HR", 16, Input.KEY_A, 1.06f, - "Everything just got a bit harder..."), + "HardRock", "Everything just got a bit harder..."), SUDDEN_DEATH (Category.HARD, 1, GameImage.MOD_SUDDEN_DEATH, "SD", 32, Input.KEY_S, 1f, - "Miss a note and fail."), + "SuddenDeath", "Miss a note and fail."), // PERFECT (Category.HARD, 1, GameImage.MOD_PERFECT, "PF", 64, Input.KEY_S, 1f, -// "SS or quit."), +// "Perfect", "SS or quit."), DOUBLE_TIME (Category.HARD, 2, GameImage.MOD_DOUBLE_TIME, "DT", 64, Input.KEY_D, 1.12f, false, - "Zoooooooooom."), + "DoubleTime", "Zoooooooooom."), // NIGHTCORE (Category.HARD, 2, GameImage.MOD_NIGHTCORE, "NT", 64, Input.KEY_D, 1.12f, -// "uguuuuuuuu"), +// "Nightcore", "uguuuuuuuu"), HIDDEN (Category.HARD, 3, GameImage.MOD_HIDDEN, "HD", 8, Input.KEY_F, 1.06f, false, - "Play with no approach circles and fading notes for a slight score advantage."), + "Hidden", "Play with no approach circles and fading notes for a slight score advantage."), FLASHLIGHT (Category.HARD, 4, GameImage.MOD_FLASHLIGHT, "FL", 1024, Input.KEY_G, 1.12f, false, - "Restricted view area."), + "Flashlight", "Restricted view area."), RELAX (Category.SPECIAL, 0, GameImage.MOD_RELAX, "RL", 128, Input.KEY_Z, 0f, - "You don't need to click.\nGive your clicking/tapping finger a break from the heat of things.\n**UNRANKED**"), + "Relax", "You don't need to click.\nGive your clicking/tapping finger a break from the heat of things.\n**UNRANKED**"), AUTOPILOT (Category.SPECIAL, 1, GameImage.MOD_AUTOPILOT, "AP", 8192, Input.KEY_X, 0f, false, - "Automatic cursor movement - just follow the rhythm.\n**UNRANKED**"), + "Relax2", "Automatic cursor movement - just follow the rhythm.\n**UNRANKED**"), SPUN_OUT (Category.SPECIAL, 2, GameImage.MOD_SPUN_OUT, "SO", 4096, Input.KEY_V, 0.9f, - "Spinners will be automatically completed."), + "SpunOut", "Spinners will be automatically completed."), AUTO (Category.SPECIAL, 3, GameImage.MOD_AUTO, "", 2048, Input.KEY_B, 1f, - "Watch a perfect automated play through the song."); + "Autoplay", "Watch a perfect automated play through the song."); /** Mod categories. */ public enum Category { @@ -148,6 +148,9 @@ public enum GameMod { /** Whether or not the mod is implemented. */ private boolean implemented; + /** The name of the mod. */ + private String name; + /** The description of the mod. */ private String description; @@ -234,6 +237,25 @@ public enum GameMod { mod.active = ((state & mod.getBit()) > 0); } + /** + * Returns a comma-separated string of mod names of active mods in the given state. + * @param state the state (bitwise OR of active mods) + */ + public static String getModString(int state) { + StringBuilder sb = new StringBuilder(); + for (GameMod mod : GameMod.values()) { + if ((state & mod.getBit()) > 0) { + sb.append(mod.getName()); + sb.append(','); + } + } + if (sb.length() > 0) { + sb.setLength(sb.length() - 1); + return sb.toString(); + } else + return "None"; + } + /** * Constructor. * @param category the category for the mod @@ -243,11 +265,12 @@ public enum GameMod { * @param bit the bit * @param key the shortcut key * @param multiplier the score multiplier + * @param name the name * @param description the description */ GameMod(Category category, int categoryIndex, GameImage image, String abbrev, - int bit, int key, float multiplier, String description) { - this(category, categoryIndex, image, abbrev, bit, key, multiplier, true, description); + int bit, int key, float multiplier, String name, String description) { + this(category, categoryIndex, image, abbrev, bit, key, multiplier, true, name, description); } /** @@ -260,10 +283,11 @@ public enum GameMod { * @param key the shortcut key * @param multiplier the score multiplier * @param implemented whether the mod is implemented + * @param name the name * @param description the description */ GameMod(Category category, int categoryIndex, GameImage image, String abbrev, - int bit, int key, float multiplier, boolean implemented, String description) { + int bit, int key, float multiplier, boolean implemented, String name, String description) { this.category = category; this.categoryIndex = categoryIndex; this.image = image; @@ -272,6 +296,7 @@ public enum GameMod { this.key = key; this.multiplier = multiplier; this.implemented = implemented; + this.name = name; this.description = description; } @@ -300,6 +325,12 @@ public enum GameMod { */ public float getMultiplier() { return multiplier; } + /** + * Returns the name of the mod. + * @return the name + */ + public String getName() { return name; } + /** * Returns a description of the mod. * @return the description diff --git a/src/itdelatrisu/opsu/ScoreData.java b/src/itdelatrisu/opsu/ScoreData.java index 970fa3fe..563bf779 100644 --- a/src/itdelatrisu/opsu/ScoreData.java +++ b/src/itdelatrisu/opsu/ScoreData.java @@ -71,6 +71,12 @@ public class ScoreData implements Comparable { /** The score percent. */ private float scorePercent = -1f; + /** A formatted string of the timestamp. */ + private String timeString; + + /** A formatted string of the mods. */ + private String modString; + /** Drawing values. */ private static float baseX, baseY, buttonWidth, buttonHeight, buttonOffset; @@ -163,7 +169,9 @@ public class ScoreData implements Comparable { * Returns the timestamp as a string. */ public String getTimeString() { - return new SimpleDateFormat("M/d/yyyy h:mm:ss a").format(new Date(timestamp * 1000L)); + if (timeString == null) + timeString = new SimpleDateFormat("M/d/yyyy h:mm:ss a").format(new Date(timestamp * 1000L)); + return timeString; } /** @@ -207,6 +215,15 @@ public class ScoreData implements Comparable { return (timeSince.isEmpty()) ? null : timeSince; } + /** + * Returns a comma-separated string of mod names. + */ + private String getModString() { + if (modString == null) + modString = GameMod.getModString(mods); + return modString; + } + /** * Draws the score data as a rectangular button. * @param g the graphics context @@ -300,13 +317,25 @@ public class ScoreData implements Comparable { } } + /** + * Draws the a tooltip containing the score information. + * @param g the graphics context + */ + public void drawTooltip(Graphics g) { + String text = String.format( + "Achieved on %s\n300:%d 100:%d 50:%d Miss:%d\nAccuracy: %.2f%%\nMods: %s", + getTimeString(), hit300, hit100, hit50, miss, + getScorePercent(), getModString()); + UI.drawTooltip(g, text, true); + } + @Override public String toString() { return String.format( "%s | ID: (%d, %d) | %s - %s [%s] (by %s) | " + - "Hits: (%d, %d, %d, %d, %d, %d) | Score: %d (%d combo%s) | Mods: %d", + "Hits: (%d, %d, %d, %d, %d, %d) | Score: %d (%d combo%s) | Mods: %s", getTimeString(), MID, MSID, artist, title, version, creator, - hit300, hit100, hit50, geki, katu, miss, score, combo, perfect ? ", FC" : "", mods + hit300, hit100, hit50, geki, katu, miss, score, combo, perfect ? ", FC" : "", getModString() ); } diff --git a/src/itdelatrisu/opsu/states/SongMenu.java b/src/itdelatrisu/opsu/states/SongMenu.java index cdba346d..60e61691 100644 --- a/src/itdelatrisu/opsu/states/SongMenu.java +++ b/src/itdelatrisu/opsu/states/SongMenu.java @@ -353,14 +353,17 @@ public class SongMenu extends BasicGameState { } // score buttons + ScoreData hoverScore = null; 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)); + long prevScore = (rank + 1 < focusScores.length) ? focusScores[rank + 1].score : -1; + boolean contains = ScoreData.buttonContains(mouseX, mouseY, i); + focusScores[rank].draw(g, i, rank, prevScore, contains); + if (contains) + hoverScore = focusScores[rank]; } // scroll bar @@ -456,6 +459,10 @@ public class SongMenu extends BasicGameState { UI.getBackButton().draw(); UI.draw(g); + + // tooltips + if (hoverScore != null) + hoverScore.drawTooltip(g); } @Override