diff --git a/data/area/misthalin/lumbridge/lumbridge.npc-spawns.toml b/data/area/misthalin/lumbridge/lumbridge.npc-spawns.toml index 7079fe9b0a..b253704f63 100644 --- a/data/area/misthalin/lumbridge/lumbridge.npc-spawns.toml +++ b/data/area/misthalin/lumbridge/lumbridge.npc-spawns.toml @@ -145,7 +145,7 @@ spawns = [ { id = "shop_assistant_lumbridge", x = 3214, y = 3243 }, { id = "bob", x = 3228, y = 3203 }, { id = "banker_3", x = 3208, y = 3222, level = 2, direction = "SOUTH" }, - { id = "hans", x = 3223, y = 3225 }, + { id = "hans", x = 3219, y = 3222 }, { id = "giant_spider", x = 3249, y = 3249 }, { id = "giant_spider", x = 3241, y = 3241 }, { id = "giant_spider", x = 3250, y = 3239 }, diff --git a/data/area/misthalin/lumbridge/lumbridge.patrols.toml b/data/area/misthalin/lumbridge/lumbridge.patrols.toml new file mode 100644 index 0000000000..0079d9baae --- /dev/null +++ b/data/area/misthalin/lumbridge/lumbridge.patrols.toml @@ -0,0 +1,17 @@ +[hans] +points = [ + { x = 3219, y = 3222, delay = 10 }, + { x = 3221, y = 3222 }, + { x = 3221, y = 3212 }, + { x = 3220, y = 3212 }, + { x = 3218, y = 3210 }, + { x = 3218, y = 3208 }, + { x = 3217, y = 3208 }, + { x = 3214, y = 3205 }, + { x = 3202, y = 3205 }, + { x = 3202, y = 3232 }, + { x = 3203, y = 3233 }, + { x = 3207, y = 3233 }, + { x = 3210, y = 3230 }, + { x = 3219, y = 3230 }, +] diff --git a/game/src/main/kotlin/content/area/misthalin/lumbridge/castle/Hans.kt b/game/src/main/kotlin/content/area/misthalin/lumbridge/castle/Hans.kt index 638c58f8b0..550781b249 100644 --- a/game/src/main/kotlin/content/area/misthalin/lumbridge/castle/Hans.kt +++ b/game/src/main/kotlin/content/area/misthalin/lumbridge/castle/Hans.kt @@ -6,18 +6,46 @@ import content.entity.player.dialogue.Neutral import content.entity.player.dialogue.type.choice import content.entity.player.dialogue.type.npc import world.gregs.voidps.engine.Script +import world.gregs.voidps.engine.client.ui.dialogue +import world.gregs.voidps.engine.data.definition.PatrolDefinitions +import world.gregs.voidps.engine.entity.character.mode.Patrol import world.gregs.voidps.engine.entity.character.mode.Retreat +import world.gregs.voidps.engine.entity.character.npc.NPC +import world.gregs.voidps.engine.entity.character.player.Player +import world.gregs.voidps.engine.queue.queue -class Hans : Script { +class Hans( + private val patrols: PatrolDefinitions, +) : Script { init { + npcSpawn("hans") { + val patrol = patrols.get("hans") + if (patrol.waypoints.isNotEmpty()) { + set("hans_patrol_index", 0) + mode = Patrol(this, patrol.waypoints) + } + } + + npcMoved("hans") { + if (mode is Patrol) { + set("hans_patrol_index", get("patrol_index", 0)) + } + } + npcOperate("Talk-to", "hans") { (target) -> + var resumeFromNearest = false + var resumeDelay = 10 + scheduleResume(this, target, resumeDelay) { resumeFromNearest } npc("Hello. What are you doing here?") choice { option("I'm looking for whoever is in charge of this place.") { npc("Who, the Duke? He's in his study, on the first floor.") } option("I have come to kill everyone in this castle!") { + resumeFromNearest = true + resumeDelay = 15 + scheduleResume(this, target, resumeDelay) { resumeFromNearest } target.say("Help! Help!") target.mode = Retreat(target, this) } @@ -27,4 +55,34 @@ class Hans : Script { } } } + + private fun scheduleResume(player: Player, target: NPC, delay: Int, nearest: () -> Boolean) { + target.queue.clear("hans_resume_patrol") + target.queue("hans_resume_patrol", delay) { + if (player.dialogue != null) { + scheduleResume(player, target, 1, nearest) + return@queue + } + resumePatrol(target, nearest = nearest()) + } + } + + private fun resumePatrol(target: NPC, nearest: Boolean = false) { + val patrol = patrols.get("hans") + if (patrol.waypoints.isEmpty()) { + return + } + val size = patrol.waypoints.size + val baseIndex = if (nearest) { + patrol.waypoints.withIndex() + .minByOrNull { target.tile.distanceTo(it.value.first) } + ?.index ?: 0 + } else { + target["hans_patrol_index", 0].mod(size) + } + val resumeIndex = if (patrol.waypoints[baseIndex].first == target.tile) (baseIndex + 1).mod(size) else baseIndex + target.mode = Patrol(target, patrol.waypoints) + target.set("patrol_index", resumeIndex) + target.steps.clear() + } }