diff --git a/src/itdelatrisu/opsu/Container.java b/src/itdelatrisu/opsu/Container.java index 56be0ad6..63880381 100644 --- a/src/itdelatrisu/opsu/Container.java +++ b/src/itdelatrisu/opsu/Container.java @@ -43,6 +43,8 @@ public class Container extends AppGameContainer { /** Exception causing game failure. */ protected Exception e = null; + public static Container instance; + /** * Create a new container wrapping a game * @@ -51,6 +53,7 @@ public class Container extends AppGameContainer { */ public Container(Game game) throws SlickException { super(game); + instance = this; } /** diff --git a/src/itdelatrisu/opsu/GameData.java b/src/itdelatrisu/opsu/GameData.java index bac8ca8e..af71979d 100644 --- a/src/itdelatrisu/opsu/GameData.java +++ b/src/itdelatrisu/opsu/GameData.java @@ -152,7 +152,8 @@ public class GameData { HIT_SLIDER30 = 8, HIT_MAX = 9, // not a hit result HIT_SLIDER_REPEAT = 10, // not a hit result - HIT_ANIMATION_RESULT = 11; // not a hit result + HIT_SLIDER_REPEAT_M = 11, // not a hit result + HIT_ANIMATION_RESULT = 12; // not a hit result /** Hit result-related images (indexed by HIT_* constants to HIT_MAX). */ private Image[] hitResults; @@ -953,16 +954,21 @@ public class GameData { */ private void drawHitAnimations(HitObjectResult hitResult, int trackPosition) { // fade out slider curve - if (hitResult.result != HIT_SLIDER_REPEAT && hitResult.curve != null) { - float progress = AnimationEquation.OUT_CUBIC.calc( - (float) Utils.clamp(trackPosition - hitResult.time, 0, HITCIRCLE_FADE_TIME) / HITCIRCLE_FADE_TIME); - float alpha = 1f - progress; - float oldWhiteAlpha = Colors.WHITE_FADE.a; - float oldColorAlpha = hitResult.color.a; - Colors.WHITE_FADE.a = hitResult.color.a = alpha; - hitResult.curve.draw(hitResult.color); - Colors.WHITE_FADE.a = oldWhiteAlpha; - hitResult.color.a = oldColorAlpha; + if (hitResult.result != HIT_SLIDER_REPEAT && hitResult.result != HIT_SLIDER_REPEAT_M && hitResult.curve != null) { + if (!Options.isShrinkingSliders()) { + float progress = AnimationEquation.OUT_CUBIC.calc( + (float) Utils.clamp(trackPosition - hitResult.time, 0, HITCIRCLE_FADE_TIME) / HITCIRCLE_FADE_TIME); + float alpha = 1f - progress; + float oldWhiteAlpha = Colors.WHITE_FADE.a; + float oldColorAlpha = hitResult.color.a; + Colors.WHITE_FADE.a = hitResult.color.a = alpha; + hitResult.curve.draw(hitResult.color); + Colors.WHITE_FADE.a = oldWhiteAlpha; + hitResult.color.a = oldColorAlpha; + } + if (!Options.isDrawSliderEndCircles()) { + return; + } } // miss, don't draw an animation @@ -982,7 +988,7 @@ public class GameData { (float) Utils.clamp(trackPosition - hitResult.time, 0, HITCIRCLE_FADE_TIME) / HITCIRCLE_FADE_TIME); float scale = (!hitResult.expand) ? 1f : 1f + (HITCIRCLE_ANIM_SCALE - 1f) * progress; float alpha = 1f - progress; - if (hitResult.result == HIT_SLIDER_REPEAT) { + if (hitResult.result == HIT_SLIDER_REPEAT || hitResult.result == HIT_SLIDER_REPEAT_M) { // repeats Image scaledRepeat = GameImage.REVERSEARROW.getImage().getScaledCopy(scale); scaledRepeat.setAlpha(alpha); @@ -992,8 +998,14 @@ public class GameData { } else { ang = hitResult.curve.getEndAngle(); } + if (hitResult.result == HIT_SLIDER_REPEAT_M) { + ang += 180f; + } scaledRepeat.rotate(ang); scaledRepeat.drawCentered(hitResult.x, hitResult.y, hitResult.color); + if (!Options.isDrawSliderEndCircles()) { + return; + } } Image scaledHitCircle = GameImage.HITCIRCLE.getImage().getScaledCopy(scale); Image scaledHitCircleOverlay = GameImage.HITCIRCLE_OVERLAY.getImage().getScaledCopy(scale); @@ -1246,7 +1258,7 @@ public class GameData { return; } float[] m = Utils.mirrorPoint(x, y); - hitResultList.add(new HitObjectResult(time, HIT_SLIDER_REPEAT, m[0], m[1], color, type, curve, true, true)); + hitResultList.add(new HitObjectResult(time, HIT_SLIDER_REPEAT_M, m[0], m[1], color, type, curve, true, true)); } /** @@ -1259,6 +1271,11 @@ public class GameData { */ public void sendSliderStartResult(int time, float x, float y, Color color, boolean expand) { hitResultList.add(new HitObjectResult(time, HIT_ANIMATION_RESULT, x, y, color, HitObjectType.CIRCLE, null, expand, true)); + if (!Options.isMirror()) { + return; + } + float[] m = Utils.mirrorPoint(x, y); + hitResultList.add(new HitObjectResult(time, HIT_ANIMATION_RESULT, m[0], m[1], color, HitObjectType.CIRCLE, null, expand, true)); } /** @@ -1451,10 +1468,10 @@ public class GameData { * @param curve the slider curve (or null if not applicable) * @param sliderHeldToEnd whether or not the slider was held to the end (if applicable) */ - public void hitResult(int time, int result, float x, float y, Color color, + public void sendHitResult(int time, int result, float x, float y, Color color, boolean end, HitObject hitObject, HitObjectType hitResultType, boolean expand, int repeat, Curve curve, boolean sliderHeldToEnd) { - hitResult(time, result, x, y, color, end, hitObject, hitResultType, expand, repeat, curve, sliderHeldToEnd, true); + sendHitResult(time, result, x, y, color, end, hitObject, hitResultType, expand, repeat, curve, sliderHeldToEnd, true); } /** @@ -1473,7 +1490,7 @@ public class GameData { * @param sliderHeldToEnd whether or not the slider was held to the end (if applicable) * @param handleResult whether or not to send a score result */ - public void hitResult(int time, int result, float x, float y, Color color, + public void sendHitResult(int time, int result, float x, float y, Color color, boolean end, HitObject hitObject, HitObjectType hitResultType, boolean expand, int repeat, Curve curve, boolean sliderHeldToEnd, boolean handleResult) { int hitResult; diff --git a/src/itdelatrisu/opsu/Options.java b/src/itdelatrisu/opsu/Options.java index 880305d5..fbfc3897 100644 --- a/src/itdelatrisu/opsu/Options.java +++ b/src/itdelatrisu/opsu/Options.java @@ -541,6 +541,7 @@ public class Options { return !FALLBACK_SLIDERS.bool; } }, + DRAW_SLIDER_ENDCIRCLES ("Draw slider endcircles", "DrawSliderEndCircles", "Old slider style", false), SHOW_HIT_LIGHTING ("Show Hit Lighting", "HitLighting", "Adds an effect behind hit explosions.", true), SHOW_HIT_ANIMATIONS ("Show Hit Animations", "HitAnimations", "Fade out circles and curves.", true), SHOW_REVERSEARROW_ANIMATIONS ("Show reverse arrow animations", "ReverseArrowAnimations", "Fade out reverse arrows after passing.", true), @@ -1543,6 +1544,7 @@ public class Options { public static boolean isShrinkingSliders() { return GameOption.SHRINKING_SLIDERS.getBooleanValue(); } public static boolean isMergingSliders() { return !isFallbackSliders() && GameOption.MERGING_SLIDERS.getBooleanValue(); } + public static boolean isDrawSliderEndCircles() { return GameOption.DRAW_SLIDER_ENDCIRCLES.getBooleanValue(); } /** * Returns the fixed circle size override, if any. diff --git a/src/itdelatrisu/opsu/objects/Slider.java b/src/itdelatrisu/opsu/objects/Slider.java index 78870133..a6db7a5f 100644 --- a/src/itdelatrisu/opsu/objects/Slider.java +++ b/src/itdelatrisu/opsu/objects/Slider.java @@ -228,16 +228,12 @@ public class Slider extends GameObject { Math.max(0f, 1f - ((float) (trackPosition - hitObject.getTime()) / (getEndTime() - hitObject.getTime())) * 1.05f); } - curveColor.a = curveAlpha; + curveColor.a = sliderAlpha; boolean isCurveCompletelyDrawn = drawSliderTrack(trackPosition, Utils.clamp(1d - fadeinScale, 0d, 1d)); color.a = alpha; - g.pushTransform(); - if (mirror) { - g.rotate(x, y, -180f); - } // end circle (only draw if ball still has to go there) - if (curveInterval == 1f && currentRepeats < repeatCount - (repeatCount % 2 == 0 ? 1 : 0)) { + if (Options.isDrawSliderEndCircles() && isCurveCompletelyDrawn && currentRepeats < repeatCount - (repeatCount % 2 == 0 ? 1 : 0)) { Color circleColor = new Color(color); Color overlayColor = new Color(Colors.WHITE_FADE); if (currentRepeats == 0) { @@ -249,11 +245,16 @@ public class Slider extends GameObject { // fade in end circle after repeats circleColor.a = overlayColor.a = sliderAlpha * getCircleAlphaAfterRepeat(trackPosition, true); } - Vec2f endCircPos = curve.pointAt(curveInterval); + Vec2f endCircPos = curve.pointAt(1f); hitCircle.drawCentered(endCircPos.x, endCircPos.y, circleColor); hitCircleOverlay.drawCentered(endCircPos.x, endCircPos.y, overlayColor); } + g.pushTransform(); + if (mirror) { + g.rotate(x, y, -180f); + } + // set first circle colors to fade in after repeats Color firstCircleColor = new Color(color); Color startCircleOverlayColor = new Color(Colors.WHITE_FADE); @@ -263,7 +264,7 @@ public class Slider extends GameObject { } // start circle, only draw if ball still has to go there - if (!sliderClickedInitial || currentRepeats < repeatCount - (repeatCount % 2 == 1 ? 1 : 0)) { + if (!sliderClickedInitial || (Options.isDrawSliderEndCircles() && currentRepeats < repeatCount - (repeatCount % 2 == 1 ? 1 : 0))) { hitCircle.drawCentered(x, y, firstCircleColor); if (!overlayAboveNumber || sliderClickedInitial) hitCircleOverlay.drawCentered(x, y, startCircleOverlayColor); @@ -572,7 +573,7 @@ public class Slider extends GameObject { currentRepeats + 1, curve, sliderHeldToEnd); if (Options.isMirror() && GameMod.AUTO.isActive()) { float[] m = Utils.mirrorPoint(cx, cy); - data.hitResult(hitObject.getTime() + (int) sliderTimeTotal, result, + data.sendHitResult(hitObject.getTime() + (int) sliderTimeTotal, result, m[0], m[1], mirrorColor, comboEnd, hitObject, type, sliderHeldToEnd, currentRepeats + 1, curve, sliderHeldToEnd, false); } @@ -602,7 +603,6 @@ public class Slider extends GameObject { //else not a hit if (result > -1) { - data.sendInitialSliderResult(trackPosition, this.x, this.y, color, mirrorColor); data.addHitError(hitObject.getTime(), x,y,trackPosition - hitObject.getTime()); sliderClickedInitial = true; data.sendSliderTickResult(hitObject.getTime(), result, this.x, this.y, hitObject, currentRepeats); diff --git a/src/itdelatrisu/opsu/states/Game.java b/src/itdelatrisu/opsu/states/Game.java index 65ed00f0..0f54df9c 100644 --- a/src/itdelatrisu/opsu/states/Game.java +++ b/src/itdelatrisu/opsu/states/Game.java @@ -462,8 +462,12 @@ public class Game extends BasicGameState { autoMousePressed = true; } } else { - // last object - autoPoint = gameObjects[objectIndex - 1].getPointAt(trackPosition); + if (objectIndex < beatmap.objects.length) { + autoPoint = gameObjects[objectIndex].getPointAt(trackPosition); + } else { + // last object + autoPoint = gameObjects[objectIndex - 1].getPointAt(trackPosition); + } } // set mouse coordinates diff --git a/src/itdelatrisu/opsu/states/MainMenu.java b/src/itdelatrisu/opsu/states/MainMenu.java index 29153854..93fd15e7 100644 --- a/src/itdelatrisu/opsu/states/MainMenu.java +++ b/src/itdelatrisu/opsu/states/MainMenu.java @@ -32,12 +32,8 @@ 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; -import itdelatrisu.opsu.ui.Fonts; -import itdelatrisu.opsu.ui.MenuButton; +import itdelatrisu.opsu.ui.*; import itdelatrisu.opsu.ui.MenuButton.Expand; -import itdelatrisu.opsu.ui.StarFountain; -import itdelatrisu.opsu.ui.UI; import itdelatrisu.opsu.ui.animations.AnimatedValue; import itdelatrisu.opsu.ui.animations.AnimationEquation; @@ -203,14 +199,15 @@ public class MainMenu extends BasicGameState { // initialize repository button float startX = width * 0.997f, startY = height * 0.997f; if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) { // only if a webpage can be opened - Image repoImg = GameImage.REPOSITORY.getImage(); + Image repoImg; + repoImg = GameImage.REPOSITORY.getImage(); repoButton = new MenuButton(repoImg, startX - repoImg.getWidth() * 2.5f, startY - repoImg.getHeight() ); repoButton.setHoverAnimationDuration(350); repoButton.setHoverAnimationEquation(AnimationEquation.IN_OUT_BACK); repoButton.setHoverExpand(); - Image repoImg = GameImage.REPOSITORY.getImage(); + repoImg = GameImage.REPOSITORY.getImage(); danceRepoButton = new MenuButton(repoImg, startX - repoImg.getWidth(), startY - repoImg.getHeight() ); @@ -282,11 +279,19 @@ public class MainMenu extends BasicGameState { } // draw logo (pulsing) + Color color = Options.isColorMainMenuLogo() ? Cursor.lastCursorColor : Color.white; Float position = MusicController.getBeatProgress(); - if (position == null) // default to 60bpm + boolean renderPiece = position != null; + if (position == null) { position = System.currentTimeMillis() % 1000 / 1000f; + } float scale = 1f + position * 0.05f; - logo.draw(Color.white, scale); + logo.draw(color, scale); + if (renderPiece) { + Image piece = GameImage.MENU_LOGO_PIECE.getImage().getScaledCopy(logo.getLastScale()); + piece.rotate(position * 360); + piece.drawCentered(logo.getX(), logo.getY(), color); + } float ghostScale = logo.getLastScale() / scale * 1.05f; Image ghostLogo = GameImage.MENU_LOGO.getImage().getScaledCopy(ghostScale); ghostLogo.drawCentered(logo.getX(), logo.getY(), Colors.GHOST_LOGO); @@ -311,15 +316,17 @@ public class MainMenu extends BasicGameState { // draw repository buttons if (repoButton != null) { + String text; + int fheight, fwidth; repoButton.draw(); - String text = "opsu!"; - int fheight = Fonts.SMALL.getLineHeight(); - int fwidth = Fonts.SMALL.getWidth(text); + text = "opsu!"; + fheight = Fonts.SMALL.getLineHeight(); + fwidth = Fonts.SMALL.getWidth(text); Fonts.SMALL.drawString(repoButton.getX() - fwidth / 2, repoButton.getY() - repoButton.getImage().getHeight() / 2 - fheight, text, Color.white); danceRepoButton.draw(); - String text = "opsu!dance"; - int fheight = Fonts.SMALL.getLineHeight(); - int fwidth = Fonts.SMALL.getWidth(text); + text = "opsu!dance"; + fheight = Fonts.SMALL.getLineHeight(); + fwidth = Fonts.SMALL.getWidth(text); Fonts.SMALL.drawString(danceRepoButton.getX() - fwidth / 2, repoButton.getY() - repoButton.getImage().getHeight() / 2 - fheight, text, Color.white); } diff --git a/src/itdelatrisu/opsu/states/OptionsMenu.java b/src/itdelatrisu/opsu/states/OptionsMenu.java index cc172bde..a6120d41 100644 --- a/src/itdelatrisu/opsu/states/OptionsMenu.java +++ b/src/itdelatrisu/opsu/states/OptionsMenu.java @@ -79,6 +79,7 @@ public class OptionsMenu extends BasicGameState implements OptionsOverlay.Parent GameOption.SHRINKING_SLIDERS, GameOption.FALLBACK_SLIDERS, GameOption.MERGING_SLIDERS, + GameOption.DRAW_SLIDER_ENDCIRCLES, GameOption.SHOW_HIT_LIGHTING, GameOption.SHOW_HIT_ANIMATIONS, GameOption.SHOW_COMBO_BURSTS,