Telepathic interaction fix, ::to puro

This commit is contained in:
dam 2026-05-14 20:14:29 +03:00
parent cd2f57f1b9
commit a9d6ce021b
No known key found for this signature in database
GPG key ID: 4AF4E722399663FB
3 changed files with 83 additions and 4 deletions

View file

@ -235,6 +235,7 @@ class ServerConstants {
arrayOf(Location.create(2722, 4886, 0), "quest the golem 1"),
arrayOf(Location.create(2704, 5349, 0), "dorgeshuun", "dorg"),
arrayOf(Location.create(2711, 10132, 0), "brine rats"),
arrayOf(Location.create(2591, 4320, 0), "puro puro", "puro-puro", "puropuro", "puro", "impling maze"),
arrayOf(Location.create(2328, 3677, 0), "piscatoris"),
arrayOf(Location.create(2660, 3158, 0), "fishing trawler", "trawler"),
arrayOf(Location.create(2800, 3667, 0), "mountain camp"),

View file

@ -86,6 +86,8 @@ public abstract class MovementPulse extends Pulse {
private Location previousLoc;
private boolean explicitInteractionLocation;
/**
* Constructs a new {@code MovementPulse} {@code Object}.
*
@ -300,7 +302,7 @@ public abstract class MovementPulse extends Pulse {
}
private boolean hasExplicitInteractionLocation() {
return optionHandler != null || useHandler != null || overrideMethod != null;
return explicitInteractionLocation;
}
/**
@ -357,11 +359,14 @@ public abstract class MovementPulse extends Pulse {
}
Location loc = null;
boolean explicitLocation = false;
if (optionHandler != null) {
loc = optionHandler.getDestination(mover, destination);
explicitLocation = loc != null;
} else if (useHandler != null) {
loc = useHandler.getDestination((Player) mover, destination);
explicitLocation = loc != null;
} else if (isInsideEntity(mover.getLocation())) {
loc = findBorderLocation();
}
@ -370,13 +375,20 @@ public abstract class MovementPulse extends Pulse {
loc = destinationFlag.getDestination(mover, destination);
} else if (loc == null && overrideMethod != null) {
loc = overrideMethod.invoke(mover, destination);
if (loc == destination.getLocation() && destinationFlag != null) loc = destinationFlag.getDestination(mover, destination);
else if (loc == destination.getLocation()) loc = null;
explicitLocation = loc != null;
if (loc == destination.getLocation() && destinationFlag != null) {
loc = destinationFlag.getDestination(mover, destination);
explicitLocation = false;
} else if (loc == destination.getLocation()) {
loc = null;
explicitLocation = false;
}
}
if (destination instanceof NPC && mover.getProperties().getCombatPulse().getVictim() != destination)
if (!explicitLocation && destination instanceof NPC && mover.getProperties().getCombatPulse().getVictim() != destination)
loc = checkForEntityPathInterrupt(loc != null ? loc : destination.getLocation());
explicitInteractionLocation = explicitLocation;
if (interactLocation == null) interactLocation = loc;
if (destination instanceof Entity || interactLocation == null || (mover.getWalkingQueue().getQueue()

View file

@ -312,6 +312,72 @@ class PathfinderTests {
}
}
@Test
fun entityOptionHandlerShouldNotInteractFromNpcQueuedDestination() {
TestUtils.getMockPlayer("queuedNpcPredictionGuard").use { p ->
val origin = Location.create(3200, 3600, 0)
val npc = NPC.create(0, origin.transform(0, 1, 0))
npc.init()
p.location = origin.transform(1, 0, 0)
npc.walkingQueue.reset(false)
npc.walkingQueue.addPath(origin.transform(4, 1, 0).x, origin.transform(4, 1, 0).y)
val optionHandler = object : OptionHandler() {
override fun newInstance(_arg: Any?): Plugin<Any> {
return this
}
override fun handle(_player: Player?, _node: Node?, _option: String?): Boolean {
return true
}
}
var pulseLocation: Location? = null
var pulseTargetLocation: Location? = null
try {
GameWorld.Pulser.submit(object : MovementPulse(p, npc, optionHandler) {
override fun pulse(): Boolean {
pulseLocation = p.location
pulseTargetLocation = npc.location
return true
}
})
TestUtils.advanceTicks(1, false)
Assertions.assertNull(
pulseLocation,
"Option-handler entity interaction must not fire from a tile that only reaches the NPC's queued destination."
)
repeat(8) {
if (pulseLocation == null) {
TestUtils.advanceTicks(1, false)
}
}
val actualPulseLocation = pulseLocation
?: throw AssertionError("Expected the movement pulse to eventually reach the moving NPC.")
val actualTargetLocation = pulseTargetLocation
?: throw AssertionError("Expected target location to be captured when the pulse fired.")
Assertions.assertTrue(
Pathfinder.canInteract(
actualPulseLocation.x,
actualPulseLocation.y,
p.size(),
actualTargetLocation.x,
actualTargetLocation.y,
npc.size(),
npc.size(),
0,
actualPulseLocation.z,
null
), "Entity interaction must fire only from a currently valid interaction tile."
)
} finally {
npc.clear()
}
}
}
@Test
fun runEnabledEntityMovementPulseShouldCatchWalkingNpcMovingDirectlyAway() {
TestUtils.getMockPlayer("runNpcInteractionChaser").use { p ->