diff --git a/src/itdelatrisu/opsu/GameMod.java b/src/itdelatrisu/opsu/GameMod.java index 6536864b..a7bd3e97 100644 --- a/src/itdelatrisu/opsu/GameMod.java +++ b/src/itdelatrisu/opsu/GameMod.java @@ -51,7 +51,7 @@ public enum GameMod { "Flashlight", "Restricted view area."), RELAX (Category.SPECIAL, 0, GameImage.MOD_RELAX, "RL", 128, Input.KEY_Z, 0f, "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, + AUTOPILOT (Category.SPECIAL, 1, GameImage.MOD_AUTOPILOT, "AP", 8192, Input.KEY_X, 0f, "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, "SpunOut", "Spinners will be automatically completed."), diff --git a/src/itdelatrisu/opsu/objects/Spinner.java b/src/itdelatrisu/opsu/objects/Spinner.java index 04ddaa60..9f6d819d 100644 --- a/src/itdelatrisu/opsu/objects/Spinner.java +++ b/src/itdelatrisu/opsu/objects/Spinner.java @@ -50,6 +50,11 @@ public class Spinner implements HitObject { /** The amount of time, in milliseconds, to fade in the spinner. */ private static final int FADE_IN_TIME = 500; + /** Angle mod multipliers: "auto" (477rpm), "spun out" (287rpm) */ + private static final float + AUTO_MULTIPLIER = 1 / 20f, // angle = 477/60f * delta/1000f * TWO_PI; + SPUN_OUT_MULTIPLIER = 1 / 33.25f; // angle = 287/60f * delta/1000f * TWO_PI; + /** PI constants. */ private static final float TWO_PI = (float) (Math.PI * 2), @@ -176,8 +181,7 @@ public class Spinner implements HitObject { // TODO: verify ratios int result; float ratio = rotations / rotationsNeeded; - if (ratio >= 1.0f || - GameMod.AUTO.isActive() || GameMod.SPUN_OUT.isActive()) { + if (ratio >= 1.0f || GameMod.AUTO.isActive() || GameMod.AUTOPILOT.isActive() || GameMod.SPUN_OUT.isActive()) { result = GameData.HIT_300; SoundController.playSound(SoundEffect.SPINNEROSU); } else if (ratio >= 0.9f) @@ -213,14 +217,12 @@ public class Spinner implements HitObject { // http://osu.ppy.sh/wiki/FAQ#Spinners float angle; if (GameMod.AUTO.isActive()) { - // "auto" mod (fast: 477rpm) lastAngle = 0; - angle = delta / 20f; // angle = 477/60f * delta/1000f * TWO_PI; + angle = delta * AUTO_MULTIPLIER; isSpinning = true; - } else if (GameMod.SPUN_OUT.isActive()) { - // "spun out" mod (slow: 287rpm) + } else if (GameMod.SPUN_OUT.isActive() || GameMod.AUTOPILOT.isActive()) { lastAngle = 0; - angle = delta / 33.25f; // angle = 287/60f * delta/1000f * TWO_PI; + angle = delta * SPUN_OUT_MULTIPLIER; isSpinning = true; } else { angle = (float) Math.atan2(mouseY - (height / 2), mouseX - (width / 2)); @@ -276,7 +278,8 @@ public class Spinner implements HitObject { timeDiff = trackPosition - hitObject.getTime(); // calculate point - float angle = timeDiff / 20f - HALF_PI; + float multiplier = (GameMod.AUTO.isActive()) ? AUTO_MULTIPLIER : SPUN_OUT_MULTIPLIER; + float angle = (timeDiff * multiplier) - HALF_PI; final float r = height / 10f; return new float[] { (float) (x + r * Math.cos(angle)), diff --git a/src/itdelatrisu/opsu/states/Game.java b/src/itdelatrisu/opsu/states/Game.java index d5598952..6a6e11b1 100644 --- a/src/itdelatrisu/opsu/states/Game.java +++ b/src/itdelatrisu/opsu/states/Game.java @@ -201,6 +201,12 @@ public class Game extends BasicGameState { /** The current flashlight area radius. */ private int flashlightRadius; + /** The cursor coordinates using the "auto" or "relax" mods. */ + private int autoMouseX = 0, autoMouseY = 0; + + /** Whether or not the cursor should be pressed using the "auto" mod. */ + private boolean autoMousePressed; + // game-related variables private GameContainer container; private StateBasedGame game; @@ -263,10 +269,12 @@ public class Game extends BasicGameState { int firstObjectTime = osu.objects[0].getTime(); int timeDiff = firstObjectTime - trackPosition; - // "auto" mod: move cursor automatically - int autoMouseX = width / 2, autoMouseY = height / 2; - boolean autoMousePress = false; - if (GameMod.AUTO.isActive()) { + // "auto" and "autopilot" mods: move cursor automatically + // TODO: this should really be in update(), not render() + autoMouseX = width / 2; + autoMouseY = height / 2; + autoMousePressed = false; + if (GameMod.AUTO.isActive() || GameMod.AUTOPILOT.isActive()) { float[] autoXY = null; if (isLeadIn()) { // lead-in @@ -306,11 +314,11 @@ public class Game extends BasicGameState { int offset300 = hitResultOffset[GameData.HIT_300]; if ((osu.objects[objectIndex].isCircle() && objectTime - trackPosition < offset300) || (osu.objects[objectIndex - 1].isCircle() && trackPosition - osu.objects[objectIndex - 1].getTime() < offset300)) - autoMousePress = true; + autoMousePressed = true; } } else { autoXY = hitObjects[objectIndex].getPointAt(trackPosition); - autoMousePress = true; + autoMousePressed = true; } } else { // last object @@ -342,7 +350,7 @@ public class Game extends BasicGameState { if (pauseTime > -1 && pausedMouseX > -1 && pausedMouseY > -1) { mouseX = pausedMouseX; mouseY = pausedMouseY; - } else if (GameMod.AUTO.isActive()) { + } else if (GameMod.AUTO.isActive() || GameMod.AUTOPILOT.isActive()) { mouseX = autoMouseX; mouseY = autoMouseY; } else if (isReplay) { @@ -510,7 +518,9 @@ public class Game extends BasicGameState { } if (GameMod.AUTO.isActive()) - UI.draw(g, autoMouseX, autoMouseY, autoMousePress); + UI.draw(g, autoMouseX, autoMouseY, autoMousePressed); + else if (GameMod.AUTOPILOT.isActive()) + UI.draw(g, autoMouseX, autoMouseY, Utils.isGameKeyPressed()); else if (!isReplay) UI.draw(g); else @@ -522,7 +532,10 @@ public class Game extends BasicGameState { throws SlickException { UI.update(delta); int mouseX, mouseY; - if (!isReplay) { + if (GameMod.AUTO.isActive() || GameMod.AUTOPILOT.isActive()) { + mouseX = autoMouseX; + mouseY = autoMouseY; + } else if (!isReplay) { mouseX = input.getMouseX(); mouseY = input.getMouseY(); } else { @@ -940,16 +953,26 @@ public class Game extends BasicGameState { if (GameMod.AUTO.isActive() || GameMod.RELAX.isActive()) return; + // "autopilot" mod: ignore actual cursor coordinates + int cx, cy; + if (GameMod.AUTOPILOT.isActive()) { + cx = autoMouseX; + cy = autoMouseY; + } else { + cx = x; + cy = y; + } + if (!isReplay) - addReplayFrame(x, y, lastKeysPressed | keys); + addReplayFrame(cx, cy, lastKeysPressed | keys); // circles - if (hitObject.isCircle() && hitObjects[objectIndex].mousePressed(x, y)) + if (hitObject.isCircle() && hitObjects[objectIndex].mousePressed(cx, cy)) objectIndex++; // circle hit // sliders else if (hitObject.isSlider()) - hitObjects[objectIndex].mousePressed(x, y); + hitObjects[objectIndex].mousePressed(cx, cy); } @Override @@ -1209,6 +1232,9 @@ public class Game extends BasicGameState { deaths = 0; deathTime = -1; replayFrames = null; + autoMouseX = 0; + autoMouseY = 0; + autoMousePressed = false; System.gc(); } @@ -1415,6 +1441,10 @@ public class Game extends BasicGameState { * @return the [x,y] coordinates */ private float[] getPointAt(float startX, float startY, float endX, float endY, float t) { + // "autopilot" mod: move quicker between objects + if (GameMod.AUTOPILOT.isActive()) + t = Utils.clamp(t * 2f, 0f, 1f); + float[] xy = new float[2]; xy[0] = startX + (endX - startX) * t; xy[1] = startY + (endY - startY) * t;