runelite-client: add items kept on death plugin
This enhances the default items kept on death interface to show what you keep, what breaks, and how long you have to return to it once you die. It also adds toggles to see what is lost in certain situations such as skulled, low and high wildy. Co-authored-by: Adam <Adam@sigterm.info> Co-authored-by: Max Weber <mii7303@gmail.com>
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user