diff --git a/Server/src/main/java/core/game/node/entity/npc/bosses/wilderness/ChaosElementalNPC.java b/Server/src/main/java/core/game/node/entity/npc/bosses/wilderness/ChaosElementalNPC.java index 80c8963ac..ca9936f48 100644 --- a/Server/src/main/java/core/game/node/entity/npc/bosses/wilderness/ChaosElementalNPC.java +++ b/Server/src/main/java/core/game/node/entity/npc/bosses/wilderness/ChaosElementalNPC.java @@ -1,5 +1,6 @@ package core.game.node.entity.npc.bosses.wilderness; +import api.ContentAPIKt; import core.game.content.global.BossKillCounter; import core.game.node.entity.Entity; import core.game.node.entity.combat.BattleState; @@ -19,6 +20,8 @@ import core.tools.RandomFunction; import rs09.game.node.entity.combat.CombatSwingHandler; import rs09.game.node.entity.combat.handlers.MultiSwingHandler; +import static api.ContentAPIKt.getPathableRandomLocalCoordinate; + /** * Handles the chaos elemental npc. * @author Vexia @@ -141,13 +144,7 @@ public class ChaosElementalNPC extends AbstractNPC { } else if (attack.getProjectile().getProjectileId() == 554) { player.getAudioManager().send(new Audio(346), true); // C. Elemental Confusion Impact SFX - Location loc = getRandomLoc(entity); - while (!RegionManager.isTeleportPermitted(loc) || RegionManager.getObject(loc) != null) { - loc = getRandomLoc(entity); - } - if (loc.equals(player.getLocation())) { - loc = entity.getLocation(); - } + Location loc = getPathableRandomLocalCoordinate(player, 10, entity.getLocation(), 3); player.teleport(loc); } else if (attack.getProjectile().getProjectileId() == 551) { player.getAudioManager().send(new Audio(353), true); // C. Elemental Madness Impact SFX diff --git a/Server/src/main/java/core/game/node/entity/skill/slayer/AbyssalDemonNPC.java b/Server/src/main/java/core/game/node/entity/skill/slayer/AbyssalDemonNPC.java index 1b41b6f3c..fab911fb3 100644 --- a/Server/src/main/java/core/game/node/entity/skill/slayer/AbyssalDemonNPC.java +++ b/Server/src/main/java/core/game/node/entity/skill/slayer/AbyssalDemonNPC.java @@ -13,6 +13,8 @@ import core.game.world.update.flag.context.Graphics; import core.plugin.Initializable; import core.tools.RandomFunction; +import static api.ContentAPIKt.getPathableRandomLocalCoordinate; + /** * Handles the abyssal npc. * @author Vexia @@ -31,11 +33,9 @@ public class AbyssalDemonNPC extends AbstractNPC { boolean npc = RandomFunction.random(100) <= 50; Entity source = npc ? victim : entity; Entity teleported = npc ? entity : victim; - Location loc = source.getLocation().transform(Direction.values()[RandomFunction.random(Direction.values().length)], 1); - if (loc != null && !loc.equals(source.getLocation()) && RegionManager.isTeleportPermitted(loc) && RegionManager.getObject(loc) == null) { - teleported.graphics(Graphics.create(409)); - teleported.teleport(loc, 1); - } + Location loc = getPathableRandomLocalCoordinate(teleported, 1, source.getLocation(), 3); + teleported.graphics(Graphics.create(409)); + teleported.teleport(loc, 1); } return super.swing(entity, victim, state); } diff --git a/Server/src/main/java/core/game/world/map/zone/ZoneBorders.java b/Server/src/main/java/core/game/world/map/zone/ZoneBorders.java index ee3e55e94..f371fae2d 100644 --- a/Server/src/main/java/core/game/world/map/zone/ZoneBorders.java +++ b/Server/src/main/java/core/game/world/map/zone/ZoneBorders.java @@ -38,7 +38,7 @@ public final class ZoneBorders { /** * The plane required to be on. */ - private int plane; + private int plane = 0; /** * The list of exceptions. @@ -231,7 +231,7 @@ public final class ZoneBorders { public Location getRandomLoc() { int x = northEastX - southWestX == 0 ? southWestX : new Random().nextInt(northEastX - southWestX + 1) + southWestX; int y = northEastY - southWestY == 0 ? southWestY : new Random().nextInt(northEastY - southWestY + 1) + southWestY; - return new Location(x, y); + return new Location(x, y, plane); } /** diff --git a/Server/src/main/kotlin/api/ContentAPI.kt b/Server/src/main/kotlin/api/ContentAPI.kt index 7de033bd6..72d959a10 100644 --- a/Server/src/main/kotlin/api/ContentAPI.kt +++ b/Server/src/main/kotlin/api/ContentAPI.kt @@ -19,7 +19,6 @@ import core.game.node.entity.player.Player import core.game.node.entity.player.link.TeleportManager import core.game.node.entity.player.link.audio.Audio import core.game.node.entity.player.link.emote.Emotes -import core.game.node.entity.player.link.quest.Quest import core.game.node.entity.player.link.quest.QuestRepository import core.game.node.entity.skill.Skills import core.game.node.entity.skill.gather.SkillingTool @@ -1463,4 +1462,21 @@ fun Player.getCutsceneStage(): Int { fun getServerConfig() : Toml { return ServerConfigParser.tomlData ?: Toml() +} + +fun getPathableRandomLocalCoordinate(target: Entity, radius: Int, center: Location, maxAttempts: Int = 3): Location { + val swCorner = center.transform(-radius,-radius, center.z) + val neCorner = center.transform(radius, radius, center.z) + val borders = ZoneBorders(swCorner.x, swCorner.y, neCorner.x, neCorner.y, center.z) + + var attempts = maxAttempts + var success: Boolean + while (attempts-- > 0) { + val dest = borders.randomLoc + val path = Pathfinder.find(target, dest) + success = path.isSuccessful && !path.isMoveNear + if (success) return dest + } + + return target.location } \ No newline at end of file