Merge branch 'master' of https://github.com/runelite/runelite into runelite-master
This commit is contained in:
@@ -46,11 +46,13 @@ import javax.inject.Singleton;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.ChatMessageType;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.Constants;
|
||||
import net.runelite.api.GameState;
|
||||
import net.runelite.client.chat.ChatColorType;
|
||||
import net.runelite.client.chat.ChatMessageBuilder;
|
||||
import net.runelite.client.chat.ChatMessageManager;
|
||||
import net.runelite.client.chat.QueuedMessage;
|
||||
import net.runelite.client.config.FlashNotification;
|
||||
import net.runelite.client.config.RuneLiteConfig;
|
||||
import net.runelite.client.ui.ClientUI;
|
||||
import net.runelite.client.util.OSType;
|
||||
@@ -68,7 +70,8 @@ public class Notifier
|
||||
|
||||
// Notifier properties
|
||||
private static final Color FLASH_COLOR = new Color(255, 0, 0, 70);
|
||||
private static final int FLASH_DURATION = 2000;
|
||||
private static final int MINIMUM_FLASH_DURATION_MILLIS = 2000;
|
||||
private static final int MINIMUM_FLASH_DURATION_TICKS = MINIMUM_FLASH_DURATION_MILLIS / Constants.CLIENT_TICK_LENGTH;
|
||||
|
||||
private final Client client;
|
||||
private final String appName;
|
||||
@@ -79,6 +82,7 @@ public class Notifier
|
||||
private final Path notifyIconPath;
|
||||
private final boolean terminalNotifierAvailable;
|
||||
private Instant flashStart;
|
||||
private long mouseLastPressedMillis;
|
||||
|
||||
@Inject
|
||||
private Notifier(
|
||||
@@ -146,9 +150,10 @@ public class Notifier
|
||||
.build());
|
||||
}
|
||||
|
||||
if (runeLiteConfig.enableFlashNotification())
|
||||
if (runeLiteConfig.flashNotification() != FlashNotification.DISABLED)
|
||||
{
|
||||
flashStart = Instant.now();
|
||||
mouseLastPressedMillis = client.getMouseLastPressedMillis();
|
||||
}
|
||||
|
||||
log.debug(message);
|
||||
@@ -156,24 +161,48 @@ public class Notifier
|
||||
|
||||
public void processFlash(final Graphics2D graphics)
|
||||
{
|
||||
if (flashStart == null || client.getGameCycle() % 40 >= 20)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if (client.getGameState() != GameState.LOGGED_IN)
|
||||
if (flashStart == null || client.getGameState() != GameState.LOGGED_IN)
|
||||
{
|
||||
flashStart = null;
|
||||
return;
|
||||
}
|
||||
|
||||
FlashNotification flashNotification = runeLiteConfig.flashNotification();
|
||||
|
||||
if (client.getGameCycle() % 40 >= 20
|
||||
// For solid colour, fall through every time.
|
||||
&& (flashNotification == FlashNotification.FLASH_TWO_SECONDS
|
||||
|| flashNotification == FlashNotification.FLASH_UNTIL_CANCELLED))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
final Color color = graphics.getColor();
|
||||
graphics.setColor(FLASH_COLOR);
|
||||
graphics.fill(new Rectangle(client.getCanvas().getSize()));
|
||||
graphics.setColor(color);
|
||||
|
||||
if (Instant.now().minusMillis(FLASH_DURATION).isAfter(flashStart))
|
||||
if (!Instant.now().minusMillis(MINIMUM_FLASH_DURATION_MILLIS).isAfter(flashStart))
|
||||
{
|
||||
flashStart = null;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (flashNotification)
|
||||
{
|
||||
case FLASH_TWO_SECONDS:
|
||||
case SOLID_TWO_SECONDS:
|
||||
flashStart = null;
|
||||
break;
|
||||
case SOLID_UNTIL_CANCELLED:
|
||||
case FLASH_UNTIL_CANCELLED:
|
||||
// Any interaction with the client since the notification started will cancel it after the minimum duration
|
||||
if (client.getMouseIdleTicks() < MINIMUM_FLASH_DURATION_TICKS
|
||||
|| client.getKeyboardIdleTicks() < MINIMUM_FLASH_DURATION_TICKS
|
||||
|| client.getMouseLastPressedMillis() > mouseLastPressedMillis)
|
||||
{
|
||||
flashStart = null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Twiglet1022 <https://github.com/Twiglet1022>
|
||||
* 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.config;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum FlashNotification
|
||||
{
|
||||
DISABLED("Off"),
|
||||
FLASH_TWO_SECONDS("Flash for 2 seconds"),
|
||||
SOLID_TWO_SECONDS("Solid for 2 seconds"),
|
||||
FLASH_UNTIL_CANCELLED("Flash until cancelled"),
|
||||
SOLID_UNTIL_CANCELLED("Solid until cancelled");
|
||||
|
||||
private final String type;
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
}
|
||||
@@ -191,9 +191,9 @@ public interface RuneLiteConfig extends Config
|
||||
description = "Flashes the game frame as a notification",
|
||||
position = 24
|
||||
)
|
||||
default boolean enableFlashNotification()
|
||||
default FlashNotification flashNotification()
|
||||
{
|
||||
return false;
|
||||
return FlashNotification.DISABLED;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
|
||||
@@ -44,6 +44,7 @@ import javax.inject.Singleton;
|
||||
import lombok.Value;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.Constants;
|
||||
import static net.runelite.api.Constants.CLIENT_DEFAULT_ZOOM;
|
||||
import static net.runelite.api.Constants.HIGH_ALCHEMY_CONSTANT;
|
||||
import net.runelite.api.GameState;
|
||||
@@ -521,7 +522,7 @@ public class ItemManager
|
||||
*/
|
||||
private AsyncBufferedImage loadImage(int itemId, int quantity, boolean stackable)
|
||||
{
|
||||
AsyncBufferedImage img = new AsyncBufferedImage(36, 32, BufferedImage.TYPE_INT_ARGB);
|
||||
AsyncBufferedImage img = new AsyncBufferedImage(Constants.ITEM_SPRITE_WIDTH, Constants.ITEM_SPRITE_HEIGHT, BufferedImage.TYPE_INT_ARGB);
|
||||
clientThread.invoke(() ->
|
||||
{
|
||||
if (client.getGameState().ordinal() < GameState.LOGIN_SCREEN.ordinal())
|
||||
|
||||
@@ -144,10 +144,12 @@ public enum ItemMapping
|
||||
// Bounty hunter
|
||||
ITEM_GRANITE_MAUL(GRANITE_MAUL, GRANITE_MAUL_12848),
|
||||
ITEM_MAGIC_SHORTBOW(MAGIC_SHORTBOW, MAGIC_SHORTBOW_I),
|
||||
ITEM_MAGIC_SHORTBOW_SCROLL(MAGIC_SHORTBOW_SCROLL, MAGIC_SHORTBOW_I),
|
||||
ITEM_SARADOMINS_BLESSED_SWORD(SARADOMINS_TEAR, SARADOMINS_BLESSED_SWORD),
|
||||
|
||||
// Jewellery with charges
|
||||
ITEM_RING_OF_WEALTH(RING_OF_WEALTH, RING_OF_WEALTH_I, RING_OF_WEALTH_1, RING_OF_WEALTH_I1, RING_OF_WEALTH_2, RING_OF_WEALTH_I2, RING_OF_WEALTH_3, RING_OF_WEALTH_I3, RING_OF_WEALTH_4, RING_OF_WEALTH_I4, RING_OF_WEALTH_I5),
|
||||
ITEM_RING_OF_WEALTH_SCROLL(RING_OF_WEALTH_SCROLL, RING_OF_WEALTH_I, RING_OF_WEALTH_I1, RING_OF_WEALTH_I2, RING_OF_WEALTH_I3, RING_OF_WEALTH_I4, RING_OF_WEALTH_I5),
|
||||
ITEM_AMULET_OF_GLORY(AMULET_OF_GLORY, AMULET_OF_GLORY1, AMULET_OF_GLORY2, AMULET_OF_GLORY3, AMULET_OF_GLORY5),
|
||||
ITEM_AMULET_OF_GLORY_T(AMULET_OF_GLORY_T, AMULET_OF_GLORY_T1, AMULET_OF_GLORY_T2, AMULET_OF_GLORY_T3, AMULET_OF_GLORY_T5),
|
||||
ITEM_SKILLS_NECKLACE(SKILLS_NECKLACE, SKILLS_NECKLACE1, SKILLS_NECKLACE2, SKILLS_NECKLACE3, SKILLS_NECKLACE5),
|
||||
|
||||
@@ -109,7 +109,7 @@ public class LootManager
|
||||
case NpcID.LIZARD:
|
||||
|
||||
case NpcID.ZYGOMITE:
|
||||
case NpcID.ZYGOMITE_474:
|
||||
case NpcID.ZYGOMITE_1024:
|
||||
case NpcID.ANCIENT_ZYGOMITE:
|
||||
|
||||
// these monsters die with >0 hp, so we just look for coincident
|
||||
|
||||
@@ -34,6 +34,7 @@ import javax.inject.Inject;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.Constants;
|
||||
import net.runelite.api.InventoryID;
|
||||
import net.runelite.api.Item;
|
||||
import net.runelite.api.ItemContainer;
|
||||
|
||||
@@ -50,6 +50,7 @@ import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import lombok.Getter;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.Constants;
|
||||
import net.runelite.api.InventoryID;
|
||||
import net.runelite.api.Item;
|
||||
import net.runelite.api.ItemDefinition;
|
||||
@@ -730,7 +731,13 @@ public class TabInterface
|
||||
|
||||
if (tagTab.getIcon() == null)
|
||||
{
|
||||
Widget icon = createGraphic(ColorUtil.wrapWithColorTag(tagTab.getTag(), HILIGHT_COLOR), -1, tagTab.getIconItemId(), 36, 32, bounds.x + 3, 1, false);
|
||||
Widget icon = createGraphic(
|
||||
ColorUtil.wrapWithColorTag(tagTab.getTag(), HILIGHT_COLOR),
|
||||
-1,
|
||||
tagTab.getIconItemId(),
|
||||
Constants.ITEM_SPRITE_WIDTH, Constants.ITEM_SPRITE_HEIGHT,
|
||||
bounds.x + 3, 1,
|
||||
false);
|
||||
int clickmask = icon.getClickMask();
|
||||
clickmask |= WidgetConfig.DRAG;
|
||||
clickmask |= WidgetConfig.DRAG_ON;
|
||||
|
||||
@@ -35,7 +35,7 @@ public enum CannonSpots
|
||||
|
||||
BLOODVELDS(new WorldPoint(2439, 9821, 0), new WorldPoint(2448, 9821, 0), new WorldPoint(2472, 9833, 0), new WorldPoint(2453, 9817, 0)),
|
||||
FIRE_GIANTS(new WorldPoint(2393, 9782, 0), new WorldPoint(2412, 9776, 0), new WorldPoint(2401, 9780, 0)),
|
||||
ABBERANT_SPECTRES(new WorldPoint(2456, 9791, 0)),
|
||||
ABERRANT_SPECTRES(new WorldPoint(2456, 9791, 0)),
|
||||
HELLHOUNDS(new WorldPoint(2431, 9776, 0), new WorldPoint(2413, 9786, 0), new WorldPoint(2783, 9686, 0), new WorldPoint(3198, 10071, 0)),
|
||||
BLACK_DEMONS(new WorldPoint(2859, 9778, 0), new WorldPoint(2841, 9791, 0)),
|
||||
ELVES(new WorldPoint(2044, 4635, 0)),
|
||||
|
||||
@@ -37,6 +37,7 @@ import lombok.Value;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.ChatMessageType;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.Constants;
|
||||
import net.runelite.api.Experience;
|
||||
import net.runelite.api.IconID;
|
||||
import net.runelite.api.ItemDefinition;
|
||||
|
||||
@@ -129,9 +129,12 @@ public class ChatNotificationsPlugin extends Plugin
|
||||
{
|
||||
List<String> items = Text.fromCSV(config.highlightWordsString());
|
||||
String joined = items.stream()
|
||||
.map(Text::escapeJagex) // we compare these strings to the raw Jagex ones
|
||||
.map(Pattern::quote)
|
||||
.collect(Collectors.joining("|"));
|
||||
highlightMatcher = Pattern.compile("\\b(" + joined + ")\\b", Pattern.CASE_INSENSITIVE);
|
||||
// To match <word> \b doesn't work due to <> not being in \w,
|
||||
// so match \b or \s
|
||||
highlightMatcher = Pattern.compile("(?:\\b|(?<=\\s))(" + joined + ")(?:\\b|(?=\\s))", Pattern.CASE_INSENSITIVE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,7 +142,6 @@ public class ChatNotificationsPlugin extends Plugin
|
||||
public void onChatMessage(ChatMessage chatMessage)
|
||||
{
|
||||
MessageNode messageNode = chatMessage.getMessageNode();
|
||||
String nodeValue = Text.removeTags(messageNode.getValue());
|
||||
boolean update = false;
|
||||
|
||||
switch (chatMessage.getType())
|
||||
@@ -202,6 +204,7 @@ public class ChatNotificationsPlugin extends Plugin
|
||||
|
||||
if (highlightMatcher != null)
|
||||
{
|
||||
String nodeValue = messageNode.getValue();
|
||||
Matcher matcher = highlightMatcher.matcher(nodeValue);
|
||||
boolean found = false;
|
||||
StringBuffer stringBuffer = new StringBuffer();
|
||||
|
||||
@@ -259,7 +259,7 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc
|
||||
new CrypticClue("Search the drawers in Catherby's Archery shop.", DRAWERS_350, new WorldPoint(2825, 3442, 0), "Hickton's Archery Emporium in Catherby."),
|
||||
new CrypticClue("The hand ain't listening.", "The Face", new WorldPoint(3019, 3232, 0), "Talk to The Face located by the manhole just north of the Port Sarim fishing shop."),
|
||||
new CrypticClue("Search the chest in the left-hand tower of Camelot Castle.", CLOSED_CHEST_25592, new WorldPoint(2748, 3495, 2), "Located on the second floor of the western tower of Camelot."),
|
||||
new CrypticClue("Kill the spiritual, magic and godly whilst representing their own god", null, "Kill a spiritual mage while wearing a corresponding god item."),
|
||||
new CrypticClue("Kill the spiritual, magic and godly whilst representing their own god.", null, "Kill a spiritual mage while wearing a corresponding god item."),
|
||||
new CrypticClue("Anger those who adhere to Saradomin's edicts to prevent travel.", "Monk of Entrana", new WorldPoint(3042, 3236, 0), "Port Sarim Docks, try to charter a ship to Entrana with armour or weapons equipped."),
|
||||
new CrypticClue("South of a river in a town surrounded by the undead, what lies beneath the furnace?", new WorldPoint(2857, 2966, 0), "Dig in front of the Shilo Village furnace."),
|
||||
new CrypticClue("Talk to the Squire in the White Knights' castle in Falador.", "Squire", new WorldPoint(2977, 3343, 0), "The squire is located in the courtyard of the White Knights' Castle."),
|
||||
|
||||
@@ -87,11 +87,11 @@ public class FaloTheBardClue extends ClueScroll implements TextClueScroll, NpcCl
|
||||
new FaloTheBardClue("A shiny helmet of flight, to obtain this with melee, struggle you might.", item(ARMADYL_HELMET)),
|
||||
// The wiki doesn't specify whether the trimmed dragon defender will work so I've assumed that it doesn't
|
||||
new FaloTheBardClue("A sword held in the other hand, red its colour, Cyclops strength you must withstand.", item(DRAGON_DEFENDER)),
|
||||
new FaloTheBardClue("A token used to kill mythical beasts, in hope of a blade or just for an xp feast.", item(WARRIOR_GUILD_TOKEN)),
|
||||
new FaloTheBardClue("A token used to kill mythical beasts, in hopes of a blade or just for an xp feast.", item(WARRIOR_GUILD_TOKEN)),
|
||||
new FaloTheBardClue("Green is my favorite, mature ale I do love, this takes your herblore above.", item(GREENMANS_ALEM)),
|
||||
new FaloTheBardClue("It can hold down a boat or crush a goat, this object, you see, is quite heavy.", item(BARRELCHEST_ANCHOR)),
|
||||
new FaloTheBardClue("It comes from the ground, underneath the snowy plain. Trolls aplenty, with what looks like a mane.", item(BASALT)),
|
||||
new FaloTheBardClue("No attack to wield, only strength is required, made of obsidian but with no room for a shield.", item(TZHAARKETOM)),
|
||||
new FaloTheBardClue("No attack to wield, only strength is required, made of obsidian, but with no room for a shield.", item(TZHAARKETOM)),
|
||||
new FaloTheBardClue("Penance healers runners and more, obtaining this body often gives much deplore.", item(FIGHTER_TORSO)),
|
||||
new FaloTheBardClue("Strangely found in a chest, many believe these gloves are the best.", item(BARROWS_GLOVES)),
|
||||
new FaloTheBardClue("These gloves of white won't help you fight, but aid in cooking, they just might.", item(COOKING_GAUNTLETS)),
|
||||
|
||||
@@ -26,6 +26,8 @@ package net.runelite.client.plugins.emojis;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.Arrays;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
import joptsimple.internal.Strings;
|
||||
@@ -52,6 +54,8 @@ import net.runelite.client.util.ImageUtil;
|
||||
@Slf4j
|
||||
public class EmojiPlugin extends Plugin
|
||||
{
|
||||
private static final Pattern TAG_REGEXP = Pattern.compile("<[^>]*>");
|
||||
|
||||
@Inject
|
||||
private Client client;
|
||||
|
||||
@@ -128,7 +132,8 @@ public class EmojiPlugin extends Plugin
|
||||
return;
|
||||
}
|
||||
|
||||
final String message = chatMessage.getMessage();
|
||||
final MessageNode messageNode = chatMessage.getMessageNode();
|
||||
final String message = messageNode.getValue();
|
||||
final String updatedMessage = updateMessage(message);
|
||||
|
||||
if (updatedMessage == null)
|
||||
@@ -136,7 +141,6 @@ public class EmojiPlugin extends Plugin
|
||||
return;
|
||||
}
|
||||
|
||||
final MessageNode messageNode = chatMessage.getMessageNode();
|
||||
messageNode.setRuneLiteFormatMessage(updatedMessage);
|
||||
chatMessageManager.update(messageNode);
|
||||
client.refreshChat();
|
||||
@@ -169,7 +173,9 @@ public class EmojiPlugin extends Plugin
|
||||
boolean editedMessage = false;
|
||||
for (int i = 0; i < messageWords.length; i++)
|
||||
{
|
||||
final Emoji emoji = Emoji.getEmoji(messageWords[i]);
|
||||
// Remove tags except for <lt> and <gt>
|
||||
final String trigger = removeTags(messageWords[i]);
|
||||
final Emoji emoji = Emoji.getEmoji(trigger);
|
||||
|
||||
if (emoji == null)
|
||||
{
|
||||
@@ -178,7 +184,7 @@ public class EmojiPlugin extends Plugin
|
||||
|
||||
final int emojiId = modIconsStart + emoji.ordinal();
|
||||
|
||||
messageWords[i] = "<img=" + emojiId + ">";
|
||||
messageWords[i] = messageWords[i].replace(trigger, "<img=" + emojiId + ">");
|
||||
editedMessage = true;
|
||||
}
|
||||
|
||||
@@ -190,4 +196,29 @@ public class EmojiPlugin extends Plugin
|
||||
|
||||
return Strings.join(messageWords, " ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove tags, except for <lt> and <gt>
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private static String removeTags(String str)
|
||||
{
|
||||
StringBuffer stringBuffer = new StringBuffer();
|
||||
Matcher matcher = TAG_REGEXP.matcher(str);
|
||||
while (matcher.find())
|
||||
{
|
||||
matcher.appendReplacement(stringBuffer, "");
|
||||
String match = matcher.group(0);
|
||||
switch (match)
|
||||
{
|
||||
case "<lt>":
|
||||
case "<gt>":
|
||||
stringBuffer.append(match);
|
||||
break;
|
||||
}
|
||||
}
|
||||
matcher.appendTail(stringBuffer);
|
||||
return stringBuffer.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ import javax.inject.Inject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.ChatMessageType;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.Constants;
|
||||
import net.runelite.api.ItemDefinition;
|
||||
import net.runelite.api.events.ChatMessage;
|
||||
import net.runelite.api.events.GameStateChanged;
|
||||
@@ -199,26 +200,26 @@ public class ExaminePlugin extends Plugin
|
||||
log.debug("Got examine for {} {}: {}", pendingExamine.getType(), pendingExamine.getId(), event.getMessage());
|
||||
|
||||
// If it is an item, show the price of it
|
||||
final ItemDefinition itemComposition;
|
||||
final ItemDefinition Itemdefinition;
|
||||
if (pendingExamine.getType() == ExamineType.ITEM || pendingExamine.getType() == ExamineType.ITEM_BANK_EQ)
|
||||
{
|
||||
final int itemId = pendingExamine.getId();
|
||||
final int itemQuantity = pendingExamine.getQuantity();
|
||||
itemComposition = itemManager.getItemDefinition(itemId);
|
||||
Itemdefinition = itemManager.getItemDefinition(itemId);
|
||||
|
||||
if (itemComposition != null)
|
||||
if (Itemdefinition != null)
|
||||
{
|
||||
final int id = itemManager.canonicalize(itemComposition.getId());
|
||||
executor.submit(() -> getItemPrice(id, itemComposition, itemQuantity));
|
||||
final int id = itemManager.canonicalize(Itemdefinition.getId());
|
||||
executor.submit(() -> getItemPrice(id, Itemdefinition, itemQuantity));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
itemComposition = null;
|
||||
Itemdefinition = null;
|
||||
}
|
||||
|
||||
// Don't submit examine info for tradeable items, which we already have from the RS item api
|
||||
if (itemComposition != null && itemComposition.isTradeable())
|
||||
if (Itemdefinition != null && Itemdefinition.isTradeable())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.Constants;
|
||||
import net.runelite.api.GameState;
|
||||
import net.runelite.api.Item;
|
||||
import net.runelite.api.ItemDefinition;
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Hydrox6 <ikada@protonmail.ch>
|
||||
* 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.interfacestyles;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import java.util.Map;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import static net.runelite.api.SpriteID.*;
|
||||
import net.runelite.client.game.SpriteOverride;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
enum HealthbarOverride implements SpriteOverride
|
||||
{
|
||||
BACK_30PX(HEALTHBAR_DEFAULT_BACK_30PX, "back_30px.png"),
|
||||
BACK_50PX(HEALTHBAR_DEFAULT_BACK_50PX, "back_30px.png"),
|
||||
BACK_60PX(HEALTHBAR_DEFAULT_BACK_60PX, "back_30px.png"),
|
||||
BACK_80PX(HEALTHBAR_DEFAULT_BACK_80PX, "back_90px.png"),
|
||||
BACK_100PX(HEALTHBAR_DEFAULT_BACK_100PX, "back_90px.png"),
|
||||
BACK_120PX(HEALTHBAR_DEFAULT_BACK_120PX, "back_90px.png"),
|
||||
BACK_140PX(HEALTHBAR_DEFAULT_BACK_140PX, "back_90px.png"),
|
||||
BACK_160PX(HEALTHBAR_DEFAULT_BACK_160PX, "back_90px.png"),
|
||||
|
||||
FRONT_30PX(HEALTHBAR_DEFAULT_FRONT_30PX, "front_30px.png"),
|
||||
FRONT_50PX(HEALTHBAR_DEFAULT_FRONT_50PX, "front_30px.png"),
|
||||
FRONT_60PX(HEALTHBAR_DEFAULT_FRONT_60PX, "front_30px.png"),
|
||||
FRONT_80PX(HEALTHBAR_DEFAULT_FRONT_80PX, "front_90px.png"),
|
||||
FRONT_100PX(HEALTHBAR_DEFAULT_FRONT_100PX, "front_90px.png"),
|
||||
FRONT_120PX(HEALTHBAR_DEFAULT_FRONT_120PX, "front_90px.png"),
|
||||
FRONT_140PX(HEALTHBAR_DEFAULT_FRONT_140PX, "front_90px.png"),
|
||||
FRONT_160PX(HEALTHBAR_DEFAULT_FRONT_160PX, "front_90px.png");
|
||||
|
||||
@Getter
|
||||
private final int spriteId;
|
||||
|
||||
private final String fileName;
|
||||
|
||||
@Getter
|
||||
private int padding = 1;
|
||||
|
||||
private static final Map<Integer, HealthbarOverride> MAP;
|
||||
|
||||
static
|
||||
{
|
||||
ImmutableMap.Builder<Integer, HealthbarOverride> builder = new ImmutableMap.Builder<>();
|
||||
|
||||
for (HealthbarOverride override : values())
|
||||
{
|
||||
builder.put(override.spriteId, override);
|
||||
}
|
||||
|
||||
MAP = builder.build();
|
||||
}
|
||||
|
||||
static HealthbarOverride get(int spriteID)
|
||||
{
|
||||
return MAP.get(spriteID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFileName()
|
||||
{
|
||||
return Skin.AROUND_2010.toString() + "/healthbar/" + this.fileName;
|
||||
}
|
||||
}
|
||||
@@ -32,8 +32,6 @@ import javax.inject.Inject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.HealthBar;
|
||||
import net.runelite.api.HealthBarOverride;
|
||||
import net.runelite.api.NodeCache;
|
||||
import net.runelite.api.SpriteID;
|
||||
import net.runelite.api.Sprite;
|
||||
import net.runelite.api.events.BeforeMenuRender;
|
||||
@@ -71,8 +69,6 @@ public class InterfaceStylesPlugin extends Plugin
|
||||
@Inject
|
||||
private SpriteManager spriteManager;
|
||||
|
||||
private HealthBarOverride healthBarOverride;
|
||||
|
||||
@Provides
|
||||
InterfaceStylesConfig provideConfig(ConfigManager configManager)
|
||||
{
|
||||
@@ -92,10 +88,7 @@ public class InterfaceStylesPlugin extends Plugin
|
||||
{
|
||||
restoreWidgetDimensions();
|
||||
removeGameframe();
|
||||
healthBarOverride = null;
|
||||
client.setHealthBarOverride(null);
|
||||
NodeCache heathBarCache = client.getHealthBarCache();
|
||||
heathBarCache.reset(); // invalidate healthbar cache so padding resets
|
||||
restoreHealthBars();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -117,19 +110,19 @@ public class InterfaceStylesPlugin extends Plugin
|
||||
@Subscribe
|
||||
public void onPostHealthBar(PostHealthBar postHealthBar)
|
||||
{
|
||||
if (healthBarOverride == null || !config.hdHealthBars())
|
||||
if (!config.hdHealthBars())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
HealthBar healthBar = postHealthBar.getHealthBar();
|
||||
Sprite frontSprite = healthBar.getHealthBarFrontSprite();
|
||||
HealthbarOverride override = HealthbarOverride.get(healthBar.getHealthBarFrontSpriteId());
|
||||
|
||||
// Check if this is the health bar we are replacing
|
||||
if (frontSprite == healthBarOverride.getFrontSprite() || frontSprite == healthBarOverride.getFrontSpriteLarge())
|
||||
if (override != null)
|
||||
{
|
||||
// Increase padding to show some more green at very low hp percentages
|
||||
healthBar.setPadding(1);
|
||||
healthBar.setPadding(override.getPadding());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,7 +155,7 @@ public class InterfaceStylesPlugin extends Plugin
|
||||
if (skin == config.skin())
|
||||
{
|
||||
String file = config.skin().toString() + "/" + spriteOverride.getSpriteID() + ".png";
|
||||
Sprite spritePixels = getFileSprite(file);
|
||||
Sprite spritePixels = getFileSpritePixels(file);
|
||||
|
||||
if (spriteOverride.getSpriteID() == SpriteID.COMPASS_TEXTURE)
|
||||
{
|
||||
@@ -194,7 +187,7 @@ public class InterfaceStylesPlugin extends Plugin
|
||||
if (widgetOverride.getSkin() == config.skin())
|
||||
{
|
||||
String file = config.skin().toString() + "/widget/" + widgetOverride.getName() + ".png";
|
||||
Sprite spritePixels = getFileSprite(file);
|
||||
Sprite spritePixels = getFileSpritePixels(file);
|
||||
|
||||
if (spritePixels != null)
|
||||
{
|
||||
@@ -218,7 +211,7 @@ public class InterfaceStylesPlugin extends Plugin
|
||||
}
|
||||
}
|
||||
|
||||
private Sprite getFileSprite(String file)
|
||||
private Sprite getFileSpritePixels(String file)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -272,31 +265,24 @@ public class InterfaceStylesPlugin extends Plugin
|
||||
|
||||
private void overrideHealthBars()
|
||||
{
|
||||
// Reset health bar cache to reset applied padding
|
||||
NodeCache healthBarCache = client.getHealthBarCache();
|
||||
healthBarCache.reset();
|
||||
|
||||
if (config.hdHealthBars())
|
||||
{
|
||||
String fileBase = Skin.AROUND_2010.toString() + "/healthbar/";
|
||||
|
||||
Sprite frontSprite = getFileSprite(fileBase + "front.png");
|
||||
Sprite backSprite = getFileSprite(fileBase + "back.png");
|
||||
|
||||
Sprite frontSpriteLarge = getFileSprite(fileBase + "front_large.png");
|
||||
Sprite backSpriteLarge = getFileSprite(fileBase + "back_large.png");
|
||||
|
||||
HealthBarOverride override = new HealthBarOverride(frontSprite, backSprite, frontSpriteLarge, backSpriteLarge);
|
||||
healthBarOverride = override;
|
||||
client.setHealthBarOverride(override);
|
||||
spriteManager.addSpriteOverrides(HealthbarOverride.values());
|
||||
// Reset health bar caches to apply the override
|
||||
clientThread.invokeLater(client::resetHealthBarCaches);
|
||||
}
|
||||
else
|
||||
{
|
||||
healthBarOverride = null;
|
||||
client.setHealthBarOverride(null);
|
||||
restoreHealthBars();
|
||||
}
|
||||
}
|
||||
|
||||
private void restoreHealthBars()
|
||||
{
|
||||
spriteManager.removeSpriteOverrides(HealthbarOverride.values());
|
||||
clientThread.invokeLater(client::resetHealthBarCaches);
|
||||
}
|
||||
|
||||
private void restoreWidgetDimensions()
|
||||
{
|
||||
for (WidgetOffset widgetOffset : WidgetOffset.values())
|
||||
|
||||
@@ -27,6 +27,7 @@ package net.runelite.client.plugins.inventorygrid;
|
||||
import net.runelite.client.config.Config;
|
||||
import net.runelite.client.config.ConfigGroup;
|
||||
import net.runelite.client.config.ConfigItem;
|
||||
import net.runelite.client.config.Range;
|
||||
|
||||
@ConfigGroup("inventorygrid")
|
||||
public interface InventoryGridConfig extends Config
|
||||
@@ -60,4 +61,15 @@ public interface InventoryGridConfig extends Config
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "dragDelay",
|
||||
name = "Drag Delay",
|
||||
description = "Time in ms to wait after item press before showing grid"
|
||||
)
|
||||
@Range(min = 100)
|
||||
default int dragDelay()
|
||||
{
|
||||
return 100;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.image.BufferedImage;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.Constants;
|
||||
import net.runelite.api.widgets.Widget;
|
||||
import net.runelite.api.widgets.WidgetInfo;
|
||||
import net.runelite.api.widgets.WidgetItem;
|
||||
@@ -45,7 +46,6 @@ import net.runelite.client.ui.overlay.OverlayPosition;
|
||||
class InventoryGridOverlay extends Overlay
|
||||
{
|
||||
private static final int INVENTORY_SIZE = 28;
|
||||
private static final int DRAG_DELAY = 5;
|
||||
|
||||
private static final Color HIGHLIGHT = new Color(0, 255, 0, 45);
|
||||
private static final Color GRID = new Color(255, 255, 255, 45);
|
||||
@@ -72,7 +72,7 @@ class InventoryGridOverlay extends Overlay
|
||||
final Widget inventoryWidget = client.getWidget(WidgetInfo.INVENTORY);
|
||||
|
||||
if (if1DraggingWidget == null || if1DraggingWidget != inventoryWidget
|
||||
|| client.getItemPressedDuration() < DRAG_DELAY)
|
||||
|| client.getItemPressedDuration() < config.dragDelay() / Constants.CLIENT_TICK_LENGTH)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import java.awt.Rectangle;
|
||||
import java.awt.image.BufferedImage;
|
||||
import javax.inject.Inject;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.Constants;
|
||||
import net.runelite.api.InventoryID;
|
||||
import net.runelite.api.Item;
|
||||
import net.runelite.api.ItemDefinition;
|
||||
@@ -51,9 +52,8 @@ import net.runelite.client.ui.overlay.components.TitleComponent;
|
||||
class InventoryViewerOverlay extends Overlay
|
||||
{
|
||||
private static final int INVENTORY_SIZE = 28;
|
||||
private static final int PLACEHOLDER_WIDTH = 36;
|
||||
private static final int PLACEHOLDER_HEIGHT = 32;
|
||||
private static final ImageComponent PLACEHOLDER_IMAGE = new ImageComponent(new BufferedImage(PLACEHOLDER_WIDTH, PLACEHOLDER_HEIGHT, BufferedImage.TYPE_4BYTE_ABGR));
|
||||
private static final ImageComponent PLACEHOLDER_IMAGE = new ImageComponent(
|
||||
new BufferedImage(Constants.ITEM_SPRITE_WIDTH, Constants.ITEM_SPRITE_HEIGHT, BufferedImage.TYPE_4BYTE_ABGR));
|
||||
|
||||
private final Client client;
|
||||
private final ItemManager itemManager;
|
||||
|
||||
@@ -29,6 +29,7 @@ import java.awt.Dimension;
|
||||
import java.awt.Graphics2D;
|
||||
import javax.inject.Inject;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.Constants;
|
||||
import net.runelite.api.InventoryID;
|
||||
import net.runelite.api.Item;
|
||||
import net.runelite.api.ItemDefinition;
|
||||
@@ -194,6 +195,7 @@ class ItemPricesOverlay extends Overlay
|
||||
int gePrice = 0;
|
||||
int haPrice = 0;
|
||||
int haProfit = 0;
|
||||
final int itemHaPrice = Math.round(itemDef.getPrice() * Constants.HIGH_ALCHEMY_MULTIPLIER);
|
||||
|
||||
if (config.showGEPrice())
|
||||
{
|
||||
@@ -203,9 +205,9 @@ class ItemPricesOverlay extends Overlay
|
||||
{
|
||||
haPrice = itemManager.getAlchValue(id);
|
||||
}
|
||||
if (gePrice > 0 && haPrice > 0 && config.showAlchProfit())
|
||||
if (gePrice > 0 && itemHaPrice > 0 && config.showAlchProfit())
|
||||
{
|
||||
haProfit = calculateHAProfit(haPrice, gePrice);
|
||||
haProfit = calculateHAProfit(itemHaPrice, gePrice);
|
||||
}
|
||||
|
||||
if (gePrice > 0 || haPrice > 0)
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2018, TheStonedTurtle <https://github.com/TheStonedTurtle>
|
||||
* 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.itemskeptondeath;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import net.runelite.api.ItemID;
|
||||
|
||||
/**
|
||||
* Certain Items receive a white outline by Jagex as they are always lost on death. This is sometimes incorrectly
|
||||
* added to Items by Jagex as the item is actually kept in non-pvp areas of the game, such as the Rune Pouch.
|
||||
*
|
||||
* The white outline will be added to these items when they are lost on death.
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
enum AlwaysLostItem
|
||||
{
|
||||
RUNE_POUCH(ItemID.RUNE_POUCH, true),
|
||||
LOOTING_BAG(ItemID.LOOTING_BAG, false),
|
||||
CLUE_BOX(ItemID.CLUE_BOX, false);
|
||||
|
||||
private final int itemID;
|
||||
private final boolean keptOutsideOfWilderness;
|
||||
|
||||
private static final ImmutableMap<Integer, AlwaysLostItem> ID_MAP;
|
||||
|
||||
static
|
||||
{
|
||||
final ImmutableMap.Builder<Integer, AlwaysLostItem> map = ImmutableMap.builder();
|
||||
for (final AlwaysLostItem p : values())
|
||||
{
|
||||
map.put(p.itemID, p);
|
||||
}
|
||||
ID_MAP = map.build();
|
||||
}
|
||||
|
||||
static AlwaysLostItem getByItemID(final int itemID)
|
||||
{
|
||||
return ID_MAP.get(itemID);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (c) 2018, TheStonedTurtle <https://github.com/TheStonedTurtle>
|
||||
* 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.itemskeptondeath;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import lombok.AllArgsConstructor;
|
||||
import net.runelite.api.ItemID;
|
||||
|
||||
/**
|
||||
* Some non tradeable items are kept on death inside low level wilderness (1-20) but are turned into a broken variant.
|
||||
*
|
||||
* The non-broken variant will be shown inside the interface.
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
enum BrokenOnDeathItem
|
||||
{
|
||||
// Capes
|
||||
FIRE_CAPE(ItemID.FIRE_CAPE),
|
||||
FIRE_MAX_CAPE(ItemID.FIRE_MAX_CAPE),
|
||||
INFERNAL_CAPE(ItemID.INFERNAL_CAPE),
|
||||
INFERNAL_MAX_CAPE(ItemID.INFERNAL_MAX_CAPE),
|
||||
AVAS_ASSEMBLER(ItemID.AVAS_ASSEMBLER),
|
||||
ASSEMBLER_MAX_CAPE(ItemID.ASSEMBLER_MAX_CAPE),
|
||||
|
||||
// Defenders
|
||||
BRONZE_DEFENDER(ItemID.BRONZE_DEFENDER),
|
||||
IRON_DEFENDER(ItemID.IRON_DEFENDER),
|
||||
STEEL_DEFENDER(ItemID.STEEL_DEFENDER),
|
||||
BLACK_DEFENDER(ItemID.BLACK_DEFENDER),
|
||||
MITHRIL_DEFENDER(ItemID.MITHRIL_DEFENDER),
|
||||
ADAMANT_DEFENDER(ItemID.ADAMANT_DEFENDER),
|
||||
RUNE_DEFENDER(ItemID.RUNE_DEFENDER),
|
||||
DRAGON_DEFENDER(ItemID.DRAGON_DEFENDER),
|
||||
AVERNIC_DEFENDER(ItemID.AVERNIC_DEFENDER),
|
||||
|
||||
// Void
|
||||
VOID_MAGE_HELM(ItemID.VOID_MAGE_HELM),
|
||||
VOID_RANGER_HELM(ItemID.VOID_RANGER_HELM),
|
||||
VOID_MELEE_HELM(ItemID.VOID_MELEE_HELM),
|
||||
VOID_KNIGHT_TOP(ItemID.VOID_KNIGHT_TOP),
|
||||
VOID_KNIGHT_ROBE(ItemID.VOID_KNIGHT_ROBE),
|
||||
VOID_KNIGHT_GLOVES(ItemID.VOID_KNIGHT_GLOVES),
|
||||
VOID_KNIGHT_MACE(ItemID.VOID_KNIGHT_MACE),
|
||||
ELITE_VOID_TOP(ItemID.ELITE_VOID_TOP),
|
||||
ELITE_VOID_ROBE(ItemID.ELITE_VOID_ROBE),
|
||||
|
||||
// Barb Assault
|
||||
FIGHTER_HAT(ItemID.FIGHTER_HAT),
|
||||
RANGER_HAT(ItemID.RANGER_HAT),
|
||||
HEALER_HAT(ItemID.HEALER_HAT),
|
||||
FIGHTER_TORSO(ItemID.FIGHTER_TORSO),
|
||||
PENANCE_SKIRT(ItemID.PENANCE_SKIRT),
|
||||
|
||||
// Castle Wars
|
||||
SARADOMIN_HALO(ItemID.SARADOMIN_HALO),
|
||||
ZAMORAK_HALO(ItemID.ZAMORAK_HALO),
|
||||
GUTHIX_HALO(ItemID.GUTHIX_HALO),
|
||||
DECORATIVE_MAGIC_HAT(ItemID.DECORATIVE_ARMOUR_11898),
|
||||
DECORATIVE_MAGIC_ROBE_TOP(ItemID.DECORATIVE_ARMOUR_11896),
|
||||
DECORATIVE_MAGIC_ROBE_LEGS(ItemID.DECORATIVE_ARMOUR_11897),
|
||||
DECORATIVE_RANGE_TOP(ItemID.DECORATIVE_ARMOUR_11899),
|
||||
DECORATIVE_RANGE_BOTTOM(ItemID.DECORATIVE_ARMOUR_11900),
|
||||
DECORATIVE_RANGE_QUIVER(ItemID.DECORATIVE_ARMOUR_11901),
|
||||
GOLD_DECORATIVE_HELM(ItemID.DECORATIVE_HELM_4511),
|
||||
GOLD_DECORATIVE_BODY(ItemID.DECORATIVE_ARMOUR_4509),
|
||||
GOLD_DECORATIVE_LEGS(ItemID.DECORATIVE_ARMOUR_4510),
|
||||
GOLD_DECORATIVE_SKIRT(ItemID.DECORATIVE_ARMOUR_11895),
|
||||
GOLD_DECORATIVE_SHIELD(ItemID.DECORATIVE_SHIELD_4512),
|
||||
GOLD_DECORATIVE_SWORD(ItemID.DECORATIVE_SWORD_4508);
|
||||
|
||||
private final int itemID;
|
||||
|
||||
private static final ImmutableSet<Integer> ID_SET;
|
||||
|
||||
static
|
||||
{
|
||||
final ImmutableSet.Builder<Integer> set = new ImmutableSet.Builder<>();
|
||||
for (final BrokenOnDeathItem p : values())
|
||||
{
|
||||
set.add(p.itemID);
|
||||
}
|
||||
ID_SET = set.build();
|
||||
}
|
||||
|
||||
static boolean isBrokenOnDeath(final int itemID)
|
||||
{
|
||||
return ID_SET.contains(itemID);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Adam <Adam@sigterm.info>
|
||||
* Copyright (c) 2019, TheStonedTurtle <https://github.com/TheStonedTurtle>
|
||||
* 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.itemskeptondeath;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import java.util.Map;
|
||||
import javax.annotation.Nullable;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import net.runelite.api.ItemID;
|
||||
|
||||
/**
|
||||
* Some items have a fixed price that is added to its default value when calculating death prices.
|
||||
* These are typically imbued items, such as Berserker ring (i), to help it protect over the non-imbued variants.
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
enum FixedPriceItem
|
||||
{
|
||||
IMBUED_BLACK_MASK_I(ItemID.BLACK_MASK_I, 5000),
|
||||
IMBUED_BLACK_MASK_1_I(ItemID.BLACK_MASK_1_I, 5000),
|
||||
IMBUED_BLACK_MASK_2_I(ItemID.BLACK_MASK_2_I, 5000),
|
||||
IMBUED_BLACK_MASK_3_I(ItemID.BLACK_MASK_3_I, 5000),
|
||||
IMBUED_BLACK_MASK_4_I(ItemID.BLACK_MASK_4_I, 5000),
|
||||
IMBUED_BLACK_MASK_5_I(ItemID.BLACK_MASK_5_I, 5000),
|
||||
IMBUED_BLACK_MASK_6_I(ItemID.BLACK_MASK_6_I, 5000),
|
||||
IMBUED_BLACK_MASK_7_I(ItemID.BLACK_MASK_7_I, 5000),
|
||||
IMBUED_BLACK_MASK_8_I(ItemID.BLACK_MASK_8_I, 5000),
|
||||
IMBUED_BLACK_MASK_9_I(ItemID.BLACK_MASK_9_I, 5000),
|
||||
IMBUED_BLACK_MASK_10_I(ItemID.BLACK_MASK_10_I, 5000),
|
||||
|
||||
IMBUED_SLAYER_HELMET_I(ItemID.SLAYER_HELMET_I, 1000),
|
||||
IMBUED_BLACK_SLAYER_HELMET_I(ItemID.BLACK_SLAYER_HELMET_I, 1000),
|
||||
IMBUED_PURPLE_SLAYER_HELMET_I(ItemID.PURPLE_SLAYER_HELMET_I, 1000),
|
||||
IMBUED_RED_SLAYER_HELMET_I(ItemID.RED_SLAYER_HELMET_I, 1000),
|
||||
IMBUED_GREEN_SLAYER_HELMET_I(ItemID.GREEN_SLAYER_HELMET_I, 1000),
|
||||
IMBUED_TURQUOISE_SLAYER_HELMET_I(ItemID.TURQUOISE_SLAYER_HELMET_I, 1000),
|
||||
IMBUED_HYDRA_SLAYER_HELMET_I(ItemID.HYDRA_SLAYER_HELMET_I, 1000),
|
||||
|
||||
IMBUED_ARCHERS_RING_I(ItemID.ARCHERS_RING_I, 2000),
|
||||
IMBUED_BERSERKER_RING_I(ItemID.BERSERKER_RING_I, 2000),
|
||||
IMBUED_SEERS_RING_I(ItemID.SEERS_RING_I, 2000),
|
||||
|
||||
IMBUED_RING_OF_THE_GODS_I(ItemID.RING_OF_THE_GODS_I, 2000),
|
||||
IMBUED_TREASONOUS_RING_I(ItemID.TREASONOUS_RING_I, 2000),
|
||||
IMBUED_TYRANNICAL_RING_I(ItemID.TYRANNICAL_RING_I, 2000);
|
||||
|
||||
private final int itemId;
|
||||
private final int offset;
|
||||
|
||||
private static final Map<Integer, FixedPriceItem> FIXED_ITEMS;
|
||||
|
||||
static
|
||||
{
|
||||
final ImmutableMap.Builder<Integer, FixedPriceItem> map = ImmutableMap.builder();
|
||||
for (final FixedPriceItem p : values())
|
||||
{
|
||||
map.put(p.itemId, p);
|
||||
}
|
||||
FIXED_ITEMS = map.build();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static FixedPriceItem find(int itemId)
|
||||
{
|
||||
return FIXED_ITEMS.get(itemId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,610 @@
|
||||
/*
|
||||
* Copyright (c) 2018, TheStonedTurtle <https://github.com/TheStonedTurtle>
|
||||
* Copyright (c) 2019, Adam <Adam@sigterm.info>
|
||||
* 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.itemskeptondeath;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.inject.Inject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.Constants;
|
||||
import net.runelite.api.FontID;
|
||||
import net.runelite.api.InventoryID;
|
||||
import net.runelite.api.Item;
|
||||
import net.runelite.api.ItemComposition;
|
||||
import net.runelite.api.ItemContainer;
|
||||
import net.runelite.api.ItemID;
|
||||
import net.runelite.api.ScriptID;
|
||||
import net.runelite.api.SkullIcon;
|
||||
import net.runelite.api.SpriteID;
|
||||
import net.runelite.api.Varbits;
|
||||
import net.runelite.api.WorldType;
|
||||
import net.runelite.api.events.ScriptCallbackEvent;
|
||||
import net.runelite.api.vars.AccountType;
|
||||
import net.runelite.api.widgets.Widget;
|
||||
import net.runelite.api.widgets.WidgetInfo;
|
||||
import net.runelite.api.widgets.WidgetType;
|
||||
import net.runelite.client.eventbus.Subscribe;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
import net.runelite.client.plugins.PluginDescriptor;
|
||||
import net.runelite.client.util.StackFormatter;
|
||||
|
||||
@PluginDescriptor(
|
||||
name = "Items Kept on Death",
|
||||
description = "Updates the Items Kept on Death interface to be more accurate",
|
||||
enabledByDefault = false
|
||||
)
|
||||
@Slf4j
|
||||
public class ItemsKeptOnDeathPlugin extends Plugin
|
||||
{
|
||||
private static final int DEEP_WILDY = 20;
|
||||
private static final Pattern WILDERNESS_LEVEL_PATTERN = Pattern.compile("^Level: (\\d+).*");
|
||||
|
||||
// Item Container helpers
|
||||
private static final int MAX_ROW_ITEMS = 8;
|
||||
private static final int ITEM_X_OFFSET = 5;
|
||||
private static final int ITEM_Y_OFFSET = 25;
|
||||
private static final int ITEM_X_STRIDE = 38;
|
||||
private static final int ITEM_Y_STRIDE = 38;
|
||||
private static final int ORIGINAL_LOST_HEIGHT = 209;
|
||||
private static final int ORIGINAL_LOST_Y = 107;
|
||||
|
||||
// Information panel text helpers
|
||||
private static final String LINE_BREAK = "<br>";
|
||||
private static final int INFORMATION_CONTAINER_HEIGHT = 183;
|
||||
private static final int FONT_COLOR = 0xFF981F;
|
||||
|
||||
// Button Images
|
||||
private static final int PROTECT_ITEM_SPRITE_ID = SpriteID.PRAYER_PROTECT_ITEM;
|
||||
private static final int SKULL_SPRITE_ID = SpriteID.PLAYER_KILLER_SKULL_523;
|
||||
private static final int SWORD_SPRITE_ID = SpriteID.MULTI_COMBAT_ZONE_CROSSED_SWORDS;
|
||||
private static final int SKULL_2_SPRITE_ID = SpriteID.FIGHT_PITS_WINNER_SKULL_RED;
|
||||
|
||||
@Inject
|
||||
private Client client;
|
||||
|
||||
@Inject
|
||||
private ItemManager itemManager;
|
||||
|
||||
private WidgetButton deepWildyButton;
|
||||
private WidgetButton lowWildyButton;
|
||||
|
||||
private boolean isSkulled;
|
||||
private boolean protectingItem;
|
||||
private int wildyLevel;
|
||||
|
||||
@Subscribe
|
||||
public void onScriptCallbackEvent(ScriptCallbackEvent event)
|
||||
{
|
||||
if (event.getEventName().equals("itemsKeptOnDeath"))
|
||||
{
|
||||
// The script in charge of building the Items Kept on Death interface has finished running.
|
||||
// Make all necessary changes now.
|
||||
|
||||
// Players inside Safe Areas (POH/Clan Wars) or playing DMM see the default interface
|
||||
if (isInSafeArea() || client.getWorldType().contains(WorldType.DEADMAN))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
syncSettings();
|
||||
createWidgetButtons();
|
||||
rebuildItemsKeptOnDeathInterface();
|
||||
|
||||
final Widget keptText = client.getWidget(WidgetInfo.ITEMS_KEPT_ON_DEATH_TEXT);
|
||||
keptText.setText("Items you will keep on death:");
|
||||
|
||||
final Widget lostText = client.getWidget(WidgetInfo.ITEMS_LOST_ON_DEATH_TEXT);
|
||||
lostText.setText("Items you will lose on death:");
|
||||
}
|
||||
}
|
||||
|
||||
// Sync user settings
|
||||
private void syncSettings()
|
||||
{
|
||||
final SkullIcon s = client.getLocalPlayer().getSkullIcon();
|
||||
// Ultimate iron men deaths are treated like they are always skulled
|
||||
isSkulled = s == SkullIcon.SKULL || isUltimateIronman();
|
||||
protectingItem = client.getVar(Varbits.PRAYER_PROTECT_ITEM) == 1;
|
||||
syncWildernessLevel();
|
||||
}
|
||||
|
||||
private void syncWildernessLevel()
|
||||
{
|
||||
if (client.getVar(Varbits.IN_WILDERNESS) != 1)
|
||||
{
|
||||
// if they are in a PvP world and not in a safe zone act like in lvl 1 wildy
|
||||
if (isInPvpWorld() && !isInPvPSafeZone())
|
||||
{
|
||||
wildyLevel = 1;
|
||||
return;
|
||||
}
|
||||
wildyLevel = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
final Widget wildernessLevelWidget = client.getWidget(WidgetInfo.PVP_WILDERNESS_LEVEL);
|
||||
if (wildernessLevelWidget == null)
|
||||
{
|
||||
wildyLevel = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
final String wildernessLevelText = wildernessLevelWidget.getText();
|
||||
final Matcher m = WILDERNESS_LEVEL_PATTERN.matcher(wildernessLevelText);
|
||||
if (!m.matches())
|
||||
{
|
||||
wildyLevel = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
wildyLevel = Integer.parseInt(m.group(1));
|
||||
}
|
||||
|
||||
private boolean isInPvpWorld()
|
||||
{
|
||||
final EnumSet<WorldType> world = client.getWorldType();
|
||||
return world.contains(WorldType.PVP);
|
||||
}
|
||||
|
||||
private boolean isProtectItemAllowed()
|
||||
{
|
||||
return !client.getWorldType().contains(WorldType.HIGH_RISK)
|
||||
&& !isUltimateIronman();
|
||||
}
|
||||
|
||||
private boolean isInPvPSafeZone()
|
||||
{
|
||||
final Widget w = client.getWidget(WidgetInfo.PVP_WORLD_SAFE_ZONE);
|
||||
return w != null && !w.isHidden();
|
||||
}
|
||||
|
||||
private boolean isInSafeArea()
|
||||
{
|
||||
final Widget w = client.getWidget(WidgetInfo.ITEMS_KEPT_SAFE_ZONE_CONTAINER);
|
||||
return w != null && !w.isHidden();
|
||||
}
|
||||
|
||||
private boolean isUltimateIronman()
|
||||
{
|
||||
return client.getAccountType() == AccountType.ULTIMATE_IRONMAN;
|
||||
}
|
||||
|
||||
private int getDefaultItemsKept()
|
||||
{
|
||||
final int count = isSkulled ? 0 : 3;
|
||||
return count + (protectingItem ? 1 : 0);
|
||||
}
|
||||
|
||||
private void rebuildItemsKeptOnDeathInterface()
|
||||
{
|
||||
final Widget lost = client.getWidget(WidgetInfo.ITEMS_LOST_ON_DEATH_CONTAINER);
|
||||
final Widget kept = client.getWidget(WidgetInfo.ITEMS_KEPT_ON_DEATH_CONTAINER);
|
||||
if (lost == null || kept == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lost.deleteAllChildren();
|
||||
kept.deleteAllChildren();
|
||||
|
||||
// Grab all items on player
|
||||
final ItemContainer inventory = client.getItemContainer(InventoryID.INVENTORY);
|
||||
final Item[] inv = inventory == null ? new Item[0] : inventory.getItems();
|
||||
final ItemContainer equipment = client.getItemContainer(InventoryID.EQUIPMENT);
|
||||
final Item[] equip = equipment == null ? new Item[0] : equipment.getItems();
|
||||
|
||||
final List<Item> items = new ArrayList<>();
|
||||
Collections.addAll(items, inv);
|
||||
Collections.addAll(items, equip);
|
||||
|
||||
// Sort by item price
|
||||
items.sort(Comparator.comparing(this::getDeathPrice).reversed());
|
||||
|
||||
boolean hasAlwaysLost = false;
|
||||
int keepCount = getDefaultItemsKept();
|
||||
|
||||
final List<Widget> keptItems = new ArrayList<>();
|
||||
final List<Widget> lostItems = new ArrayList<>();
|
||||
for (final Item i : items)
|
||||
{
|
||||
final int id = i.getId();
|
||||
int itemQuantity = i.getQuantity();
|
||||
|
||||
if (id == -1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
final ItemComposition c = itemManager.getItemComposition(i.getId());
|
||||
|
||||
// Bonds are always kept and do not count towards the limit.
|
||||
if (id == ItemID.OLD_SCHOOL_BOND || id == ItemID.OLD_SCHOOL_BOND_UNTRADEABLE)
|
||||
{
|
||||
final Widget itemWidget = createItemWidget(kept, itemQuantity, c);
|
||||
itemWidget.setOnOpListener(ScriptID.DEATH_KEEP_ITEM_EXAMINE, 1, itemQuantity, c.getName());
|
||||
keptItems.add(itemWidget);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Certain items are always lost on death and have a white outline which we need to add
|
||||
final AlwaysLostItem alwaysLostItem = AlwaysLostItem.getByItemID(i.getId());
|
||||
if (alwaysLostItem != null)
|
||||
{
|
||||
// Some of these items are kept on death (outside wildy), like the Rune pouch. Ignore them
|
||||
if (!alwaysLostItem.isKeptOutsideOfWilderness() || wildyLevel > 0)
|
||||
{
|
||||
final Widget itemWidget = createItemWidget(lost, itemQuantity, c);
|
||||
itemWidget.setOnOpListener(ScriptID.DEATH_KEEP_ITEM_EXAMINE, 0, itemQuantity, c.getName());
|
||||
itemWidget.setBorderType(2); // white outline
|
||||
lostItems.add(itemWidget);
|
||||
hasAlwaysLost = true;
|
||||
continue;
|
||||
}
|
||||
// the rune pouch is "always lost" but its kept outside of pvp, and does not count towards your keep count
|
||||
}
|
||||
else if (keepCount > 0)
|
||||
{
|
||||
// Keep most valuable items regardless of trade-ability.
|
||||
if (i.getQuantity() > keepCount)
|
||||
{
|
||||
final Widget itemWidget = createItemWidget(kept, keepCount, c);
|
||||
itemWidget.setOnOpListener(ScriptID.DEATH_KEEP_ITEM_EXAMINE, 1, keepCount, c.getName());
|
||||
keptItems.add(itemWidget);
|
||||
itemQuantity -= keepCount;
|
||||
keepCount = 0;
|
||||
// Fall through to below to drop the rest of the stack
|
||||
}
|
||||
else
|
||||
{
|
||||
final Widget itemWidget = createItemWidget(kept, itemQuantity, c);
|
||||
itemWidget.setOnOpListener(ScriptID.DEATH_KEEP_ITEM_EXAMINE, 1, itemQuantity, c.getName());
|
||||
keptItems.add(itemWidget);
|
||||
keepCount -= i.getQuantity();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Items are kept if:
|
||||
// 1) is not tradeable
|
||||
// 2) is under the deep wilderness line
|
||||
// 3) is outside of the wilderness, or item has a broken form
|
||||
if (!Pets.isPet(id)
|
||||
&& !isTradeable(c) && wildyLevel <= DEEP_WILDY
|
||||
&& (wildyLevel <= 0 || BrokenOnDeathItem.isBrokenOnDeath(i.getId())))
|
||||
{
|
||||
final Widget itemWidget = createItemWidget(kept, itemQuantity, c);
|
||||
itemWidget.setOnOpListener(ScriptID.DEATH_KEEP_ITEM_EXAMINE, 1, itemQuantity, c.getName());
|
||||
keptItems.add(itemWidget);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise, the item is lost
|
||||
final Widget itemWidget = createItemWidget(lost, itemQuantity, c);
|
||||
itemWidget.setOnOpListener(ScriptID.DEATH_KEEP_ITEM_EXAMINE, 0, itemQuantity, c.getName());
|
||||
lostItems.add(itemWidget);
|
||||
}
|
||||
}
|
||||
|
||||
int rows = (keptItems.size() + MAX_ROW_ITEMS - 1) / MAX_ROW_ITEMS;
|
||||
// Show an empty row if there isn't anything
|
||||
if (rows > 0)
|
||||
{
|
||||
// ORIGINAL_LOST_Y/HEIGHT includes a row already
|
||||
rows--;
|
||||
}
|
||||
// Adjust items lost container position if new rows were added to kept items container
|
||||
lost.setOriginalY(ORIGINAL_LOST_Y + (rows * ITEM_Y_STRIDE));
|
||||
lost.setOriginalHeight(ORIGINAL_LOST_HEIGHT - (rows * ITEM_Y_STRIDE));
|
||||
positionWidgetItems(kept, keptItems);
|
||||
positionWidgetItems(lost, lostItems);
|
||||
|
||||
updateKeptWidgetInfoText(hasAlwaysLost, keptItems, lostItems);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the price of an item
|
||||
* @param item
|
||||
* @return
|
||||
*/
|
||||
private int getDeathPrice(Item item)
|
||||
{
|
||||
int itemId = item.getId();
|
||||
// Unnote/unplaceholder item
|
||||
int canonicalizedItemId = itemManager.canonicalize(itemId);
|
||||
int exchangePrice = itemManager.getItemPrice(canonicalizedItemId);
|
||||
if (exchangePrice == 0)
|
||||
{
|
||||
final ItemComposition c1 = itemManager.getItemComposition(canonicalizedItemId);
|
||||
exchangePrice = c1.getPrice();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Some items have artifically applied death prices - such as ring imbues
|
||||
// which are +2k over the non imbues. Check if the item has a fixed price.
|
||||
FixedPriceItem fixedPrice = FixedPriceItem.find(canonicalizedItemId);
|
||||
if (fixedPrice != null)
|
||||
{
|
||||
// Apply fixed price offset
|
||||
exchangePrice += fixedPrice.getOffset();
|
||||
}
|
||||
}
|
||||
return exchangePrice;
|
||||
}
|
||||
|
||||
/**
|
||||
* Position a list of widget items in the parent container
|
||||
*/
|
||||
private static void positionWidgetItems(final Widget parent, final List<Widget> widgets)
|
||||
{
|
||||
int startingIndex = 0;
|
||||
for (final Widget w : widgets)
|
||||
{
|
||||
final int originalX = ITEM_X_OFFSET + ((startingIndex % MAX_ROW_ITEMS) * ITEM_X_STRIDE);
|
||||
final int originalY = ITEM_Y_OFFSET + ((startingIndex / MAX_ROW_ITEMS) * ITEM_Y_STRIDE);
|
||||
|
||||
w.setOriginalX(originalX);
|
||||
w.setOriginalY(originalY);
|
||||
w.revalidate();
|
||||
|
||||
++startingIndex;
|
||||
}
|
||||
|
||||
parent.revalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the text to be displayed in the right side of the interface based on current selections
|
||||
*/
|
||||
private String getInfoText(final boolean hasAlwaysLost)
|
||||
{
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
if (isUltimateIronman())
|
||||
{
|
||||
sb.append("You are an <col=FFFFFF>UIM<col=FF981F> which means <col=FFFFFF>0<col=FF981F> items are protected by default");
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append("<col=FFFFFF>3<col=FF981F> items protected by default");
|
||||
|
||||
if (isSkulled)
|
||||
{
|
||||
sb.append(LINE_BREAK)
|
||||
.append("<col=ff3333>PK skull<col=ff981f> -3");
|
||||
}
|
||||
|
||||
if (protectingItem)
|
||||
{
|
||||
sb.append(LINE_BREAK)
|
||||
.append("<col=ff3333>Protect Item prayer<col=ff981f> +1");
|
||||
}
|
||||
|
||||
sb.append(LINE_BREAK)
|
||||
.append(String.format("Actually protecting <col=FFFFFF>%s<col=FF981F> items", getDefaultItemsKept()));
|
||||
}
|
||||
|
||||
|
||||
if (wildyLevel < 1)
|
||||
{
|
||||
sb.append(LINE_BREAK)
|
||||
.append(LINE_BREAK)
|
||||
.append("You will have 1 hour to retrieve your lost items.");
|
||||
}
|
||||
|
||||
if (hasAlwaysLost)
|
||||
{
|
||||
sb.append(LINE_BREAK)
|
||||
.append(LINE_BREAK)
|
||||
.append("Items with a <col=ffffff>white outline<col=ff981f> will always be lost.");
|
||||
}
|
||||
|
||||
sb.append(LINE_BREAK)
|
||||
.append(LINE_BREAK)
|
||||
.append("Untradeable items are kept on death in non-pvp scenarios.");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the information panel based on the item containers
|
||||
*/
|
||||
private void updateKeptWidgetInfoText(final boolean hasAlwaysLost, final List<Widget> keptItems, final List<Widget> lostItems)
|
||||
{
|
||||
// Add Information text widget
|
||||
final Widget textWidget = findOrCreateInfoText();
|
||||
textWidget.setText(getInfoText(hasAlwaysLost));
|
||||
textWidget.revalidate();
|
||||
|
||||
// Update Items lost total value
|
||||
long total = 0;
|
||||
for (final Widget w : lostItems)
|
||||
{
|
||||
int cid = itemManager.canonicalize(w.getItemId());
|
||||
int price = itemManager.getItemPrice(cid);
|
||||
if (price == 0)
|
||||
{
|
||||
// Default to alch price
|
||||
price = (int) (itemManager.getItemComposition(cid).getPrice() * Constants.HIGH_ALCHEMY_MULTIPLIER);
|
||||
}
|
||||
total += (long) price * w.getItemQuantity();
|
||||
}
|
||||
final Widget lostValue = client.getWidget(WidgetInfo.ITEMS_LOST_VALUE);
|
||||
lostValue.setText(StackFormatter.quantityToStackSize(total) + " gp");
|
||||
|
||||
// Update Max items kept
|
||||
final Widget max = client.getWidget(WidgetInfo.ITEMS_KEPT_MAX);
|
||||
final int keptQty = keptItems.stream().mapToInt(Widget::getItemQuantity).sum();
|
||||
max.setText(String.format("<col=ffcc33>Max items kept on death:<br><br><col=ffcc33>~ %d ~", keptQty));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an item is tradeable to another player
|
||||
*
|
||||
* @param c The item
|
||||
* @return
|
||||
*/
|
||||
private static boolean isTradeable(final ItemComposition c)
|
||||
{
|
||||
// ItemComposition:: isTradeable checks if they are traded on the grand exchange, some items are trade-able but not via GE
|
||||
if (c.getNote() != -1
|
||||
|| c.getLinkedNoteId() != -1
|
||||
|| c.isTradeable())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
final int id = c.getId();
|
||||
switch (id)
|
||||
{
|
||||
case ItemID.COINS_995:
|
||||
case ItemID.PLATINUM_TOKEN:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private Widget findOrCreateInfoText()
|
||||
{
|
||||
// The text was on the ITEMS_KEPT_INFORMATION_CONTAINER widget - but now that it is a layer,
|
||||
// we need to create a child widget to hold the text
|
||||
final Widget parent = client.getWidget(WidgetInfo.ITEMS_KEPT_INFORMATION_CONTAINER);
|
||||
|
||||
// Use the text TEXT widget if it already exists. It should be the last child of the parent
|
||||
final Widget[] children = parent.getChildren();
|
||||
if (children != null && children.length > 0)
|
||||
{
|
||||
final Widget w = parent.getChild(children.length - 1);
|
||||
if (w != null && w.getType() == WidgetType.TEXT)
|
||||
{
|
||||
log.debug("Reusing old text widget");
|
||||
return w;
|
||||
}
|
||||
}
|
||||
|
||||
log.debug("Creating new text widget");
|
||||
|
||||
final Widget w = parent.createChild(-1, WidgetType.TEXT);
|
||||
// Position under buttons taking remaining space
|
||||
w.setOriginalWidth(parent.getOriginalWidth());
|
||||
w.setOriginalHeight(INFORMATION_CONTAINER_HEIGHT - parent.getOriginalHeight());
|
||||
w.setOriginalY(parent.getOriginalHeight());
|
||||
|
||||
w.setFontId(FontID.PLAIN_11);
|
||||
w.setTextShadowed(true);
|
||||
w.setTextColor(FONT_COLOR);
|
||||
|
||||
// Need to adjust parent height so text is visible
|
||||
parent.setOriginalHeight(INFORMATION_CONTAINER_HEIGHT);
|
||||
parent.revalidate();
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
private void createWidgetButtons()
|
||||
{
|
||||
final Widget parent = client.getWidget(WidgetInfo.ITEMS_KEPT_INFORMATION_CONTAINER);
|
||||
// Change the information container from a text widget to a layer
|
||||
parent.setType(WidgetType.LAYER);
|
||||
parent.deleteAllChildren();
|
||||
|
||||
// Ultimate Iron men are always skulled and can't use the protect item prayer
|
||||
WidgetButton protectItemButton = isProtectItemAllowed()
|
||||
? new WidgetButton(parent, "Protect Item Prayer", PROTECT_ITEM_SPRITE_ID, protectingItem, selected ->
|
||||
{
|
||||
protectingItem = selected;
|
||||
rebuildItemsKeptOnDeathInterface();
|
||||
}) : null;
|
||||
|
||||
WidgetButton skulledButton = !isUltimateIronman()
|
||||
? new WidgetButton(parent, "Skulled", SKULL_SPRITE_ID, isSkulled, selected ->
|
||||
{
|
||||
isSkulled = selected;
|
||||
rebuildItemsKeptOnDeathInterface();
|
||||
}) : null;
|
||||
|
||||
lowWildyButton = new WidgetButton(parent, "Low Wildy (1-20)", SWORD_SPRITE_ID, wildyLevel > 0 && wildyLevel <= DEEP_WILDY, selected ->
|
||||
{
|
||||
if (!selected)
|
||||
{
|
||||
syncWildernessLevel();
|
||||
}
|
||||
else
|
||||
{
|
||||
wildyLevel = 1;
|
||||
deepWildyButton.setSelected(false);
|
||||
}
|
||||
|
||||
rebuildItemsKeptOnDeathInterface();
|
||||
});
|
||||
|
||||
deepWildyButton = new WidgetButton(parent, "Deep Wildy (21+)", SKULL_2_SPRITE_ID, wildyLevel > DEEP_WILDY, selected ->
|
||||
{
|
||||
if (!selected)
|
||||
{
|
||||
syncWildernessLevel();
|
||||
}
|
||||
else
|
||||
{
|
||||
wildyLevel = DEEP_WILDY + 1;
|
||||
lowWildyButton.setSelected(false);
|
||||
}
|
||||
|
||||
rebuildItemsKeptOnDeathInterface();
|
||||
});
|
||||
|
||||
parent.revalidate();
|
||||
WidgetButton.layoutButtonsToContainer(parent, protectItemButton, skulledButton, lowWildyButton, deepWildyButton);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an Item Widget for use inside the Kept on Death Interface
|
||||
*
|
||||
* @param qty Amount of item
|
||||
* @param c Items Composition
|
||||
* @return
|
||||
*/
|
||||
private static Widget createItemWidget(final Widget parent, final int qty, final ItemComposition c)
|
||||
{
|
||||
final Widget itemWidget = parent.createChild(-1, WidgetType.GRAPHIC);
|
||||
itemWidget.setItemId(c.getId());
|
||||
itemWidget.setItemQuantity(qty);
|
||||
itemWidget.setHasListener(true);
|
||||
itemWidget.setOriginalWidth(Constants.ITEM_SPRITE_WIDTH);
|
||||
itemWidget.setOriginalHeight(Constants.ITEM_SPRITE_HEIGHT);
|
||||
itemWidget.setBorderType(1);
|
||||
|
||||
itemWidget.setAction(1, String.format("Item: <col=ff981f>%s", c.getName()));
|
||||
|
||||
return itemWidget;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Abex
|
||||
* 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.itemskeptondeath;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.util.Set;
|
||||
import static net.runelite.api.ItemID.*;
|
||||
|
||||
final class Pets
|
||||
{
|
||||
private Pets()
|
||||
{
|
||||
}
|
||||
|
||||
private static final Set<Integer> PETS = ImmutableSet.of(
|
||||
BABY_MOLE,
|
||||
PRINCE_BLACK_DRAGON,
|
||||
PET_CORPOREAL_CRITTER, PET_DARK_CORE,
|
||||
JALNIBREK, TZREKZUK,
|
||||
KALPHITE_PRINCESS, KALPHITE_PRINCESS_12654,
|
||||
LIL_ZIK,
|
||||
SKOTOS,
|
||||
PET_SNAKELING, PET_SNAKELING_12939, PET_SNAKELING_12940,
|
||||
TZREKJAD,
|
||||
VORKI,
|
||||
|
||||
OLMLET, PUPPADILE, TEKTINY, VANGUARD, VASA_MINIRIO, VESPINA,
|
||||
|
||||
PET_DAGANNOTH_PRIME, PET_DAGANNOTH_REX, PET_DAGANNOTH_SUPREME,
|
||||
|
||||
PET_GENERAL_GRAARDOR, PET_KRIL_TSUTSAROTH, PET_KREEARRA, PET_ZILYANA,
|
||||
|
||||
ABYSSAL_ORPHAN,
|
||||
HELLPUPPY,
|
||||
PET_KRAKEN,
|
||||
MIDNIGHT, NOON,
|
||||
PET_SMOKE_DEVIL, PET_SMOKE_DEVIL_22663,
|
||||
IKKLE_HYDRA, IKKLE_HYDRA_22748, IKKLE_HYDRA_22750, IKKLE_HYDRA_22752,
|
||||
|
||||
CALLISTO_CUB,
|
||||
PET_CHAOS_ELEMENTAL,
|
||||
SCORPIAS_OFFSPRING,
|
||||
VENENATIS_SPIDERLING,
|
||||
VETION_JR, VETION_JR_13180,
|
||||
|
||||
BABY_CHINCHOMPA, BABY_CHINCHOMPA_13324, BABY_CHINCHOMPA_13325, BABY_CHINCHOMPA_13326,
|
||||
BEAVER,
|
||||
GIANT_SQUIRREL,
|
||||
HERON,
|
||||
RIFT_GUARDIAN, RIFT_GUARDIAN_20667, RIFT_GUARDIAN_20669, RIFT_GUARDIAN_20671, RIFT_GUARDIAN_20673, RIFT_GUARDIAN_20675,
|
||||
RIFT_GUARDIAN_20677, RIFT_GUARDIAN_20679, RIFT_GUARDIAN_20681, RIFT_GUARDIAN_20683, RIFT_GUARDIAN_20685, RIFT_GUARDIAN_20687,
|
||||
RIFT_GUARDIAN_20689, RIFT_GUARDIAN_20691, RIFT_GUARDIAN_21990,
|
||||
ROCK_GOLEM, ROCK_GOLEM_21187, ROCK_GOLEM_21188, ROCK_GOLEM_21189, ROCK_GOLEM_21190, ROCK_GOLEM_21191, ROCK_GOLEM_21192,
|
||||
ROCK_GOLEM_21193, ROCK_GOLEM_21194, ROCK_GOLEM_21195, ROCK_GOLEM_21196, ROCK_GOLEM_21197, ROCK_GOLEM_21340, ROCK_GOLEM_21358,
|
||||
ROCK_GOLEM_21359, ROCK_GOLEM_21360,
|
||||
ROCKY,
|
||||
TANGLEROOT,
|
||||
|
||||
PET_KITTEN, PET_KITTEN_1556, PET_KITTEN_1557, PET_KITTEN_1558, PET_KITTEN_1559, PET_KITTEN_1560,
|
||||
PET_CAT, PET_CAT_1562, PET_CAT_1563, PET_CAT_1564, PET_CAT_1565, PET_CAT_1566, PET_CAT_1567, PET_CAT_1568, PET_CAT_1569,
|
||||
PET_CAT_1570, PET_CAT_1571, PET_CAT_1572,
|
||||
LAZY_CAT, LAZY_CAT_6550, LAZY_CAT_6551, LAZY_CAT_6552, LAZY_CAT_6553, LAZY_CAT_6554,
|
||||
WILY_CAT, WILY_CAT_6556, WILY_CAT_6557, WILY_CAT_6558, WILY_CAT_6559, WILY_CAT_6560,
|
||||
OVERGROWN_HELLCAT, HELL_CAT, HELLKITTEN, LAZY_HELL_CAT, WILY_HELLCAT,
|
||||
|
||||
BLOODHOUND,
|
||||
CHOMPY_CHICK,
|
||||
HERBI,
|
||||
PET_PENANCE_QUEEN,
|
||||
PHOENIX
|
||||
);
|
||||
|
||||
public static boolean isPet(int id)
|
||||
{
|
||||
return PETS.contains(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright (c) 2018, TheStonedTurtle <https://github.com/TheStonedTurtle>
|
||||
* 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.itemskeptondeath;
|
||||
|
||||
import net.runelite.api.ScriptEvent;
|
||||
import net.runelite.api.SpriteID;
|
||||
import net.runelite.api.widgets.JavaScriptCallback;
|
||||
import net.runelite.api.widgets.Widget;
|
||||
import net.runelite.api.widgets.WidgetType;
|
||||
|
||||
class WidgetButton
|
||||
{
|
||||
private static final int ICON_HEIGHT = 26;
|
||||
private static final int ICON_WIDTH = 26;
|
||||
private static final int BACKGROUND_HEIGHT = 32;
|
||||
private static final int BACKGROUND_WIDTH = 32;
|
||||
private static final int PADDING = 5;
|
||||
private static final int ICON_PADDING = (BACKGROUND_HEIGHT - ICON_HEIGHT) / 2;
|
||||
|
||||
private static final int BACKGROUND_SPRITE_ID = SpriteID.EQUIPMENT_SLOT_TILE;
|
||||
private static final int SELECTED_BACKGROUND_SPRITE_ID = SpriteID.EQUIPMENT_SLOT_SELECTED;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface WidgetButtonCallback
|
||||
{
|
||||
void run(boolean newState);
|
||||
}
|
||||
|
||||
private final Widget parent;
|
||||
private final String name;
|
||||
private final int spriteID;
|
||||
private boolean selected;
|
||||
private final WidgetButtonCallback callback;
|
||||
|
||||
private Widget icon;
|
||||
private Widget background;
|
||||
|
||||
WidgetButton(
|
||||
final Widget parent,
|
||||
final String name,
|
||||
final int spriteID,
|
||||
final boolean selectedStartState,
|
||||
final WidgetButtonCallback callback)
|
||||
{
|
||||
this.parent = parent;
|
||||
this.name = name;
|
||||
this.spriteID = spriteID;
|
||||
this.selected = selectedStartState;
|
||||
this.callback = callback;
|
||||
createBackgroundWidget();
|
||||
createIconWidget();
|
||||
}
|
||||
|
||||
private void createBackgroundWidget()
|
||||
{
|
||||
background = createWidget();
|
||||
background.setOriginalWidth(BACKGROUND_WIDTH);
|
||||
background.setOriginalHeight(BACKGROUND_HEIGHT);
|
||||
syncBackgroundSprite();
|
||||
}
|
||||
|
||||
private void createIconWidget()
|
||||
{
|
||||
icon = createWidget();
|
||||
icon.setAction(1, "Toggle:");
|
||||
icon.setOnOpListener((JavaScriptCallback) this::onButtonClicked);
|
||||
icon.setOnMouseRepeatListener((JavaScriptCallback) e -> e.getSource().setOpacity(120));
|
||||
icon.setOnMouseLeaveListener((JavaScriptCallback) e -> e.getSource().setOpacity(0));
|
||||
icon.setHasListener(true);
|
||||
icon.setSpriteId(spriteID);
|
||||
}
|
||||
|
||||
private Widget createWidget()
|
||||
{
|
||||
final Widget w = parent.createChild(-1, WidgetType.GRAPHIC);
|
||||
w.setOriginalWidth(ICON_WIDTH);
|
||||
w.setOriginalHeight(ICON_HEIGHT);
|
||||
w.setName("<col=ff981f>" + this.name);
|
||||
return w;
|
||||
}
|
||||
|
||||
public void setSelected(boolean selected)
|
||||
{
|
||||
this.selected = selected;
|
||||
syncBackgroundSprite();
|
||||
}
|
||||
|
||||
private void syncBackgroundSprite()
|
||||
{
|
||||
background.setSpriteId(selected ? SELECTED_BACKGROUND_SPRITE_ID : BACKGROUND_SPRITE_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the collection of WidgetButtons to the container overriding any existing children.
|
||||
*
|
||||
* @param container Widget to add buttons too
|
||||
* @param buttons buttons to add
|
||||
*/
|
||||
static void layoutButtonsToContainer(final Widget container, final WidgetButton... buttons)
|
||||
{
|
||||
// Each button has two widgets, Icon and Background
|
||||
final int xIncrement = BACKGROUND_WIDTH + PADDING;
|
||||
final int yIncrement = BACKGROUND_HEIGHT + PADDING;
|
||||
int maxRowItems = container.getWidth() / xIncrement;
|
||||
// Ensure at least 1 button per row
|
||||
maxRowItems = maxRowItems < 1 ? 1 : maxRowItems;
|
||||
|
||||
int index = 0;
|
||||
for (final WidgetButton w : buttons)
|
||||
{
|
||||
if (w == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
final int originalX = ((index % maxRowItems) * xIncrement);
|
||||
final int originalY = ((index / maxRowItems) * yIncrement);
|
||||
w.background.setOriginalX(originalX);
|
||||
w.background.setOriginalY(originalY);
|
||||
w.background.revalidate();
|
||||
|
||||
// Icon must be padded to center inside image
|
||||
w.icon.setOriginalX(originalX + ICON_PADDING);
|
||||
w.icon.setOriginalY(originalY + ICON_PADDING);
|
||||
w.icon.revalidate();
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
final int numButtons = index;
|
||||
final int rows = 1 + (numButtons > maxRowItems ? numButtons / maxRowItems : 0);
|
||||
container.setOriginalHeight(yIncrement * rows);
|
||||
container.revalidate();
|
||||
}
|
||||
|
||||
private void onButtonClicked(ScriptEvent scriptEvent)
|
||||
{
|
||||
setSelected(!selected);
|
||||
callback.run(selected);
|
||||
}
|
||||
}
|
||||
@@ -92,6 +92,16 @@ public interface ItemStatConfig extends Config
|
||||
return false;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "showWeight",
|
||||
name = "Show Weight",
|
||||
description = "Show weight in tooltip"
|
||||
)
|
||||
default boolean showWeight()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "colorBetterUncapped",
|
||||
name = "Better (Uncapped)",
|
||||
|
||||
@@ -189,7 +189,10 @@ public class ItemStatOverlay extends Overlay
|
||||
private String buildStatBonusString(ItemStats s)
|
||||
{
|
||||
final StringBuilder b = new StringBuilder();
|
||||
b.append(getChangeString("Weight", s.getWeight(), true, false));
|
||||
if (config.showWeight())
|
||||
{
|
||||
b.append(getChangeString("Weight", s.getWeight(), true, false));
|
||||
}
|
||||
|
||||
ItemStats other = null;
|
||||
final ItemEquipmentStats currentEquipment = s.getEquipment();
|
||||
|
||||
@@ -35,6 +35,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.Constants;
|
||||
import net.runelite.api.FontID;
|
||||
import net.runelite.api.InventoryID;
|
||||
import net.runelite.api.Item;
|
||||
@@ -232,8 +233,8 @@ public class ItemStatPlugin extends Plugin
|
||||
Widget icon = invContainer.createChild(-1, WidgetType.GRAPHIC);
|
||||
icon.setOriginalX(8);
|
||||
icon.setOriginalY(yPos);
|
||||
icon.setOriginalWidth(36);
|
||||
icon.setOriginalHeight(32);
|
||||
icon.setOriginalWidth(Constants.ITEM_SPRITE_WIDTH);
|
||||
icon.setOriginalHeight(Constants.ITEM_SPRITE_HEIGHT);
|
||||
icon.setItemId(id);
|
||||
icon.setItemQuantityMode(0);
|
||||
icon.setBorderType(1);
|
||||
|
||||
@@ -47,7 +47,7 @@ class MiningOverlay extends Overlay
|
||||
{
|
||||
// Range of Motherlode vein respawn time not 100% confirmed but based on observation
|
||||
@Getter(AccessLevel.PACKAGE)
|
||||
private static final int ORE_VEIN_MAX_RESPAWN_TIME = 123;
|
||||
public static final int ORE_VEIN_MAX_RESPAWN_TIME = 123;
|
||||
private static final int ORE_VEIN_MIN_RESPAWN_TIME = 90;
|
||||
private static final float ORE_VEIN_RANDOM_PERCENT_THRESHOLD = (float) ORE_VEIN_MIN_RESPAWN_TIME / ORE_VEIN_MAX_RESPAWN_TIME;
|
||||
private static final Color DARK_GREEN = new Color(0, 100, 0);
|
||||
|
||||
@@ -168,6 +168,7 @@ public class MiningPlugin extends Plugin
|
||||
case ORE_VEIN_26663: // Motherlode vein
|
||||
case ORE_VEIN_26664: // Motherlode vein
|
||||
{
|
||||
// If the vein respawns before the timer is up, remove it
|
||||
final WorldPoint point = object.getWorldLocation();
|
||||
respawns.removeIf(rockRespawn -> rockRespawn.getWorldPoint().equals(point));
|
||||
break;
|
||||
|
||||
@@ -49,6 +49,7 @@ import static net.runelite.api.ObjectID.ROCKS_11376;
|
||||
import static net.runelite.api.ObjectID.ROCKS_11377;
|
||||
import static net.runelite.api.ObjectID.ROCKS_11386;
|
||||
import static net.runelite.api.ObjectID.ROCKS_11387;
|
||||
import static net.runelite.api.ObjectID.ASH_PILE;
|
||||
|
||||
enum Rock
|
||||
{
|
||||
@@ -98,8 +99,9 @@ enum Rock
|
||||
return inMiningGuild ? Duration.ofMinutes(6) : super.respawnTime;
|
||||
}
|
||||
},
|
||||
ORE_VEIN(Duration.ofSeconds(MiningOverlay.getORE_VEIN_MAX_RESPAWN_TIME()), 150),
|
||||
AMETHYST(Duration.ofSeconds(75), 120);
|
||||
ORE_VEIN(Duration.ofSeconds(MiningOverlay.ORE_VEIN_MAX_RESPAWN_TIME), 150),
|
||||
AMETHYST(Duration.ofSeconds(75), 120),
|
||||
ASH_VEIN(Duration.ofSeconds(30), 0, ASH_PILE);
|
||||
|
||||
private static final Map<Integer, Rock> ROCKS;
|
||||
|
||||
|
||||
@@ -784,7 +784,7 @@ public class SlayerPlugin extends Plugin
|
||||
private boolean doubleTroubleExtraKill()
|
||||
{
|
||||
return WorldPoint.fromLocalInstance(client, client.getLocalPlayer().getLocalLocation()).getRegionID() == GROTESQUE_GUARDIANS_REGION &&
|
||||
SlayerUnlock.GROTESQUE_GARDIAN_DOUBLE_COUNT.isEnabled(client);
|
||||
SlayerUnlock.GROTESQUE_GUARDIAN_DOUBLE_COUNT.isEnabled(client);
|
||||
}
|
||||
|
||||
// checks if any contiguous subsequence of seq0 exactly matches the String toMatch
|
||||
|
||||
@@ -126,13 +126,13 @@ public class TimersPlugin extends Plugin
|
||||
private static final String CANNON_REPAIR_MESSAGE = "You repair your cannon, restoring it to working order.";
|
||||
private static final String CHARGE_EXPIRED_MESSAGE = "<col=ef1020>Your magical charge fades away.</col>";
|
||||
private static final String CHARGE_MESSAGE = "<col=ef1020>You feel charged with magic power.</col>";
|
||||
private static final String DEADMAN_HALF_TELEBLOCK_MESSAGE = "<col=4f006f>A teleblock spell has been cast on you. It will expire in 1 minute, 15 seconds.</col>";
|
||||
private static final String DEADMAN_HALF_TELEBLOCK_MESSAGE = "<col=4f006f>A Tele Block spell has been cast on you. It will expire in 1 minute, 15 seconds.</col>";
|
||||
private static final String EXTENDED_ANTIFIRE_DRINK_MESSAGE = "You drink some of your extended antifire potion.";
|
||||
private static final String EXTENDED_SUPER_ANTIFIRE_DRINK_MESSAGE = "You drink some of your extended super antifire potion.";
|
||||
private static final String FROZEN_MESSAGE = "<col=ef1020>You have been frozen!</col>";
|
||||
private static final String FULL_TELEBLOCK_MESSAGE = "<col=4f006f>A teleblock spell has been cast on you. It will expire in 5 minutes, 0 seconds.</col>";
|
||||
private static final String FULL_TELEBLOCK_MESSAGE = "<col=4f006f>A Tele Block spell has been cast on you. It will expire in 5 minutes, 0 seconds.</col>";
|
||||
private static final String GOD_WARS_ALTAR_MESSAGE = "you recharge your prayer.";
|
||||
private static final String HALF_TELEBLOCK_MESSAGE = "<col=4f006f>A teleblock spell has been cast on you. It will expire in 2 minutes, 30 seconds.</col>";
|
||||
private static final String HALF_TELEBLOCK_MESSAGE = "<col=4f006f>A Tele Block spell has been cast on you. It will expire in 2 minutes, 30 seconds.</col>";
|
||||
private static final String IMBUED_HEART_READY_MESSAGE = "<col=ef1020>Your imbued heart has regained its magical power.</col>";
|
||||
private static final String IMBUED_HEART_NOTREADY_MESSAGE = "The heart is still drained of its power.";
|
||||
private static final String MAGIC_IMBUE_EXPIRED_MESSAGE = "Your Magic Imbue charge has ended.";
|
||||
|
||||
@@ -35,6 +35,7 @@ import javax.swing.ImageIcon;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import net.runelite.api.Constants;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.ui.FontManager;
|
||||
@@ -60,7 +61,7 @@ class OverviewItemPanel extends JPanel
|
||||
setBorder(new EmptyBorder(7, 7, 7, 7));
|
||||
|
||||
JLabel iconLabel = new JLabel();
|
||||
iconLabel.setMinimumSize(new Dimension(36, 32));
|
||||
iconLabel.setMinimumSize(new Dimension(Constants.ITEM_SPRITE_WIDTH, Constants.ITEM_SPRITE_HEIGHT));
|
||||
itemManager.getImage(tab.getItemID()).addTo(iconLabel);
|
||||
add(iconLabel, BorderLayout.WEST);
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import lombok.Getter;
|
||||
import net.runelite.api.Constants;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.ui.FontManager;
|
||||
import net.runelite.client.ui.components.ThinProgressBar;
|
||||
@@ -58,7 +59,7 @@ public class TimeablePanel<T> extends JPanel
|
||||
topContainer.setLayout(new BorderLayout());
|
||||
topContainer.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
|
||||
icon.setMinimumSize(new Dimension(36, 32));
|
||||
icon.setMinimumSize(new Dimension(Constants.ITEM_SPRITE_WIDTH, Constants.ITEM_SPRITE_HEIGHT));
|
||||
|
||||
JPanel infoPanel = new JPanel();
|
||||
infoPanel.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
|
||||
@@ -27,151 +27,159 @@ package net.runelite.client.plugins.worldmap;
|
||||
|
||||
import lombok.Getter;
|
||||
import net.runelite.api.coords.WorldPoint;
|
||||
import net.runelite.api.Quest;
|
||||
|
||||
// Some quests are in the same spot, but they are done in order. If multiple
|
||||
// quests start in the same location, an array of quests is expected.
|
||||
enum QuestStartLocation
|
||||
{
|
||||
//Free Quests
|
||||
COOKS_ASSISTANT_RFD("Cook's Assistant", new WorldPoint(3211, 3216, 0)),
|
||||
THE_CORSAIR_CURSE("The Corsair Curse", new WorldPoint(3029, 3273, 0)),
|
||||
DEMON_SLAYER("Demon Slayer", new WorldPoint(3204, 3424, 0)),
|
||||
DORICS_QUEST("Doric's Quest", new WorldPoint(2952, 3450, 0)),
|
||||
DRAGON_SLAYER("Dragon Slayer", new WorldPoint(3190, 3362, 0)),
|
||||
ERNEST_THE_CHICKEN("Ernest the Chicken", new WorldPoint(3109, 3330, 0)),
|
||||
GOBLIN_DIPLOMACY("Goblin Diplomacy", new WorldPoint(2957, 3509, 0)),
|
||||
IMP_CATCHER("Imp Catcher", new WorldPoint(3108, 3160, 0)),
|
||||
THE_KNIGHTS_SWORD("The Knight's Sword", new WorldPoint(2976, 3342, 0)),
|
||||
MISTHALIN_MYSTERY("Misthalin Mystery", new WorldPoint(3234, 3155, 0)),
|
||||
PIRATES_TREASURE("Pirate's Treasure", new WorldPoint(3051, 3252, 0)),
|
||||
PRINCE_ALI_RESCUE("Prince Ali Rescue", new WorldPoint(3301, 3163, 0)),
|
||||
THE_RESTLESS_GHOST("The Restless Ghost", new WorldPoint(3240, 3210, 0)),
|
||||
RUNE_MYSTERIES("Rune Mysteries", new WorldPoint(3210, 3220, 0)),
|
||||
SHEEP_SHEARER("Sheep Shearer", new WorldPoint(3190, 3272, 0)),
|
||||
SHIELD_OF_ARRAV_PHOENIX_GANG("Shield of Arrav (Phoenix Gang)", new WorldPoint(3208, 3495, 0)),
|
||||
SHIELD_OF_ARRAV_BLACK_ARM_GANG("Shield of Arrav (Black Arm Gang)", new WorldPoint(3208, 3392, 0)),
|
||||
VAMPIRE_SLAYER("Vampire Slayer", new WorldPoint(3096, 3266, 0)),
|
||||
WITCHS_POTION("Witch's Potion", new WorldPoint(2967, 3203, 0)),
|
||||
X_MARKS_THE_SPOT("X Marks the Spot", new WorldPoint(3227, 3242, 0)),
|
||||
COOKS_ASSISTANT_RFD(Quest.COOKS_ASSISTANT, new WorldPoint(3211, 3216, 0)),
|
||||
THE_CORSAIR_CURSE(Quest.THE_CORSAIR_CURSE, new WorldPoint(3029, 3273, 0)),
|
||||
DEMON_SLAYER(Quest.DEMON_SLAYER, new WorldPoint(3204, 3424, 0)),
|
||||
DORICS_QUEST(Quest.DORICS_QUEST, new WorldPoint(2952, 3450, 0)),
|
||||
DRAGON_SLAYER(Quest.DRAGON_SLAYER, new WorldPoint(3190, 3362, 0)),
|
||||
ERNEST_THE_CHICKEN(Quest.ERNEST_THE_CHICKEN, new WorldPoint(3109, 3330, 0)),
|
||||
GOBLIN_DIPLOMACY(Quest.GOBLIN_DIPLOMACY, new WorldPoint(2957, 3509, 0)),
|
||||
IMP_CATCHER(Quest.IMP_CATCHER, new WorldPoint(3108, 3160, 0)),
|
||||
THE_KNIGHTS_SWORD(Quest.THE_KNIGHTS_SWORD, new WorldPoint(2976, 3342, 0)),
|
||||
MISTHALIN_MYSTERY(Quest.MISTHALIN_MYSTERY, new WorldPoint(3234, 3155, 0)),
|
||||
PIRATES_TREASURE(Quest.PIRATES_TREASURE, new WorldPoint(3051, 3252, 0)),
|
||||
PRINCE_ALI_RESCUE(Quest.PRINCE_ALI_RESCUE, new WorldPoint(3301, 3163, 0)),
|
||||
THE_RESTLESS_GHOST(Quest.THE_RESTLESS_GHOST, new WorldPoint(3240, 3210, 0)),
|
||||
RUNE_MYSTERIES(Quest.RUNE_MYSTERIES, new WorldPoint(3210, 3220, 0)),
|
||||
SHEEP_SHEARER(Quest.SHEEP_SHEARER, new WorldPoint(3190, 3272, 0)),
|
||||
SHIELD_OF_ARRAV(Quest.SHIELD_OF_ARRAV, new WorldPoint(3208, 3495, 0)),
|
||||
VAMPIRE_SLAYER(Quest.VAMPIRE_SLAYER, new WorldPoint(3096, 3266, 0)),
|
||||
WITCHS_POTION(Quest.WITCHS_POTION, new WorldPoint(2967, 3203, 0)),
|
||||
X_MARKS_THE_SPOT(Quest.X_MARKS_THE_SPOT, new WorldPoint(3227, 3242, 0)),
|
||||
|
||||
//Members' Quests
|
||||
ANIMAL_MAGNETISM("Animal Magnetism", new WorldPoint(3094, 3360, 0)),
|
||||
ANOTHER_SLICE_OF_HAM("Another Slice of H.A.M.", new WorldPoint(2799, 5428, 0)),
|
||||
THE_ASCENT_OF_ARCEUUS("The Ascent of Arceuus", new WorldPoint(1700, 3742, 0)),
|
||||
BETWEEN_A_ROCK("Between a Rock...", new WorldPoint(2823, 10168, 0)),
|
||||
BIG_CHOMPY_BIRD_HUNTING("Big Chompy Bird Hunting", new WorldPoint(2629, 2981, 0)),
|
||||
BIOHAZARD("Biohazard", new WorldPoint(2591, 3335, 0)),
|
||||
BONE_VOYAGE("Bone Voyage", new WorldPoint(3259, 3450, 0)),
|
||||
CABIN_FEVER("Cabin Fever", new WorldPoint(3674, 3496, 0)),
|
||||
CLIENT_OF_KOUREND("Client of Kourend", new WorldPoint(1823, 3690, 0)),
|
||||
CLOCK_TOWER("Clock Tower", new WorldPoint(2568, 3249, 0)),
|
||||
COLD_WAR("Cold War", new WorldPoint(2593, 3265, 0)),
|
||||
CONTACT("Contact!", new WorldPoint(3280, 2770, 0)),
|
||||
CREATURE_OF_FENKENSTRAIN("Creature of Fenkenstrain", new WorldPoint(3487, 3485, 0)),
|
||||
DARKNESS_OF_HALLOWVALE("Darkness of Hallowvale", new WorldPoint(3494, 9628, 0)),
|
||||
DEATH_PLATEAU_TROLL_STRONGHOLD("Death Plateau & Troll Stronghold", new WorldPoint(2895, 3528, 0)),
|
||||
DEATH_TO_THE_DORGESHUUN("Death to the Dorgeshuun", new WorldPoint(3316, 9613, 0)),
|
||||
THE_DEPTHS_OF_DESPAIR("The Depths of Despair", new WorldPoint(1846, 3556, 0)),
|
||||
DESERT_TREASURE("Desert Treasure", new WorldPoint(3177, 3043, 0)),
|
||||
DEVIOUS_MINDS("Devious Minds", new WorldPoint(3405, 3492, 0)),
|
||||
THE_DIG_SITE("The Dig Site", new WorldPoint(3363, 3337, 0)),
|
||||
DRAGON_SLAYER_II("Dragon Slayer II", new WorldPoint(2456, 2868, 0)),
|
||||
DREAM_MENTOR("Dream Mentor", new WorldPoint(2144, 10346, 0)),
|
||||
DRUIDIC_RITUAL("Druidic Ritual", new WorldPoint(2916, 3484, 0)),
|
||||
DWARF_CANNON("Dwarf Cannon", new WorldPoint(2566, 3461, 0)),
|
||||
EADGARS_RUSE("Eadgar's Ruse", new WorldPoint(2896, 3426, 0)),
|
||||
EAGLES_PEAK("Eagles' Peak", new WorldPoint(2605, 3264, 0)),
|
||||
ELEMENTAL_WORKSHOP("Elemental Workshop I & II", new WorldPoint(2714, 3482, 0)),
|
||||
ENAKHRAS_LAMENT("Enakhra's Lament", new WorldPoint(3190, 2926, 0)),
|
||||
ENLIGHTENED_JOURNEY("Enlightened Journey", new WorldPoint(2809, 3356, 0)),
|
||||
THE_EYES_OF_GLOUPHRIE("The Eyes of Glouphrie", new WorldPoint(2400, 3419, 0)),
|
||||
FAIRYTALE("Fairytale I & II", new WorldPoint(3077, 3258, 0)),
|
||||
FAMILY_CREST("Family Crest", new WorldPoint(3278, 3404, 0)),
|
||||
THE_FEUD("The Feud", new WorldPoint(3301, 3211, 0)),
|
||||
FIGHT_ARENA("Fight Arena", new WorldPoint(2565, 3199, 0)),
|
||||
FISHING_CONTEST_1("Fishing Contest", new WorldPoint(2875, 3483, 0)),
|
||||
FISHING_CONTEST_2("Fishing Contest", new WorldPoint(2820, 3487, 0)),
|
||||
FORGETTABLE_TALE("Forgettable Tale...", new WorldPoint(2826, 10215, 0)),
|
||||
THE_FORSAKEN_TOWER("The Forsaken Tower", new WorldPoint(1484, 3747, 0)),
|
||||
THE_FREMENNIK_ISLES("The Fremennik Isles", new WorldPoint(2645, 3711, 0)),
|
||||
THE_FREMENNIK_TRIALS("The Fremennik Trials", new WorldPoint(2657, 3669, 0)),
|
||||
GARDEN_OF_TRANQUILLITY("Garden of Tranquillity", new WorldPoint(3227, 3477, 0)),
|
||||
GERTRUDES_CAT_RATCATCHERS("Gertrude's Cat & Ratcatchers", new WorldPoint(3150, 3411, 0)),
|
||||
GHOSTS_AHOY("Ghosts Ahoy", new WorldPoint(3677, 3510, 0)),
|
||||
THE_GIANT_DWARF("The Giant Dwarf", new WorldPoint(2841, 10129, 0)),
|
||||
THE_GOLEM("The Golem", new WorldPoint(3487, 3089, 0)),
|
||||
THE_GRAND_TREE_MONKEY_MADNESS("The Grand Tree & Monkey Madness I & II", new WorldPoint(2466, 3497, 0)),
|
||||
THE_GREAT_BRAIN_ROBBERY("The Great Brain Robbery", new WorldPoint(3681, 2963, 0)),
|
||||
GRIM_TALES("Grim Tales", new WorldPoint(2890, 3454, 0)),
|
||||
THE_HAND_IN_THE_SAND("The Hand in the Sand", new WorldPoint(2552, 3101, 0)),
|
||||
HAUNTED_MINE("Haunted Mine", new WorldPoint(3443, 3258, 0)),
|
||||
HAZEEL_CULT("Hazeel Cult", new WorldPoint(2565, 3271, 0)),
|
||||
HEROES_QUEST("Heroes' Quest", new WorldPoint(2903, 3511, 0)),
|
||||
HOLY_GRAIL("Holy Grail & Merlin's Crystal", new WorldPoint(2763, 3515, 0)),
|
||||
HORROR_FROM_THE_DEEP("Horror from the Deep", new WorldPoint(2507, 3635, 0)),
|
||||
ICTHLARINS_LITTLE_HELPER("Icthlarin's Little Helper", new WorldPoint(3314, 2849, 0)),
|
||||
IN_SEARCH_OF_THE_MYREQUE("In Search of the Myreque", new WorldPoint(3502, 3477, 0)),
|
||||
JUNGLE_POTION("Jungle Potion", new WorldPoint(2809, 3086, 0)),
|
||||
KINGS_RANSOM("King's Ransom", new WorldPoint(2741, 3554, 0)),
|
||||
LEGENDS_QUEST("Legends' Quest", new WorldPoint(2725, 3367, 0)),
|
||||
LOST_CITY("Lost City", new WorldPoint(3149, 3205, 0)),
|
||||
THE_LOST_TRIBE("The Lost Tribe", new WorldPoint(3211, 3224, 0)),
|
||||
LUNAR_DIPLOMACY("Lunar Diplomacy", new WorldPoint(2619, 3689, 0)),
|
||||
MAKING_FRIENDS_WITH_MY_ARM("Making Friends with My Arm", new WorldPoint(2904, 10092, 0)),
|
||||
MAKING_HISTORY("Making History", new WorldPoint(2435, 3346, 0)),
|
||||
MONKS_FRIEND("Monk's Friend", new WorldPoint(2605, 3209, 0)),
|
||||
MOUNTAIN_DAUGHTER("Mountain Daughter", new WorldPoint(2810, 3672, 0)),
|
||||
MOURNINGS_ENDS_PART_I("Mourning's Ends Part I", new WorldPoint(2289, 3149, 0)),
|
||||
MOURNINGS_ENDS_PART_II("Mourning's Ends Part II", new WorldPoint(2352, 3172, 0)),
|
||||
MURDER_MYSTERY("Murder Mystery", new WorldPoint(2740, 3562, 0)),
|
||||
MY_ARMS_BIG_ADVENTURE("My Arm's Big Adventure", new WorldPoint(2908, 10088, 0)),
|
||||
NATURE_SPIRIT("Nature Spirit", new WorldPoint(3440, 9894, 0)),
|
||||
OBSERVATORY_QUEST("Observatory Quest", new WorldPoint(2438, 3185, 0)),
|
||||
OLAFS_QUEST("Olaf's Quest", new WorldPoint(2723, 3729, 0)),
|
||||
ONE_SMALL_FAVOUR("One Small Favour", new WorldPoint(2834, 2985, 0)),
|
||||
PLAGUE_CITY("Plague City", new WorldPoint(2567, 3334, 0)),
|
||||
PRIEST_IN_PERIL("Priest in Peril", new WorldPoint(3219, 3473, 0)),
|
||||
THE_QUEEN_OF_THIEVES("The Queen of Thieves", new WorldPoint(1795, 3782, 0)),
|
||||
RAG_AND_BONE_MAN("Rag and Bone Man I & II", new WorldPoint(3359, 3504, 0)),
|
||||
RECRUITMENT_DRIVE_BLACK_KNIGHTS_FORTRESS("Recruitment Drive & Black Knights' Fortress", new WorldPoint(2959, 3336, 0)),
|
||||
ROVING_ELVES("Roving Elves", new WorldPoint(2289, 3146, 0)),
|
||||
RUM_DEAL("Rum Deal", new WorldPoint(3679, 3535, 0)),
|
||||
SCORPION_CATCHER("Scorpion Catcher", new WorldPoint(2701, 3399, 0)),
|
||||
SEA_SLUG("Sea Slug", new WorldPoint(2715, 3302, 0)),
|
||||
SHADES_OF_MORTTON("Shades of Mort'ton", new WorldPoint(3463, 3308, 0)),
|
||||
SHADOW_OF_THE_STORM("Shadow of the Storm", new WorldPoint(3270, 3159, 0)),
|
||||
SHEEP_HERDER("Sheep Herder", new WorldPoint(2616, 3299, 0)),
|
||||
SHILO_VILLAGE("Shilo Village", new WorldPoint(2882, 2951, 0)),
|
||||
A_SOULS_BANE("A Soul's Bane", new WorldPoint(3307, 3454, 0)),
|
||||
SPIRITS_OF_THE_ELID("Spirits of the Elid", new WorldPoint(3441, 2911, 0)),
|
||||
SWAN_SONG("Swan Song", new WorldPoint(2345, 3652, 0)),
|
||||
TAI_BWO_WANNAI_TRIO("Tai Bwo Wannai Trio", new WorldPoint(2779, 3087, 0)),
|
||||
A_TAIL_OF_TWO_CATS("A Tail of Two Cats", new WorldPoint(2917, 3557, 0)),
|
||||
TALE_OF_THE_RIGHTEOUS("Tale of the Righteous", new WorldPoint(1511, 3631, 0)),
|
||||
A_TASTE_OF_HOPE("A Taste of Hope", new WorldPoint(3668, 3216, 0)),
|
||||
TEARS_OF_GUTHIX("Tears of Guthix", new WorldPoint(3251, 9517, 0)),
|
||||
TEMPLE_OF_IKOV("Temple of Ikov", new WorldPoint(2574, 3320, 0)),
|
||||
THRONE_OF_MISCELLANIA_ROYAL_TROUBLE("Throne of Miscellania & Royal Trouble", new WorldPoint(2497, 3859, 0)),
|
||||
THE_TOURIST_TRAP("The Tourist Trap", new WorldPoint(3302, 3113, 0)),
|
||||
TOWER_OF_LIFE("Tower of Life", new WorldPoint(2640, 3218, 0)),
|
||||
TREE_GNOME_VILLAGE("Tree Gnome Village", new WorldPoint(2541, 3169, 0)),
|
||||
TRIBAL_TOTEM("Tribal Totem", new WorldPoint(2790, 3182, 0)),
|
||||
TROLL_ROMANCE("Troll Romance", new WorldPoint(2890, 10097, 0)),
|
||||
UNDERGROUND_PASS_REGICIDE("Underground Pass & Regicide", new WorldPoint(2575, 3293, 0)),
|
||||
WANTED_SLUG_MENACE("Wanted! & The Slug Menace", new WorldPoint(2996, 3373, 0)),
|
||||
WATCHTOWER("Watchtower", new WorldPoint(2545, 3112, 0)),
|
||||
WATERFALL_QUEST("Waterfall Quest", new WorldPoint(2521, 3498, 0)),
|
||||
WHAT_LIES_BELOW("What Lies Below", new WorldPoint(3265, 3333, 0)),
|
||||
WITCHS_HOUSE("Witch's House", new WorldPoint(2927, 3456, 0)),
|
||||
ZOGRE_FLESH_EATERS("Zogre Flesh Eaters", new WorldPoint(2442, 3051, 0));
|
||||
|
||||
@Getter
|
||||
private final String tooltip;
|
||||
ANIMAL_MAGNETISM(Quest.ANIMAL_MAGNETISM, new WorldPoint(3094, 3360, 0)),
|
||||
ANOTHER_SLICE_OF_HAM(Quest.ANOTHER_SLICE_OF_HAM, new WorldPoint(2799, 5428, 0)),
|
||||
THE_ASCENT_OF_ARCEUUS(Quest.THE_ASCENT_OF_ARCEUUS, new WorldPoint(1700, 3742, 0)),
|
||||
BETWEEN_A_ROCK(Quest.BETWEEN_A_ROCK, new WorldPoint(2823, 10168, 0)),
|
||||
BIG_CHOMPY_BIRD_HUNTING(Quest.BIG_CHOMPY_BIRD_HUNTING, new WorldPoint(2629, 2981, 0)),
|
||||
BIOHAZARD(Quest.BIOHAZARD, new WorldPoint(2591, 3335, 0)),
|
||||
BONE_VOYAGE(Quest.BONE_VOYAGE, new WorldPoint(3259, 3450, 0)),
|
||||
CABIN_FEVER(Quest.CABIN_FEVER, new WorldPoint(3674, 3496, 0)),
|
||||
CLIENT_OF_KOUREND(Quest.CLIENT_OF_KOUREND, new WorldPoint(1823, 3690, 0)),
|
||||
CLOCK_TOWER(Quest.CLOCK_TOWER, new WorldPoint(2568, 3249, 0)),
|
||||
COLD_WAR(Quest.COLD_WAR, new WorldPoint(2593, 3265, 0)),
|
||||
CONTACT(Quest.CONTACT, new WorldPoint(3280, 2770, 0)),
|
||||
CREATURE_OF_FENKENSTRAIN(Quest.CREATURE_OF_FENKENSTRAIN, new WorldPoint(3487, 3485, 0)),
|
||||
DARKNESS_OF_HALLOWVALE(Quest.DARKNESS_OF_HALLOWVALE, new WorldPoint(3494, 9628, 0)),
|
||||
DEATH_PLATEAU_TROLL_STRONGHOLD(new Quest[]{Quest.DEATH_PLATEAU, Quest.TROLL_STRONGHOLD}, new WorldPoint(2895, 3528, 0)),
|
||||
DEATH_TO_THE_DORGESHUUN(Quest.DEATH_TO_THE_DORGESHUUN, new WorldPoint(3316, 9613, 0)),
|
||||
THE_DEPTHS_OF_DESPAIR(Quest.THE_DEPTHS_OF_DESPAIR, new WorldPoint(1846, 3556, 0)),
|
||||
DESERT_TREASURE(Quest.DESERT_TREASURE, new WorldPoint(3177, 3043, 0)),
|
||||
DEVIOUS_MINDS(Quest.DEVIOUS_MINDS, new WorldPoint(3405, 3492, 0)),
|
||||
THE_DIG_SITE(Quest.THE_DIG_SITE, new WorldPoint(3363, 3337, 0)),
|
||||
DRAGON_SLAYER_II(Quest.DRAGON_SLAYER_II, new WorldPoint(2456, 2868, 0)),
|
||||
DREAM_MENTOR(Quest.DREAM_MENTOR, new WorldPoint(2144, 10346, 0)),
|
||||
DRUIDIC_RITUAL(Quest.DRUIDIC_RITUAL, new WorldPoint(2916, 3484, 0)),
|
||||
DWARF_CANNON(Quest.DWARF_CANNON, new WorldPoint(2566, 3461, 0)),
|
||||
EADGARS_RUSE(Quest.EADGARS_RUSE, new WorldPoint(2896, 3426, 0)),
|
||||
EAGLES_PEAK(Quest.EAGLES_PEAK, new WorldPoint(2605, 3264, 0)),
|
||||
ELEMENTAL_WORKSHOP(new Quest[]{Quest.ELEMENTAL_WORKSHOP_I, Quest.ELEMENTAL_WORKSHOP_II}, new WorldPoint(2714, 3482, 0)),
|
||||
ENAKHRAS_LAMENT(Quest.ENAKHRAS_LAMENT, new WorldPoint(3190, 2926, 0)),
|
||||
ENLIGHTENED_JOURNEY(Quest.ENLIGHTENED_JOURNEY, new WorldPoint(2809, 3356, 0)),
|
||||
THE_EYES_OF_GLOUPHRIE(Quest.THE_EYES_OF_GLOUPHRIE, new WorldPoint(2400, 3419, 0)),
|
||||
FAIRYTALE(new Quest[]{Quest.FAIRYTALE_I__GROWING_PAINS, Quest.FAIRYTALE_II__CURE_A_QUEEN}, new WorldPoint(3077, 3258, 0)),
|
||||
FAMILY_CREST(Quest.FAMILY_CREST, new WorldPoint(3278, 3404, 0)),
|
||||
THE_FEUD(Quest.THE_FEUD, new WorldPoint(3301, 3211, 0)),
|
||||
FIGHT_ARENA(Quest.FIGHT_ARENA, new WorldPoint(2565, 3199, 0)),
|
||||
FISHING_CONTEST_1(Quest.FISHING_CONTEST, new WorldPoint(2875, 3483, 0)),
|
||||
FISHING_CONTEST_2(Quest.FISHING_CONTEST, new WorldPoint(2820, 3487, 0)),
|
||||
FORGETTABLE_TALE(Quest.FORGETTABLE_TALE, new WorldPoint(2826, 10215, 0)),
|
||||
THE_FORSAKEN_TOWER(Quest.THE_FORSAKEN_TOWER, new WorldPoint(1484, 3747, 0)),
|
||||
THE_FREMENNIK_ISLES(Quest.THE_FREMENNIK_ISLES, new WorldPoint(2645, 3711, 0)),
|
||||
THE_FREMENNIK_TRIALS(Quest.THE_FREMENNIK_TRIALS, new WorldPoint(2657, 3669, 0)),
|
||||
GARDEN_OF_TRANQUILLITY(Quest.GARDEN_OF_TRANQUILLITY, new WorldPoint(3227, 3477, 0)),
|
||||
GERTRUDES_CAT_RATCATCHERS(Quest.GERTRUDES_CAT, new WorldPoint(3150, 3411, 0)),
|
||||
GHOSTS_AHOY(Quest.GHOSTS_AHOY, new WorldPoint(3677, 3510, 0)),
|
||||
THE_GIANT_DWARF(Quest.THE_GIANT_DWARF, new WorldPoint(2841, 10129, 0)),
|
||||
THE_GOLEM(Quest.THE_GOLEM, new WorldPoint(3487, 3089, 0)),
|
||||
THE_GRAND_TREE_MONKEY_MADNESS(new Quest[]{Quest.THE_GRAND_TREE, Quest.MONKEY_MADNESS_I, Quest.MONKEY_MADNESS_II}, new WorldPoint(2466, 3497, 0)),
|
||||
THE_GREAT_BRAIN_ROBBERY(Quest.THE_GREAT_BRAIN_ROBBERY, new WorldPoint(3681, 2963, 0)),
|
||||
GRIM_TALES(Quest.GRIM_TALES, new WorldPoint(2890, 3454, 0)),
|
||||
THE_HAND_IN_THE_SAND(Quest.THE_HAND_IN_THE_SAND, new WorldPoint(2552, 3101, 0)),
|
||||
HAUNTED_MINE(Quest.HAUNTED_MINE, new WorldPoint(3443, 3258, 0)),
|
||||
HAZEEL_CULT(Quest.HAZEEL_CULT, new WorldPoint(2565, 3271, 0)),
|
||||
HEROES_QUEST(Quest.HEROES_QUEST, new WorldPoint(2903, 3511, 0)),
|
||||
HOLY_GRAIL(new Quest[]{Quest.MERLINS_CRYSTAL, Quest.HOLY_GRAIL}, new WorldPoint(2763, 3515, 0)),
|
||||
HORROR_FROM_THE_DEEP(Quest.HORROR_FROM_THE_DEEP, new WorldPoint(2507, 3635, 0)),
|
||||
ICTHLARINS_LITTLE_HELPER(Quest.ICTHLARINS_LITTLE_HELPER, new WorldPoint(3314, 2849, 0)),
|
||||
IN_SEARCH_OF_THE_MYREQUE(Quest.IN_SEARCH_OF_THE_MYREQUE, new WorldPoint(3502, 3477, 0)),
|
||||
JUNGLE_POTION(Quest.JUNGLE_POTION, new WorldPoint(2809, 3086, 0)),
|
||||
KINGS_RANSOM(Quest.KINGS_RANSOM, new WorldPoint(2741, 3554, 0)),
|
||||
LEGENDS_QUEST(Quest.LEGENDS_QUEST, new WorldPoint(2725, 3367, 0)),
|
||||
LOST_CITY(Quest.LOST_CITY, new WorldPoint(3149, 3205, 0)),
|
||||
THE_LOST_TRIBE(Quest.THE_LOST_TRIBE, new WorldPoint(3211, 3224, 0)),
|
||||
LUNAR_DIPLOMACY(Quest.LUNAR_DIPLOMACY, new WorldPoint(2619, 3689, 0)),
|
||||
MAKING_FRIENDS_WITH_MY_ARM(Quest.MAKING_FRIENDS_WITH_MY_ARM, new WorldPoint(2904, 10092, 0)),
|
||||
MAKING_HISTORY(Quest.MAKING_HISTORY, new WorldPoint(2435, 3346, 0)),
|
||||
MONKS_FRIEND(Quest.MONKS_FRIEND, new WorldPoint(2605, 3209, 0)),
|
||||
MOUNTAIN_DAUGHTER(Quest.MOUNTAIN_DAUGHTER, new WorldPoint(2810, 3672, 0)),
|
||||
MOURNINGS_ENDS_PART_I(Quest.MOURNINGS_ENDS_PART_I, new WorldPoint(2289, 3149, 0)),
|
||||
MOURNINGS_ENDS_PART_II(Quest.MONKEY_MADNESS_II, new WorldPoint(2352, 3172, 0)),
|
||||
MURDER_MYSTERY(Quest.MURDER_MYSTERY, new WorldPoint(2740, 3562, 0)),
|
||||
MY_ARMS_BIG_ADVENTURE(Quest.MY_ARMS_BIG_ADVENTURE, new WorldPoint(2908, 10088, 0)),
|
||||
NATURE_SPIRIT(Quest.NATURE_SPIRIT, new WorldPoint(3440, 9894, 0)),
|
||||
OBSERVATORY_QUEST(Quest.OBSERVATORY_QUEST, new WorldPoint(2438, 3185, 0)),
|
||||
OLAFS_QUEST(Quest.OLAFS_QUEST, new WorldPoint(2723, 3729, 0)),
|
||||
ONE_SMALL_FAVOUR(Quest.ONE_SMALL_FAVOUR, new WorldPoint(2834, 2985, 0)),
|
||||
PLAGUE_CITY(Quest.PLAGUE_CITY, new WorldPoint(2567, 3334, 0)),
|
||||
PRIEST_IN_PERIL(Quest.PRIEST_IN_PERIL, new WorldPoint(3219, 3473, 0)),
|
||||
THE_QUEEN_OF_THIEVES(Quest.THE_QUEEN_OF_THIEVES, new WorldPoint(1795, 3782, 0)),
|
||||
RAG_AND_BONE_MAN(new Quest[]{Quest.RAG_AND_BONE_MAN, Quest.RAG_AND_BONE_MAN_II}, new WorldPoint(3359, 3504, 0)),
|
||||
RECRUITMENT_DRIVE_BLACK_KNIGHTS_FORTRESS(new Quest[]{Quest.BLACK_KNIGHTS_FORTRESS, Quest.RECRUITMENT_DRIVE}, new WorldPoint(2959, 3336, 0)),
|
||||
ROVING_ELVES(Quest.ROVING_ELVES, new WorldPoint(2289, 3146, 0)),
|
||||
RUM_DEAL(Quest.RUM_DEAL, new WorldPoint(3679, 3535, 0)),
|
||||
SCORPION_CATCHER(Quest.SCORPION_CATCHER, new WorldPoint(2701, 3399, 0)),
|
||||
SEA_SLUG(Quest.SEA_SLUG, new WorldPoint(2715, 3302, 0)),
|
||||
SHADES_OF_MORTTON(Quest.SHADES_OF_MORTTON, new WorldPoint(3463, 3308, 0)),
|
||||
SHADOW_OF_THE_STORM(Quest.SHADES_OF_MORTTON, new WorldPoint(3270, 3159, 0)),
|
||||
SHEEP_HERDER(Quest.SHEEP_HERDER, new WorldPoint(2616, 3299, 0)),
|
||||
SHILO_VILLAGE(Quest.SHILO_VILLAGE, new WorldPoint(2882, 2951, 0)),
|
||||
A_SOULS_BANE(Quest.A_SOULS_BANE, new WorldPoint(3307, 3454, 0)),
|
||||
SPIRITS_OF_THE_ELID(Quest.SPIRITS_OF_THE_ELID, new WorldPoint(3441, 2911, 0)),
|
||||
SWAN_SONG(Quest.SWAN_SONG, new WorldPoint(2345, 3652, 0)),
|
||||
TAI_BWO_WANNAI_TRIO(Quest.TAI_BWO_WANNAI_TRIO, new WorldPoint(2779, 3087, 0)),
|
||||
A_TAIL_OF_TWO_CATS(Quest.A_TAIL_OF_TWO_CATS, new WorldPoint(2917, 3557, 0)),
|
||||
TALE_OF_THE_RIGHTEOUS(Quest.TALE_OF_THE_RIGHTEOUS, new WorldPoint(1511, 3631, 0)),
|
||||
A_TASTE_OF_HOPE(Quest.A_TASTE_OF_HOPE, new WorldPoint(3668, 3216, 0)),
|
||||
TEARS_OF_GUTHIX(Quest.TEARS_OF_GUTHIX, new WorldPoint(3251, 9517, 0)),
|
||||
TEMPLE_OF_IKOV(Quest.TEMPLE_OF_IKOV, new WorldPoint(2574, 3320, 0)),
|
||||
THRONE_OF_MISCELLANIA_ROYAL_TROUBLE(new Quest[]{Quest.THRONE_OF_MISCELLANIA, Quest.ROYAL_TROUBLE}, new WorldPoint(2497, 3859, 0)),
|
||||
THE_TOURIST_TRAP(Quest.THE_TOURIST_TRAP, new WorldPoint(3302, 3113, 0)),
|
||||
TOWER_OF_LIFE(Quest.TOWER_OF_LIFE, new WorldPoint(2640, 3218, 0)),
|
||||
TREE_GNOME_VILLAGE(Quest.TREE_GNOME_VILLAGE, new WorldPoint(2541, 3169, 0)),
|
||||
TRIBAL_TOTEM(Quest.TRIBAL_TOTEM, new WorldPoint(2790, 3182, 0)),
|
||||
TROLL_ROMANCE(Quest.TROLL_ROMANCE, new WorldPoint(2890, 10097, 0)),
|
||||
UNDERGROUND_PASS_REGICIDE(new Quest[]{Quest.REGICIDE, Quest.UNDERGROUND_PASS}, new WorldPoint(2575, 3293, 0)),
|
||||
WANTED_SLUG_MENACE(new Quest[]{Quest.WANTED, Quest.THE_SLUG_MENACE}, new WorldPoint(2996, 3373, 0)),
|
||||
WATCHTOWER(Quest.WATCHTOWER, new WorldPoint(2545, 3112, 0)),
|
||||
WATERFALL_QUEST(Quest.WATERFALL_QUEST, new WorldPoint(2521, 3498, 0)),
|
||||
WHAT_LIES_BELOW(Quest.WHAT_LIES_BELOW, new WorldPoint(3265, 3333, 0)),
|
||||
WITCHS_HOUSE(Quest.WITCHS_HOUSE, new WorldPoint(2927, 3456, 0)),
|
||||
ZOGRE_FLESH_EATERS(Quest.ZOGRE_FLESH_EATERS, new WorldPoint(2442, 3051, 0));
|
||||
|
||||
@Getter
|
||||
private final WorldPoint location;
|
||||
|
||||
QuestStartLocation(String description, WorldPoint location)
|
||||
@Getter
|
||||
private final Quest[] quests;
|
||||
|
||||
QuestStartLocation(Quest[] quests, WorldPoint location)
|
||||
{
|
||||
this.tooltip = "Quest Start - " + description;
|
||||
this.location = location;
|
||||
this.quests = quests;
|
||||
}
|
||||
|
||||
QuestStartLocation(Quest quest, WorldPoint location)
|
||||
{
|
||||
this.location = location;
|
||||
this.quests = new Quest[]{quest};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,15 +25,15 @@
|
||||
*/
|
||||
package net.runelite.client.plugins.worldmap;
|
||||
|
||||
import net.runelite.api.coords.WorldPoint;
|
||||
import java.awt.image.BufferedImage;
|
||||
import net.runelite.client.ui.overlay.worldmap.WorldMapPoint;
|
||||
|
||||
class QuestStartPoint extends WorldMapPoint
|
||||
{
|
||||
QuestStartPoint(QuestStartLocation data, BufferedImage icon)
|
||||
QuestStartPoint(WorldPoint location, BufferedImage icon, String tooltip)
|
||||
{
|
||||
super(data.getLocation(), icon);
|
||||
|
||||
setTooltip(data.getTooltip());
|
||||
super(location, icon);
|
||||
setTooltip(tooltip);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,8 +166,8 @@ public interface WorldMapConfig extends Config
|
||||
|
||||
@ConfigItem(
|
||||
keyName = WorldMapPlugin.CONFIG_KEY_QUEST_START_TOOLTIPS,
|
||||
name = "Show quest names",
|
||||
description = "Indicates the names of quests and highlights incomplete ones",
|
||||
name = "Show quest names and status",
|
||||
description = "Indicates the names of quests and shows completion status",
|
||||
position = 13
|
||||
)
|
||||
default boolean questStartTooltips()
|
||||
|
||||
@@ -31,9 +31,15 @@ import java.awt.image.BufferedImage;
|
||||
import java.util.Arrays;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.Experience;
|
||||
import net.runelite.api.GameState;
|
||||
import net.runelite.api.Skill;
|
||||
import net.runelite.api.Quest;
|
||||
import net.runelite.api.QuestState;
|
||||
import net.runelite.api.events.ConfigChanged;
|
||||
import net.runelite.api.events.ExperienceChanged;
|
||||
import net.runelite.api.events.WidgetLoaded;
|
||||
import net.runelite.api.widgets.WidgetID;
|
||||
import net.runelite.client.callback.ClientThread;
|
||||
import net.runelite.client.config.ConfigManager;
|
||||
import net.runelite.client.eventbus.Subscribe;
|
||||
import net.runelite.client.game.AgilityShortcut;
|
||||
@@ -52,6 +58,9 @@ public class WorldMapPlugin extends Plugin
|
||||
static final BufferedImage BLANK_ICON;
|
||||
private static final BufferedImage FAIRY_TRAVEL_ICON;
|
||||
private static final BufferedImage NOPE_ICON;
|
||||
private static final BufferedImage NOT_STARTED_ICON;
|
||||
private static final BufferedImage STARTED_ICON;
|
||||
private static final BufferedImage FINISHED_ICON;
|
||||
|
||||
static final String CONFIG_KEY = "worldmap";
|
||||
static final String CONFIG_KEY_FAIRY_RING_TOOLTIPS = "fairyRingTooltips";
|
||||
@@ -77,6 +86,9 @@ public class WorldMapPlugin extends Plugin
|
||||
//A size of 17 gives us a buffer when triggering tooltips
|
||||
final int iconBufferSize = 17;
|
||||
|
||||
//Quest icons are a bit bigger.
|
||||
final int questIconBufferSize = 22;
|
||||
|
||||
BLANK_ICON = new BufferedImage(iconBufferSize, iconBufferSize, BufferedImage.TYPE_INT_ARGB);
|
||||
|
||||
FAIRY_TRAVEL_ICON = new BufferedImage(iconBufferSize, iconBufferSize, BufferedImage.TYPE_INT_ARGB);
|
||||
@@ -86,11 +98,26 @@ public class WorldMapPlugin extends Plugin
|
||||
NOPE_ICON = new BufferedImage(iconBufferSize, iconBufferSize, BufferedImage.TYPE_INT_ARGB);
|
||||
final BufferedImage nopeImage = ImageUtil.getResourceStreamFromClass(WorldMapPlugin.class, "nope_icon.png");
|
||||
NOPE_ICON.getGraphics().drawImage(nopeImage, 1, 1, null);
|
||||
|
||||
NOT_STARTED_ICON = new BufferedImage(questIconBufferSize, questIconBufferSize, BufferedImage.TYPE_INT_ARGB);
|
||||
final BufferedImage notStartedIcon = ImageUtil.getResourceStreamFromClass(WorldMapPlugin.class, "quest_not_started_icon.png");
|
||||
NOT_STARTED_ICON.getGraphics().drawImage(notStartedIcon, 4, 4, null);
|
||||
|
||||
STARTED_ICON = new BufferedImage(questIconBufferSize, questIconBufferSize, BufferedImage.TYPE_INT_ARGB);
|
||||
final BufferedImage startedIcon = ImageUtil.getResourceStreamFromClass(WorldMapPlugin.class, "quest_started_icon.png");
|
||||
STARTED_ICON.getGraphics().drawImage(startedIcon, 4, 4, null);
|
||||
|
||||
FINISHED_ICON = new BufferedImage(questIconBufferSize, questIconBufferSize, BufferedImage.TYPE_INT_ARGB);
|
||||
final BufferedImage finishedIcon = ImageUtil.getResourceStreamFromClass(WorldMapPlugin.class, "quest_completed_icon.png");
|
||||
FINISHED_ICON.getGraphics().drawImage(finishedIcon, 4, 4, null);
|
||||
}
|
||||
|
||||
@Inject
|
||||
private Client client;
|
||||
|
||||
@Inject
|
||||
private ClientThread clientThread;
|
||||
|
||||
@Inject
|
||||
private WorldMapConfig config;
|
||||
|
||||
@@ -164,6 +191,17 @@ public class WorldMapPlugin extends Plugin
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onWidgetLoaded(WidgetLoaded widgetLoaded)
|
||||
{
|
||||
if (widgetLoaded.getGroupId() == WidgetID.WORLD_MAP_GROUP_ID)
|
||||
{
|
||||
// Quest icons are per-account due to showing quest status,
|
||||
// so we recreate them each time the map is loaded
|
||||
updateQuestStartPointIcons();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateAgilityIcons()
|
||||
{
|
||||
worldMapPointManager.removeIf(AgilityShortcutPoint.class::isInstance);
|
||||
@@ -200,6 +238,7 @@ public class WorldMapPlugin extends Plugin
|
||||
{
|
||||
updateAgilityIcons();
|
||||
updateRareTreeIcons();
|
||||
updateQuestStartPointIcons();
|
||||
|
||||
worldMapPointManager.removeIf(FairyRingPoint.class::isInstance);
|
||||
if (config.fairyRingIcon() || config.fairyRingTooltips())
|
||||
@@ -219,14 +258,6 @@ public class WorldMapPlugin extends Plugin
|
||||
.forEach(worldMapPointManager::add);
|
||||
}
|
||||
|
||||
worldMapPointManager.removeIf(QuestStartPoint.class::isInstance);
|
||||
if (config.questStartTooltips())
|
||||
{
|
||||
Arrays.stream(QuestStartLocation.values())
|
||||
.map(value -> new QuestStartPoint(value, BLANK_ICON))
|
||||
.forEach(worldMapPointManager::add);
|
||||
}
|
||||
|
||||
worldMapPointManager.removeIf(TransportationPoint.class::isInstance);
|
||||
if (config.transportationTeleportTooltips())
|
||||
{
|
||||
@@ -271,4 +302,72 @@ public class WorldMapPlugin extends Plugin
|
||||
}).map(TeleportPoint::new)
|
||||
.forEach(worldMapPointManager::add);
|
||||
}
|
||||
|
||||
private void updateQuestStartPointIcons()
|
||||
{
|
||||
worldMapPointManager.removeIf(QuestStartPoint.class::isInstance);
|
||||
|
||||
if (!config.questStartTooltips())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Must setup the quest icons on the client thread, after the player has logged in.
|
||||
clientThread.invokeLater(() ->
|
||||
{
|
||||
if (client.getGameState() != GameState.LOGGED_IN)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Arrays.stream(QuestStartLocation.values())
|
||||
.map(this::createQuestStartPoint)
|
||||
.forEach(worldMapPointManager::add);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private QuestStartPoint createQuestStartPoint(QuestStartLocation data)
|
||||
{
|
||||
Quest[] quests = data.getQuests();
|
||||
|
||||
// Get first uncompleted quest. Else, return the last quest.
|
||||
Quest quest = null;
|
||||
for (int i = 0; i < quests.length; i++)
|
||||
{
|
||||
if (quests[i].getState(client) != QuestState.FINISHED)
|
||||
{
|
||||
quest = quests[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (quest == null)
|
||||
{
|
||||
quest = quests[quests.length - 1];
|
||||
}
|
||||
|
||||
BufferedImage icon = BLANK_ICON;
|
||||
String tooltip = "";
|
||||
if (quest != null)
|
||||
{
|
||||
tooltip = quest.getName();
|
||||
switch (quest.getState(client))
|
||||
{
|
||||
case FINISHED:
|
||||
icon = FINISHED_ICON;
|
||||
tooltip += " - Finished";
|
||||
break;
|
||||
case IN_PROGRESS:
|
||||
icon = STARTED_ICON;
|
||||
tooltip += " - Started";
|
||||
break;
|
||||
case NOT_STARTED:
|
||||
icon = NOT_STARTED_ICON;
|
||||
tooltip += " - Not Started";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return new QuestStartPoint(data.getLocation(), icon, tooltip);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user