From eb9a2082b786923841b479c5272d0177fbcb9a96 Mon Sep 17 00:00:00 2001
From: James <38226001+james-munson@users.noreply.github.com>
Date: Mon, 22 Apr 2019 16:00:03 -0700
Subject: [PATCH 1/3] Rebrand to runeliteplus (#58)
* Rebrand to runeliteplus
---
README.md | 4 ++--
.../main/java/net/runelite/client/RuneLite.java | 2 +-
.../java/net/runelite/client/flexo/Flexo.java | 2 +-
.../runelite/client/plugins/info/InfoPanel.java | 15 ++++++++-------
.../plugins/pluginsorter/PluginSorterConfig.java | 2 +-
.../plugins/pluginsorter/PluginSorterPlugin.java | 2 +-
.../java/net/runelite/client/rs/ClientLoader.java | 8 ++++----
.../client/rs/bytecode/ByteCodePatcher.java | 14 +++++++-------
.../rs/bytecode/transformers/ErrorTransform.java | 4 ++--
.../runelite/client/ui/RuneLiteSplashScreen.java | 2 +-
10 files changed, 28 insertions(+), 27 deletions(-)
diff --git a/README.md b/README.md
index 17a5f83847..a7355d2681 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
-
+
[](https://discord.gg/HN5gf3m) [](https://travis-ci.org/runelite-extended/runelite)
-RuneLit is a fork of [RuneLite](https://github.com/runelite/runelite) that provides more functionality and less restrictions while staying open source. This is meant to directly compete with 3rd party RL clients that are trying to sell their code.
+RuneLitePlus is a fork of [RuneLite](https://github.com/runelite/runelite) that provides more functionality and less restrictions while staying open source. This is meant to directly compete with 3rd party RL clients that are trying to sell their code.
# Notable Features:
diff --git a/runelite-client/src/main/java/net/runelite/client/RuneLite.java b/runelite-client/src/main/java/net/runelite/client/RuneLite.java
index 4c8cefbdac..9aa7760168 100644
--- a/runelite-client/src/main/java/net/runelite/client/RuneLite.java
+++ b/runelite-client/src/main/java/net/runelite/client/RuneLite.java
@@ -213,7 +213,7 @@ public class RuneLite
if (options.has("flexo"))
{
- System.out.println("[RuneLit] Flexo config enabled");
+ System.out.println("[RuneLitePlus] Flexo config enabled");
ConfigPanel.flexoConfigEnabled = true;
}
diff --git a/runelite-client/src/main/java/net/runelite/client/flexo/Flexo.java b/runelite-client/src/main/java/net/runelite/client/flexo/Flexo.java
index 298621b87e..77a91b2fad 100644
--- a/runelite-client/src/main/java/net/runelite/client/flexo/Flexo.java
+++ b/runelite-client/src/main/java/net/runelite/client/flexo/Flexo.java
@@ -24,7 +24,7 @@
*/
/*
-Modified java.awt.Robot for use with RuneLit. Hopefully we can make it stand far apart.
+Modified java.awt.Robot for use with RuneLitePlus. Hopefully we can make it stand far apart.
Uses
https://github.com/JoonasVali/NaturalMouseMotion
for mouse motion.
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/info/InfoPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/info/InfoPanel.java
index f9dc12f4e7..48e1ead428 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/info/InfoPanel.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/info/InfoPanel.java
@@ -45,6 +45,7 @@ import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.event.HyperlinkEvent;
import net.runelite.api.Client;
+import net.runelite.client.RuneLite;
import net.runelite.client.events.SessionClose;
import net.runelite.client.events.SessionOpen;
import net.runelite.client.RuneLiteProperties;
@@ -176,10 +177,10 @@ public class InfoPanel extends PluginPanel
}
});
- actionsContainer.add(buildLinkPanel(GITHUB_ICON, "Report an issue or", "make a suggestion", runeLiteProperties.getGithubLink()));
- actionsContainer.add(buildLinkPanel(DISCORD_ICON, "Talk to us on our", "discord server", runeLiteProperties.getDiscordInvite()));
- actionsContainer.add(buildLinkPanel(PATREON_ICON, "Become a patron to", "help support RuneLite", runeLiteProperties.getPatreonLink()));
- actionsContainer.add(buildLinkPanel(WIKI_ICON, "Information about", "RuneLite and plugins", runeLiteProperties.getWikiLink()));
+ //actionsContainer.add(buildLinkPanel(GITHUB_ICON, "Report an issue or", "make a suggestion", runeLiteProperties.getGithubLink()));
+ //actionsContainer.add(buildLinkPanel(DISCORD_ICON, "Talk to us on our", "discord server", runeLiteProperties.getDiscordInvite()));
+ //actionsContainer.add(buildLinkPanel(PATREON_ICON, "Become a patron to", "help support RuneLite", runeLiteProperties.getPatreonLink()));
+ //actionsContainer.add(buildLinkPanel(WIKI_ICON, "Information about", "RuneLite and plugins", runeLiteProperties.getWikiLink()));
add(versionPanel, BorderLayout.NORTH);
add(actionsContainer, BorderLayout.CENTER);
@@ -285,9 +286,9 @@ public class InfoPanel extends PluginPanel
}
else
{
- emailLabel.setContentType("text/html");
- emailLabel.setText("Login to sync settings to the cloud.");
- loggedLabel.setText("Not logged in");
+ //emailLabel.setContentType("text/html");
+ //emailLabel.setText("Login to sync settings to the cloud.");
+ //loggedLabel.setText("Not logged in");
actionsContainer.remove(syncPanel);
}
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/pluginsorter/PluginSorterConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/pluginsorter/PluginSorterConfig.java
index 2477c8070a..4e1be32ead 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/pluginsorter/PluginSorterConfig.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/pluginsorter/PluginSorterConfig.java
@@ -6,7 +6,7 @@ import net.runelite.client.config.ConfigItem;
import java.awt.*;
-@ConfigGroup("runelit")
+@ConfigGroup("pluginsorter")
public interface PluginSorterConfig extends Config {
Color rlDefault = new Color(250, 155, 23);
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/pluginsorter/PluginSorterPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/pluginsorter/PluginSorterPlugin.java
index c5d48b0d82..b108f74340 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/pluginsorter/PluginSorterPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/pluginsorter/PluginSorterPlugin.java
@@ -22,7 +22,7 @@ import java.util.List;
@PluginDescriptor(
name = "Plugin Organizer",
description = "Hides and colors 3rd party plugins for better control",
- tags = {"Fuck RL","Abex is shit :p"},
+ tags = {"plugins","organizer"},
type = PluginType.PLUGIN_ORGANIZER
)
public class PluginSorterPlugin extends Plugin {
diff --git a/runelite-client/src/main/java/net/runelite/client/rs/ClientLoader.java b/runelite-client/src/main/java/net/runelite/client/rs/ClientLoader.java
index 696acb15f9..30c143a33e 100644
--- a/runelite-client/src/main/java/net/runelite/client/rs/ClientLoader.java
+++ b/runelite-client/src/main/java/net/runelite/client/rs/ClientLoader.java
@@ -183,7 +183,7 @@ public class ClientLoader
if (!file.getValue().equals(ourHash))
{
if (hijackedClientFile.exists()) {
- Logger.getAnonymousLogger().warning("[RuneLit] Hash checking / Client patching skipped due to hijacked client.");
+ Logger.getAnonymousLogger().warning("[RuneLitePlus] Hash checking / Client patching skipped due to hijacked client.");
updateCheckMode = VANILLA;
break;
} else {
@@ -239,17 +239,17 @@ public class ClientLoader
hooks.projectileClass.equals("") ||
hooks.actorClass.equals("") ||
hooks.playerClass.equals("")) {
- System.out.println("[RuneLit] Bad hooks, re-scraping.");
+ System.out.println("[RuneLitePlus] Bad hooks, re-scraping.");
ByteCodePatcher.clientInstance = initHookScrape(ByteCodeUtils.injectedClientFile.getPath());
ByteCodePatcher.findHooks(injectedClientFile.getPath());
} else {
ByteCodePatcher.clientInstance = hooks.clientInstance;
ByteCodePatcher.applyHooks(ByteCodeUtils.injectedClientFile, hooks);
- System.out.println("[RuneLit] Loaded hooks");
+ System.out.println("[RuneLitePlus] Loaded hooks");
}
} else {
- System.out.println("[RuneLit] Hooks file not found, scraping hooks.");
+ System.out.println("[RuneLitePlus] Hooks file not found, scraping hooks.");
ByteCodePatcher.clientInstance = initHookScrape(ByteCodeUtils.injectedClientFile.getPath());
ByteCodePatcher.hooks.protectedStuff = preotectedStuffs;
ByteCodePatcher.findHooks(injectedClientFile.getPath());
diff --git a/runelite-client/src/main/java/net/runelite/client/rs/bytecode/ByteCodePatcher.java b/runelite-client/src/main/java/net/runelite/client/rs/bytecode/ByteCodePatcher.java
index abd4a970dc..c71005dd98 100644
--- a/runelite-client/src/main/java/net/runelite/client/rs/bytecode/ByteCodePatcher.java
+++ b/runelite-client/src/main/java/net/runelite/client/rs/bytecode/ByteCodePatcher.java
@@ -127,7 +127,7 @@ public class ByteCodePatcher {
Method method = current.getDeclaredMethod("setCombatInfo", new Class[] { int.class, int.class, int.class, int.class, int.class, int.class });
if (method!=null) {
hooks.actorClass = current.getName();
- System.out.println("[RuneLit] Transforming Actor at class: "+current.getName());
+ System.out.println("[RuneLitePlus] Transforming Actor at class: "+current.getName());
ActorTransform at = new ActorTransform();
at.modify(current);
}
@@ -139,7 +139,7 @@ public class ByteCodePatcher {
}
public static void transformActor(Class actor) {
- System.out.println("[RuneLit] Transforming Actor at class: "+actor.getName());
+ System.out.println("[RuneLitePlus] Transforming Actor at class: "+actor.getName());
ActorTransform at = new ActorTransform();
at.modify(actor);
}
@@ -149,7 +149,7 @@ public class ByteCodePatcher {
Method method = current.getDeclaredMethod("projectileMoved", new Class[] { int.class, int.class, int.class, int.class});
if (method!=null) {
hooks.projectileClass = current.getName();
- System.out.println("[RuneLit] Transforming Projectile at class: "+current.getName());
+ System.out.println("[RuneLitePlus] Transforming Projectile at class: "+current.getName());
ProjectileTransform pt = new ProjectileTransform();
pt.modify(current);
}
@@ -161,7 +161,7 @@ public class ByteCodePatcher {
}
public static void transformProjectile(Class projectile) {
- System.out.println("[RuneLit] Transforming Projectile at class: "+projectile.getName());
+ System.out.println("[RuneLitePlus] Transforming Projectile at class: "+projectile.getName());
ProjectileTransform pt = new ProjectileTransform();
pt.modify(projectile);
}
@@ -171,7 +171,7 @@ public class ByteCodePatcher {
Method method = current.getDeclaredMethod("getSkullIcon");
if (method!=null) {
hooks.playerClass = current.getName();
- System.out.println("[RuneLit] Transforming Player at class: "+current.getName());
+ System.out.println("[RuneLitePlus] Transforming Player at class: "+current.getName());
PlayerTransform pt = new PlayerTransform();
pt.modify(current);
}
@@ -183,13 +183,13 @@ public class ByteCodePatcher {
}
public static void transformPlayer(Class player) {
- System.out.println("[RuneLit] Transforming Player at class: "+player.getName());
+ System.out.println("[RuneLitePlus] Transforming Player at class: "+player.getName());
PlayerTransform pt = new PlayerTransform();
pt.modify(player);
}
public static void transformBlackjack(Class clazz) {
- System.out.println("[RuneLit] Transforming Blackjack at class: "+clazz.getName());
+ System.out.println("[RuneLitePlus] Transforming Blackjack at class: "+clazz.getName());
ClientTransform bt = new ClientTransform();
bt.modify(clazz);
}
diff --git a/runelite-client/src/main/java/net/runelite/client/rs/bytecode/transformers/ErrorTransform.java b/runelite-client/src/main/java/net/runelite/client/rs/bytecode/transformers/ErrorTransform.java
index 89a3075970..573f7d954c 100644
--- a/runelite-client/src/main/java/net/runelite/client/rs/bytecode/transformers/ErrorTransform.java
+++ b/runelite-client/src/main/java/net/runelite/client/rs/bytecode/transformers/ErrorTransform.java
@@ -17,13 +17,13 @@ public class ErrorTransform implements Transform {
@Override
public void modify(Class clazz) {
try {
- System.out.println("[RuneLit] Transforming error method at class: "+ERROR_INSTANCE_CLASS);
+ System.out.println("[RuneLitePlus] Transforming error method at class: "+ERROR_INSTANCE_CLASS);
ct = ByteCodePatcher.classPool.get(ERROR_INSTANCE_CLASS);
CtMethod error = ct.getDeclaredMethod(ERROR_INSTANCE_METHOD);
ct.removeMethod(error);
error = CtMethod.make("public static void a(String string, Throwable throwable, byte by) {"+
" throwable.printStackTrace();"+
- " System.out.println(\"[RuneLit] Prevented preceeding stack trace from being sent to Jagex\");"+
+ " System.out.println(\"[RuneLitePlus] Prevented preceeding stack trace from being sent to Jagex\");"+
" }", ct);
ct.addMethod(error);
ByteCodePatcher.modifiedClasses.add(ct);
diff --git a/runelite-client/src/main/java/net/runelite/client/ui/RuneLiteSplashScreen.java b/runelite-client/src/main/java/net/runelite/client/ui/RuneLiteSplashScreen.java
index 211997cdf4..08bd88afba 100644
--- a/runelite-client/src/main/java/net/runelite/client/ui/RuneLiteSplashScreen.java
+++ b/runelite-client/src/main/java/net/runelite/client/ui/RuneLiteSplashScreen.java
@@ -123,7 +123,7 @@ public class RuneLiteSplashScreen
panel.add(version, versionConstraints);
// version
- final JLabel litVersion = new JLabel("Lit Version : PRE-" + RuneLite.RUNELIT_VERSION);
+ final JLabel litVersion = new JLabel("Plus Version : PRE-" + RuneLite.RUNELIT_VERSION);
litVersion.setForeground(Color.GREEN);
litVersion.setFont(FontManager.getRunescapeSmallFont());
litVersion.setForeground(litVersion.getForeground().darker());
From c64b2762fc54562d4585d697fe0ba9ba9fdb3931 Mon Sep 17 00:00:00 2001
From: sdburns1998 <49877861+sdburns1998@users.noreply.github.com>
Date: Tue, 23 Apr 2019 01:14:55 +0200
Subject: [PATCH 2/3] Remove log spam (#60)
---
.../plugins/suppliestracker/SuppliesTrackerPlugin.java | 10 ----------
1 file changed, 10 deletions(-)
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/suppliestracker/SuppliesTrackerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/suppliestracker/SuppliesTrackerPlugin.java
index 6efab67061..0c6371c64e 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/suppliestracker/SuppliesTrackerPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/suppliestracker/SuppliesTrackerPlugin.java
@@ -357,11 +357,6 @@ public class SuppliesTrackerPlugin extends Plugin
{
ItemContainer itemContainer = itemContainerChanged.getItemContainer();
- for (MenuAction action : actionStack)
- {
- System.out.println(action.getType());
- }
-
if (itemContainer == client.getItemContainer(InventoryID.INVENTORY) && old != null && !actionStack.isEmpty())
{
while (!actionStack.isEmpty())
@@ -487,11 +482,6 @@ public class SuppliesTrackerPlugin extends Plugin
@Subscribe
public void onMenuOptionClicked(final MenuOptionClicked event)
{
- System.out.println(event.getMenuAction().getId());
- System.out.println(event.getActionParam());
- System.out.println(event.getMenuOption());
- System.out.println(event.getMenuTarget());
-
// Uses stacks to push/pop for tick eating
// Create pattern to find eat/drink at beginning
Pattern eatPattern = Pattern.compile(EAT_PATTERN);
From e6429eec22a1ac0b01cc9401ea190834b1fa290c Mon Sep 17 00:00:00 2001
From: Kyleeld <48519776+Kyleeld@users.noreply.github.com>
Date: Tue, 23 Apr 2019 00:17:20 +0100
Subject: [PATCH 3/3] add specbar (#57)
* Create SpecBarPlugin.java
* Update SpecBarPlugin.java
* Update SpecBarPlugin.java
included imports
* Update WidgetInfo.java
COMBAT_SPECIAL_ATTACK(WidgetID.COMBAT_GROUP_ID, WidgetID.Combat.SPECIAL_ATTACK_BAR)
* Update WidgetID.java
static final int SPECIAL_ATTACK_BAR = 34
* easyscape
current release of easyscape is broken, this one is confirmed working correctly.
---
.../net/runelite/api/widgets/WidgetID.java | 1 +
.../net/runelite/api/widgets/WidgetInfo.java | 1 +
.../plugins/easyscape/DuelingRingMode.java | 18 +
.../plugins/easyscape/EasyscapePlugin.java | 368 ++++++++++++++++++
.../easyscape/EasyscapePluginConfig.java | 268 +++++++++++++
.../client/plugins/easyscape/EssenceMode.java | 17 +
.../plugins/easyscape/GamesNecklaceMode.java | 20 +
.../client/plugins/easyscape/GloryMode.java | 19 +
.../client/plugins/easyscape/Swapper.java | 36 ++
.../plugins/easyscape/WealthRingMode.java | 19 +
.../client/plugins/specbar/SpecBarPlugin.java | 75 ++++
11 files changed, 842 insertions(+)
create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/easyscape/DuelingRingMode.java
create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/easyscape/EasyscapePlugin.java
create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/easyscape/EasyscapePluginConfig.java
create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/easyscape/EssenceMode.java
create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/easyscape/GamesNecklaceMode.java
create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/easyscape/GloryMode.java
create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/easyscape/Swapper.java
create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/easyscape/WealthRingMode.java
create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/specbar/SpecBarPlugin.java
diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java
index 360f1a556c..b532865c86 100644
--- a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java
+++ b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java
@@ -547,6 +547,7 @@ public class WidgetID
static final int SPELL_ICON = 27;
static final int SPELL_TEXT = 28;
static final int AUTO_RETALIATE = 29;
+ static final int SPECIAL_ATTACK_BAR = 34;
}
static class VolcanicMine
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 9872efeb23..16b2002bc2 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
@@ -319,6 +319,7 @@ public enum WidgetInfo
COMBAT_SPELL_ICON(WidgetID.COMBAT_GROUP_ID, WidgetID.Combat.SPELL_ICON),
COMBAT_SPELL_TEXT(WidgetID.COMBAT_GROUP_ID, WidgetID.Combat.SPELL_TEXT),
COMBAT_AUTO_RETALIATE(WidgetID.COMBAT_GROUP_ID, WidgetID.Combat.AUTO_RETALIATE),
+ COMBAT_SPECIAL_ATTACK(WidgetID.COMBAT_GROUP_ID, WidgetID.Combat.SPECIAL_ATTACK_BAR),
DIALOG_OPTION(WidgetID.DIALOG_OPTION_GROUP_ID, 0),
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/DuelingRingMode.java b/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/DuelingRingMode.java
new file mode 100644
index 0000000000..0e06ddd4da
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/DuelingRingMode.java
@@ -0,0 +1,18 @@
+package net.runelite.client.plugins.easyscape;
+
+public enum DuelingRingMode {
+ DUEL_ARENA("Duel Arena"),
+ CASTLE_WARS("Castle Wars"),
+ CLAN_WARS("Clan Wars");
+
+ private final String name;
+
+ DuelingRingMode(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/EasyscapePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/EasyscapePlugin.java
new file mode 100644
index 0000000000..27e56ba62f
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/EasyscapePlugin.java
@@ -0,0 +1,368 @@
+package net.runelite.client.plugins.easyscape;
+
+import com.google.inject.Provides;
+import lombok.extern.slf4j.Slf4j;
+import net.runelite.api.*;
+import net.runelite.api.coords.WorldPoint;
+import net.runelite.api.events.MenuEntryAdded;
+import net.runelite.api.widgets.Widget;
+import net.runelite.api.widgets.WidgetInfo;
+import net.runelite.client.config.ConfigManager;
+import net.runelite.client.eventbus.Subscribe;
+import net.runelite.client.plugins.Plugin;
+import net.runelite.client.plugins.PluginDescriptor;
+import net.runelite.client.plugins.PluginManager;
+import net.runelite.client.plugins.PluginType;
+import net.runelite.client.util.Text;
+import org.apache.commons.lang3.ArrayUtils;
+
+import javax.inject.Inject;
+
+import java.util.*;
+
+import static net.runelite.api.MenuAction.MENU_ACTION_DEPRIORITIZE_OFFSET;
+import static net.runelite.api.MenuAction.WALK;
+
+
+@PluginDescriptor(
+ name = "!Easyscape",
+ description = "Easyscape.",
+ tags = {"Easyscape"},
+ enabledByDefault = false,
+ type = PluginType.UTILITY
+)
+
+@Slf4j
+public class EasyscapePlugin extends Plugin {
+
+ private static final int PURO_PURO_REGION_ID = 10307;
+ private static final int HOUSE_REGION_ID = 7513;
+
+ private Set swapping;
+ private MenuEntry[] entries;
+
+ @Inject
+ private Client client;
+
+ @Inject
+ private EasyscapePluginConfig config;
+
+ @Provides
+ EasyscapePluginConfig provideConfig(ConfigManager configManager) {
+ return configManager.getConfig(EasyscapePluginConfig.class);
+ }
+
+ @Override
+ public void startUp() {
+ log.debug("Easyscape Started.");
+ swapping = new HashSet<>();
+ }
+
+ @Override
+ public void shutDown() {
+ log.debug("Easyscape Stopped.");
+ }
+
+ @Subscribe
+ public void onMenuEntryAdded(MenuEntryAdded event) {
+
+ if (client.getGameState() != GameState.LOGGED_IN) {
+ return;
+ }
+
+ Widget loginScreenOne = client.getWidget(WidgetInfo.LOGIN_CLICK_TO_PLAY_SCREEN);
+ Widget loginScreenTwo = client.getWidget(WidgetInfo.LOGIN_CLICK_TO_PLAY_SCREEN_MESSAGE_OF_THE_DAY);
+
+ if (loginScreenOne != null || loginScreenTwo != null) {
+ return;
+ }
+
+ final String option = Text.removeTags(event.getOption()).toLowerCase();
+ final String target = Text.removeTags(event.getTarget()).toLowerCase();
+
+ entries = client.getMenuEntries();
+
+ if (config.getRemoveExamine()) {
+ for (int i = entries.length - 1; i >= 0; i--) {
+ if (entries[i].getOption().equals("Examine")) {
+ entries = ArrayUtils.remove(entries, i);
+ i--;
+ }
+ }
+ client.setMenuEntries(entries);
+ }
+
+ if (config.getRemoveObjects() && !config.getRemovedObjects().equals("")) {
+ for (String removed : config.getRemovedObjects().split(",")) {
+ removed = removed.trim();
+ if (target.contains("->")) {
+ String trimmed = target.split("->")[1].trim();
+ if (trimmed.length() >= removed.length() && trimmed.substring(0, removed.length()).equalsIgnoreCase(removed)) {
+ delete(event.getIdentifier());
+ break;
+ }
+ }
+ if (target.length() >= removed.length() && target.substring(0, removed.length()).equalsIgnoreCase(removed)) {
+ delete(event.getIdentifier());
+ break;
+ }
+ }
+ }
+
+ if (config.getSwapPuro() && isPuroPuro()) {
+ if (event.getType() == WALK.getId()) {
+ MenuEntry menuEntry = entries[entries.length - 1];
+ menuEntry.setType(MenuAction.WALK.getId() + MENU_ACTION_DEPRIORITIZE_OFFSET);
+ client.setMenuEntries(entries);
+ }
+ else if (option.equalsIgnoreCase("examine")) {
+ swap("push-through", option, target);
+ }
+ else if (option.equalsIgnoreCase("use")) {
+ swap("escape", option, target);
+ }
+ }
+
+ if (config.getEasyConstruction() && !config.getConstructionItems().equals("")) {
+ if (event.getType() == WALK.getId()) {
+ MenuEntry menuEntry = entries[entries.length - 1];
+ menuEntry.setType(MenuAction.WALK.getId() + MENU_ACTION_DEPRIORITIZE_OFFSET);
+ client.setMenuEntries(entries);
+ }
+
+ swap("Build", option, target);
+
+ for (int i = entries.length - 1; i >= 0; i--) {
+ for (String item : config.getConstructionItems().split(",")) {
+ if (item.trim().equalsIgnoreCase(Text.removeTags(entries[i].getTarget()))) {
+ if (!entries[i].getOption().equalsIgnoreCase("remove")) {
+ entries = ArrayUtils.remove(entries, i);
+ i--;
+ }
+ }
+ }
+ }
+
+ client.setMenuEntries(entries);
+ }
+
+ if (config.getSwapShop() && !config.getSwappedItems().equals("")) {
+ for (String item : config.getSwappedItems().split(",")) {
+ if (target.equalsIgnoreCase(item.trim())) {
+ swap("Buy 50", option, target);
+ }
+ }
+ }
+
+ if (config.getSwapSmithing()) {
+ if (option.equalsIgnoreCase("Smith 1")) {
+ swap("Smith All", option, target);
+ } else if (option.equalsIgnoreCase("Smith 1 Set")) {
+ swap("Smith All Sets", option, target);
+ }
+ }
+
+ if (config.getSwapTanning() && option.equalsIgnoreCase("Tan 1")) {
+ swap("Tan All", option, target);
+ }
+
+ if (config.getSwapCrafting() && option.equalsIgnoreCase("Make-1")) {
+ swap("Make-All", option, target);
+ }
+
+ if (config.getSwapSawmill() && target.equalsIgnoreCase("Sawmill operator")) {
+ swap("Buy-plank", option, target);
+ }
+
+ if (config.getSwapSawmillPlanks() && option.equalsIgnoreCase("Buy 1")) {
+ swap("Buy All", option, target);
+ }
+
+ if (config.getSwapStairs() && option.equalsIgnoreCase("Climb Stairs")) {
+ swap("Climb Up Stairs", option, target);
+ }
+
+ if (option.equalsIgnoreCase("Clear-All") && target.equalsIgnoreCase("Bank Filler")) {
+ swap("Clear", option, target);
+ }
+
+ if (target.toLowerCase().contains("ardougne cloak") && config.getSwapArdougneCape()) {
+ swap("Kandarin Monastery", option, target);
+ swap("Monastery Teleport", option, target);
+ }
+
+ if (config.getSwapEssencePouch()) {
+ if (isEssencePouch(target)) {
+ Widget widgetBankTitleBar = client.getWidget(WidgetInfo.BANK_TITLE_BAR);
+ switch (config.getEssenceMode()) {
+ case RUNECRAFTING:
+ if (widgetBankTitleBar == null || widgetBankTitleBar.isHidden()) {
+ swap("Empty", option, target);
+ } else {
+ swap("Fill", option, target);
+ }
+ break;
+ case ESSENCE_MINING:
+ if (widgetBankTitleBar == null || widgetBankTitleBar.isHidden()) {
+ swap("Fill", option, target);
+ } else {
+ swap("Empty", option, target);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (config.getGamesNecklace()) {
+ if (target.toLowerCase().contains("games necklace")) {
+ switch (config.getGamesNecklaceMode()) {
+ case BURTHORPE:
+ swap(GamesNecklaceMode.BURTHORPE.toString(), option, target);
+ break;
+ case BARBARIAN_OUTPOST:
+ swap(GamesNecklaceMode.BARBARIAN_OUTPOST.toString(), option, target);
+ break;
+ case CORPOREAL_BEAST:
+ swap(GamesNecklaceMode.CORPOREAL_BEAST.toString(), option, target);
+ break;
+ case TEARS_OF_GUTHIX:
+ swap(GamesNecklaceMode.TEARS_OF_GUTHIX.toString(), option, target);
+ break;
+ case WINTERTODT:
+ swap(GamesNecklaceMode.WINTERTODT.toString(), option, target);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (config.getDuelingRing()) {
+ if (target.toLowerCase().contains("ring of dueling")) {
+ switch (config.getDuelingRingMode()) {
+ case DUEL_ARENA:
+ swap(DuelingRingMode.DUEL_ARENA.toString(), option, target);
+ break;
+ case CASTLE_WARS:
+ swap(DuelingRingMode.CASTLE_WARS.toString(), option, target);
+ break;
+ case CLAN_WARS:
+ swap(DuelingRingMode.CLAN_WARS.toString(), option, target);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (config.getWealthRing()) {
+ if (target.toLowerCase().contains("ring of wealth")) {
+ switch (config.getWealthRingMode()) {
+ case MISCELLANIA:
+ swap(WealthRingMode.MISCELLANIA.toString(), option, target);
+ break;
+ case GRAND_EXCHANGE:
+ swap(WealthRingMode.GRAND_EXCHANGE.toString(), option, target);
+ break;
+ case FALADOR:
+ swap(WealthRingMode.FALADOR.toString(), option, target);
+ break;
+ case DONDAKAN:
+ swap(WealthRingMode.DONDAKAN.toString(), option, target);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (config.getGlory()) {
+ if (target.toLowerCase().contains("amulet of glory")) {
+ switch (config.getGloryMode()) {
+ case EDGEVILLE:
+ swap(GloryMode.EDGEVILLE.toString(), option, target);
+ break;
+ case KARAMJA:
+ swap(GloryMode.KARAMJA.toString(), option, target);
+ break;
+ case DRAYNOR_VILLAGE:
+ swap(GloryMode.DRAYNOR_VILLAGE.toString(), option, target);
+ break;
+ case AL_KHARID:
+ swap(GloryMode.AL_KHARID.toString(), option, target);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ startSwap();
+ performSwap();
+ }
+
+ private void swap(String optionA, String optionB, String target) {
+ swapping.add(new Swapper(target, optionA, optionB));
+ }
+
+ private void startSwap() {
+ int index = 0;
+ for (MenuEntry entry : entries) {
+ String target = Text.removeTags(entry.getTarget()).toLowerCase();
+ for (Swapper swap : swapping) {
+ if (swap.getTarget().equalsIgnoreCase(target)) {
+ if (entry.getOption().equalsIgnoreCase(swap.getOptionOne())) {
+ swap.setIndexOne(index);
+ } else if (entry.getOption().equalsIgnoreCase(swap.getOptionTwo())) {
+ swap.setIndexTwo(index);
+ }
+ }
+ }
+ index++;
+ }
+ }
+
+ private void performSwap() {
+ for (Swapper swap : swapping) {
+ if (swap.isReady()) {
+ MenuEntry entry = entries[swap.getIndexOne()];
+ entries[swap.getIndexOne()] = entries[swap.getIndexTwo()];
+ entries[swap.getIndexTwo()] = entry;
+ }
+ }
+ client.setMenuEntries(entries);
+ swapping.clear();
+ }
+
+ private void delete(int target) {
+ for (int i = entries.length - 1; i >= 0; i--) {
+ if (entries[i].getIdentifier() == target) {
+ entries = ArrayUtils.remove(entries, i);
+ i--;
+ }
+ }
+ client.setMenuEntries(entries);
+ }
+
+ private boolean isEssencePouch(String target) {
+ return (target.equalsIgnoreCase("Small Pouch") || target.equalsIgnoreCase("Medium Pouch") || target.equalsIgnoreCase("Large Pouch") || target.equalsIgnoreCase("Giant Pouch"));
+ }
+
+ private boolean isHouse() {
+ return client.getMapRegions()[0] == HOUSE_REGION_ID;
+ }
+
+ private boolean isPuroPuro() {
+ Player player = client.getLocalPlayer();
+
+ if (player == null) {
+ return false;
+ } else {
+ WorldPoint location = player.getWorldLocation();
+ return location.getRegionID() == PURO_PURO_REGION_ID;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/EasyscapePluginConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/EasyscapePluginConfig.java
new file mode 100644
index 0000000000..ef1074a4bd
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/EasyscapePluginConfig.java
@@ -0,0 +1,268 @@
+package net.runelite.client.plugins.easyscape;
+
+import net.runelite.client.config.Config;
+import net.runelite.client.config.ConfigGroup;
+import net.runelite.client.config.ConfigItem;
+
+@ConfigGroup("easyscape")
+public interface EasyscapePluginConfig extends Config {
+
+ @ConfigItem(
+ keyName = "removeExamine",
+ name = "Remove Examine",
+ description = "",
+ position = 0
+ )
+ default boolean getRemoveExamine() {
+ return true;
+ }
+
+ @ConfigItem(
+ keyName = "swapShop",
+ name = "Easy Shop",
+ description = "Enables swapping of items in the shop with their buy-50 option.",
+ position = 1
+ )
+ default boolean getSwapShop() {
+ return true;
+ }
+
+ @ConfigItem(
+ keyName = "swappedItems",
+ name = "Shop Items",
+ description = "Items listed here will have their value and buy-50 options swapped.",
+ position = 2
+ )
+ default String getSwappedItems() {
+ return "";
+ }
+
+ @ConfigItem(
+ keyName = "easyConstruction",
+ name = "Easy Construction",
+ description = "",
+ position = 3
+ )
+
+ default boolean getEasyConstruction() {
+ return true;
+ }
+
+ @ConfigItem(
+ keyName = "constructionItems",
+ name = "Construction Items",
+ description = "",
+ position = 4
+ )
+
+ default String getConstructionItems() {
+ return "";
+ }
+
+ @ConfigItem(
+ keyName = "removeObjects",
+ name = "Remove Objects",
+ description = "",
+ position = 5
+ )
+ default boolean getRemoveObjects() {
+ return true;
+ }
+
+ @ConfigItem(
+ keyName = "removedObjects",
+ name = "Removed Objects",
+ description = "",
+ position = 6
+ )
+ default String getRemovedObjects() {
+ return "";
+ }
+
+ @ConfigItem(
+ keyName = "swapSmithing",
+ name = "Swap Smithing",
+ description = "Enables swapping of smith-1 and smith-all options.",
+ position = 7
+ )
+ default boolean getSwapSmithing() {
+ return true;
+ }
+
+ @ConfigItem(
+ keyName = "swapTanning",
+ name = "Swap Tanning",
+ description = "Enables swapping of tan-1 and tan-all options.",
+ position = 8
+ )
+ default boolean getSwapTanning() {
+ return true;
+ }
+
+ @ConfigItem(
+ keyName = "swapCrafting",
+ name = "Swap Crafting",
+ description = "",
+ position = 9
+ )
+ default boolean getSwapCrafting() {
+ return true;
+ }
+
+ @ConfigItem(
+ keyName = "swapArdougneCape",
+ name = "Swap Ardougne Cape",
+ description = "Enables swapping of teleport and wear.",
+ position = 10
+ )
+ default boolean getSwapArdougneCape() {
+ return true;
+ }
+
+ @ConfigItem(
+ keyName = "swapStairs",
+ name = "Swap Stairs",
+ description = "",
+ position = 11
+ )
+
+ default boolean getSwapStairs() {
+ return true;
+ }
+
+ @ConfigItem(
+ keyName = "swapSawmill",
+ name = "Swap Sawmill Operator",
+ description = "",
+ position = 12
+ )
+ default boolean getSwapSawmill() {
+ return true;
+ }
+
+ @ConfigItem(
+ keyName = "swapSawmillPlanks",
+ name = "Swap Buy Planks",
+ description = "",
+ position = 13
+ )
+
+ default boolean getSwapSawmillPlanks() {
+ return true;
+ }
+
+ @ConfigItem(
+ keyName = "swapPuroPuro",
+ name = "Swap Puro Puro Wheat",
+ description = "",
+ position = 14
+ )
+ default boolean getSwapPuro() {
+ return true;
+ }
+
+ @ConfigItem(
+ keyName = "swapEssencePounch",
+ name = "Swap Essence Pouch",
+ description = "Enables swapping of fill and empty for essence pounch.",
+ position = 15
+ )
+ default boolean getSwapEssencePouch() {
+ return true;
+ }
+
+ @ConfigItem(
+ keyName = "essenceMode",
+ name = "Essence Pouch Mode",
+ description = "Runecrafting or essence mining mode.",
+ position = 16
+ )
+
+ default EssenceMode getEssenceMode() {
+ return EssenceMode.RUNECRAFTING;
+ }
+
+ @ConfigItem(
+ keyName = "swapGamesNecklace",
+ name = "Swap Games Necklace",
+ description = "Enables swapping of games necklace.",
+ position = 17
+ )
+ default boolean getGamesNecklace() {
+ return true;
+ }
+
+ @ConfigItem(
+ keyName = "gamesNecklaceMode",
+ name = "Games Necklace Mode",
+ description = "Teleport location mode.",
+ position = 18
+ )
+
+ default GamesNecklaceMode getGamesNecklaceMode() {
+ return GamesNecklaceMode.BURTHORPE;
+ }
+
+ @ConfigItem(
+ keyName = "swapDuelingRing",
+ name = "Swap Dueling Ring",
+ description = "Enables swapping of dueling ring.",
+ position = 19
+ )
+ default boolean getDuelingRing() {
+ return true;
+ }
+
+ @ConfigItem(
+ keyName = "duelingRingMode",
+ name = "Dueling Ring Mode",
+ description = "Teleport location mode.",
+ position = 20
+ )
+
+ default DuelingRingMode getDuelingRingMode() {
+ return DuelingRingMode.DUEL_ARENA;
+ }
+
+ @ConfigItem(
+ keyName = "swapGlory",
+ name = "Swap Glory",
+ description = "Enables swapping of Amulet of Glory.",
+ position = 21
+ )
+ default boolean getGlory() {
+ return true;
+ }
+
+ @ConfigItem(
+ keyName = "gloryMode",
+ name = "Glory Mode",
+ description = "Teleport location mode.",
+ position = 22
+ )
+
+ default GloryMode getGloryMode() {
+ return GloryMode.EDGEVILLE;
+ }
+
+ @ConfigItem(
+ keyName = "swapWealthRing",
+ name = "Swap Ring of Wealth",
+ description = "Enables swapping of Ring of Wealth.",
+ position = 23
+ )
+ default boolean getWealthRing() {
+ return true;
+ }
+ @ConfigItem(
+ keyName = "WealthRingMode",
+ name = "Wealth Ring Mode",
+ description = "Teleport location mode.",
+ position = 24
+ )
+
+ default WealthRingMode getWealthRingMode() {
+ return WealthRingMode.GRAND_EXCHANGE;
+ }
+}
+
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/EssenceMode.java b/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/EssenceMode.java
new file mode 100644
index 0000000000..8cb09d94c3
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/EssenceMode.java
@@ -0,0 +1,17 @@
+package net.runelite.client.plugins.easyscape;
+
+public enum EssenceMode {
+ RUNECRAFTING("Runecrafting"),
+ ESSENCE_MINING("Essence Mining");
+
+ private final String name;
+
+ EssenceMode(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/GamesNecklaceMode.java b/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/GamesNecklaceMode.java
new file mode 100644
index 0000000000..ca52de44f8
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/GamesNecklaceMode.java
@@ -0,0 +1,20 @@
+package net.runelite.client.plugins.easyscape;
+
+public enum GamesNecklaceMode {
+ BURTHORPE("Burthorpe"),
+ BARBARIAN_OUTPOST("Barbarian Outpost"),
+ CORPOREAL_BEAST("Corporeal Beast"),
+ TEARS_OF_GUTHIX("Tears of Guthix"),
+ WINTERTODT("Wintertodt Camp");
+
+ private final String name;
+
+ GamesNecklaceMode(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/GloryMode.java b/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/GloryMode.java
new file mode 100644
index 0000000000..4926c9d829
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/GloryMode.java
@@ -0,0 +1,19 @@
+package net.runelite.client.plugins.easyscape;
+
+public enum GloryMode {
+ EDGEVILLE("Edgeville"),
+ KARAMJA("Karamja"),
+ DRAYNOR_VILLAGE("Draynor Village"),
+ AL_KHARID("Al Kharid");
+
+ private final String name;
+
+ GloryMode(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/Swapper.java b/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/Swapper.java
new file mode 100644
index 0000000000..6ddd92d33d
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/Swapper.java
@@ -0,0 +1,36 @@
+package net.runelite.client.plugins.easyscape;
+
+import lombok.Getter;
+import lombok.Setter;
+
+public class Swapper {
+
+ @Getter
+ private String target;
+
+ @Getter
+ private String optionOne;
+
+ @Getter
+ private String optionTwo;
+
+ @Getter
+ @Setter
+ private int indexOne;
+
+ @Getter
+ @Setter
+ private int indexTwo;
+
+ public Swapper(String target, String optionOne, String optionTwo) {
+ this.target = target;
+ this.optionOne = optionOne;
+ this.optionTwo = optionTwo;
+ this.indexOne = -1;
+ this.indexTwo = -1;
+ }
+
+ public boolean isReady() {
+ return this.indexOne != -1 && this.indexTwo != -1;
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/WealthRingMode.java b/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/WealthRingMode.java
new file mode 100644
index 0000000000..d20e454f06
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/WealthRingMode.java
@@ -0,0 +1,19 @@
+package net.runelite.client.plugins.easyscape;
+
+public enum WealthRingMode {
+ MISCELLANIA ("Miscellania"),
+ GRAND_EXCHANGE ("Grand Exchange"),
+ FALADOR ("Falador"),
+ DONDAKAN ("Dondakan");
+
+ private final String name;
+
+ WealthRingMode(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/specbar/SpecBarPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/specbar/SpecBarPlugin.java
new file mode 100644
index 0000000000..7630f0292a
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/specbar/SpecBarPlugin.java
@@ -0,0 +1,75 @@
+package net.runelite.client.plugins.specbar;
+
+import javax.inject.Inject;
+import net.runelite.api.Client;
+import net.runelite.api.GameState;
+import net.runelite.api.events.GameStateChanged;
+import net.runelite.api.events.WidgetHiddenChanged;
+import net.runelite.api.widgets.Widget;
+import net.runelite.api.widgets.WidgetID;
+import net.runelite.api.widgets.WidgetInfo;
+import net.runelite.client.eventbus.Subscribe;
+import net.runelite.client.plugins.Plugin;
+import net.runelite.client.plugins.PluginDescriptor;
+import net.runelite.client.plugins.PluginManager;
+import net.runelite.client.plugins.PluginType;
+
+@PluginDescriptor(
+ name = "Spec Bar",
+ description = "Adds a spec bar to every weapon",
+ tags = {"spec bar", "special attack", "spec", "bar", "pklite"},
+ enabledByDefault = false,
+ type = PluginType.PVP
+)
+public class SpecBarPlugin extends Plugin
+{
+
+ @Inject
+ private Client client;
+
+ @Override
+ protected void startUp() throws Exception
+ {
+ }
+
+ @Override
+ protected void shutDown() throws Exception
+ {
+ }
+
+ @Subscribe
+ private void onWidgetHiddenChanged(WidgetHiddenChanged event)
+ {
+ if (WidgetInfo.TO_GROUP(event.getWidget().getId()) == WidgetID.COMBAT_GROUP_ID)
+ {
+ hideSpecBar();
+ }
+ }
+
+ @Subscribe
+ private void onGameStateChanged(GameStateChanged event)
+ {
+ if (event.getGameState().equals(GameState.LOGGING_IN))
+ {
+ hideSpecBar();
+ }
+
+ }
+
+ /**
+ * Displays the special attack bar
+ */
+ private void hideSpecBar()
+ {
+ try
+ {
+ Widget specBar = client.getWidget(WidgetInfo.COMBAT_SPECIAL_ATTACK);
+ specBar.setHidden(false);
+ specBar.revalidate();
+ }
+ catch (NullPointerException e)
+ {
+ // Stops the nulls that occur before the spec bar is loaded by player equipping a spec wep
+ }
+ }
+}