From 30c2d18928a0600fbbadd17d77d7b611b040cdb0 Mon Sep 17 00:00:00 2001 From: Guillaume Desktop Date: Wed, 10 Sep 2025 20:53:50 +0200 Subject: [PATCH 1/5] feature: added an interface for bosses with a custom modifier --- .../predictedhit/npcswithscalingbonus/IModifierBoss.java | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/IModifierBoss.java diff --git a/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/IModifierBoss.java b/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/IModifierBoss.java new file mode 100644 index 0000000..ccbc62f --- /dev/null +++ b/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/IModifierBoss.java @@ -0,0 +1,7 @@ +package com.xpdrops.predictedhit.npcswithscalingbonus; + +public interface IModifierBoss +{ + boolean containsId(int npcId); + double getModifier(int npcId); +} From 120358f7bf00939dade643acc5cdf668e5df4634 Mon Sep 17 00:00:00 2001 From: Guillaume Desktop Date: Wed, 10 Sep 2025 21:08:59 +0200 Subject: [PATCH 2/5] refactor: moved delve to its own folder --- .../npcswithscalingbonus/DelveNpc.java | 30 ------------------- .../npcswithscalingbonus/delve/DelveNpc.java | 12 ++++++++ 2 files changed, 12 insertions(+), 30 deletions(-) delete mode 100644 src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/DelveNpc.java create mode 100644 src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/delve/DelveNpc.java diff --git a/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/DelveNpc.java b/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/DelveNpc.java deleted file mode 100644 index 7decbce..0000000 --- a/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/DelveNpc.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.xpdrops.predictedhit.npcswithscalingbonus; - -import com.google.common.collect.ImmutableSet; -import net.runelite.api.gameval.NpcID; - -public class DelveNpc -{ - private static final int BASE_HP = 525; - private static final NPCStats NPC_STATS = new NPCStats(BASE_HP, 300, 190, 90, 275, 110, 210, 45, 300, 300, 60, 160, 160); - private static final ImmutableSet DELVE_NPC_IDS = ImmutableSet.of(NpcID.DOM_BOSS, NpcID.DOM_BOSS_SHIELDED, NpcID.DOM_BOSS_BURROWED); - private static int lastHp = BASE_HP; - - public static boolean isDelveNpc(int npcId) - { - return DELVE_NPC_IDS.contains(npcId); - } - - public static double modifierFromState(int maxHp) - { - if (maxHp < BASE_HP) - { - maxHp = lastHp; - } - else - { - lastHp = maxHp; - } - return NPCStats.modifierFromStats(NPC_STATS.withHp(maxHp)); - } -} diff --git a/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/delve/DelveNpc.java b/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/delve/DelveNpc.java new file mode 100644 index 0000000..cacb9f3 --- /dev/null +++ b/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/delve/DelveNpc.java @@ -0,0 +1,12 @@ +package com.xpdrops.predictedhit.npcswithscalingbonus.delve; + +import com.google.common.collect.ImmutableSet; +import com.xpdrops.predictedhit.npcswithscalingbonus.NPCStats; +import net.runelite.api.gameval.NpcID; + +public class DelveNpc +{ + protected static final int BASE_HP = 525; + protected static final NPCStats NPC_STATS = new NPCStats(BASE_HP, 300, 190, 90, 275, 110, 210, 45, 300, 300, 60, 160, 160); + protected static final ImmutableSet DELVE_NPC_IDS = ImmutableSet.of(NpcID.DOM_BOSS, NpcID.DOM_BOSS_SHIELDED, NpcID.DOM_BOSS_BURROWED); +} From 1e11ccf7f23b88f80de72dc5ae4a760bd7c13e44 Mon Sep 17 00:00:00 2001 From: Guillaume Desktop Date: Wed, 10 Sep 2025 21:10:38 +0200 Subject: [PATCH 3/5] refactor: removed isNpc and getModifier logic from NPCs files --- .../npcswithscalingbonus/cox/CoXNPCs.java | 24 +++++-------------- .../npcswithscalingbonus/toa/ToANPCs.java | 23 +++++------------- .../npcswithscalingbonus/tob/ToBNPCs.java | 24 ++++++------------- 3 files changed, 19 insertions(+), 52 deletions(-) diff --git a/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/cox/CoXNPCs.java b/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/cox/CoXNPCs.java index 6c97e08..b5fd097 100644 --- a/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/cox/CoXNPCs.java +++ b/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/cox/CoXNPCs.java @@ -1,11 +1,13 @@ package com.xpdrops.predictedhit.npcswithscalingbonus.cox; +import lombok.AccessLevel; import lombok.Getter; import net.runelite.api.gameval.NpcID; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; +import java.util.Map; public enum CoXNPCs { @@ -40,35 +42,21 @@ public enum CoXNPCs this.ids = new HashSet<>(); Arrays.stream(ids).forEach(this.ids::add); } - - private static final HashMap COXNPC_MAPPING; + @Getter(AccessLevel.PACKAGE) + private static final Map COX_NPC_MAPPING; static { - COXNPC_MAPPING = new HashMap<>(); + COX_NPC_MAPPING = new HashMap<>(); for (CoXNPCs value : CoXNPCs.values()) { for (Integer id : value.ids) { - COXNPC_MAPPING.put(id, value.npcWithScalingBonus); + COX_NPC_MAPPING.put(id, value.npcWithScalingBonus); } } } - public static boolean isCOXNPC(int id) - { - return COXNPC_MAPPING.containsKey(id); - } - - public static double getModifier(int id, int scaledPartySize, int playersInRaid, int raidType) - { - if (isCOXNPC(id)) - { - return COXNPC_MAPPING.get(id).calculateModifier(raidType, scaledPartySize, playersInRaid); - } - return 1.0; - } - @Getter enum CoXNPCStats { diff --git a/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/toa/ToANPCs.java b/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/toa/ToANPCs.java index 8a8158a..2669e81 100644 --- a/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/toa/ToANPCs.java +++ b/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/toa/ToANPCs.java @@ -1,11 +1,13 @@ package com.xpdrops.predictedhit.npcswithscalingbonus.toa; +import lombok.AccessLevel; import lombok.Getter; import net.runelite.api.gameval.NpcID; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; +import java.util.Map; public enum ToANPCs { @@ -39,34 +41,21 @@ public enum ToANPCs Arrays.stream(ids).forEach(this.ids::add); } - private static final HashMap TOANPCMAPPING; + @Getter(AccessLevel.PACKAGE) + private static final Map TOA_NPC_MAPPING; static { - TOANPCMAPPING = new HashMap<>(); + TOA_NPC_MAPPING = new HashMap<>(); for (ToANPCs value : ToANPCs.values()) { for (Integer id : value.ids) { - TOANPCMAPPING.put(id, value.npcWithScalingBonus); + TOA_NPC_MAPPING.put(id, value.npcWithScalingBonus); } } } - public static boolean isToANPC(int id) - { - return TOANPCMAPPING.containsKey(id); - } - - public static double getModifier(int id, int partySize, int raidLevel, int pathLevel) - { - if (isToANPC(id)) - { - return TOANPCMAPPING.get(id).calculateModifier(raidLevel, partySize, pathLevel); - } - return 1.0; - } - enum ToANPCStats { AKKHA(new CoreBoss(40, 100, 140, 80, 100, 100, 115, 30, 60, 120, 120, 10, 60)), diff --git a/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/tob/ToBNPCs.java b/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/tob/ToBNPCs.java index 03c30c7..2482534 100644 --- a/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/tob/ToBNPCs.java +++ b/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/tob/ToBNPCs.java @@ -1,10 +1,13 @@ package com.xpdrops.predictedhit.npcswithscalingbonus.tob; +import lombok.AccessLevel; +import lombok.Getter; import net.runelite.api.gameval.NpcID; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; +import java.util.Map; // We need a mapping (npc id, raid_type) -> xp bonus // EM = Entry Mode @@ -43,31 +46,18 @@ public enum ToBNPCs Arrays.stream(ids).forEach(this.ids::add); } - private static final HashMap NPCS_WITH_SCALING_BONUS_MAPPING; + @Getter(AccessLevel.PACKAGE) + private static final Map TOB_NPC_MAPPING; static { - NPCS_WITH_SCALING_BONUS_MAPPING = new HashMap<>(); + TOB_NPC_MAPPING = new HashMap<>(); for (ToBNPCs value : ToBNPCs.values()) { for (Integer id : value.ids) { - NPCS_WITH_SCALING_BONUS_MAPPING.put(id, value.npcWithScalingBonus); + TOB_NPC_MAPPING.put(id, value.npcWithScalingBonus); } } } - - public static boolean isTOBNPC(int id) - { - return NPCS_WITH_SCALING_BONUS_MAPPING.containsKey(id); - } - - public static double getModifier(int id, int partySize) - { - if (isTOBNPC(id)) - { - return NPCS_WITH_SCALING_BONUS_MAPPING.get(id).calculateModifier(partySize); - } - return 1.0; - } } \ No newline at end of file From 3655fbe440b5d6927d79a993ee0ce962992a3065 Mon Sep 17 00:00:00 2001 From: Guillaume Desktop Date: Wed, 10 Sep 2025 21:11:15 +0200 Subject: [PATCH 4/5] refactor: moved isNpc and getModifier logic to its own file --- .../predictedhit/XpDropDamageCalculator.java | 146 +++--------------- .../npcswithscalingbonus/NPCStats.java | 2 +- .../npcswithscalingbonus/cox/CoX.java | 59 +++++++ .../npcswithscalingbonus/delve/Delve.java | 46 ++++++ .../npcswithscalingbonus/toa/ToA.java | 85 ++++++++++ .../npcswithscalingbonus/tob/ToB.java | 54 +++++++ 6 files changed, 269 insertions(+), 123 deletions(-) create mode 100644 src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/cox/CoX.java create mode 100644 src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/delve/Delve.java create mode 100644 src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/toa/ToA.java create mode 100644 src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/tob/ToB.java diff --git a/src/main/java/com/xpdrops/predictedhit/XpDropDamageCalculator.java b/src/main/java/com/xpdrops/predictedhit/XpDropDamageCalculator.java index 4aead44..b7bf15e 100644 --- a/src/main/java/com/xpdrops/predictedhit/XpDropDamageCalculator.java +++ b/src/main/java/com/xpdrops/predictedhit/XpDropDamageCalculator.java @@ -4,15 +4,13 @@ import com.google.gson.internal.LinkedTreeMap; import com.google.gson.reflect.TypeToken; import com.xpdrops.predictedhit.npcswithscalingbonus.ChambersLayoutSolver; -import com.xpdrops.predictedhit.npcswithscalingbonus.DelveNpc; -import com.xpdrops.predictedhit.npcswithscalingbonus.cox.CoXNPCs; -import com.xpdrops.predictedhit.npcswithscalingbonus.toa.ToANPCs; -import com.xpdrops.predictedhit.npcswithscalingbonus.tob.ToBNPCs; +import com.xpdrops.predictedhit.npcswithscalingbonus.IModifierBoss; +import com.xpdrops.predictedhit.npcswithscalingbonus.cox.CoX; +import com.xpdrops.predictedhit.npcswithscalingbonus.delve.Delve; +import com.xpdrops.predictedhit.npcswithscalingbonus.toa.ToA; +import com.xpdrops.predictedhit.npcswithscalingbonus.tob.ToB; import lombok.extern.slf4j.Slf4j; import net.runelite.api.Client; -import net.runelite.api.gameval.VarbitID; -import net.runelite.api.widgets.Widget; -import net.runelite.client.util.Text; import org.apache.commons.lang3.tuple.Pair; import javax.inject.Inject; @@ -22,10 +20,7 @@ import java.io.InputStreamReader; import java.lang.reflect.Type; import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; +import java.util.*; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -36,25 +31,20 @@ public class XpDropDamageCalculator private static final HashMap XP_BONUS_MAPPING = new HashMap<>(); private static final HashMap USER_DEFINED_XP_BONUS_MAPPING = new HashMap<>(); private static final Pattern RAID_LEVEL_MATCHER = Pattern.compile("(\\d+)"); - private static final int RAID_LEVEL_WIDGET_ID = (481 << 16) | 42; - private static final int ROOM_LEVEL_WIDGET_ID = (481 << 16) | 45; - private static final int COX_SCALED_PARTY_SIZE_VARBIT = 9540; - private static final int RAID_PARTY_SIZE = 5424; - - private int lastToARaidLevel = 0; - private int lastToARaidPartySize = 1; - private int lastToARaidRoomLevel = 0; private final Gson GSON; - private final Client client; - private final ChambersLayoutSolver chambersLayoutSolver; + private final List modifierBosses; @Inject protected XpDropDamageCalculator(Gson gson, Client client, ChambersLayoutSolver chambersLayoutSolver) { this.GSON = gson; - this.client = client; - this.chambersLayoutSolver = chambersLayoutSolver; + this.modifierBosses = Arrays.asList( + new CoX(client, chambersLayoutSolver), + new Delve(client), + new ToB(client), + new ToA(client) + ); } public void populateMap() @@ -63,69 +53,6 @@ public void populateMap() XP_BONUS_MAPPING.putAll(getNpcsWithXpBonus()); } - private int getCoxTotalPartySize() - { - return Math.max(1, client.getVarbitValue(COX_SCALED_PARTY_SIZE_VARBIT)); - } - - // Currently it checks a varbit for the amount of players in the raid. - // Ideally this method returns how many non board scaling accounts started the raid. - private int getCoxPlayersInRaid() - { - return Math.max(1, client.getVarbitValue(RAID_PARTY_SIZE)); - } - - private int getToBPartySize() - { - int count = 0; - for (int i = 330; i < 335; i++) - { - String jagexName = client.getVarcStrValue(i); - if (jagexName != null) - { - String name = Text.removeTags(jagexName).replace('\u00A0', ' ').trim(); - if (!"".equals(name)) - { - count++; - } - } - } - return count; - } - - private int getToAPartySize() - { - return 1 + - (client.getVarbitValue(VarbitID.TOA_CLIENT_P1) != 0 ? 1 : 0) + - (client.getVarbitValue(VarbitID.TOA_CLIENT_P2) != 0 ? 1 : 0) + - (client.getVarbitValue(VarbitID.TOA_CLIENT_P3) != 0 ? 1 : 0) + - (client.getVarbitValue(VarbitID.TOA_CLIENT_P4) != 0 ? 1 : 0) + - (client.getVarbitValue(VarbitID.TOA_CLIENT_P5) != 0 ? 1 : 0) + - (client.getVarbitValue(VarbitID.TOA_CLIENT_P6) != 0 ? 1 : 0) + - (client.getVarbitValue(VarbitID.TOA_CLIENT_P7) != 0 ? 1 : 0); - } - - private int getToARaidLevel() - { - return client.getVarbitValue(VarbitID.TOA_CLIENT_RAID_LEVEL); - } - - private int getToARoomLevel() - { - Widget levelWidget = client.getWidget(ROOM_LEVEL_WIDGET_ID); - if (levelWidget != null && !levelWidget.isHidden()) - { - try - { - return Integer.parseInt(Text.sanitize(levelWidget.getText())); - } - catch (Exception ignored) - { - } - } - return -1; - } - private int calculateHit(int hpXpDiff, double modifier, double configModifier) { if (Math.abs(configModifier) < 1e-6) @@ -149,45 +76,19 @@ public int calculateHitOnPlayer(int cmb, int hpXpDiff, double configModifier) public int calculateHitOnNpc(int id, int hpXpDiff, double configModifier) { double modifier = 1.0; - if (DelveNpc.isDelveNpc(id)) - { - int maxHp = client.getVarbitValue(VarbitID.HPBAR_HUD_BASEHP); - modifier = DelveNpc.modifierFromState(maxHp); - log.debug("Delve modifier {} {} max hp {}", id, modifier, maxHp); - } - else if (CoXNPCs.isCOXNPC(id)) - { - int scaledPartySize = getCoxTotalPartySize(); - int playersInRaid = getCoxPlayersInRaid(); - // Wrong. only follows the setting of the player's board -// int raidType = client.getVarbitValue(6385) > 0 ? 1 : 0; - int raidType = chambersLayoutSolver.getRaidType() == ChambersLayoutSolver.RaidType.CM ? 1 : 0; - modifier = CoXNPCs.getModifier(id, scaledPartySize, playersInRaid, raidType); - log.debug("COX modifier {} {} party size {} players in raid {} raid type {}", id, modifier, scaledPartySize, playersInRaid, raidType); - } - else if (ToBNPCs.isTOBNPC(id)) - { - int partySize = getToBPartySize(); - modifier = ToBNPCs.getModifier(id, partySize); - log.debug("TOB modifier {} {} part size {}", id, modifier, partySize); - } - else if (ToANPCs.isToANPC(id)) + for(IModifierBoss boss: modifierBosses) { - int partySize = getToAPartySize(); - int roomLevel = getToARoomLevel(); - int raidLevel = getToARaidLevel(); - // If we cannot determine any of the above; use last known settings. - if (partySize < 0) partySize = lastToARaidPartySize; - else lastToARaidPartySize = partySize; - if (roomLevel < 0) roomLevel = lastToARaidRoomLevel; - else lastToARaidRoomLevel = roomLevel; - if (raidLevel < 0) raidLevel = lastToARaidLevel; - else lastToARaidLevel = raidLevel; - modifier = ToANPCs.getModifier(id, partySize, raidLevel, roomLevel); - log.debug("TOA modifier {} {} party size {} raid level {} room level {}", id, modifier, partySize, raidLevel, roomLevel); + if (boss.containsId(id)) + { + modifier = boss.getModifier(id); + + log.debug("id: {}, boss: {} , modifier: {}", id, boss.getClass().getSimpleName(), modifier); + return calculateHit(hpXpDiff, modifier, configModifier); + } } - else if (USER_DEFINED_XP_BONUS_MAPPING.containsKey(id)) + + if (USER_DEFINED_XP_BONUS_MAPPING.containsKey(id)) { modifier = USER_DEFINED_XP_BONUS_MAPPING.get(id); } @@ -195,6 +96,7 @@ else if (XP_BONUS_MAPPING.containsKey(id)) { modifier = XP_BONUS_MAPPING.get(id); } + return calculateHit(hpXpDiff, modifier, configModifier); } diff --git a/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/NPCStats.java b/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/NPCStats.java index 5ac2aa7..8ce1aeb 100644 --- a/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/NPCStats.java +++ b/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/NPCStats.java @@ -31,7 +31,7 @@ public class NPCStats private static final int MAX_HP_FOR_MULTIPLIER = 2000; - protected static double modifierFromStats(NPCStats npcStats) + public static double modifierFromStats(NPCStats npcStats) { int hp = Math.min(npcStats.hp, MAX_HP_FOR_MULTIPLIER); double averageLevel = Math.floor((hp + npcStats.getAtt() + npcStats.getStr() + npcStats.getDef()) / 4.0); diff --git a/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/cox/CoX.java b/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/cox/CoX.java new file mode 100644 index 0000000..f566aa9 --- /dev/null +++ b/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/cox/CoX.java @@ -0,0 +1,59 @@ +package com.xpdrops.predictedhit.npcswithscalingbonus.cox; + +import com.xpdrops.predictedhit.npcswithscalingbonus.IModifierBoss; +import com.xpdrops.predictedhit.npcswithscalingbonus.ChambersLayoutSolver; +import net.runelite.api.Client; + +import javax.inject.Inject; + +public class CoX implements IModifierBoss +{ + private final Client client; + private final ChambersLayoutSolver chambersLayoutSolver; + + private static final int COX_SCALED_PARTY_SIZE_VARBIT = 9540; + private static final int RAID_PARTY_SIZE = 5424; + + + @Inject + public CoX(Client client, ChambersLayoutSolver chambersLayoutSolver) + { + this.client = client; + this.chambersLayoutSolver = chambersLayoutSolver; + } + + private int getCoxTotalPartySize() + { + return Math.max(1, client.getVarbitValue(COX_SCALED_PARTY_SIZE_VARBIT)); + } + + // Currently it checks a varbit for the amount of players in the raid. + // Ideally this method returns how many non board scaling accounts started the raid. + private int getCoxPlayersInRaid() + { + return Math.max(1, client.getVarbitValue(RAID_PARTY_SIZE)); + } + + @Override + public boolean containsId(int npcId) + { + return CoXNPCs.getCOX_NPC_MAPPING().containsKey(npcId); + } + + @Override + public double getModifier(int npcId) + { + if (!containsId(npcId)) + { + return 1.0; + } + + int scaledPartySize = getCoxTotalPartySize(); + int playersInRaid = getCoxPlayersInRaid(); + // Wrong. only follows the setting of the player's board + // int raidType = client.getVarbitValue(6385) > 0 ? 1 : 0; + int raidType = chambersLayoutSolver.getRaidType() == ChambersLayoutSolver.RaidType.CM ? 1 : 0; + + return CoXNPCs.getCOX_NPC_MAPPING().get(npcId).calculateModifier(raidType, scaledPartySize, playersInRaid); + } +} diff --git a/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/delve/Delve.java b/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/delve/Delve.java new file mode 100644 index 0000000..9b372c0 --- /dev/null +++ b/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/delve/Delve.java @@ -0,0 +1,46 @@ +package com.xpdrops.predictedhit.npcswithscalingbonus.delve; + +import com.xpdrops.predictedhit.npcswithscalingbonus.IModifierBoss; +import com.xpdrops.predictedhit.npcswithscalingbonus.NPCStats; +import net.runelite.api.Client; +import net.runelite.api.gameval.VarbitID; + +import javax.inject.Inject; + +public class Delve implements IModifierBoss +{ + private final Client client; + + private static int lastHp = DelveNpc.BASE_HP; + + @Inject + public Delve(Client client) + { + this.client = client; + } + + @Override + public boolean containsId(int npcId) + { + return DelveNpc.DELVE_NPC_IDS.contains(npcId); + } + + @Override + public double getModifier(int npcId) { + if (!containsId(npcId)) + { + return 1.0; + } + + int maxHp = client.getVarbitValue(VarbitID.HPBAR_HUD_BASEHP); + if (maxHp < DelveNpc.BASE_HP) + { + maxHp = lastHp; + } + else + { + lastHp = maxHp; + } + return NPCStats.modifierFromStats(DelveNpc.NPC_STATS.withHp(maxHp)); + } +} diff --git a/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/toa/ToA.java b/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/toa/ToA.java new file mode 100644 index 0000000..fcb3516 --- /dev/null +++ b/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/toa/ToA.java @@ -0,0 +1,85 @@ +package com.xpdrops.predictedhit.npcswithscalingbonus.toa; + +import com.xpdrops.predictedhit.npcswithscalingbonus.IModifierBoss; +import net.runelite.api.Client; +import net.runelite.api.gameval.VarbitID; +import net.runelite.api.widgets.Widget; +import net.runelite.client.util.Text; + +import javax.inject.Inject; + +public class ToA implements IModifierBoss +{ + private final Client client; + + private int lastToARaidLevel = 0; + private int lastToARaidPartySize = 1; + private int lastToARaidRoomLevel = 0; + private static final int ROOM_LEVEL_WIDGET_ID = (481 << 16) | 45; + + @Inject + public ToA(Client client) + { + this.client = client; + } + + private int getToAPartySize() + { + return 1 + + (client.getVarbitValue(VarbitID.TOA_CLIENT_P1) != 0 ? 1 : 0) + + (client.getVarbitValue(VarbitID.TOA_CLIENT_P2) != 0 ? 1 : 0) + + (client.getVarbitValue(VarbitID.TOA_CLIENT_P3) != 0 ? 1 : 0) + + (client.getVarbitValue(VarbitID.TOA_CLIENT_P4) != 0 ? 1 : 0) + + (client.getVarbitValue(VarbitID.TOA_CLIENT_P5) != 0 ? 1 : 0) + + (client.getVarbitValue(VarbitID.TOA_CLIENT_P6) != 0 ? 1 : 0) + + (client.getVarbitValue(VarbitID.TOA_CLIENT_P7) != 0 ? 1 : 0); + } + + private int getToARaidLevel() + { + return client.getVarbitValue(VarbitID.TOA_CLIENT_RAID_LEVEL); + } + + private int getToARoomLevel() + { + Widget levelWidget = client.getWidget(ROOM_LEVEL_WIDGET_ID); + if (levelWidget != null && !levelWidget.isHidden()) + { + try + { + return Integer.parseInt(Text.sanitize(levelWidget.getText())); + } + catch (Exception ignored) + { + } + } + return -1; + } + + @Override + public boolean containsId(int npcId) { + return ToANPCs.getTOA_NPC_MAPPING().containsKey(npcId); + } + + @Override + public double getModifier(int npcId) { + if (!containsId(npcId)) + { + return 1.0; + } + + int partySize = getToAPartySize(); + int roomLevel = getToARoomLevel(); + int raidLevel = getToARaidLevel(); + + // If we cannot determine any of the above; use last known settings. + if (partySize < 0) partySize = lastToARaidPartySize; + else lastToARaidPartySize = partySize; + if (roomLevel < 0) roomLevel = lastToARaidRoomLevel; + else lastToARaidRoomLevel = roomLevel; + if (raidLevel < 0) raidLevel = lastToARaidLevel; + else lastToARaidLevel = raidLevel; + + return ToANPCs.getTOA_NPC_MAPPING().get(npcId).calculateModifier(raidLevel, partySize, roomLevel); + } +} diff --git a/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/tob/ToB.java b/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/tob/ToB.java new file mode 100644 index 0000000..beae17b --- /dev/null +++ b/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/tob/ToB.java @@ -0,0 +1,54 @@ +package com.xpdrops.predictedhit.npcswithscalingbonus.tob; + +import com.xpdrops.predictedhit.npcswithscalingbonus.IModifierBoss; +import net.runelite.api.Client; +import net.runelite.client.util.Text; + +import javax.inject.Inject; + +public class ToB implements IModifierBoss +{ + private final Client client; + + @Inject + public ToB(Client client) + { + this.client = client; + } + + private int getToBPartySize() + { + int count = 0; + for (int i = 330; i < 335; i++) + { + String jagexName = client.getVarcStrValue(i); + if (jagexName != null) + { + String name = Text.removeTags(jagexName).replace('\u00A0', ' ').trim(); + if (!name.isEmpty()) + { + count++; + } + } + } + return count; + } + + @Override + public boolean containsId(int npcId) + { + return ToBNPCs.getTOB_NPC_MAPPING().containsKey(npcId); + } + + @Override + public double getModifier(int npcId) + { + if (!containsId(npcId)) + { + return 1.0; + } + + int partySize = getToBPartySize(); + return ToBNPCs.getTOB_NPC_MAPPING().get(npcId).calculateModifier(partySize); + } +} From 9ed29d178311f943698d8015725e567c49f47b2f Mon Sep 17 00:00:00 2001 From: Guillaume Desktop Date: Thu, 11 Sep 2025 00:52:58 +0200 Subject: [PATCH 5/5] refactor: moved X_NPC_MAPPING inside class impl responsible for containsId and getModifier --- .../npcswithscalingbonus/cox/CoX.java | 23 +++++++++++++--- .../npcswithscalingbonus/cox/CoXNPCs.java | 22 ++++------------ .../npcswithscalingbonus/toa/ToA.java | 22 +++++++++++++--- .../npcswithscalingbonus/toa/ToANPCs.java | 26 +++++-------------- .../npcswithscalingbonus/tob/ToB.java | 20 ++++++++++++-- .../npcswithscalingbonus/tob/ToBNPCs.java | 21 +++------------ 6 files changed, 72 insertions(+), 62 deletions(-) diff --git a/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/cox/CoX.java b/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/cox/CoX.java index f566aa9..fdc3d4c 100644 --- a/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/cox/CoX.java +++ b/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/cox/CoX.java @@ -2,19 +2,24 @@ import com.xpdrops.predictedhit.npcswithscalingbonus.IModifierBoss; import com.xpdrops.predictedhit.npcswithscalingbonus.ChambersLayoutSolver; +import lombok.AccessLevel; +import lombok.Getter; import net.runelite.api.Client; import javax.inject.Inject; +import java.util.HashMap; +import java.util.Map; public class CoX implements IModifierBoss { private final Client client; private final ChambersLayoutSolver chambersLayoutSolver; + private static final Map COX_NPC_MAPPING; + private static final int COX_SCALED_PARTY_SIZE_VARBIT = 9540; private static final int RAID_PARTY_SIZE = 5424; - @Inject public CoX(Client client, ChambersLayoutSolver chambersLayoutSolver) { @@ -22,6 +27,18 @@ public CoX(Client client, ChambersLayoutSolver chambersLayoutSolver) this.chambersLayoutSolver = chambersLayoutSolver; } + static + { + COX_NPC_MAPPING = new HashMap<>(); + for (CoXNPCs value : CoXNPCs.values()) + { + for (Integer id : value.getIds()) + { + COX_NPC_MAPPING.put(id, value.getNpcWithScalingBonus()); + } + } + } + private int getCoxTotalPartySize() { return Math.max(1, client.getVarbitValue(COX_SCALED_PARTY_SIZE_VARBIT)); @@ -37,7 +54,7 @@ private int getCoxPlayersInRaid() @Override public boolean containsId(int npcId) { - return CoXNPCs.getCOX_NPC_MAPPING().containsKey(npcId); + return COX_NPC_MAPPING.containsKey(npcId); } @Override @@ -54,6 +71,6 @@ public double getModifier(int npcId) // int raidType = client.getVarbitValue(6385) > 0 ? 1 : 0; int raidType = chambersLayoutSolver.getRaidType() == ChambersLayoutSolver.RaidType.CM ? 1 : 0; - return CoXNPCs.getCOX_NPC_MAPPING().get(npcId).calculateModifier(raidType, scaledPartySize, playersInRaid); + return COX_NPC_MAPPING.get(npcId).calculateModifier(raidType, scaledPartySize, playersInRaid); } } diff --git a/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/cox/CoXNPCs.java b/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/cox/CoXNPCs.java index b5fd097..9041511 100644 --- a/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/cox/CoXNPCs.java +++ b/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/cox/CoXNPCs.java @@ -31,9 +31,11 @@ public enum CoXNPCs GREAT_OLM(CoXNPCStats.GREAT_OLM.getCoxnpc(), NpcID.OLM_HEAD_SPAWNING, NpcID.OLM_HEAD), GREAT_OLM_MAGE_HAND(CoXNPCStats.GREAT_OLM_MAGE_HAND.getCoxnpc(), NpcID.OLM_HAND_LEFT_SPAWNING, NpcID.OLM_HAND_LEFT_SPAWNING), GREAT_OLM_MELEE_HAND(CoXNPCStats.GREAT_OLM_MELEE_HAND.getCoxnpc(), NpcID.OLM_HAND_RIGHT_SPAWNING, NpcID.OLM_HAND_RIGHT), - SCAVENGER(CoXNPCStats.SCAVENGER.getCoxnpc(), NpcID.RAIDS_SCAVENGER_BEAST_A, NpcID.RAIDS_SCAVENGER_BEAST_B), - ; + SCAVENGER(CoXNPCStats.SCAVENGER.getCoxnpc(), NpcID.RAIDS_SCAVENGER_BEAST_A, NpcID.RAIDS_SCAVENGER_BEAST_B); + + @Getter(AccessLevel.PACKAGE) private final HashSet ids; + @Getter(AccessLevel.PACKAGE) private final CoXNPC npcWithScalingBonus; CoXNPCs(CoXNPC coxnpc, int... ids) @@ -42,23 +44,9 @@ public enum CoXNPCs this.ids = new HashSet<>(); Arrays.stream(ids).forEach(this.ids::add); } - @Getter(AccessLevel.PACKAGE) - private static final Map COX_NPC_MAPPING; - - static - { - COX_NPC_MAPPING = new HashMap<>(); - for (CoXNPCs value : CoXNPCs.values()) - { - for (Integer id : value.ids) - { - COX_NPC_MAPPING.put(id, value.npcWithScalingBonus); - } - } - } @Getter - enum CoXNPCStats + enum CoXNPCStats { TEKTON(new Tekton(300, 390, 390, 205, 1, 205, 64, 20, 155, 165, 105, 0, 0)), TEKTON_ENRAGED(new Tekton(300, 390, 390, 205, 1, 205, 64, 30, 280, 290, 180, 0, 0)), diff --git a/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/toa/ToA.java b/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/toa/ToA.java index fcb3516..73aea40 100644 --- a/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/toa/ToA.java +++ b/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/toa/ToA.java @@ -7,15 +7,19 @@ import net.runelite.client.util.Text; import javax.inject.Inject; +import java.util.HashMap; +import java.util.Map; public class ToA implements IModifierBoss { private final Client client; + private static final Map TOA_NPC_MAPPING; + + private static final int ROOM_LEVEL_WIDGET_ID = (481 << 16) | 45; private int lastToARaidLevel = 0; private int lastToARaidPartySize = 1; private int lastToARaidRoomLevel = 0; - private static final int ROOM_LEVEL_WIDGET_ID = (481 << 16) | 45; @Inject public ToA(Client client) @@ -23,6 +27,18 @@ public ToA(Client client) this.client = client; } + static + { + TOA_NPC_MAPPING = new HashMap<>(); + for (ToANPCs value : ToANPCs.values()) + { + for (Integer id : value.getIds()) + { + TOA_NPC_MAPPING.put(id, value.getNpcWithScalingBonus()); + } + } + } + private int getToAPartySize() { return 1 + @@ -58,7 +74,7 @@ private int getToARoomLevel() @Override public boolean containsId(int npcId) { - return ToANPCs.getTOA_NPC_MAPPING().containsKey(npcId); + return TOA_NPC_MAPPING.containsKey(npcId); } @Override @@ -80,6 +96,6 @@ public double getModifier(int npcId) { if (raidLevel < 0) raidLevel = lastToARaidLevel; else lastToARaidLevel = raidLevel; - return ToANPCs.getTOA_NPC_MAPPING().get(npcId).calculateModifier(raidLevel, partySize, roomLevel); + return TOA_NPC_MAPPING.get(npcId).calculateModifier(raidLevel, partySize, roomLevel); } } diff --git a/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/toa/ToANPCs.java b/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/toa/ToANPCs.java index 2669e81..724c6c6 100644 --- a/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/toa/ToANPCs.java +++ b/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/toa/ToANPCs.java @@ -31,7 +31,10 @@ public enum ToANPCs E_WARDEN_544(ToANPCStats.E_WARDEN_544.getToANPC(), NpcID.TOA_WARDEN_ELIDINIS_PHASE3, NpcID.TOA_WARDEN_ELIDINIS_PHASE3_CHARGING), AKKHA_SHADOW(ToANPCStats.AKKHA_SHADOW.getToANPC(), NpcID.AKKHA_SHADOW, NpcID.AKKHA_SHADOW_ENRAGE, NpcID.AKKHA_SHADOW_ENRAGE_DUMMY), OBELISK(ToANPCStats.OBELISK.getToANPC(), NpcID.TOA_WARDENS_P1_OBELISK_NPC_INACTIVE, NpcID.TOA_WARDENS_P1_OBELISK_NPC, NpcID.TOA_WARDENS_P2_OBELISK_NPC); + + @Getter(AccessLevel.PACKAGE) private final HashSet ids; + @Getter(AccessLevel.PACKAGE) private final ToANPC npcWithScalingBonus; ToANPCs(ToANPC coxnpc, int... ids) @@ -41,22 +44,8 @@ public enum ToANPCs Arrays.stream(ids).forEach(this.ids::add); } - @Getter(AccessLevel.PACKAGE) - private static final Map TOA_NPC_MAPPING; - - static - { - TOA_NPC_MAPPING = new HashMap<>(); - for (ToANPCs value : ToANPCs.values()) - { - for (Integer id : value.ids) - { - TOA_NPC_MAPPING.put(id, value.npcWithScalingBonus); - } - } - } - - enum ToANPCStats + @Getter + enum ToANPCStats { AKKHA(new CoreBoss(40, 100, 140, 80, 100, 100, 115, 30, 60, 120, 120, 10, 60)), BABA(new CoreBoss(38, 150, 160, 80, 100, 0, 0, 26, 80, 160, 240, 280, 200)), @@ -79,11 +68,8 @@ enum ToANPCStats E_WARDEN_544(new RoomLevelInvariant.RoomLevelInvariant10x(88, 150, 150, 150, 150, 150, 0, 40, 40, 40, 20, 20, 20)), //E_WARDEN_544_ENRAGED(new RoomLevelInvariant.RoomLevelInvariant10x(88, 150, 150, 180, 150, 150, 0, 40, 40, 40, 20, 20, 20)), // Maps to the same ids but also leads to same xp bonus AKKHA_SHADOW(new RoomLevelInvariant.RoomLevelInvariant5x(14, 100, 140, 30, 100, 100, 115, 30, 60, 120, 120, 10, 60)), - OBELISK(new RoomLevelInvariant.RoomLevelInvariant10x(26, 200, 150, 100, 100, 100, 0, 0, 70, 70, 70, 50, 60)), - ; - @Getter + OBELISK(new RoomLevelInvariant.RoomLevelInvariant10x(26, 200, 150, 100, 100, 100, 0, 0, 70, 70, 70, 50, 60)); private final ToANPC toANPC; - ToANPCStats(ToANPC toANPC) { this.toANPC = toANPC; diff --git a/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/tob/ToB.java b/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/tob/ToB.java index beae17b..7033bc9 100644 --- a/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/tob/ToB.java +++ b/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/tob/ToB.java @@ -5,17 +5,33 @@ import net.runelite.client.util.Text; import javax.inject.Inject; +import java.util.HashMap; +import java.util.Map; public class ToB implements IModifierBoss { private final Client client; + private static final Map TOB_NPC_MAPPING; + @Inject public ToB(Client client) { this.client = client; } + static + { + TOB_NPC_MAPPING = new HashMap<>(); + for (ToBNPCs value : ToBNPCs.values()) + { + for (Integer id : value.getIds()) + { + TOB_NPC_MAPPING.put(id, value.getNpcWithScalingBonus()); + } + } + } + private int getToBPartySize() { int count = 0; @@ -37,7 +53,7 @@ private int getToBPartySize() @Override public boolean containsId(int npcId) { - return ToBNPCs.getTOB_NPC_MAPPING().containsKey(npcId); + return TOB_NPC_MAPPING.containsKey(npcId); } @Override @@ -49,6 +65,6 @@ public double getModifier(int npcId) } int partySize = getToBPartySize(); - return ToBNPCs.getTOB_NPC_MAPPING().get(npcId).calculateModifier(partySize); + return TOB_NPC_MAPPING.get(npcId).calculateModifier(partySize); } } diff --git a/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/tob/ToBNPCs.java b/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/tob/ToBNPCs.java index 2482534..0dadf63 100644 --- a/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/tob/ToBNPCs.java +++ b/src/main/java/com/xpdrops/predictedhit/npcswithscalingbonus/tob/ToBNPCs.java @@ -35,9 +35,11 @@ public enum ToBNPCs SOTETSEG_HM( new ToBNPC(1.4, 1.4, 1.4 ), NpcID.TOB_SOTETSEG_COMBAT_HARD), VERZIK_P1_HM( new ToBNPC(1.05, 1.05, 1.05 ), NpcID.VERZIK_PHASE1_HARD, NpcID.VERZIK_PHASE1_TO2_TRANSITION_HARD), VERZIK_P2_HM( new ToBNPC(1.30, 1.30, 1.30 ), NpcID.VERZIK_PHASE2_HARD, NpcID.VERZIK_PHASE2_TO3_TRANSITION_HARD), - VERZIK_P3_HM( new ToBNPC(1.575, 1.575, 1.575 ), NpcID.VERZIK_PHASE3_HARD, NpcID.VERZIK_DEATH_BAT_HARD), - ; + VERZIK_P3_HM( new ToBNPC(1.575, 1.575, 1.575 ), NpcID.VERZIK_PHASE3_HARD, NpcID.VERZIK_DEATH_BAT_HARD); + + @Getter(AccessLevel.PACKAGE) private final HashSet ids; + @Getter(AccessLevel.PACKAGE) private final ToBNPC npcWithScalingBonus; ToBNPCs(ToBNPC npcWithScalingBonus, int ... ids) { @@ -45,19 +47,4 @@ public enum ToBNPCs this.ids = new HashSet<>(); Arrays.stream(ids).forEach(this.ids::add); } - - @Getter(AccessLevel.PACKAGE) - private static final Map TOB_NPC_MAPPING; - - static - { - TOB_NPC_MAPPING = new HashMap<>(); - for (ToBNPCs value : ToBNPCs.values()) - { - for (Integer id : value.ids) - { - TOB_NPC_MAPPING.put(id, value.npcWithScalingBonus); - } - } - } } \ No newline at end of file