From 200dfc64f935aee0b517cf601a0405a9d4354e14 Mon Sep 17 00:00:00 2001 From: Pwn <24796277-iampwn@users.noreply.gitlab.com> Date: Sun, 21 Jun 2026 08:51:29 -0400 Subject: [PATCH] King Black Dragon breath effects now trigger on impact instead of attack launch --- .../handlers/KingBlackDragonNPC.java | 5 +- .../handlers/KBDBreathEffectTests.kt | 56 +++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 Server/src/test/kotlin/content/region/wilderness/handlers/KBDBreathEffectTests.kt diff --git a/Server/src/main/content/region/wilderness/handlers/KingBlackDragonNPC.java b/Server/src/main/content/region/wilderness/handlers/KingBlackDragonNPC.java index ab5559616..51ec635a5 100644 --- a/Server/src/main/content/region/wilderness/handlers/KingBlackDragonNPC.java +++ b/Server/src/main/content/region/wilderness/handlers/KingBlackDragonNPC.java @@ -14,6 +14,7 @@ import core.game.node.entity.impl.Animator.Priority; import core.game.node.entity.npc.AbstractNPC; import core.game.node.entity.npc.NPC; import core.game.node.entity.player.Player; +import core.game.world.GameWorld; import core.game.world.map.Location; import core.game.world.update.flag.context.Animation; import core.plugin.Initializable; @@ -127,7 +128,6 @@ public final class KingBlackDragonNPC extends AbstractNPC { @Override public void adjustBattleState(Entity entity, Entity victim, BattleState state) { if (style == CombatStyle.RANGE) { - fireType.getTask().exec(victim, entity); state.setStyle(null); DRAGONFIRE.adjustBattleState(entity, victim, state); state.setStyle(CombatStyle.RANGE); @@ -184,6 +184,9 @@ public final class KingBlackDragonNPC extends AbstractNPC { @Override public void impact(Entity entity, Entity victim, BattleState state) { + if (style != CombatStyle.MELEE && victim.getImpactHandler().getDisabledTicks() <= GameWorld.getTicks()) { + fireType.getTask().exec(victim, entity); + } style.getSwingHandler().impact(entity, victim, state); } diff --git a/Server/src/test/kotlin/content/region/wilderness/handlers/KBDBreathEffectTests.kt b/Server/src/test/kotlin/content/region/wilderness/handlers/KBDBreathEffectTests.kt new file mode 100644 index 000000000..d40bef56b --- /dev/null +++ b/Server/src/test/kotlin/content/region/wilderness/handlers/KBDBreathEffectTests.kt @@ -0,0 +1,56 @@ +package content.region.wilderness.handlers + +import TestUtils +import core.api.getTimer +import core.game.node.entity.combat.BattleState +import core.game.node.entity.combat.equipment.FireType +import core.game.system.timer.impl.Poison +import core.game.world.map.Location +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test + +class KBDBreathEffectTests { + init { + TestUtils.preTestSetup() + } + + @Test fun toxicBreathShouldPoisonOnImpactNotOnLaunch() { + val kbd = KingBlackDragonNPC(50, Location.create(2273, 4698, 0)) + val handler = kbd.getSwingHandler(false) + // KBD rolls a random FireType per swing, force toxic breath for determinism + val fireTypeField = handler.javaClass.getDeclaredField("fireType") + fireTypeField.isAccessible = true + fireTypeField.set(handler, FireType.TOXIC_BREATH) + + TestUtils.getMockPlayer("kbdbreathtiming").use { player -> + val state = BattleState(kbd, player) + state.estimatedHit = 0 + + handler.adjustBattleState(kbd, player, state) + Assertions.assertNull(getTimer(player), "Breath effect must not apply on the launch tick.") + + handler.impact(kbd, player, state) + Assertions.assertNotNull(getTimer(player), "Breath effect must apply when the attack lands.") + } + } + + @Test fun toxicBreathShouldNotPoisonVictimWhoTeleportedMidFlight() { + val kbd = KingBlackDragonNPC(50, Location.create(2273, 4698, 0)) + val handler = kbd.getSwingHandler(false) + val fireTypeField = handler.javaClass.getDeclaredField("fireType") + fireTypeField.isAccessible = true + fireTypeField.set(handler, FireType.TOXIC_BREATH) + + TestUtils.getMockPlayer("kbdbreathteleport").use { player -> + val state = BattleState(kbd, player) + state.estimatedHit = 0 + + handler.adjustBattleState(kbd, player, state) + // Disable impacts like TeleportManager.send does for a real teleport + player.impactHandler.setDisabledTicks(12) + + handler.impact(kbd, player, state) + Assertions.assertNull(getTimer(player), "Breath effect must not apply to a victim whose impacts are disabled (teleported away).") + } + } +}