diff --git a/http-api/src/main/java/net/runelite/http/api/discord/DiscordClient.java b/http-api/src/main/java/net/runelite/http/api/discord/DiscordClient.java index 63a41be11d..0640494a62 100644 --- a/http-api/src/main/java/net/runelite/http/api/discord/DiscordClient.java +++ b/http-api/src/main/java/net/runelite/http/api/discord/DiscordClient.java @@ -46,7 +46,7 @@ public class DiscordClient public void message(HttpUrl url, DiscordMessage discordMessage) { - log.info("Message being sent"); + log.debug("Message being sent"); message(url, discordMessage, 0, 5); } @@ -58,7 +58,7 @@ public class DiscordClient .url(url) .build(); - log.info("Attempting to message with {}", discordMessage); + log.debug("Attempting to message with {}", discordMessage); RuneLiteAPI.CLIENT.newCall(request).enqueue(new Callback() { @@ -80,12 +80,12 @@ public class DiscordClient { if (response.body() == null) { - log.error("API Call - Reponse was null."); + log.debug("API Call - Reponse was null."); return; } if (response.body().string().contains("You are being rate limited") && retryAttempt < maxAttempts) { - log.error("You are being rate limited, retrying..."); + log.debug("You are being rate limited, retrying..."); message(url, discordMessage, retryAttempt + 1, maxAttempts); } } diff --git a/http-api/src/main/java/net/runelite/http/api/discord/DiscordMessage.java b/http-api/src/main/java/net/runelite/http/api/discord/DiscordMessage.java index 48cc3c3665..061568da9d 100644 --- a/http-api/src/main/java/net/runelite/http/api/discord/DiscordMessage.java +++ b/http-api/src/main/java/net/runelite/http/api/discord/DiscordMessage.java @@ -48,7 +48,6 @@ public class DiscordMessage String avatarUrl; @SerializedName("tts") boolean textToSpeech; - @Builder.Default List embeds = new ArrayList<>(); public DiscordMessage() diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/playerscouter/AttackStyle.java b/runelite-client/src/main/java/net/runelite/client/plugins/playerscouter/AttackStyle.java deleted file mode 100644 index 14dd4b7be5..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/playerscouter/AttackStyle.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2019, ganom - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.playerscouter; - -import java.awt.Color; -import lombok.AllArgsConstructor; -import lombok.Getter; -import net.runelite.api.Prayer; - -@AllArgsConstructor -@Getter -public enum AttackStyle -{ - MAGE("Mage", Color.CYAN, Prayer.PROTECT_FROM_MAGIC), - RANGE("Range", Color.GREEN, Prayer.PROTECT_FROM_MISSILES), - MELEE("Melee", Color.RED, Prayer.PROTECT_FROM_MELEE), - UNKNOWN("Unknown", Color.WHITE, null); - - private String name; - private Color color; - private Prayer prayer; -} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/playerscouter/AttackerOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/playerscouter/AttackerOverlay.java deleted file mode 100644 index 12e055918c..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/playerscouter/AttackerOverlay.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2019, ganom - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.playerscouter; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; -import javax.inject.Inject; -import javax.inject.Singleton; -import net.runelite.client.graphics.ModelOutlineRenderer; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayLayer; -import net.runelite.client.ui.overlay.OverlayPosition; - -@Singleton -public class AttackerOverlay extends Overlay -{ - private static final Color TRANSPARENT = new Color(0, 0, 0, 0); - - private final PlayerScouter plugin; - private final ModelOutlineRenderer outlineRenderer; - - @Inject - public AttackerOverlay(final PlayerScouter plugin, final ModelOutlineRenderer outlineRenderer) - { - this.plugin = plugin; - this.outlineRenderer = outlineRenderer; - setPosition(OverlayPosition.DYNAMIC); - setLayer(OverlayLayer.ABOVE_SCENE); - } - - @Override - public Dimension render(Graphics2D graphics) - { - if (!plugin.isOverlayEnabled() || plugin.getPlayerContainer().isEmpty()) - { - return null; - } - - plugin.getPlayerContainer().forEach(player -> - { - if (!player.isTarget()) - { - return; - } - - final AttackStyle attackStyle = player.getAttackStyle(); - - if (attackStyle.getPrayer() == null) - { - return; - } - - outlineRenderer.drawOutline(player.getPlayer(), 2, attackStyle.getColor(), TRANSPARENT); - }); - return null; - } -} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/playerscouter/PlayerContainer.java b/runelite-client/src/main/java/net/runelite/client/plugins/playerscouter/PlayerContainer.java index c98f24f465..8acd83ad03 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/playerscouter/PlayerContainer.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/playerscouter/PlayerContainer.java @@ -29,8 +29,7 @@ import lombok.Getter; import lombok.Setter; import lombok.ToString; import net.runelite.api.Player; -import net.runelite.api.Prayer; -import net.runelite.http.api.hiscore.Skill; +import net.runelite.http.api.hiscore.HiscoreResult; /* You may be asking, why in the fuck is there so much information @@ -42,67 +41,35 @@ Better to have too much than to have too little. @ToString(exclude = "player") class PlayerContainer { - private AttackStyle attackStyle; - private AttackStyle weakness; - private boolean attacking; - private boolean logging; + private boolean httpRetry; private boolean scouted; - private boolean target; - private double drainRate; - private double estimatedPrayer; - private int magicAttack; - private int magicDefence; - private int meleeAttack; - private int meleeDefence; - private int prayerBonus; - private int rangeAttack; - private int rangeDefence; + private HiscoreResult skills; + private int prayer; private int risk; private int scoutTimer; - private int timer; private int weapon; private int wildyLevel; private LinkedHashMap gear; private LinkedHashMap riskedGear; private Player player; - private Prayer overhead; - private Prayer predictedPrayer; - private Skill prayer; - private String estimatedPrayerString; private String location; private String name; private String targetString; - PlayerContainer(Player player, Skill prayer) + PlayerContainer(Player player) { - this.attacking = false; - this.attackStyle = AttackStyle.UNKNOWN; - this.drainRate = 0; - this.estimatedPrayer = 0; - this.estimatedPrayerString = ""; this.gear = new LinkedHashMap<>(); + this.httpRetry = false; this.location = "N/A"; - this.logging = false; - this.magicAttack = 0; - this.magicDefence = 0; - this.meleeAttack = 0; - this.meleeDefence = 0; this.name = player.getName(); - this.overhead = null; this.player = player; - this.prayer = prayer; - this.prayerBonus = 0; - this.predictedPrayer = null; - this.rangeAttack = 0; - this.rangeDefence = 0; + this.prayer = -1; this.risk = 0; this.riskedGear = new LinkedHashMap<>(); this.scouted = false; this.scoutTimer = 500; - this.target = false; + this.skills = null; this.targetString = ""; - this.timer = 0; - this.weakness = AttackStyle.UNKNOWN; this.weapon = 0; this.wildyLevel = 0; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/playerscouter/PlayerScouter.java b/runelite-client/src/main/java/net/runelite/client/plugins/playerscouter/PlayerScouter.java index 05e4483e2f..91fe06308a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/playerscouter/PlayerScouter.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/playerscouter/PlayerScouter.java @@ -25,45 +25,60 @@ package net.runelite.client.plugins.playerscouter; import com.google.inject.Provides; import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.Date; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.stream.Collectors; import javax.inject.Inject; -import lombok.AccessLevel; -import lombok.Getter; import lombok.extern.slf4j.Slf4j; import net.runelite.api.Actor; import net.runelite.api.Client; import net.runelite.api.GameState; +import net.runelite.api.ItemDefinition; +import net.runelite.api.NPC; import net.runelite.api.Player; import net.runelite.api.Varbits; import net.runelite.api.WorldType; import net.runelite.api.coords.WorldArea; -import net.runelite.api.events.AnimationChanged; +import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.ConfigChanged; import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.GameTick; -import net.runelite.api.events.InteractingChanged; import net.runelite.api.events.PlayerDespawned; import net.runelite.api.events.PlayerSpawned; -import net.runelite.client.callback.ClientThread; +import net.runelite.api.kit.KitType; import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.EventBus; import net.runelite.client.game.ItemManager; +import net.runelite.client.game.PvPValueBrokenItem; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.plugins.PluginType; -import net.runelite.client.ui.overlay.OverlayManager; import net.runelite.client.util.PvPUtil; +import net.runelite.client.util.StackFormatter; import net.runelite.client.util.WildernessLocation; import net.runelite.http.api.discord.DiscordClient; +import net.runelite.http.api.discord.DiscordEmbed; +import net.runelite.http.api.discord.DiscordMessage; +import net.runelite.http.api.discord.embed.AuthorEmbed; +import net.runelite.http.api.discord.embed.FieldEmbed; +import net.runelite.http.api.discord.embed.FooterEmbed; +import net.runelite.http.api.discord.embed.ThumbnailEmbed; import net.runelite.http.api.hiscore.HiscoreClient; -import net.runelite.http.api.hiscore.HiscoreSkill; -import net.runelite.http.api.hiscore.SingleHiscoreSkillResult; +import net.runelite.http.api.hiscore.HiscoreResult; +import net.runelite.http.api.item.ItemStats; import okhttp3.HttpUrl; @PluginDescriptor( @@ -75,36 +90,28 @@ import okhttp3.HttpUrl; @Slf4j public class PlayerScouter extends Plugin { - private static final DiscordClient DISCORD_CLIENT = new DiscordClient(); - private static final String ICONBASEURL = "https://www.osrsbox.com/osrsbox-db/items-icons/"; // Add item id + ".png" private static final HiscoreClient HISCORE_CLIENT = new HiscoreClient(); + private static final DiscordClient DISCORD_CLIENT = new DiscordClient(); private static final Map WILD_LOCS = getLocationMap(); + private static final SimpleDateFormat SDF = new SimpleDateFormat("MMM dd h:mm a z"); + private static final String ICONBASEURL = "https://www.osrsbox.com/osrsbox-db/items-icons/"; // Add item id + ".png" @Inject private Client client; @Inject private ItemManager itemManager; @Inject - private AttackerOverlay attackerOverlay; - @Inject - private OverlayManager overlayManager; - @Inject - private ClientThread clientThread; - @Inject private PlayerScouterConfig config; @Inject private EventBus eventBus; - @Getter(AccessLevel.PACKAGE) private Set playerContainer = new HashSet<>(); - @Getter(AccessLevel.PACKAGE) - private boolean overlayEnabled; - private boolean onlyWildy; private ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2); + private Map resultCache = new HashMap<>(); private Map blacklist = new HashMap<>(); - private int reset; private HttpUrl url; private int minimumRisk; private int minimumValue; private int timeout; + private boolean onlyWildy; private boolean outputItems; private static Map getLocationMap() @@ -124,7 +131,6 @@ public class PlayerScouter extends Plugin @Override protected void startUp() { - overlayManager.add(attackerOverlay); blacklist.clear(); updateConfig(); addSubscriptions(); @@ -133,7 +139,6 @@ public class PlayerScouter extends Plugin @Override protected void shutDown() { - overlayManager.remove(attackerOverlay); playerContainer.clear(); blacklist.clear(); eventBus.unregister(this); @@ -143,21 +148,9 @@ public class PlayerScouter extends Plugin { eventBus.subscribe(ConfigChanged.class, this, this::onConfigChanged); eventBus.subscribe(GameStateChanged.class, this, this::onGameStateChanged); - eventBus.subscribe(InteractingChanged.class, this, this::onInteractingChanged); - eventBus.subscribe(AnimationChanged.class, this, this::onAnimationChanged); - eventBus.subscribe(PlayerSpawned.class, this, this::onPlayerSpawned); - eventBus.subscribe(PlayerDespawned.class, this, this::onPlayerDespawned); eventBus.subscribe(GameTick.class, this, this::onGameTick); - } - - private void onGameStateChanged(GameStateChanged event) - { - if (event.getGameState() == GameState.LOGGED_IN) - { - return; - } - - blacklist.clear(); + eventBus.subscribe(PlayerDespawned.class, this, this::onPlayerDespawned); + eventBus.subscribe(PlayerSpawned.class, this, this::onPlayerSpawned); } private void onConfigChanged(ConfigChanged event) @@ -170,73 +163,40 @@ public class PlayerScouter extends Plugin updateConfig(); } - private void onInteractingChanged(InteractingChanged event) + private void onGameStateChanged(GameStateChanged event) { - if ((event.getSource() instanceof Player) && (event.getTarget() instanceof Player)) + if (event.getGameState() == GameState.LOGGED_IN) { - final Player source = (Player) event.getSource(); - final Player target = (Player) event.getTarget(); - - if (source == client.getLocalPlayer()) - { - if (!PvPUtil.isAttackable(client, target)) - { - return; - } - - playerContainer.forEach(player -> - { - if (player.getPlayer() == target) - { - player.setTimer(16); - player.setTarget(true); - } - }); - } - else if (target == client.getLocalPlayer()) - { - if (!PvPUtil.isAttackable(client, source)) - { - return; - } - playerContainer.forEach(player -> - { - if (player.getPlayer() == source) - { - player.setTimer(16); - player.setTarget(true); - } - }); - } + return; } + + blacklist.clear(); } - private void onAnimationChanged(AnimationChanged event) + private void onGameTick(GameTick event) { - final Actor actor = event.getActor(); + resetBlacklist(); - if (actor.getInteracting() != client.getLocalPlayer()) + if (!checkWildy() || playerContainer.isEmpty()) { return; } - if (!(actor instanceof Player)) + playerContainer.forEach(player -> { - return; - } - - if (PvPUtil.isAttackable(client, (Player) actor) && actor.getAnimation() != -1) - { - playerContainer.forEach(player -> + update(player); + if (player.getRisk() > this.minimumRisk) { - if (player.getPlayer() == actor) - { - player.setTimer(16); - player.setTarget(true); - player.setAttacking(true); - } - }); - } + scoutPlayer(player); + } + }); + } + + private void onPlayerDespawned(PlayerDespawned event) + { + final Player player = event.getPlayer(); + + playerContainer.removeIf(p -> p.getPlayer() == player); } private void onPlayerSpawned(PlayerSpawned event) @@ -253,52 +213,10 @@ public class PlayerScouter extends Plugin return; } - executorService.submit(() -> - { - SingleHiscoreSkillResult result; - - try - { - result = HISCORE_CLIENT.lookup(player.getName(), HiscoreSkill.PRAYER); - } - catch (IOException ex) - { - log.warn("Error fetching Hiscore data " + ex.getMessage()); - return; - } - - playerContainer.add(new PlayerContainer(player, result.getSkill())); - blacklist.put(player.getName(), client.getTickCount() + this.timeout); - }); + playerContainer.add(new PlayerContainer(player)); + blacklist.put(player.getName(), client.getTickCount() + this.timeout); } - private void onPlayerDespawned(PlayerDespawned event) - { - final Player player = event.getPlayer(); - - playerContainer.removeIf(p -> p.getPlayer() == player); - } - - private void onGameTick(GameTick event) - { - resetBlacklist(); - - if (!checkWildy() || playerContainer.isEmpty()) - { - return; - } - - playerContainer.forEach(player -> - { - Utils.reset(player); - Utils.update(player, itemManager, 6, WILD_LOCS); - - if (player.getRisk() > this.minimumRisk) - { - Utils.scoutPlayer(player, url, DISCORD_CLIENT, itemManager, client, this.minimumValue, this.outputItems); - } - }); - } private void resetBlacklist() { @@ -316,17 +234,6 @@ public class PlayerScouter extends Plugin }); } - private void updateConfig() - { - this.url = HttpUrl.parse(config.webhook()); - this.minimumRisk = config.minimumRisk(); - this.minimumValue = config.minimumValue(); - this.overlayEnabled = config.overlayEnabled(); - this.timeout = config.timeout(); - this.onlyWildy = config.onlyWildy(); - this.outputItems = config.outputItems(); - } - private boolean checkWildy() { if (!this.onlyWildy) @@ -335,4 +242,407 @@ public class PlayerScouter extends Plugin } return client.getVar(Varbits.IN_WILDERNESS) == 1 || WorldType.isPvpWorld(client.getWorldType()); } + + private void updateConfig() + { + this.url = HttpUrl.parse(config.webhook()); + this.minimumRisk = config.minimumRisk(); + this.minimumValue = config.minimumValue(); + this.timeout = config.timeout(); + this.onlyWildy = config.onlyWildy(); + this.outputItems = config.outputItems(); + } + + private void update(PlayerContainer player) + { + player.setRisk(0); + updatePlayerGear(player); + updateStats(player); + player.setLocation(location(player)); + player.setWildyLevel(PvPUtil.getWildernessLevelFrom(player.getPlayer().getWorldLocation())); + player.setTargetString(targetStringBuilder(player)); + if (player.isScouted()) + { + player.setScoutTimer(player.getScoutTimer() - 1); + if (player.getScoutTimer() <= 0) + { + player.setScouted(false); + player.setScoutTimer(500); + } + } + log.debug(player.toString()); + } + + private void updateStats(PlayerContainer player) + { + if (player.getSkills() == null) + { + if (player.isHttpRetry()) + { + return; + } + executorService.submit(() -> + { + player.setHttpRetry(true); + HiscoreResult result = null; + try + { + if (!resultCache.values().contains(player.getName())) + { + result = HISCORE_CLIENT.lookup(player.getName()); + } + else + { + for (Map.Entry entry : resultCache.entrySet()) + { + if (!entry.getValue().equals(player.getName())) + { + continue; + } + result = entry.getKey(); + } + } + } + catch (IOException ex) + { + log.warn("Error fetching Hiscore data " + ex.getMessage()); + player.setHttpRetry(false); + return; + } + resultCache.put(result, player.getName()); + player.setHttpRetry(false); + player.setSkills(result); + player.setPrayer(player.getSkills().getPrayer().getLevel()); + }); + } + } + + private void updatePlayerGear(PlayerContainer player) + { + Map prices = new HashMap<>(); + + if (player.getPlayer().getPlayerAppearance() != null) + { + for (KitType kitType : KitType.values()) + { + if (kitType.equals(KitType.RING) || kitType.equals(KitType.AMMUNITION)) + { + continue; + } + + final int id = player.getPlayer().getPlayerAppearance().getEquipmentId(kitType); + + if (id == -1) + { + continue; + } + + if (kitType.equals(KitType.WEAPON)) + { + player.setWeapon(id); + } + + final ItemStats item = itemManager.getItemStats(id, false); + final ItemDefinition itemDefinition = itemManager.getItemDefinition(id); + + if (item == null) + { + log.debug("Item is null: {}", id); + continue; + } + + if (PvPValueBrokenItem.breaksOnDeath(id)) + { + prices.put(id, itemManager.getBrokenValue(id)); + log.debug("Item has a broken value: Id {}, Value {}", id, itemManager.getBrokenValue(id)); + } + + if (!itemDefinition.isTradeable() && !PvPValueBrokenItem.breaksOnDeath(id)) + { + prices.put(id, itemDefinition.getPrice()); + } + else if (itemDefinition.isTradeable()) + { + prices.put(id, itemManager.getItemPrice(id, false)); + } + } + updateGear(player, prices); + } + } + + private void updateGear(PlayerContainer player, Map prices) + { + player.setGear(prices.entrySet() + .stream() + .sorted(Collections.reverseOrder(Map.Entry.comparingByValue())) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -> oldValue, LinkedHashMap::new))); + + player.setRiskedGear(prices.entrySet() + .stream() + .sorted(Collections.reverseOrder(Map.Entry.comparingByValue())) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -> oldValue, LinkedHashMap::new))); + + if (player.getPlayer().getSkullIcon() == null) + { + removeEntries(player.getRiskedGear(), player.getPrayer() <= 25 ? 3 : 4); + } + else + { + removeEntries(player.getRiskedGear(), player.getPrayer() <= 25 ? 0 : 1); + } + + player.getRiskedGear().values().forEach(price -> player.setRisk(player.getRisk() + price)); + prices.clear(); + } + + private static void removeEntries(LinkedHashMap map, int quantity) + { + if (map.size() < quantity) + { + log.debug("Size is lower than removal quantity."); + } + for (int i = 0; i < quantity; i++) + { + if (!map.entrySet().iterator().hasNext()) + { + log.debug("Attempted to remove entries, but there was not enough to remove."); + return; + } + log.debug("Entry Removed: " + map.entrySet().iterator().next()); + map.entrySet().remove(map.entrySet().iterator().next()); + } + } + + private static Map.Entry getEntry(LinkedHashMap map) + { + if (!map.isEmpty()) + { + Iterator> entry = map.entrySet().iterator(); + + for (int i = 0; i < 1; i++) + { + entry.next(); + } + + return entry.next(); + } + return null; + } + + private String targetStringBuilder(PlayerContainer player) + { + if (player.getPlayer().getInteracting() != null) + { + Actor actor = player.getPlayer().getInteracting(); + if (actor instanceof Player) + { + return "(Player) " + actor.getName(); + } + else if (actor instanceof NPC) + { + return "(NPC) " + actor.getName(); + } + } + return "No Target Detected"; + } + + private void scoutPlayer(PlayerContainer player) + { + if (player.isScouted() || player.getSkills() == null) + { + return; + } + + List fieldList = new ArrayList<>(); + //green + String color = "8388352"; + + if (player.getRisk() < 1000000 && player.getRisk() > 150000) + { + //blue + color = "32767"; + } + else if (player.getRisk() > 1000000) + { + //orange + color = "16744448"; + } + + ThumbnailEmbed image = ThumbnailEmbed.builder() + .url(ICONBASEURL + player.getWeapon() + ".png") + .build(); + + fieldList.add(FieldEmbed.builder() + .name("Risk") + .value(StackFormatter.quantityToRSDecimalStack(player.getRisk())) + .inline(true) + .build()); + + fieldList.add(FieldEmbed.builder() + .name("World") + .value(Integer.toString(client.getWorld())) + .inline(true) + .build()); + + fieldList.add(FieldEmbed.builder() + .name("Combat Level") + .value(Integer.toString(player.getPlayer().getCombatLevel())) + .inline(true) + .build()); + if (client.getVar(Varbits.IN_WILDERNESS) == 1) + { + fieldList.add(FieldEmbed.builder() + .name("Wildy Level") + .value(Integer.toString(player.getWildyLevel())) + .inline(true) + .build()); + + fieldList.add(FieldEmbed.builder() + .name("Location") + .value(player.getLocation()) + .inline(true) + .build()); + } + + fieldList.add(FieldEmbed.builder() + .name("Target") + .value(player.getTargetString()) + .inline(true) + .build()); + + if (this.outputItems) + { + fieldList.add(FieldEmbed.builder() + .name("Risked Items Sorted by Value") + .value("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━") + .build()); + + final int[] items = {0}; + + player.getRiskedGear().forEach((gear, value) -> + { + if (value <= 0 || value <= this.minimumValue) + { + items[0]++; + return; + } + + ItemStats item = itemManager.getItemStats(gear, false); + + if (item == null) + { + log.error("Item is Null: {}", gear); + return; + } + + fieldList.add(FieldEmbed.builder() + .name(item.getName()) + .value("Value: " + StackFormatter.quantityToRSDecimalStack(value)) + .inline(true) + .build()); + }); + + if (items[0] > 0) + { + fieldList.add(FieldEmbed.builder() + .name("Items below value: " + this.minimumValue) + .value(Integer.toString(items[0])) + .inline(true) + .build()); + } + } + + String icon = ICONBASEURL + Objects.requireNonNull(getEntry(player.getGear())).getKey() + ".png"; + String name = "☠️ " + player.getName() + " ☠️"; + + if (player.getPlayer().getSkullIcon() == null) + { + name = player.getName(); + } + + message(name, icon, image, fieldList, color); + player.setScouted(true); + fieldList.clear(); + } + + private void message(String name, String iconUrl, ThumbnailEmbed thumbnail, List fields, String color) + { + log.debug("Message Contents: {}, {}, {}, {}, {}", name, " ", thumbnail, Arrays.toString(fields.toArray()), this.url); + log.debug("Fields: {}", fields); + + if (name.isEmpty() || fields.isEmpty()) + { + log.error("Discord message will fail with a missing name/description/field"); + return; + } + + final Date currentTime = new Date(System.currentTimeMillis()); + + DiscordEmbed discordEmbed = DiscordEmbed.builder() + .author(AuthorEmbed.builder() + .icon_url(iconUrl) + .name(name) + .build()) + .thumbnail(thumbnail) + .description(" ") + .fields(fields) + .footer(FooterEmbed.builder() + .icon_url("https://raw.githubusercontent.com/runelite/runelite/master/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/ultimate_ironman.png") + .text("Gabon Scouter | Time: " + SDF.format(currentTime)) + .build()) + .color(color) + .build(); + + DiscordMessage discordMessage = new DiscordMessage("Gabon Scouter", " ", "https://i.imgur.com/2A6dr7q.png"); + discordMessage.getEmbeds().add(discordEmbed); + DISCORD_CLIENT.message(this.url, discordMessage); + fields.clear(); + } + + private String location(PlayerContainer player) + { + final WorldPoint wl = player.getPlayer().getWorldLocation(); + int dist = 10000; + String s = ""; + WorldArea closestArea = null; + for (Map.Entry entry : WILD_LOCS.entrySet()) + { + WorldArea worldArea = entry.getKey(); + + if (worldArea.toWorldPointList().contains(wl)) + { + s = entry.getValue(); + return s; + } + int distTo = worldArea.distanceTo(wl); + if (distTo < dist) + { + dist = distTo; + closestArea = worldArea; + } + } + if (wl.getY() > (Objects.requireNonNull(closestArea).toWorldPoint().getY() + closestArea.getHeight())) + { + s = s + "N"; + } + if (wl.getY() < closestArea.toWorldPoint().getY()) + { + s = s + "S"; + } + if (wl.getX() < closestArea.toWorldPoint().getX()) + { + s = s + "W"; + } + if (wl.getX() > (closestArea.toWorldPoint().getX() + closestArea.getWidth())) + { + s = s + "E"; + } + s = s + " of "; + s = s + WILD_LOCS.get(closestArea); + if (s.startsWith(" of ")) + { + s = s.substring(3); + } + return s; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/playerscouter/PlayerScouterConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/playerscouter/PlayerScouterConfig.java index 258341e610..a8b63c3aa1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/playerscouter/PlayerScouterConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/playerscouter/PlayerScouterConfig.java @@ -41,22 +41,11 @@ public interface PlayerScouterConfig extends Config return ""; } - @ConfigItem( - keyName = "overlayEnabled", - name = "Attacker Overlay", - description = "This will highlight your attacker.", - position = 1 - ) - default boolean overlayEnabled() - { - return true; - } - @ConfigItem( keyName = "onlyWildy", name = "Only Scout in Wildy", description = "This will only scout players in the wilderness.", - position = 2 + position = 1 ) default boolean onlyWildy() { @@ -67,7 +56,7 @@ public interface PlayerScouterConfig extends Config keyName = "outputItems", name = "Output Items", description = "This will output all of their risked gear to the webhook.", - position = 3 + position = 2 ) default boolean outputItems() { @@ -78,7 +67,7 @@ public interface PlayerScouterConfig extends Config keyName = "minimumRisk", name = "Minimum Risk", description = "Minimum risk for the player to be scouted.", - position = 4 + position = 3 ) default int minimumRisk() { @@ -89,7 +78,7 @@ public interface PlayerScouterConfig extends Config keyName = "minimumValue", name = "Minimum Value", description = "Minimum value for the item to be posted on discord.", - position = 5 + position = 4 ) default int minimumValue() { @@ -100,7 +89,7 @@ public interface PlayerScouterConfig extends Config keyName = "timeout", name = "Timeout", description = "Minimum amount of ticks before the player can be scouted again. (1 tick = 600ms)", - position = 6 + position = 5 ) default int timeout() { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/playerscouter/Utils.java b/runelite-client/src/main/java/net/runelite/client/plugins/playerscouter/Utils.java deleted file mode 100644 index 0c5fa3e69d..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/playerscouter/Utils.java +++ /dev/null @@ -1,701 +0,0 @@ -/* - * Copyright (c) 2019, ganom - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.playerscouter; - -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; -import lombok.extern.slf4j.Slf4j; -import net.runelite.api.Actor; -import net.runelite.api.Client; -import net.runelite.api.ItemDefinition; -import net.runelite.api.NPC; -import net.runelite.api.Player; -import net.runelite.api.Prayer; -import net.runelite.api.Varbits; -import net.runelite.api.coords.WorldArea; -import net.runelite.api.coords.WorldPoint; -import net.runelite.api.kit.KitType; -import net.runelite.client.game.ItemManager; -import net.runelite.client.game.PvPValueBrokenItem; -import net.runelite.client.util.StackFormatter; -import net.runelite.http.api.discord.DiscordClient; -import net.runelite.http.api.discord.DiscordEmbed; -import net.runelite.http.api.discord.DiscordMessage; -import net.runelite.http.api.discord.embed.AuthorEmbed; -import net.runelite.http.api.discord.embed.FieldEmbed; -import net.runelite.http.api.discord.embed.FooterEmbed; -import net.runelite.http.api.discord.embed.ThumbnailEmbed; -import net.runelite.http.api.item.ItemEquipmentStats; -import net.runelite.http.api.item.ItemStats; -import okhttp3.HttpUrl; - -/* -This class is pretty useless, its not called anywhere else, -but I mainly have it so its pretty obvious whats happening -in the main class. Pretty much stuffing the ugly in here. - */ - -@Slf4j -class Utils -{ - private static final double INCREASE = 0.60; - private static final String ICONBASEURL = "https://www.osrsbox.com/osrsbox-db/items-icons/"; // Add item id + ".png" - private static final SimpleDateFormat SDF = new SimpleDateFormat("MMM dd h:mm a z"); - - static void reset(PlayerContainer player) - { - player.setMeleeAttack(0); - player.setMagicAttack(0); - player.setRangeAttack(0); - player.setMeleeDefence(0); - player.setMagicDefence(0); - player.setRangeDefence(0); - player.setRisk(0); - player.setPrayerBonus(0); - player.setDrainRate(0); - player.setOverhead(Utils.iconToPrayer(player.getPlayer())); - player.setAttackStyle(AttackStyle.UNKNOWN); - } - - static void update(PlayerContainer player, ItemManager itemManager, int restores, Map map) - { - updatePlayerGear(player, itemManager); - updateAttackStyle(player); - updateWeakness(player); - player.setPredictedPrayer(predictOffensivePrayer(player.getPrayer().getLevel(), player.getAttackStyle())); - updatePrayerDrainRate(player); - updateEstimatedPrayer(player, restores); - player.setLocation(location(player, map)); - player.setWildyLevel(getWildernessLevelFrom(player.getPlayer().getWorldLocation())); - player.setTargetString(targetStringBuilder(player)); - if (player.isScouted()) - { - player.setScoutTimer(player.getScoutTimer() - 1); - - if (player.getScoutTimer() <= 0) - { - player.setScouted(false); - player.setScoutTimer(500); - } - } - log.debug(player.toString()); - } - - //pvputil is private, so atm i can't grab from it. - private static int getWildernessLevelFrom(WorldPoint point) - { - int y = point.getY(); - - int underLevel = ((y - 9920) / 8) + 1; - int upperLevel = ((y - 3520) / 8) + 1; - - return y > 6400 ? underLevel : upperLevel; - } - - private static void updatePlayerGear(PlayerContainer player, ItemManager itemManager) - { - Map prices = new HashMap<>(); - - if (player.getPlayer().getPlayerAppearance() != null) - { - for (KitType kitType : KitType.values()) - { - if (kitType.equals(KitType.RING) || kitType.equals(KitType.AMMUNITION)) - { - continue; - } - - final int id = player.getPlayer().getPlayerAppearance().getEquipmentId(kitType); - - if (id == -1) - { - continue; - } - - if (kitType.equals(KitType.WEAPON)) - { - player.setWeapon(id); - } - - final ItemStats item = itemManager.getItemStats(id, false); - final ItemDefinition itemDefinition = itemManager.getItemDefinition(id); - - if (item == null) - { - log.debug("Item is null: {}", id); - continue; - } - - if (itemDefinition == null) - { - log.debug("Item Def is null: {}", id); - continue; - } - - if (PvPValueBrokenItem.breaksOnDeath(id)) - { - prices.put(id, itemManager.getBrokenValue(id)); - log.debug("Item has a broken value: Id {}, Value {}", id, itemManager.getBrokenValue(id)); - } - - if (!itemDefinition.isTradeable() && !PvPValueBrokenItem.breaksOnDeath(id)) - { - prices.put(id, itemDefinition.getPrice()); - } - else if (itemDefinition.isTradeable()) - { - prices.put(id, itemManager.getItemPrice(id, false)); - } - - ItemEquipmentStats stats = item.getEquipment(); - - if (stats == null) - { - log.debug("Stats are null: {}", item); - continue; - } - - player.setMeleeAttack(player.getMeleeAttack() + ((stats.getAcrush() + stats.getAslash() + stats.getAstab()) / 3)); - player.setMagicAttack(player.getMagicAttack() + stats.getAmagic()); - player.setRangeAttack(player.getRangeAttack() + stats.getArange()); - player.setMeleeDefence(player.getMeleeDefence() + ((stats.getDcrush() + stats.getDslash() + stats.getDstab()) / 3)); - player.setMagicDefence(player.getMagicDefence() + stats.getDmagic()); - player.setRangeDefence(player.getRangeDefence() + stats.getDrange()); - player.setPrayerBonus(player.getPrayerBonus() + stats.getPrayer()); - } - updateGear(player, prices); - } - } - - static void updateTarget(PlayerContainer player) - { - if (player.isTarget()) - { - if (player.getTimer() > 0) - { - player.setTimer(player.getTimer() - 1); - } - else if (player.getTimer() == 0) - { - player.setTarget(false); - } - } - } - - static void updateDefence(PlayerContainer player) - { - if (player.getOverhead() != null) - { - //yeah i know this is a shit way to do it :shrug: - switch (player.getOverhead()) - { - case PROTECT_FROM_MELEE: - player.setMeleeDefence((int) (player.getMeleeDefence() / INCREASE)); - log.debug("Melee Overhead, Defence Increased"); - break; - case PROTECT_FROM_MAGIC: - player.setMagicDefence((int) (player.getMagicDefence() / INCREASE)); - log.debug("Magic Overhead, Defence Increased"); - break; - case PROTECT_FROM_MISSILES: - player.setRangeDefence((int) (player.getRangeDefence() / INCREASE)); - log.debug("Range Overhead, Defence Increased"); - break; - } - } - } - - private static void updateGear(PlayerContainer player, Map prices) - { - player.setGear(prices.entrySet() - .stream() - .sorted(Collections.reverseOrder(Map.Entry.comparingByValue())) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -> oldValue, LinkedHashMap::new))); - - player.setRiskedGear(prices.entrySet() - .stream() - .sorted(Collections.reverseOrder(Map.Entry.comparingByValue())) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -> oldValue, LinkedHashMap::new))); - - if (player.getPlayer().getSkullIcon() == null) - { - removeEntries(player.getRiskedGear(), player.getPrayer().getLevel() <= 25 ? 3 : 4); - } - else - { - removeEntries(player.getRiskedGear(), player.getPrayer().getLevel() <= 25 ? 0 : 1); - } - - player.getRiskedGear().values().forEach(price -> player.setRisk(player.getRisk() + price)); - prices.clear(); - } - - private static void updateAttackStyle(PlayerContainer player) - { - if (player.getMagicAttack() >= player.getRangeAttack() && player.getMagicAttack() >= player.getMeleeAttack()) - { - player.setAttackStyle(AttackStyle.MAGE); - } - else if (player.getRangeAttack() >= player.getMagicAttack() && player.getRangeAttack() >= player.getMeleeAttack()) - { - player.setAttackStyle(AttackStyle.RANGE); - } - else if (player.getMeleeAttack() >= player.getMagicAttack() && player.getMeleeAttack() >= player.getRangeAttack()) - { - player.setAttackStyle(AttackStyle.MELEE); - } - } - - private static void updateWeakness(PlayerContainer player) - { - if (player.getMagicDefence() <= player.getRangeDefence() && player.getMagicDefence() <= player.getMeleeDefence()) - { - player.setWeakness(AttackStyle.MAGE); - } - else if (player.getRangeDefence() <= player.getMagicDefence() && player.getRangeDefence() <= player.getMeleeDefence()) - { - player.setWeakness(AttackStyle.RANGE); - } - else if (player.getMeleeAttack() <= player.getRangeDefence() && player.getMeleeAttack() <= player.getMagicDefence()) - { - player.setWeakness(AttackStyle.MELEE); - } - } - - private static void updateEstimatedPrayer(PlayerContainer player, int restores) - { - player.setEstimatedPrayerString(getEstimatedPrayerRemaining(player, restores)); - - if (player.getOverhead() == null) - { - return; - } - - if (player.getEstimatedPrayer() >= 0) - { - player.setEstimatedPrayer(player.getEstimatedPrayer() - player.getDrainRate()); - } - } - - private static void updatePrayerDrainRate(PlayerContainer player) - { - double drainRate = 0.0; - - if (player.getOverhead() != null) - { - drainRate += player.getOverhead().getDrainRate(); - } - if (player.getPredictedPrayer() != null) - { - drainRate += player.getPredictedPrayer().getDrainRate(); - } - if (player.getPrayer().getLevel() >= 25) - { - drainRate += Prayer.PROTECT_ITEM.getDrainRate(); - } - drainRate = (((drainRate / 100)) / (1.0 + (player.getPrayerBonus() / 30.0))); - - player.setDrainRate(drainRate); - } - - private static String getEstimatedPrayerRemaining(PlayerContainer player, int restores) - { - final double drainRate = player.getDrainRate(); - - if (drainRate == 0) - { - return "N/A"; - } - - log.debug("Drain Rate: " + drainRate); - - final int prayerLevel = player.getPrayer().getLevel(); - final int restoreValue = (int) (4 * (prayerLevel * 0.25) + 8); - final double estimatedTotalPrayer = prayerLevel + (restoreValue * restores); - final double estimatedPrayer = player.getEstimatedPrayer(); - final int restoreValueLeft = (int) Math.round(estimatedPrayer - player.getPrayer().getLevel()); - - if (player.getEstimatedPrayer() == 0) - { - player.setEstimatedPrayer(estimatedTotalPrayer); - } - - if (restoreValueLeft > 0) - { - return player.getPrayer().getLevel() + "(" + restoreValueLeft + ")"; - } - - return Integer.toString((int) Math.round(estimatedPrayer)); - } - - private static void removeEntries(LinkedHashMap map, int quantity) - { - if (map.size() < quantity) - { - log.debug("Size is lower than removal quantity."); - } - for (int i = 0; i < quantity; i++) - { - if (!map.entrySet().iterator().hasNext()) - { - log.debug("Attempted to remove entries, but there was not enough to remove."); - return; - } - log.debug("Entry Removed: " + map.entrySet().iterator().next()); - map.entrySet().remove(map.entrySet().iterator().next()); - } - } - - private static Map.Entry getEntry(LinkedHashMap map) - { - if (!map.isEmpty()) - { - Iterator> entry = map.entrySet().iterator(); - - for (int i = 0; i < 1; i++) - { - entry.next(); - } - - return entry.next(); - } - return null; - } - - private static Prayer iconToPrayer(Player player) - { - if (player.getOverheadIcon() != null) - { - switch (player.getOverheadIcon()) - { - case RANGED: - return Prayer.PROTECT_FROM_MISSILES; - case MAGIC: - return Prayer.PROTECT_FROM_MAGIC; - case MELEE: - return Prayer.PROTECT_FROM_MELEE; - case SMITE: - return Prayer.SMITE; - case REDEMPTION: - return Prayer.REDEMPTION; - case RETRIBUTION: - return Prayer.RETRIBUTION; - default: - return null; - } - } - return null; - } - - private static Prayer predictOffensivePrayer(int prayerLevel, AttackStyle attackStyle) - { - switch (attackStyle) - { - case MELEE: - if (prayerLevel <= 12 && prayerLevel >= 1) - { - return Prayer.BURST_OF_STRENGTH; - } - else if (prayerLevel <= 30 && prayerLevel >= 13) - { - return Prayer.SUPERHUMAN_STRENGTH; - } - else if (prayerLevel <= 59 && prayerLevel >= 31) - { - return Prayer.ULTIMATE_STRENGTH; - } - else if (prayerLevel <= 69 && prayerLevel >= 60) - { - return Prayer.CHIVALRY; - } - else if (prayerLevel >= 70) - { - return Prayer.PIETY; - } - case RANGE: - if (prayerLevel <= 8 && prayerLevel >= 1) - { - return Prayer.SHARP_EYE; - } - else if (prayerLevel <= 43 && prayerLevel >= 26) - { - return Prayer.HAWK_EYE; - } - else if (prayerLevel <= 73 && prayerLevel >= 44) - { - return Prayer.EAGLE_EYE; - } - else if (prayerLevel >= 74) - { - return Prayer.RIGOUR; - } - case MAGE: - if (prayerLevel <= 26 && prayerLevel >= 9) - { - return Prayer.MYSTIC_WILL; - } - else if (prayerLevel <= 44 && prayerLevel >= 27) - { - return Prayer.MYSTIC_LORE; - } - else if (prayerLevel <= 76 && prayerLevel >= 45) - { - return Prayer.MYSTIC_MIGHT; - } - else if (prayerLevel >= 77) - { - return Prayer.AUGURY; - } - default: - return Prayer.PROTECT_ITEM; - } - } - - private static String targetStringBuilder(PlayerContainer player) - { - if (player.getPlayer().getInteracting() != null) - { - Actor actor = player.getPlayer().getInteracting(); - if (actor instanceof Player) - { - return "(Player) " + actor.getName(); - } - else if (actor instanceof NPC) - { - return "(NPC) " + actor.getName(); - } - } - return "No Target Detected"; - } - - static void scoutPlayer(PlayerContainer player, HttpUrl url, DiscordClient discordClient, ItemManager itemManager, Client client, int minimumValue, boolean outputItems) - { - if (player.isScouted()) - { - return; - } - - List fieldList = new ArrayList<>(); - //green - String color = "8388352"; - - if (player.getRisk() < 1000000 && player.getRisk() > 150000) - { - //blue - color = "32767"; - } - else if (player.getRisk() > 1000000) - { - //orange - color = "16744448"; - } - - ThumbnailEmbed image = ThumbnailEmbed.builder() - .url(ICONBASEURL + player.getWeapon() + ".png") - .build(); - - fieldList.add(FieldEmbed.builder() - .name("Risk") - .value(StackFormatter.quantityToRSDecimalStack(player.getRisk())) - .inline(true) - .build()); - - fieldList.add(FieldEmbed.builder() - .name("World") - .value(Integer.toString(client.getWorld())) - .inline(true) - .build()); - - fieldList.add(FieldEmbed.builder() - .name("Combat Level") - .value(Integer.toString(player.getPlayer().getCombatLevel())) - .inline(true) - .build()); - if (client.getVar(Varbits.IN_WILDERNESS) == 1) - { - fieldList.add(FieldEmbed.builder() - .name("Wildy Level") - .value(Integer.toString(player.getWildyLevel())) - .inline(true) - .build()); - - fieldList.add(FieldEmbed.builder() - .name("Location") - .value(player.getLocation()) - .inline(true) - .build()); - } - - fieldList.add(FieldEmbed.builder() - .name("Target") - .value(player.getTargetString()) - .inline(true) - .build()); - - if (outputItems) - { - fieldList.add(FieldEmbed.builder() - .name("Risked Items Sorted by Value") - .value("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━") - .build()); - - final int[] items = {0}; - - player.getRiskedGear().forEach((gear, value) -> - { - if (value <= 0 || value <= minimumValue) - { - items[0]++; - return; - } - - ItemStats item = itemManager.getItemStats(gear, false); - - if (item == null) - { - log.error("Item is Null: {}", gear); - return; - } - - fieldList.add(FieldEmbed.builder() - .name(item.getName()) - .value("Value: " + StackFormatter.quantityToRSDecimalStack(value)) - .inline(true) - .build()); - }); - - if (items[0] > 0) - { - fieldList.add(FieldEmbed.builder() - .name("Items below value: " + minimumValue) - .value(Integer.toString(items[0])) - .inline(true) - .build()); - } - } - - String icon = ICONBASEURL + Objects.requireNonNull(getEntry(player.getGear())).getKey() + ".png"; - String name = "☠️ " + player.getName() + " ☠️"; - - if (player.getPlayer().getSkullIcon() == null) - { - name = player.getName(); - } - - message(name, " ", icon, image, fieldList, url, discordClient, color); - player.setScouted(true); - fieldList.clear(); - } - - private static void message(String name, String description, String iconUrl, ThumbnailEmbed thumbnail, List fields, HttpUrl url, DiscordClient discordClient, String color) - { - log.debug("Message Contents: {}, {}, {}, {}, {}", name, description, thumbnail, Arrays.toString(fields.toArray()), url); - log.debug("Fields: {}", fields); - - if (name.isEmpty() || fields.isEmpty()) - { - log.error("Discord message will fail with a missing name/description/field"); - return; - } - - final Date currentTime = new Date(System.currentTimeMillis()); - - DiscordEmbed discordEmbed = DiscordEmbed.builder() - .author(AuthorEmbed.builder() - .icon_url(iconUrl) - .name(name) - .build()) - .thumbnail(thumbnail) - .description(description) - .fields(fields) - .footer(FooterEmbed.builder() - .icon_url("https://raw.githubusercontent.com/runelite/runelite/master/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/ultimate_ironman.png") - .text("Gabon Scouter | Time: " + SDF.format(currentTime)) - .build()) - .color(color) - .build(); - - DiscordMessage discordMessage = new DiscordMessage("Gabon Scouter", "", "https://i.imgur.com/2A6dr7q.png"); - discordMessage.getEmbeds().add(discordEmbed); - discordClient.message(url, discordMessage); - fields.clear(); - } - - private static String location(PlayerContainer player, Map map) - { - final WorldPoint wl = player.getPlayer().getWorldLocation(); - int dist = 10000; - String s = ""; - WorldArea closestArea = null; - for (Map.Entry entry : map.entrySet()) - { - WorldArea worldArea = entry.getKey(); - - if (worldArea.toWorldPointList().contains(wl)) - { - s = entry.getValue(); - return s; - } - int distTo = worldArea.distanceTo(wl); - if (distTo < dist) - { - dist = distTo; - closestArea = worldArea; - } - } - if (wl.getY() > (Objects.requireNonNull(closestArea).toWorldPoint().getY() + closestArea.getHeight())) - { - s = s + "N"; - } - if (wl.getY() < closestArea.toWorldPoint().getY()) - { - s = s + "S"; - } - if (wl.getX() < closestArea.toWorldPoint().getX()) - { - s = s + "W"; - } - if (wl.getX() > (closestArea.toWorldPoint().getX() + closestArea.getWidth())) - { - s = s + "E"; - } - s = s + " of "; - s = s + map.get(closestArea); - if (s.startsWith(" of ")) - { - s = s.substring(3); - } - return s; - } -}