Death combat state clearing

This commit is contained in:
dam 2026-05-06 16:46:10 +03:00
parent ae0e3425bd
commit b9cef728a6
No known key found for this signature in database
GPG key ID: 4AF4E722399663FB
2 changed files with 73 additions and 1 deletions

View file

@ -280,7 +280,7 @@ public abstract class Entity extends Node {
impactHandler.getImpactQueue().clear();
impactHandler.setDisabledTicks(10);
timers.onEntityDeath();
removeAttribute("combat-time");
clearCombatDeathState(killer);
face(null);
//Check if it's a Loar shade and transform back into the shadow version.
if(this.getId() == 1240 || this.getId() == 1241){
@ -288,6 +288,37 @@ public abstract class Entity extends Node {
}
}
private void clearCombatDeathState(Entity killer) {
Object attacker = getAttribute("combat-attacker");
Object aggressor = getAttribute("aggressor");
properties.getCombatPulse().stop();
removeAttribute("combat-time");
removeAttribute("combat-attacker");
removeAttribute("aggressor");
clearCombatReference(killer);
if (attacker instanceof Entity) {
clearCombatReference((Entity) attacker);
}
if (aggressor instanceof Entity) {
clearCombatReference((Entity) aggressor);
}
}
private void clearCombatReference(Entity entity) {
if (entity == null) {
return;
}
if (entity.getAttribute("combat-attacker") == this) {
entity.removeAttribute("combat-attacker");
}
if (entity.getAttribute("aggressor") == this) {
entity.removeAttribute("aggressor");
}
if (entity.getProperties().getCombatPulse().getVictim() == this) {
entity.getProperties().getCombatPulse().stop();
}
}
/**
* Updates the location of an entity.
* @param last the last location.

View file

@ -31,6 +31,7 @@ import org.rs09.consts.Items
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertFalse
import org.junit.jupiter.api.Assertions.assertNotEquals
import org.junit.jupiter.api.Assertions.assertNull
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test
import kotlin.math.abs
@ -808,6 +809,46 @@ class CombatMovementTests {
}
}
@Test
fun npcRespawnShouldNotKeepPreviousPlayerCombatAggroState() {
TestUtils.getMockPlayer("combat_respawn_previous_player").use { player ->
val origin = arenaOrigin()
place(player, origin)
configureMelee(player)
val npc = NPC.create(100, origin.transform(1, 0, 0))
npc.init()
try {
configureMelee(npc)
npc.setAttribute("disable:drop", true)
npc.setAttribute("combat-attacker", player)
player.setAttribute("combat-attacker", npc)
player.setAttribute("aggressor", npc)
player.attack(npc)
npc.attack(player)
assertEquals(player, npc.getAttribute<Entity>("combat-attacker"))
assertEquals(npc, player.getAttribute<Entity>("combat-attacker"))
assertEquals(npc, player.getAttribute<Entity>("aggressor"))
npc.finalizeDeath(npc)
npc.respawnTick = GameWorld.ticks
npc.isRespawning = true
npc.tick()
assertNull(npc.getAttribute<Entity>("combat-attacker"))
assertNull(npc.getAttribute<Entity>("aggressor"))
assertNull(player.getAttribute<Entity>("combat-attacker"))
assertNull(player.getAttribute<Entity>("aggressor"))
assertFalse(npc.properties.combatPulse.isAttacking)
assertFalse(npc.properties.combatPulse.isInCombat)
} finally {
npc.clear()
CombatMovementIntents.clear()
}
}
}
@Test
fun combatMovementShouldOnlyQueueImmediateMovementSteps() {
TestUtils.getMockPlayer("combat_short_queue_attacker").use { player ->