From 0a8d4f463d99af2b3061390d6ad0f959c1ec32ae Mon Sep 17 00:00:00 2001 From: Alexei Frolov Date: Mon, 17 Aug 2026 11:58:31 -0700 Subject: [PATCH] Correctly initialize HP of resurrected Inferno mobs A non-bloblet NPC spawning later than the start of the wave can only be a mager resurrection, which spawns with half of its full HP. --- .../blert/challenges/inferno/InfernoNpc.java | 18 +++++++++++++ .../challenges/inferno/WaveDataTracker.java | 25 ++++++++++++------- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/main/java/io/blert/challenges/inferno/InfernoNpc.java b/src/main/java/io/blert/challenges/inferno/InfernoNpc.java index ba54f0c..aaaaa1f 100644 --- a/src/main/java/io/blert/challenges/inferno/InfernoNpc.java +++ b/src/main/java/io/blert/challenges/inferno/InfernoNpc.java @@ -23,6 +23,7 @@ package io.blert.challenges.inferno; +import io.blert.core.Hitpoints; import io.blert.core.NpcAttack; import java.util.Optional; import lombok.Getter; @@ -105,6 +106,23 @@ boolean isPillar() { return this == ROCKY_SUPPORT; } + boolean isResurrectable() { + switch (this) { + case BAT: + case BLOB: + case MELEER: + case RANGER: + case MAGER: + return true; + default: + return false; + } + } + + Hitpoints resurrectedHitpoints() { + return new Hitpoints((hitpoints + 1) / 2, hitpoints); + } + @SafeVarargs InfernoNpc(int id, int hitpoints, Pair... attacks) { this.id = id; diff --git a/src/main/java/io/blert/challenges/inferno/WaveDataTracker.java b/src/main/java/io/blert/challenges/inferno/WaveDataTracker.java index 73f61f0..4b4f663 100644 --- a/src/main/java/io/blert/challenges/inferno/WaveDataTracker.java +++ b/src/main/java/io/blert/challenges/inferno/WaveDataTracker.java @@ -69,13 +69,16 @@ protected void start() { } // NPC spawn events are typically received before the wave start message, - // so capture any NPCs that are already present. - client.getTopLevelWorldView().npcs().stream().forEach(npc -> { - InfernoNpc.withId(npc.getId()) - .filter(inf -> !inf.isPillar()) - .ifPresent(infernoNpc -> addTrackedNpc( - new BasicTrackedNpc(npc, generateRoomId(npc), new Hitpoints(infernoNpc.getHitpoints())))); - }); + // so capture any NPCs that are already present, ignoring those already + // captured during NOT_STARTED. + client.getTopLevelWorldView().npcs().stream() + .filter(npc -> getTrackedNpcs().getByNpc(npc).isEmpty()) + .forEach(npc -> { + InfernoNpc.withId(npc.getId()) + .filter(inf -> !inf.isPillar()) + .ifPresent(infernoNpc -> addTrackedNpc(new BasicTrackedNpc( + npc, generateRoomId(npc), new Hitpoints(infernoNpc.getHitpoints())))); + }); } @Override @@ -88,8 +91,12 @@ protected Optional onNpcSpawn(NpcSpawned event) { // Pillars are managed by the challenge itself. return Optional.empty(); } - return Optional.of(new BasicTrackedNpc( - event.getNpc(), generateRoomId(event.getNpc()), new Hitpoints(npc.getHitpoints()))); + + Hitpoints hitpoints = getTick() > 0 && wave <= 66 && npc.isResurrectable() + ? npc.resurrectedHitpoints() + : new Hitpoints(npc.getHitpoints()); + + return Optional.of(new BasicTrackedNpc(event.getNpc(), generateRoomId(event.getNpc()), hitpoints)); }); }