From 895c41756a5a5529efdc019755cd93c9ba15ad2c Mon Sep 17 00:00:00 2001 From: Ceikry Date: Mon, 4 Sep 2023 06:46:10 +0000 Subject: [PATCH] Rewrote stiles Added a new ContentAPI function, animationCycles, that returns the exact number of cycles an animation lasts for (useful for forced movement) Added a new function to Vector objects that allows convertion into Direction objects (useful for transforming locations) --- .../agility/shortcuts/StileShortcut.java | 108 ------------------ .../skill/agility/shortcuts/StileShortcut.kt | 78 +++++++++++++ Server/src/main/core/api/ContentAPI.kt | 8 +- Server/src/main/core/api/utils/Vector.kt | 16 +++ .../cache/def/impl/AnimationDefinition.java | 8 ++ Server/src/test/kotlin/APITests.kt | 22 ++++ .../content/skill/agility/ShortcutTests.kt | 46 ++++++++ 7 files changed, 177 insertions(+), 109 deletions(-) delete mode 100644 Server/src/main/content/global/skill/agility/shortcuts/StileShortcut.java create mode 100644 Server/src/main/content/global/skill/agility/shortcuts/StileShortcut.kt create mode 100644 Server/src/test/kotlin/content/skill/agility/ShortcutTests.kt diff --git a/Server/src/main/content/global/skill/agility/shortcuts/StileShortcut.java b/Server/src/main/content/global/skill/agility/shortcuts/StileShortcut.java deleted file mode 100644 index 78e5fcd8c..000000000 --- a/Server/src/main/content/global/skill/agility/shortcuts/StileShortcut.java +++ /dev/null @@ -1,108 +0,0 @@ -package content.global.skill.agility.shortcuts; - -import core.game.activity.ActivityManager; -import core.game.node.entity.impl.PulseType; -import core.plugin.Initializable; -import content.global.skill.agility.AgilityShortcut; -import core.game.interaction.MovementPulse; -import core.game.node.entity.impl.ForceMovement; -import core.game.node.entity.player.Player; -import core.game.node.scenery.Scenery; -import core.game.system.task.Pulse; -import core.game.world.GameWorld; -import core.game.world.map.Direction; -import core.game.world.map.Location; -import core.game.world.update.flag.context.Animation; - -/** - * Handles a stile shortcut. - * @author Vexia - */ -@Initializable -public class StileShortcut extends AgilityShortcut { - - /** - * Constructs a new {@Code StileShortcut} {@Code Object} - */ - public StileShortcut() { - super(new int[] { 993, 3730, 7527, 12982, 19222, 22302, 29460, 33842, 34776, 39508, 39509, 39510 }, 1, 0.0, false, 0.0, new String[] { "climb-over" }); - - } - - @Override - public void run(final Player player, final Scenery object, String option, boolean failed) { - player.getWalkingQueue().reset(); - Location loc = getLocation(player, object, true); - player.getWalkingQueue().addPath(loc.getX(), loc.getY()); - player.getPulseManager().run(new MovementPulse(player, loc) { - @Override - public boolean pulse() { - climb(player, object); - return true; - } - }, PulseType.STANDARD); - } - - /** - * Method used to climb the stile. - * @param player the player. - * @param object the object. - */ - public static void climb(final Player player, final Scenery object) { - player.lock(1); - int delay = 0; - GameWorld.getPulser().submit(new Pulse(delay, player) { - @Override - public boolean pulse() { - ForceMovement movement = new ForceMovement(player, getLocation(player, object, true), getLocation(player, object, false), Animation.create(839)) { - @Override - public void stop() { - super.stop(); - if (object.getId() == 19222) {// falconry. - handleFalconry(player, object); - } - } - }; - movement.run(player, 5); - return true; - } - }); - } - - /** - * Method used to get the end location. - * @param player the player. - * @param object the object. - * @param start if getting the start loc. - * @return the location. - */ - public static Location getLocation(final Player player, final Scenery object, boolean start) { - if ((object.getDirection() == Direction.NORTH || object.getDirection() == Direction.SOUTH)) { - if (player.getLocation().getY() <= object.getLocation().getY()) { - return start ? object.getLocation() : object.getLocation().transform(0, 1, 0); - } else { - return start ? object.getLocation().transform(0, 1, 0) : object.getLocation(); - } - } else { - if (player.getLocation().getX() <= object.getLocation().getX()) { - return start ? object.getLocation() : object.getLocation().transform(1, 0, 0); - } else { - return start ? object.getLocation().transform(1, 0, 0) : object.getLocation(); - } - } - } - - /** - * Method used to handle the falconry stile. - * @param player the player. - * @param object the object. - */ - private static void handleFalconry(final Player player, Scenery object) { - if (player.getLocation().equals(Location.create(2371, 3621, 0))) { - ActivityManager.start(player, "falconry", false); - } else { - ActivityManager.getActivity("falconry").leave(player, false); - } - } - -} diff --git a/Server/src/main/content/global/skill/agility/shortcuts/StileShortcut.kt b/Server/src/main/content/global/skill/agility/shortcuts/StileShortcut.kt new file mode 100644 index 000000000..3116cecd2 --- /dev/null +++ b/Server/src/main/content/global/skill/agility/shortcuts/StileShortcut.kt @@ -0,0 +1,78 @@ +package content.global.skill.agility.shortcuts + +import core.api.* +import core.api.utils.Vector +import core.game.activity.ActivityManager +import core.game.interaction.IntType +import core.game.interaction.InteractionListener +import core.game.interaction.QueueStrength +import core.game.node.entity.player.Player +import core.game.world.map.Direction +import core.game.world.map.Location + +class StileShortcut : InteractionListener { + val ids = intArrayOf(993, 3730, 7527, 12982, 19222, 22302, 29460, 33842, 34776, 39508, 39509, 39510) + val FALCONRY_STILE = 19222 + override fun defineListeners() { + on (ids, IntType.SCENERY, "climb-over") {p, n -> + val direction = Vector.betweenLocs(p.location, n.location).toDirection() + val startLoc = p.location.transform(direction, 1) + val endLoc = p.location.transform(direction, 2) + + p.walkingQueue.reset() + p.walkingQueue.addPath(startLoc.x, startLoc.y) + forceMove(p, startLoc, endLoc, 0, animationCycles(839), direction, 839) + + queueScript(p, 5, QueueStrength.SOFT) {_ -> + val end = endLoc.transform(direction, 1) + p.walkingQueue.reset() + p.walkingQueue.addPath(end.x, end.y) + + if (n.id == FALCONRY_STILE) + handleFalconry(p, endLoc) + return@queueScript stopExecuting(p) + } + return@on true + } + + setDest(IntType.SCENERY, ids, "climb-over") {e, n -> + return@setDest getInteractLocation(e.location, n.location, getOrientation(n.direction)) + } + } + + + + companion object { + fun getInteractLocation (pLoc: Location, sLoc: Location, orientation: Orientation) : Location { + when (orientation) { + Orientation.Horizontal -> { + if (pLoc.x <= sLoc.x) return sLoc.transform(-1, 0, 0) + else return sLoc.transform(2, 0, 0) + } + Orientation.Vertical -> { + if (pLoc.y <= sLoc.y) return sLoc.transform(0, -1, 0) + else return sLoc.transform(0, 2, 0) + } + } + } + + fun getOrientation (rotation: Direction) : Orientation { + when (rotation) { + Direction.EAST, Direction.WEST -> return Orientation.Horizontal + else -> return Orientation.Vertical + } + } + + fun handleFalconry (p: Player, endLoc: Location) { + if (endLoc.y == 3619) + ActivityManager.start(p, "falconry", false) + else + ActivityManager.getActivity("falconry").leave(p, false) + } + } + + enum class Orientation { + Horizontal, + Vertical + } +} \ No newline at end of file diff --git a/Server/src/main/core/api/ContentAPI.kt b/Server/src/main/core/api/ContentAPI.kt index 0d921a48e..c45eb392b 100644 --- a/Server/src/main/core/api/ContentAPI.kt +++ b/Server/src/main/core/api/ContentAPI.kt @@ -64,6 +64,7 @@ import core.game.world.repository.Repository import core.game.consumable.* import core.ServerConstants import core.api.utils.Vector +import core.cache.def.impl.AnimationDefinition import core.game.node.entity.player.link.quest.Quest import core.tools.* import core.game.world.update.flag.* @@ -431,7 +432,12 @@ fun resetAnimator(player: Player) { * @return the number of ticks the given animation lasts for */ fun animationDuration(animation: Animation): Int { - return animation.definition.durationTicks + return cyclesToTicks(animation.definition.cycles) +} + +fun animationCycles (animation: Int) : Int { + val def = AnimationDefinition.forId(animation) + return def.cycles } /** diff --git a/Server/src/main/core/api/utils/Vector.kt b/Server/src/main/core/api/utils/Vector.kt index 937861cbc..eb0688ff9 100644 --- a/Server/src/main/core/api/utils/Vector.kt +++ b/Server/src/main/core/api/utils/Vector.kt @@ -1,5 +1,6 @@ package core.api.utils +import core.game.world.map.Direction import core.game.world.map.Location import kotlin.math.* @@ -45,6 +46,21 @@ class Vector (val x: Double, val y: Double) { return Location.create(floor(x).toInt(), floor(y).toInt(), plane) } + fun toDirection() : Direction { + val norm = normalized() + + if (norm.x >= 0.85) return Direction.EAST + else if (norm.x <= -0.85) return Direction.WEST + + if (norm.y > 0) { + if (norm.y >= 0.85) return Direction.NORTH + return if (norm.x > 0) Direction.NORTH_EAST else Direction.NORTH_WEST + } else { + if (norm.y <= -0.85) return Direction.SOUTH + return if (norm.x > 0) Direction.SOUTH_EAST else Direction.SOUTH_WEST + } + } + companion object { @JvmStatic fun betweenLocs (from: Location, to: Location) : Vector { val xDiff = to.x - from.x diff --git a/Server/src/main/core/cache/def/impl/AnimationDefinition.java b/Server/src/main/core/cache/def/impl/AnimationDefinition.java index a8ed65614..1f56d91cd 100644 --- a/Server/src/main/core/cache/def/impl/AnimationDefinition.java +++ b/Server/src/main/core/cache/def/impl/AnimationDefinition.java @@ -88,6 +88,14 @@ public final class AnimationDefinition { return duration; } + public int getCycles() { + if (durations == null) return 0; + int duration = 0; + for (int i : durations) + duration += i; + return duration; + } + /** * Gets the duration of this animation in (600ms) ticks. * @return The duration in ticks. diff --git a/Server/src/test/kotlin/APITests.kt b/Server/src/test/kotlin/APITests.kt index 4bd3cb512..e76e85852 100644 --- a/Server/src/test/kotlin/APITests.kt +++ b/Server/src/test/kotlin/APITests.kt @@ -5,6 +5,8 @@ import content.global.skill.slayer.Master import content.global.skill.slayer.SlayerManager import content.global.skill.slayer.Tasks import core.game.node.item.Item +import core.api.utils.Vector +import core.game.world.map.Direction import org.json.simple.JSONObject import org.json.simple.parser.JSONParser import org.junit.jupiter.api.Assertions @@ -348,4 +350,24 @@ class APITests { } } } + + @Test fun vectorToDirectionShouldReturnExpectedDirections() { + val testData = arrayOf( + Pair(Vector(1.0, 0.0), Direction.EAST), + Pair(Vector(-1.0, 0.0), Direction.WEST), + Pair(Vector(0.0, 1.0), Direction.NORTH), + Pair(Vector(0.0, -1.0), Direction.SOUTH), + Pair(Vector(1.0, 1.0), Direction.NORTH_EAST), + Pair(Vector(1.0, -1.0), Direction.SOUTH_EAST), + Pair(Vector(-1.0, 1.0), Direction.NORTH_WEST), + Pair(Vector(-1.0, -1.0), Direction.SOUTH_WEST), + Pair(Vector(15.0, 0.0), Direction.EAST), + Pair(Vector(15.0, 1.0), Direction.EAST), + Pair(Vector(-15.0, -9.7), Direction.SOUTH_WEST) + ) + + for ((vec, expDir) in testData) { + Assertions.assertEquals(expDir, vec.toDirection(), "Vector: $vec") + } + } } \ No newline at end of file diff --git a/Server/src/test/kotlin/content/skill/agility/ShortcutTests.kt b/Server/src/test/kotlin/content/skill/agility/ShortcutTests.kt new file mode 100644 index 000000000..c8d95b78d --- /dev/null +++ b/Server/src/test/kotlin/content/skill/agility/ShortcutTests.kt @@ -0,0 +1,46 @@ +package content.skill.agility + +import content.global.skill.agility.shortcuts.StileShortcut +import core.game.world.map.Direction +import core.game.world.map.Location +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test + +class ShortcutTests { + @Test fun stileGetInteractionLocShouldReturnCorrectLoc() { + data class StileTestData (val playerLoc: Location, val expectedLoc: Location, val stileLoc: Location, val stileOrientation: StileShortcut.Orientation) + val testData = arrayOf( + //Horizontal + StileTestData(Location.create(3044, 3308, 0), Location.create(3045, 3305, 0), Location.create(3043, 3305, 0), StileShortcut.Orientation.Horizontal), + StileTestData(Location.create(3048, 3303, 0), Location.create(3045, 3305, 0), Location.create(3043, 3305, 0), StileShortcut.Orientation.Horizontal), + StileTestData(Location.create(3043, 3307, 0), Location.create(3042, 3305, 0), Location.create(3043, 3305, 0), StileShortcut.Orientation.Horizontal), + StileTestData(Location.create(3039, 3301, 0), Location.create(3042, 3305, 0), Location.create(3043, 3305, 0), StileShortcut.Orientation.Horizontal), + //Vertical + StileTestData(Location.create(3203, 3276, 0), Location.create(3197, 3275, 0), Location.create(3197, 3276, 0), StileShortcut.Orientation.Vertical), + StileTestData(Location.create(3195, 3274, 0), Location.create(3197, 3275, 0), Location.create(3197, 3276, 0), StileShortcut.Orientation.Vertical), + StileTestData(Location.create(3191, 3280, 0), Location.create(3197, 3278, 0), Location.create(3197, 3276, 0), StileShortcut.Orientation.Vertical), + StileTestData(Location.create(3206, 3281, 0), Location.create(3197, 3278, 0), Location.create(3197, 3276, 0), StileShortcut.Orientation.Vertical) + ) + + for ((pLoc, expLoc, sLoc, ori) in testData) { + Assertions.assertEquals(expLoc, StileShortcut.getInteractLocation(pLoc, sLoc, ori)) + } + } + + @Test fun stileGetOrientationShouldReturnCorrectOrientation() { + val testData = arrayOf( + Pair (Direction.NORTH, StileShortcut.Orientation.Vertical), + Pair (Direction.SOUTH, StileShortcut.Orientation.Vertical), + Pair (Direction.NORTH_WEST, StileShortcut.Orientation.Vertical), + Pair (Direction.NORTH_EAST, StileShortcut.Orientation.Vertical), + Pair (Direction.SOUTH_EAST, StileShortcut.Orientation.Vertical), + Pair (Direction.SOUTH_WEST, StileShortcut.Orientation.Vertical), + Pair (Direction.EAST, StileShortcut.Orientation.Horizontal), + Pair (Direction.WEST, StileShortcut.Orientation.Horizontal) + ) + + for ((dir, expOri) in testData) { + Assertions.assertEquals(expOri, StileShortcut.getOrientation(dir)) + } + } +} \ No newline at end of file