diff --git a/res/logo2.png b/res/logo2.png new file mode 100644 index 00000000..25ec41c8 Binary files /dev/null and b/res/logo2.png differ diff --git a/res/logo2piece2.png b/res/logo2piece2.png new file mode 100644 index 00000000..35484e97 Binary files /dev/null and b/res/logo2piece2.png differ diff --git a/res/menu-exit2.png b/res/menu-exit2.png new file mode 100644 index 00000000..7acd9900 Binary files /dev/null and b/res/menu-exit2.png differ diff --git a/res/menu-play2.png b/res/menu-play2.png new file mode 100644 index 00000000..0ba86471 Binary files /dev/null and b/res/menu-play2.png differ diff --git a/src/itdelatrisu/opsu/GameImage.java b/src/itdelatrisu/opsu/GameImage.java index ac18af23..6e366f94 100644 --- a/src/itdelatrisu/opsu/GameImage.java +++ b/src/itdelatrisu/opsu/GameImage.java @@ -271,19 +271,25 @@ public enum GameImage { return img.getScaledCopy(w, h); } }, - MENU_LOGO ("logo", "png", false, true) { + MENU_LOGO ("logo2", "png", false, true) { @Override protected Image process_sub(Image img, int w, int h) { return img.getScaledCopy(0.8f); } }, - MENU_PLAY ("menu-play", "png", false, false) { + MENU_LOGO_PIECE ("logo2piece2", "png", false, true) { @Override protected Image process_sub(Image img, int w, int h) { return img.getScaledCopy(0.8f); } }, - MENU_EXIT ("menu-exit", "png", false, false) { + MENU_PLAY ("menu-play2", "png", false, false) { + @Override + protected Image process_sub(Image img, int w, int h) { + return img.getScaledCopy(0.8f); + } + }, + MENU_EXIT ("menu-exit2", "png", false, false) { @Override protected Image process_sub(Image img, int w, int h) { return img.getScaledCopy(0.8f); diff --git a/src/itdelatrisu/opsu/audio/MusicController.java b/src/itdelatrisu/opsu/audio/MusicController.java index 5ecfa76d..369eddaf 100644 --- a/src/itdelatrisu/opsu/audio/MusicController.java +++ b/src/itdelatrisu/opsu/audio/MusicController.java @@ -348,7 +348,7 @@ public class MusicController { public static void playThemeSong() { Beatmap beatmap = Options.getThemeBeatmap(); if (beatmap != null) { - play(beatmap, true, false); + play(beatmap, false, false); themePlaying = true; } } diff --git a/src/itdelatrisu/opsu/beatmap/BeatmapParser.java b/src/itdelatrisu/opsu/beatmap/BeatmapParser.java index c7004703..1016aad3 100644 --- a/src/itdelatrisu/opsu/beatmap/BeatmapParser.java +++ b/src/itdelatrisu/opsu/beatmap/BeatmapParser.java @@ -24,15 +24,7 @@ import itdelatrisu.opsu.Utils; import itdelatrisu.opsu.db.BeatmapDB; import itdelatrisu.opsu.io.MD5InputStreamWrapper; -import java.io.BufferedInputStream; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileReader; -import java.io.FilenameFilter; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; +import java.io.*; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Collections; @@ -212,6 +204,63 @@ public class BeatmapParser { return lastNode; } + public static void parseOnlyTimingPoints(Beatmap map) { + if (map == null || map.getFile() == null || !map.getFile().exists()) { + return; + } + if (map.timingPoints == null) { + map.timingPoints = new ArrayList(); + } + try ( + InputStream bis = new BufferedInputStream(new FileInputStream(map.getFile())); + MD5InputStreamWrapper md5stream = (!hasNoMD5Algorithm) ? new MD5InputStreamWrapper(bis) : null; + BufferedReader in = new BufferedReader(new InputStreamReader((md5stream != null) ? md5stream : bis, "UTF-8")); + ) { + String line; + boolean found = false; + while((line = in.readLine()) != null) { + line = line.trim(); + if(!isValidLine(line)) { + continue; + } + if ("[TimingPoints]".equals(line)) { + found = true; + continue; + } + if (found) { + if (line.startsWith("[")) { + break; + } + parseSectionTimingPoints(map, line); + } + } + map.timingPoints.trimToSize(); + } catch (IOException e) { + ErrorHandler.error(String.format("Failed to read file '%s'.", map.getFile().getAbsolutePath()), e, false); + } catch (NoSuchAlgorithmException e) { + ErrorHandler.error("Failed to get MD5 hash stream.", e, true); + + // retry without MD5 + hasNoMD5Algorithm = true; + parseOnlyTimingPoints(map); + } + } + + private static void parseSectionTimingPoints(Beatmap beatmap, String line) { + TimingPoint timingPoint = new TimingPoint(line); + if(!timingPoint.isInherited()) { + int bpm = Math.round(60000 / timingPoint.getBeatLength()); + if( beatmap.bpmMin == 0 ) { + beatmap.bpmMin = beatmap.bpmMax = bpm; + } else if( bpm < beatmap.bpmMin ) { + beatmap.bpmMin = bpm; + } else if( bpm > beatmap.bpmMax ) { + beatmap.bpmMax = bpm; + } + } + beatmap.timingPoints.add(timingPoint); + } + /** * Parses a beatmap. * @param file the file to parse diff --git a/src/itdelatrisu/opsu/states/MainMenu.java b/src/itdelatrisu/opsu/states/MainMenu.java index 5a4c969d..59694c57 100644 --- a/src/itdelatrisu/opsu/states/MainMenu.java +++ b/src/itdelatrisu/opsu/states/MainMenu.java @@ -29,6 +29,7 @@ import itdelatrisu.opsu.audio.SoundEffect; import itdelatrisu.opsu.beatmap.Beatmap; import itdelatrisu.opsu.beatmap.BeatmapSetList; import itdelatrisu.opsu.beatmap.BeatmapSetNode; +import itdelatrisu.opsu.beatmap.TimingPoint; import itdelatrisu.opsu.downloads.Updater; import itdelatrisu.opsu.states.ButtonMenu.MenuState; import itdelatrisu.opsu.ui.Colors; @@ -269,7 +270,23 @@ public class MainMenu extends BasicGameState { playButton.draw(); exitButton.draw(); } - logo.draw(); + + Double position = getBPMPiecePosition(); + + if (position != null) { + double scale = 1 - (0 - position) * 0.05; + logo.draw(Color.white, (float) scale); + Image piece = GameImage.MENU_LOGO_PIECE.getImage(); + float xRadius = piece.getWidth() / 2; + float yRadius = piece.getHeight() / 2; + piece = piece.getScaledCopy(logo.getCurrentScale()); + float scaleposmodx = piece.getWidth() / 2 - xRadius; + float scaleposmody = piece.getHeight() / 2 - yRadius; + piece.rotate((float)(position * 360)); + piece.draw(logo.getX() - xRadius - scaleposmodx, logo.getY() - yRadius - scaleposmody); + } else { + logo.draw(); + } // draw music buttons if (MusicController.isPlaying()) @@ -341,6 +358,34 @@ public class MainMenu extends BasicGameState { UI.draw(g); } + private Double getBPMPiecePosition() { + if (!MusicController.isPlaying() || MusicController.getBeatmap() == null) { + return null; + } + Beatmap map = MusicController.getBeatmap(); + if (map.timingPoints == null) { + return null; + } + int trackposition = MusicController.getPosition(); + TimingPoint p = null; + float beatlen = 0f; + int time = 0; + for (TimingPoint pts : map.timingPoints) { + if (p == null || pts.getTime() < MusicController.getPosition()) { + p = pts; + if (!p.isInherited() && p.getBeatLength() > 0) { + beatlen = p.getBeatLength(); + time = p.getTime(); + } + } + } + if (p == null) { + return null; + } + double beatLength = beatlen * 100; + return (((trackposition * 100 - time * 100) % beatLength) / beatLength); + } + @Override public void update(GameContainer container, StateBasedGame game, int delta) throws SlickException { @@ -611,6 +656,12 @@ public class MainMenu extends BasicGameState { switch (key) { case Input.KEY_ESCAPE: case Input.KEY_Q: + if (logoTimer > 0) { + logoState = LogoState.CLOSING; + logoClose.setTime(0); + logoTimer = 0; + break; + } ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).setMenuState(MenuState.EXIT); game.enterState(Opsu.STATE_BUTTONMENU); break; diff --git a/src/itdelatrisu/opsu/states/SongMenu.java b/src/itdelatrisu/opsu/states/SongMenu.java index 6a91880f..cfb2bda6 100644 --- a/src/itdelatrisu/opsu/states/SongMenu.java +++ b/src/itdelatrisu/opsu/states/SongMenu.java @@ -1391,6 +1391,9 @@ public class SongMenu extends BasicGameState { focusNode = BeatmapSetList.get().getNode(node, beatmapIndex); Beatmap beatmap = focusNode.getSelectedBeatmap(); + if (beatmap.timingPoints == null) { + BeatmapParser.parseOnlyTimingPoints(beatmap); + } MusicController.play(beatmap, false, preview); // load scores diff --git a/src/itdelatrisu/opsu/ui/MenuButton.java b/src/itdelatrisu/opsu/ui/MenuButton.java index 1aa524dc..1a71c536 100644 --- a/src/itdelatrisu/opsu/ui/MenuButton.java +++ b/src/itdelatrisu/opsu/ui/MenuButton.java @@ -98,6 +98,12 @@ public class MenuButton { /** The default max rotation angle of the button. */ private static final float DEFAULT_ANGLE_MAX = 30f; + private float currentScale = 1f; + + public float getCurrentScale() { + return currentScale; + } + /** * Creates a new button from an Image. * @param img the image @@ -191,14 +197,21 @@ public class MenuButton { /** * Draws the button. */ - public void draw() { draw(Color.white); } + public void draw() { draw(Color.white, 1.0f); } /** - * Draw the button with a color filter. + * Draws the button with a color filter. * @param filter the color to filter with when drawing */ + public void draw(Color filter) { draw(filter, 1.0f); } + + /** + * Draw the button with a color filter and scale. + * @param filter the color to filter with when drawing + * @param scaleoverride the scale to use when drawing + */ @SuppressWarnings("deprecation") - public void draw(Color filter) { + public void draw(Color filter, float scaleoverride) { // animations: get current frame Image image = this.img; if (image == null) { @@ -206,10 +219,20 @@ public class MenuButton { image = anim.getCurrentFrame(); } + currentScale = 1f; + // normal images if (imgL == null) { + float scaleposmodx = 0; + float scaleposmody = 0; + if (scaleoverride != 1f) { + image = image.getScaledCopy(scaleoverride); + scaleposmodx = image.getWidth() / 2 - xRadius; + scaleposmody = image.getHeight() / 2 - yRadius; + currentScale = scaleoverride; + } if (hoverEffect == 0) - image.draw(x - xRadius, y - yRadius, filter); + image.draw(x - xRadius - scaleposmodx, y - yRadius - scaleposmody, filter); else { float oldAlpha = image.getAlpha(); float oldAngle = image.getRotation(); @@ -217,13 +240,16 @@ public class MenuButton { if (scale.getValue() != 1f) { image = image.getScaledCopy(scale.getValue()); image.setAlpha(oldAlpha); + scaleposmodx = image.getWidth() / 2 - xRadius; + scaleposmody = image.getHeight() / 2 - yRadius; + currentScale *= scale.getValue(); } } if ((hoverEffect & EFFECT_FADE) > 0) image.setAlpha(alpha.getValue()); if ((hoverEffect & EFFECT_ROTATE) > 0) image.setRotation(angle.getValue()); - image.draw(x - xRadius, y - yRadius, filter); + image.draw(x - xRadius - scaleposmodx, y - yRadius - scaleposmody, filter); if (image == this.img) { image.setAlpha(oldAlpha); image.setRotation(oldAngle);