diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java index 43e03dde4a..f1daefab90 100644 --- a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java +++ b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java @@ -447,7 +447,7 @@ public enum WidgetInfo PVP_CONTAINER(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.PVP_WIDGET_CONTAINER), PVP_SKULL_CONTAINER(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.SKULL_CONTAINER), PVP_SKULL(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.SKULL), - PVP_WILDERNESS_LEVEL(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.ATTACK_RANGE), + PVP_WILDERNESS_LEVEL(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.WILDERNESS_LEVEL), PVP_BOUNTY_HUNTER_INFO(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.BOUNTY_HUNTER_INFO), PVP_BOUNTY_HUNTER_STATS(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.BOUNTY_HUNTER_STATS), PVP_KILLDEATH_COUNTER(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.KILLDEATH_RATIO), diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/combatlevel/CombatLevelConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/combatlevel/CombatLevelConfig.java index cf910192f2..cc82bcea65 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/combatlevel/CombatLevelConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/combatlevel/CombatLevelConfig.java @@ -40,4 +40,14 @@ public interface CombatLevelConfig extends Config { return true; } + + @ConfigItem( + keyName = "wildernessAttackLevelRange", + name = "Show level range in wilderness", + description = "Displays a PVP-world-like attack level range in the wilderness" + ) + default boolean wildernessAttackLevelRange() + { + return true; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/combatlevel/CombatLevelPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/combatlevel/CombatLevelPlugin.java index a72e0bf2df..bbde15c2e0 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/combatlevel/CombatLevelPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/combatlevel/CombatLevelPlugin.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2017, Devin French + * Copyright (c) 2019, Jordan Atwood * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,14 +27,20 @@ package net.runelite.client.plugins.combatlevel; import com.google.inject.Provides; import java.text.DecimalFormat; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.inject.Inject; import net.runelite.api.Client; import net.runelite.api.Experience; import net.runelite.api.GameState; import net.runelite.api.Skill; +import net.runelite.api.WorldType; +import net.runelite.api.events.ConfigChanged; import net.runelite.api.events.GameTick; +import net.runelite.api.events.ScriptCallbackEvent; import net.runelite.api.widgets.Widget; import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.callback.ClientThread; import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.plugins.Plugin; @@ -42,15 +49,31 @@ import net.runelite.client.ui.overlay.OverlayManager; @PluginDescriptor( name = "Combat Level", - description = "Show a more accurate combat level in Combat Options panel" + description = "Show a more accurate combat level in Combat Options panel and other combat level functions", + tags = {"wilderness", "attack", "range"} ) public class CombatLevelPlugin extends Plugin { - private final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#.###"); + private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#.###"); + private static final String CONFIG_GROUP = "combatlevel"; + private static final String ATTACK_RANGE_CONFIG_KEY = "wildernessAttackLevelRange"; + private static final Pattern WILDERNESS_LEVEL_PATTERN = Pattern.compile("^Level: (\\d+)$"); + private static final int SKULL_CONTAINER_ADJUSTED_ORIGINAL_Y = 6; + private static final int WILDERNESS_LEVEL_TEXT_ADJUSTED_ORIGINAL_Y = 3; + private static final int MIN_COMBAT_LEVEL = 3; + + private int originalWildernessLevelTextPosition = -1; + private int originalSkullContainerPosition = -1; @Inject private Client client; + @Inject + private ClientThread clientThread; + + @Inject + private CombatLevelConfig config; + @Inject private CombatLevelOverlay overlay; @@ -67,6 +90,11 @@ public class CombatLevelPlugin extends Plugin protected void startUp() throws Exception { overlayManager.add(overlay); + + if (config.wildernessAttackLevelRange()) + { + appendAttackLevelRangeText(); + } } @Override @@ -84,6 +112,8 @@ public class CombatLevelPlugin extends Plugin combatLevelWidget.setText(widgetText.substring(0, widgetText.indexOf("."))); } } + + shutDownAttackLevelRange(); } @Subscribe @@ -112,4 +142,103 @@ public class CombatLevelPlugin extends Plugin combatLevelWidget.setText("Combat Lvl: " + DECIMAL_FORMAT.format(combatLevelPrecise)); } + + @Subscribe + public void onConfigChanged(ConfigChanged event) + { + if (!CONFIG_GROUP.equals(event.getGroup()) || !ATTACK_RANGE_CONFIG_KEY.equals(event.getKey())) + { + return; + } + + if (config.wildernessAttackLevelRange()) + { + appendAttackLevelRangeText(); + } + else + { + shutDownAttackLevelRange(); + } + } + + @Subscribe + public void onScriptCallbackEvent(ScriptCallbackEvent event) + { + if (config.wildernessAttackLevelRange() + && "wildernessWidgetTextSet".equals(event.getEventName())) + { + appendAttackLevelRangeText(); + } + } + + private void appendAttackLevelRangeText() + { + final Widget wildernessLevelWidget = client.getWidget(WidgetInfo.PVP_WILDERNESS_LEVEL); + if (wildernessLevelWidget == null) + { + return; + } + + final String wildernessLevelText = wildernessLevelWidget.getText(); + final Matcher m = WILDERNESS_LEVEL_PATTERN.matcher(wildernessLevelText); + if (!m.matches() + || WorldType.isPvpWorld(client.getWorldType())) + { + return; + } + + final Widget skullContainer = client.getWidget(WidgetInfo.PVP_SKULL_CONTAINER); + if (originalWildernessLevelTextPosition == -1) + { + originalWildernessLevelTextPosition = wildernessLevelWidget.getOriginalY(); + } + if (originalSkullContainerPosition == -1) + { + originalSkullContainerPosition = skullContainer.getRelativeY(); + } + + final int wildernessLevel = Integer.parseInt(m.group(1)); + final int combatLevel = client.getLocalPlayer().getCombatLevel(); + + wildernessLevelWidget.setText(wildernessLevelText + "
" + combatAttackRange(combatLevel, wildernessLevel)); + wildernessLevelWidget.setOriginalY(WILDERNESS_LEVEL_TEXT_ADJUSTED_ORIGINAL_Y); + skullContainer.setOriginalY(SKULL_CONTAINER_ADJUSTED_ORIGINAL_Y); + + clientThread.invoke(wildernessLevelWidget::revalidate); + clientThread.invoke(skullContainer::revalidate); + } + + private void shutDownAttackLevelRange() + { + if (WorldType.isPvpWorld(client.getWorldType())) + { + return; + } + + final Widget wildernessLevelWidget = client.getWidget(WidgetInfo.PVP_WILDERNESS_LEVEL); + if (wildernessLevelWidget != null) + { + String wildernessLevelText = wildernessLevelWidget.getText(); + if (wildernessLevelText.contains("
")) + { + wildernessLevelWidget.setText(wildernessLevelText.substring(0, wildernessLevelText.indexOf("
"))); + } + wildernessLevelWidget.setOriginalY(originalWildernessLevelTextPosition); + clientThread.invoke(wildernessLevelWidget::revalidate); + } + originalWildernessLevelTextPosition = -1; + + final Widget skullContainer = client.getWidget(WidgetInfo.PVP_SKULL_CONTAINER); + if (skullContainer != null) + { + skullContainer.setOriginalY(originalSkullContainerPosition); + clientThread.invoke(skullContainer::revalidate); + } + originalSkullContainerPosition = -1; + } + + private static String combatAttackRange(final int combatLevel, final int wildernessLevel) + { + return Math.max(MIN_COMBAT_LEVEL, combatLevel - wildernessLevel) + "-" + Math.min(Experience.MAX_COMBAT_LEVEL, combatLevel + wildernessLevel); + } } diff --git a/runelite-client/src/main/scripts/PvpWidgetBuilder.hash b/runelite-client/src/main/scripts/PvpWidgetBuilder.hash new file mode 100644 index 0000000000..144ac0aea6 --- /dev/null +++ b/runelite-client/src/main/scripts/PvpWidgetBuilder.hash @@ -0,0 +1 @@ +08461B2A942D4D792EEB9D9BCCEB9B11256AD8B217B1EAF1BDBA71314F816D6F \ No newline at end of file diff --git a/runelite-client/src/main/scripts/PvpWidgetBuilder.rs2asm b/runelite-client/src/main/scripts/PvpWidgetBuilder.rs2asm new file mode 100644 index 0000000000..ba8bf2ec2f --- /dev/null +++ b/runelite-client/src/main/scripts/PvpWidgetBuilder.rs2asm @@ -0,0 +1,119 @@ +.id 388 +.int_stack_count 1 +.string_stack_count 0 +.int_var_count 3 +.string_var_count 0 + invoke 384 + istore 1 + invoke 1138 + istore 2 + iload 2 + iconst 1 + if_icmpeq LABEL8 + jump LABEL74 +LABEL8: + get_varp 1676 + iconst 4 + if_icmpgt LABEL12 + jump LABEL31 +LABEL12: + iload 1 + iconst 0 + if_icmpgt LABEL16 + jump LABEL27 +LABEL16: + get_varbit 5954 + iconst 1 + if_icmpeq LABEL20 + jump LABEL27 +LABEL20: + sconst "Level: " + iload 1 + tostring + join_string 2 + iload 0 + if_settext + jump LABEL30 +LABEL27: + sconst "Deadman" + iload 0 + if_settext +LABEL30: + jump LABEL73 +LABEL31: + get_varbit 4965 + iconst 0 + if_icmpgt LABEL35 + jump LABEL39 +LABEL35: + sconst "Protection" + iload 0 + if_settext + jump LABEL73 +LABEL39: + iload 1 + iconst 0 + if_icmpgt LABEL43 + jump LABEL54 +LABEL43: + get_varbit 5954 + iconst 1 + if_icmpeq LABEL47 + jump LABEL54 +LABEL47: + sconst "Level: " + iload 1 + tostring + join_string 2 + iload 0 + if_settext + jump LABEL73 +LABEL54: + get_varc_int 78 + iconst 1 + if_icmpeq LABEL58 + jump LABEL62 +LABEL58: + sconst "Guarded" + iload 0 + if_settext + jump LABEL73 +LABEL62: + get_varc_int 78 + iconst 2 + if_icmpeq LABEL66 + jump LABEL70 +LABEL66: + sconst "No PvP" + iload 0 + if_settext + jump LABEL73 +LABEL70: + sconst "Deadman" + iload 0 + if_settext +LABEL73: + jump LABEL88 +LABEL74: + iload 1 + iconst 0 + if_icmpgt LABEL78 + jump LABEL85 +LABEL78: + sconst "Level: " + iload 1 + tostring + join_string 2 + iload 0 + if_settext + jump LABEL88 +LABEL85: + sconst "" + iload 0 + if_settext +LABEL88: + iload 1 + invoke 387 + sconst "wildernessWidgetTextSet" ; set callback name + runelite_callback ; invoke callback + return