mirror of
https://gitlab.com/2009scape/2009scape.git
synced 2026-08-28 05:45:10 -06:00
Talk-to option overrider fix
This commit is contained in:
parent
e85f3a6812
commit
ae0e3425bd
2 changed files with 256 additions and 2 deletions
|
|
@ -162,6 +162,29 @@ object InteractionListeners {
|
|||
return destinationOverrides["$type:$option"]
|
||||
}
|
||||
|
||||
private fun getOptionHandlerDestination(id: Int, option: String, node: Node): ((Entity, Node) -> Location?)? {
|
||||
val handlers = ArrayList<OptionHandler>(2)
|
||||
Option.defaultHandler(node, id, option)?.let { handlers.add(it) }
|
||||
node.interaction?.options
|
||||
?.firstOrNull { it != null && it.name.equals(option, ignoreCase = true) }
|
||||
?.handler
|
||||
?.takeIf { it !in handlers }
|
||||
?.let { handlers.add(it) }
|
||||
if (handlers.isEmpty()) {
|
||||
return null
|
||||
}
|
||||
return { entity, target ->
|
||||
handlers.firstNotNullOfOrNull { it.getDestination(entity, target) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun getDestinationOverride(type: Int, id: Int, option: String, node: Node): ((Entity, Node) -> Location?)? {
|
||||
return getOverride(type, id, option)
|
||||
?: getOverride(type, node.id)
|
||||
?: getOverride(type, option.toLowerCase())
|
||||
?: getOptionHandlerDestination(id, option, node)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun run(id: Int, player: Player, node: Node, isEquip: Boolean): Boolean{
|
||||
player.scripts.removeWeakScripts()
|
||||
|
|
@ -255,7 +278,7 @@ object InteractionListeners {
|
|||
return true
|
||||
}
|
||||
|
||||
val destOverride = getOverride(type.ordinal, id, option) ?: getOverride(type.ordinal,node.id) ?: getOverride(type.ordinal,option.toLowerCase())
|
||||
val destOverride = getDestinationOverride(type.ordinal, id, option, node)
|
||||
|
||||
if(type != IntType.ITEM && !isInstant(method)) {
|
||||
if(player.locks.isMovementLocked) return false
|
||||
|
|
|
|||
|
|
@ -1,12 +1,18 @@
|
|||
package core
|
||||
|
||||
import TestUtils
|
||||
import content.global.handlers.scenery.BankBoothListener
|
||||
import content.global.handlers.npc.NPCTalkListener
|
||||
import content.global.skill.gather.GatheringSkillOptionListeners
|
||||
import content.global.skill.gather.woodcutting.WoodcuttingListener
|
||||
import content.region.misthalin.varrock.dialogue.GrandExchangeClerk
|
||||
import content.region.misthalin.varrock.handlers.GrandExchangePlugin
|
||||
import core.api.log
|
||||
import core.cache.def.impl.NPCDefinition
|
||||
import core.game.dialogue.DialogueInterpreter
|
||||
import core.game.interaction.*
|
||||
import core.game.node.scenery.Scenery
|
||||
import core.game.world.map.Direction
|
||||
import core.game.world.map.Location
|
||||
import core.game.world.map.RegionManager
|
||||
import org.junit.jupiter.api.Assertions
|
||||
|
|
@ -24,9 +30,18 @@ import core.plugin.ClassScanner
|
|||
import core.plugin.Plugin
|
||||
import core.tools.Log
|
||||
import org.rs09.consts.NPCs
|
||||
import org.rs09.consts.Scenery as SceneryIds
|
||||
|
||||
class PathfinderTests {
|
||||
companion object {init {TestUtils.preTestSetup(); GatheringSkillOptionListeners().defineListeners(); WoodcuttingListener().defineListeners() }; val NPC_TEST_LOC = ServerConstants.HOME_LOCATION!!.transform(2, 10, 0)}
|
||||
companion object {
|
||||
init {
|
||||
TestUtils.preTestSetup()
|
||||
GatheringSkillOptionListeners().defineListeners()
|
||||
WoodcuttingListener().defineListeners()
|
||||
BankBoothListener().defineListeners()
|
||||
}
|
||||
val NPC_TEST_LOC = ServerConstants.HOME_LOCATION!!.transform(2, 10, 0)
|
||||
}
|
||||
|
||||
@Test fun getOccupiedTilesShouldReturnCorrectSetOfTilesThatAnObjectOccupiesAtAllRotations() {
|
||||
//clay fireplace - 13609 - sizex: 1, sizey: 2
|
||||
|
|
@ -65,6 +80,222 @@ class PathfinderTests {
|
|||
)
|
||||
}
|
||||
|
||||
@Test fun dumbPathfinderShouldUseRsmodRouting() {
|
||||
val start = Location.create(3200, 3200, 0)
|
||||
val dest = Location.create(3202, 3200, 0)
|
||||
val blockedMiddle = ClipMaskSupplier { _, x, y ->
|
||||
if (x == 3201 && y == 3200) 0x100 else 0
|
||||
}
|
||||
|
||||
val path = Pathfinder.DUMB.find(start, 1, dest, 0, 0, 0, -1, 0, false, blockedMiddle)
|
||||
|
||||
Assertions.assertTrue(path.isSuccessful)
|
||||
Assertions.assertTrue(path.points.isNotEmpty())
|
||||
}
|
||||
|
||||
@Test fun projectilePathfinderShouldUseRsmodLineOfSightFlags() {
|
||||
val start = Location.create(3200, 3200, 0)
|
||||
val dest = Location.create(3202, 3200, 0)
|
||||
RegionManager.loadClippingWindow(start, 128)
|
||||
try {
|
||||
RegionManager.setRsmodFlag(0, 3201, 3200, true, 0x20000)
|
||||
|
||||
val blocked = Pathfinder.PROJECTILE.find(start, 1, dest, 0, 0, 0, -1, 0, false, null)
|
||||
|
||||
Assertions.assertFalse(blocked.isSuccessful)
|
||||
} finally {
|
||||
RegionManager.setRsmodFlag(0, 3201, 3200, true, 0)
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun metadataSceneryInteractionShouldTriggerWhenAlreadyAtRsmodApproachTile() {
|
||||
TestUtils.getMockPlayer("bankBoothApproach").use { p ->
|
||||
val (booth, approach) = findReachableBankBoothFixture()
|
||||
p.location = approach
|
||||
val alreadyAtPath = Pathfinder.find(p, booth)
|
||||
Assertions.assertTrue(alreadyAtPath.isSuccessful)
|
||||
Assertions.assertFalse(alreadyAtPath.isMoveNear)
|
||||
|
||||
Assertions.assertTrue(InteractionListeners.run(booth.id, IntType.SCENERY, "bank", p, booth))
|
||||
TestUtils.advanceTicks(10, false)
|
||||
|
||||
Assertions.assertTrue(p.bank.isOpen)
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun metadataSceneryCollectShouldTriggerWhenAlreadyAtRsmodApproachTile() {
|
||||
TestUtils.getMockPlayer("bankBoothCollectApproach").use { p ->
|
||||
val (booth, approach) = findReachableBankBoothFixture()
|
||||
p.location = approach
|
||||
var collected = false
|
||||
InteractionListeners.addMetadata(
|
||||
booth.id,
|
||||
IntType.SCENERY,
|
||||
arrayOf("collect"),
|
||||
InteractionListener.InteractionMetadata({ _, _, _ ->
|
||||
collected = true
|
||||
true
|
||||
}, 1, false)
|
||||
)
|
||||
|
||||
try {
|
||||
Assertions.assertTrue(InteractionListeners.run(booth.id, IntType.SCENERY, "collect", p, booth))
|
||||
TestUtils.advanceTicks(10, false)
|
||||
|
||||
Assertions.assertTrue(collected)
|
||||
} finally {
|
||||
BankBoothListener().defineListeners()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun directObjectMovementPulseShouldTriggerWhenAlreadyAtRsmodApproachTile() {
|
||||
TestUtils.getMockPlayer("objectPulseApproach").use { p ->
|
||||
val tree = RegionManager.getObject(0, 2720, 3475, 1307)
|
||||
?: throw AssertionError("Expected test tree object.")
|
||||
val approach = findReachableApproachTile(tree)
|
||||
var pulsed = false
|
||||
p.location = approach
|
||||
|
||||
GameWorld.Pulser.submit(object : MovementPulse(p, tree) {
|
||||
override fun pulse(): Boolean {
|
||||
pulsed = true
|
||||
return true
|
||||
}
|
||||
})
|
||||
TestUtils.advanceTicks(3, false)
|
||||
|
||||
Assertions.assertTrue(pulsed)
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun entityMovementPulseShouldTriggerWhenDestinationOverrideIsAlreadyReached() {
|
||||
TestUtils.getMockPlayer("bankerOverrideApproach").use { p ->
|
||||
val npc = NPC.create(0, NPC_TEST_LOC)
|
||||
npc.isNeverWalks = true
|
||||
npc.init()
|
||||
p.location = ServerConstants.HOME_LOCATION
|
||||
var pulsed = false
|
||||
|
||||
GameWorld.Pulser.submit(object : MovementPulse(p, npc, DestinationFlag.ENTITY, { _, _ -> p.location }) {
|
||||
override fun pulse(): Boolean {
|
||||
pulsed = true
|
||||
return true
|
||||
}
|
||||
})
|
||||
TestUtils.advanceTicks(3, false)
|
||||
|
||||
Assertions.assertTrue(pulsed)
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun interactionListenerShouldUseOptionHandlerDestinationWhenNoListenerDestinationOverride() {
|
||||
val npc = NPC.create(0, NPC_TEST_LOC)
|
||||
npc.isNeverWalks = true
|
||||
npc.init()
|
||||
|
||||
var listenerRan = false
|
||||
var optionHandlerRan = false
|
||||
val optionName = "listener-custom-destination"
|
||||
val option = Option(optionName, 4)
|
||||
val destinationHandler = object : OptionHandler() {
|
||||
override fun newInstance(arg: Any?): Plugin<Any> {
|
||||
NPCDefinition.forId(0).handlers["option:$optionName"] = this
|
||||
return this
|
||||
}
|
||||
|
||||
override fun handle(player: Player?, node: Node?, option: String?): Boolean {
|
||||
optionHandlerRan = true
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getDestination(n: Node, node: Node): Location {
|
||||
return n.location
|
||||
}
|
||||
}
|
||||
destinationHandler.newInstance(null)
|
||||
option.handler = destinationHandler
|
||||
npc.interaction.set(option)
|
||||
InteractionListeners.add(0, IntType.NPC.ordinal, arrayOf(optionName)) { _, _ ->
|
||||
listenerRan = true
|
||||
true
|
||||
}
|
||||
|
||||
TestUtils.getMockPlayer("listenerOptionDestination").use { p ->
|
||||
p.location = ServerConstants.HOME_LOCATION
|
||||
TestUtils.simulateInteraction(p, npc, 4)
|
||||
TestUtils.advanceTicks(3, false)
|
||||
|
||||
Assertions.assertTrue(listenerRan)
|
||||
Assertions.assertFalse(optionHandlerRan)
|
||||
Assertions.assertEquals(ServerConstants.HOME_LOCATION, p.location)
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun genericTalkToShouldOpenGrandExchangeClerkDialogueFromCounterApproachTile() {
|
||||
GrandExchangePlugin().newInstance(null)
|
||||
if (!DialogueInterpreter.contains(6528)) {
|
||||
GrandExchangeClerk().init()
|
||||
}
|
||||
if (InteractionListeners.get("talk-to", IntType.NPC.ordinal) == null) {
|
||||
NPCTalkListener().defineListeners()
|
||||
}
|
||||
|
||||
val clerk = NPC.create(6528, Location.create(3165, 3491, 0), Direction.NORTH)
|
||||
clerk.isNeverWalks = true
|
||||
clerk.init()
|
||||
|
||||
try {
|
||||
TestUtils.getMockPlayer("geClerkTalk").use { p ->
|
||||
p.location = Location.create(3165, 3492, 0)
|
||||
|
||||
TestUtils.simulateInteraction(p, clerk, 0)
|
||||
TestUtils.advanceTicks(3, false)
|
||||
|
||||
Assertions.assertNotNull(p.dialogueInterpreter.dialogue)
|
||||
Assertions.assertEquals(GrandExchangeClerk::class.java, p.dialogueInterpreter.dialogue.javaClass)
|
||||
Assertions.assertEquals(Location.create(3165, 3492, 0), p.location)
|
||||
}
|
||||
} finally {
|
||||
clerk.clear()
|
||||
}
|
||||
}
|
||||
|
||||
private fun findReachableBankBoothFixture(): Pair<Scenery, Location> {
|
||||
val base = ServerConstants.HOME_LOCATION!!.transform(8, 8, 0)
|
||||
for (rotation in 0..3) {
|
||||
val booth = Scenery(SceneryIds.BANK_BOOTH_2213, base, 10, rotation)
|
||||
runCatching { findReachableApproachTile(booth) }
|
||||
.getOrNull()
|
||||
?.let { return booth to it }
|
||||
}
|
||||
throw AssertionError("Could not find a reachable synthetic bank booth fixture.")
|
||||
}
|
||||
|
||||
private fun findReachableApproachTile(scenery: Scenery): Location {
|
||||
for (radius in 1..8) {
|
||||
for (x in scenery.location.x - radius..scenery.location.x + radius) {
|
||||
for (y in scenery.location.y - radius..scenery.location.y + radius) {
|
||||
val start = Location.create(x, y, scenery.location.z)
|
||||
if (!RegionManager.isTeleportPermitted(start)) {
|
||||
continue
|
||||
}
|
||||
val path = Pathfinder.find(start, scenery)
|
||||
if (!path.isSuccessful || path.isMoveNear) {
|
||||
continue
|
||||
}
|
||||
val point = path.points.lastOrNull()
|
||||
val approach = Location.create(point?.x ?: start.x, point?.y ?: start.y, start.z)
|
||||
val check = Pathfinder.find(approach, scenery)
|
||||
if (check.isSuccessful && !check.isMoveNear) {
|
||||
return approach
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
throw AssertionError("Could not find a reachable approach tile for $scenery.")
|
||||
}
|
||||
|
||||
@Test fun movementPulseShouldStopEarlyIfNextToATileOccupiedByTargetObject() {
|
||||
val start = Location.create(2731, 3481)
|
||||
val dest = RegionManager.getObject(0, 2720, 3475, 1307)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue