diff --git a/runelite-api/src/main/java/net/runelite/api/ScriptID.java b/runelite-api/src/main/java/net/runelite/api/ScriptID.java
index 7f33380f28..56f29fb073 100644
--- a/runelite-api/src/main/java/net/runelite/api/ScriptID.java
+++ b/runelite-api/src/main/java/net/runelite/api/ScriptID.java
@@ -95,6 +95,16 @@ public final class ScriptID
*/
public static final int CHAT_PROMPT_INIT = 223;
+ /**
+ * Displays the game messages when clicking on an item inside the Items Kept on Death interface
+ *
+ * - int (boolean) Item kept on death
+ * - int Item Quantity
+ * - String Item Name
+ *
+ */
+ public static final int DEATH_KEEP_ITEM_EXAMINE = 1603;
+
/**
* Checks the state of the given stash unit.
*
diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java
index 63d2260be8..a91f295588 100644
--- a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java
+++ b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java
@@ -140,6 +140,7 @@ public class WidgetID
public static final int BEGINNER_CLUE_MAP_NORTH_OF_FALADOR = 351;
public static final int BEGINNER_CLUE_MAP_WIZARDS_TOWER = 356;
public static final int SEED_BOX_GROUP_ID = 128;
+ public static final int ITEMS_KEPT_ON_DEATH_GROUP_ID = 4;
static class WorldMap
{
@@ -806,4 +807,16 @@ public class WidgetID
static final int ANSWER3_CONTAINER = 16;
static final int ANSWER3 = 17;
}
+
+ static class KeptOnDeath
+ {
+ static final int KEPT_ITEMS_TEXT = 17;
+ static final int KEPT_ITEMS_CONTAINER = 18;
+ static final int LOST_ITEMS_TEXT = 20;
+ static final int LOST_ITEMS_CONTAINER = 21;
+ static final int LOST_ITEMS_VALUE = 23;
+ static final int INFORMATION_CONTAINER = 29;
+ static final int MAX_ITEMS_KEPT_ON_DEATH = 30;
+ static final int SAFE_ZONE_CONTAINER = 31;
+ }
}
diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java
index 78bb2832b4..6173fd2f83 100644
--- a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java
+++ b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java
@@ -482,7 +482,16 @@ public enum WidgetInfo
QUESTLIST_MEMBERS_CONTAINER(WidgetID.QUESTLIST_GROUP_ID, WidgetID.QuestList.MEMBERS_CONTAINER),
QUESTLIST_MINIQUEST_CONTAINER(WidgetID.QUESTLIST_GROUP_ID, WidgetID.QuestList.MINIQUEST_CONTAINER),
- QUESTTAB_QUEST_TAB(WidgetID.QUESTTAB_GROUP_ID, WidgetID.QuestTab.QUEST_TAB);
+ QUESTTAB_QUEST_TAB(WidgetID.QUESTTAB_GROUP_ID, WidgetID.QuestTab.QUEST_TAB),
+
+ ITEMS_KEPT_ON_DEATH_TEXT(WidgetID.ITEMS_KEPT_ON_DEATH_GROUP_ID, WidgetID.KeptOnDeath.KEPT_ITEMS_TEXT),
+ ITEMS_KEPT_ON_DEATH_CONTAINER(WidgetID.ITEMS_KEPT_ON_DEATH_GROUP_ID, WidgetID.KeptOnDeath.KEPT_ITEMS_CONTAINER),
+ ITEMS_LOST_ON_DEATH_TEXT(WidgetID.ITEMS_KEPT_ON_DEATH_GROUP_ID, WidgetID.KeptOnDeath.LOST_ITEMS_TEXT),
+ ITEMS_LOST_ON_DEATH_CONTAINER(WidgetID.ITEMS_KEPT_ON_DEATH_GROUP_ID, WidgetID.KeptOnDeath.LOST_ITEMS_CONTAINER),
+ ITEMS_KEPT_INFORMATION_CONTAINER(WidgetID.ITEMS_KEPT_ON_DEATH_GROUP_ID, WidgetID.KeptOnDeath.INFORMATION_CONTAINER),
+ ITEMS_KEPT_SAFE_ZONE_CONTAINER(WidgetID.ITEMS_KEPT_ON_DEATH_GROUP_ID, WidgetID.KeptOnDeath.SAFE_ZONE_CONTAINER),
+ ITEMS_LOST_VALUE(WidgetID.ITEMS_KEPT_ON_DEATH_GROUP_ID, WidgetID.KeptOnDeath.LOST_ITEMS_VALUE),
+ ITEMS_KEPT_MAX(WidgetID.ITEMS_KEPT_ON_DEATH_GROUP_ID, WidgetID.KeptOnDeath.MAX_ITEMS_KEPT_ON_DEATH);
private final int groupId;
private final int childId;
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemskeptondeath/AlwaysLostItem.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemskeptondeath/AlwaysLostItem.java
new file mode 100644
index 0000000000..37066622bc
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemskeptondeath/AlwaysLostItem.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018, 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 ID_MAP;
+
+ static
+ {
+ final ImmutableMap.Builder 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);
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemskeptondeath/BrokenOnDeathItem.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemskeptondeath/BrokenOnDeathItem.java
new file mode 100644
index 0000000000..9f1fd5c95e
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemskeptondeath/BrokenOnDeathItem.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2018, 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 ID_SET;
+
+ static
+ {
+ final ImmutableSet.Builder 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);
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemskeptondeath/FixedPriceItem.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemskeptondeath/FixedPriceItem.java
new file mode 100644
index 0000000000..a40851dc65
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemskeptondeath/FixedPriceItem.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2019, Adam
+ * Copyright (c) 2019, 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 FIXED_ITEMS;
+
+ static
+ {
+ final ImmutableMap.Builder 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);
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemskeptondeath/ItemsKeptOnDeathPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemskeptondeath/ItemsKeptOnDeathPlugin.java
new file mode 100644
index 0000000000..dd9a5403e5
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemskeptondeath/ItemsKeptOnDeathPlugin.java
@@ -0,0 +1,610 @@
+/*
+ * Copyright (c) 2018, TheStonedTurtle
+ * Copyright (c) 2019, Adam
+ * 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 = "
";
+ 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 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- 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 keptItems = new ArrayList<>();
+ final List 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 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 UIM which means 0 items are protected by default");
+ }
+ else
+ {
+ sb.append("3 items protected by default");
+
+ if (isSkulled)
+ {
+ sb.append(LINE_BREAK)
+ .append("PK skull -3");
+ }
+
+ if (protectingItem)
+ {
+ sb.append(LINE_BREAK)
+ .append("Protect Item prayer +1");
+ }
+
+ sb.append(LINE_BREAK)
+ .append(String.format("Actually protecting %s 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 white outline 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 keptItems, final List 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("Max items kept on death:
~ %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: %s", c.getName()));
+
+ return itemWidget;
+ }
+}
\ No newline at end of file
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemskeptondeath/Pets.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemskeptondeath/Pets.java
new file mode 100644
index 0000000000..de2b0edcb7
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemskeptondeath/Pets.java
@@ -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 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);
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemskeptondeath/WidgetButton.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemskeptondeath/WidgetButton.java
new file mode 100644
index 0000000000..93cb27e41c
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemskeptondeath/WidgetButton.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2018, 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("" + 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);
+ }
+}
diff --git a/runelite-client/src/main/scripts/DeathkeepBuild.hash b/runelite-client/src/main/scripts/DeathkeepBuild.hash
new file mode 100644
index 0000000000..18f92dce5c
--- /dev/null
+++ b/runelite-client/src/main/scripts/DeathkeepBuild.hash
@@ -0,0 +1 @@
+15F58F5939D9311F3D76FA2F0F3441B7B0DA1E8EAE23C654948095A7D51E07F0
\ No newline at end of file
diff --git a/runelite-client/src/main/scripts/DeathkeepBuild.rs2asm b/runelite-client/src/main/scripts/DeathkeepBuild.rs2asm
new file mode 100644
index 0000000000..75ade43db2
--- /dev/null
+++ b/runelite-client/src/main/scripts/DeathkeepBuild.rs2asm
@@ -0,0 +1,634 @@
+.id 1601
+.int_stack_count 4
+.string_stack_count 2
+.int_var_count 14
+.string_var_count 3
+; callback "itemsKeptOnDeath"
+; Used by the ItemsKepthOnDeath plugin to edit the interface
+; Put a rune pouch in your inventory and it shouldn't have a white outline
+; in the Items kept on death screen
+ sload 1
+ iconst 262167
+ if_settext
+ iconst 0
+ istore 4
+ iconst 0
+ istore 5
+ iconst -1
+ istore 6
+ iconst 0
+ istore 7
+ sconst ""
+ sstore 2
+ iconst 0
+ istore 8
+ iconst 0
+ istore 9
+ iconst 0
+ istore 10
+ iconst 0
+ istore 11
+ iload 1
+ define_array 111
+ iconst 0
+ istore 12
+ iconst 0
+ istore 13
+ iload 0
+ iconst 0
+ if_icmpeq LABEL31
+ jump LABEL525
+LABEL31:
+ iconst 93
+ iconst 13190
+ inv_total
+ iconst 0
+ if_icmpgt LABEL42
+ iconst 93
+ iconst 13192
+ inv_total
+ iconst 0
+ if_icmpgt LABEL42
+ jump LABEL44
+LABEL42:
+ iconst 1
+ istore 9
+LABEL44:
+ iload 10
+ iload 1
+ if_icmplt LABEL48
+ jump LABEL88
+LABEL48:
+ iconst 584
+ iload 11
+ inv_getobj
+ istore 6
+ iload 6
+ iconst -1
+ if_icmpne LABEL56
+ jump LABEL85
+LABEL56:
+ iconst 584
+ iload 11
+ inv_getnum
+ istore 7
+LABEL60:
+ iload 10
+ iload 1
+ if_icmplt LABEL64
+ jump LABEL80
+LABEL64:
+ iload 7
+ iconst 0
+ if_icmpgt LABEL68
+ jump LABEL80
+LABEL68:
+ iload 10
+ iload 6
+ set_array_int
+ iload 7
+ iconst 1
+ sub
+ istore 7
+ iload 10
+ iconst 1
+ add
+ istore 10
+ jump LABEL60
+LABEL80:
+ iload 11
+ iconst 1
+ add
+ istore 11
+ jump LABEL87
+LABEL85:
+ iload 1
+ istore 10
+LABEL87:
+ jump LABEL44
+LABEL88:
+ iload 4
+ iload 1
+ if_icmplt LABEL92
+ jump LABEL147
+LABEL92:
+ iconst 262162
+ iconst 5
+ iload 4
+ cc_create
+ iconst 36
+ iconst 32
+ iconst 0
+ iconst 0
+ cc_setsize
+ iconst 5
+ iload 4
+ iconst 40
+ multiply
+ add
+ iconst 25
+ iconst 0
+ iconst 0
+ cc_setposition
+ iload 4
+ get_array_int
+ istore 6
+ iload 6
+ iconst -1
+ if_icmpne LABEL117
+ jump LABEL144
+LABEL117:
+ iload 6
+ iconst 1
+ cc_setobject
+ sconst ""
+ iload 6
+ oc_name
+ join_string 2
+ cc_setopbase
+ iconst 1
+ sconst "Item:"
+ cc_setop
+ iconst 1603
+ iconst 1
+ iconst 1
+ iload 6
+ oc_name
+ sconst "1is"
+ cc_setonop
+ iconst 1118481
+ cc_setgraphicshadow
+ iconst 1
+ cc_setoutline
+ iload 4
+ iconst 1
+ add
+ istore 4
+ jump LABEL146
+LABEL144:
+ iload 1
+ istore 4
+LABEL146:
+ jump LABEL88
+LABEL147:
+ iconst 0
+ istore 4
+LABEL149:
+ iload 4
+ iconst 468
+ inv_size
+ if_icmplt LABEL154
+ jump LABEL350
+LABEL154:
+ iconst 468
+ iload 4
+ inv_getobj
+ istore 6
+ iload 6
+ iconst -1
+ if_icmpne LABEL162
+ jump LABEL345
+LABEL162:
+ iconst 262165
+ iconst 5
+ iload 5
+ cc_create
+ iconst 36
+ iconst 32
+ iconst 0
+ iconst 0
+ cc_setsize
+ iconst 5
+ iload 5
+ iconst 8
+ mod
+ iconst 38
+ multiply
+ add
+ iconst 25
+ iconst 38
+ iload 5
+ iconst 8
+ div
+ multiply
+ add
+ iconst 0
+ iconst 0
+ cc_setposition
+ iload 6
+ iconst 468
+ iload 4
+ inv_getnum
+ cc_setobject
+ sconst ""
+ iload 6
+ oc_name
+ join_string 2
+ cc_setopbase
+ iconst 1
+ sconst "Item:"
+ cc_setop
+ iconst 1603
+ iconst 0
+ iconst 468
+ iload 4
+ inv_getnum
+ iload 6
+ oc_name
+ sconst "1is"
+ cc_setonop
+ iconst 1118481
+ cc_setgraphicshadow
+ iconst 111
+ iconst 49
+ iconst 879
+ iload 6
+ oc_uncert
+ enum
+ iconst 1
+ if_icmpeq LABEL221
+ jump LABEL226
+LABEL221:
+ iconst 2
+ cc_setoutline
+ iconst 1
+ istore 8
+ jump LABEL228
+LABEL226:
+ iconst 1
+ cc_setoutline
+LABEL228:
+ iload 5
+ iconst 1
+ add
+ istore 5
+ iload 6
+ oc_stackable
+ iconst 1
+ if_icmpeq LABEL237
+ jump LABEL345
+LABEL237:
+ iconst 0
+ istore 10
+ iconst 0
+ istore 13
+LABEL241:
+ iload 10
+ iload 1
+ if_icmplt LABEL245
+ jump LABEL259
+LABEL245:
+ iload 10
+ get_array_int
+ iload 6
+ if_icmpeq LABEL250
+ jump LABEL254
+LABEL250:
+ iload 13
+ iconst 1
+ add
+ istore 13
+LABEL254:
+ iload 10
+ iconst 1
+ add
+ istore 10
+ jump LABEL241
+LABEL259:
+ iconst 2147483647
+ iconst 94
+ iload 6
+ inv_total
+ sub
+ iconst 93
+ iload 6
+ inv_total
+ sub
+ iload 13
+ add
+ istore 12
+ iconst 0
+ iload 12
+ sub
+ istore 12
+ iload 12
+ iconst 0
+ if_icmpgt LABEL279
+ jump LABEL345
+LABEL279:
+ iconst 262165
+ iconst 5
+ iload 5
+ cc_create
+ iconst 36
+ iconst 32
+ iconst 0
+ iconst 0
+ cc_setsize
+ iconst 5
+ iload 5
+ iconst 8
+ mod
+ iconst 38
+ multiply
+ add
+ iconst 25
+ iconst 38
+ iload 5
+ iconst 8
+ div
+ multiply
+ add
+ iconst 0
+ iconst 0
+ cc_setposition
+ iload 6
+ iload 12
+ cc_setobject
+ sconst ""
+ iload 6
+ oc_name
+ join_string 2
+ cc_setopbase
+ iconst 1
+ sconst "Item:"
+ cc_setop
+ iconst 1603
+ iconst 0
+ iload 12
+ iload 6
+ oc_name
+ sconst "1is"
+ cc_setonop
+ iconst 1118481
+ cc_setgraphicshadow
+ iconst 111
+ iconst 49
+ iconst 879
+ iload 6
+ oc_uncert
+ enum
+ iconst 1
+ if_icmpeq LABEL334
+ jump LABEL339
+LABEL334:
+ iconst 2
+ cc_setoutline
+ iconst 1
+ istore 8
+ jump LABEL341
+LABEL339:
+ iconst 1
+ cc_setoutline
+LABEL341:
+ iload 5
+ iconst 1
+ add
+ istore 5
+LABEL345:
+ iload 4
+ iconst 1
+ add
+ istore 4
+ jump LABEL149
+LABEL350:
+ sconst "The normal amount of items kept is "
+ sconst "three"
+ sconst "."
+ sconst "
"
+ sconst "
"
+ join_string 5
+ sstore 2
+ iload 3
+ iconst 1
+ if_icmpeq LABEL361
+ jump LABEL371
+LABEL361:
+ sload 2
+ sconst "You're an "
+ sconst ""
+ sconst "Ultimate Iron Man"
+ sconst ""
+ sconst ", so you will always keep zero items."
+ join_string 5
+ append
+ sstore 2
+ jump LABEL434
+LABEL371:
+ iload 1
+ iconst 0
+ if_icmpeq LABEL375
+ jump LABEL387
+LABEL375:
+ sload 2
+ sconst "You're marked with a "
+ sconst ""
+ sconst "PK skull"
+ sconst ""
+ sconst ". This reduces the items you keep from "
+ sconst "three"
+ sconst " to zero!"
+ join_string 7
+ append
+ sstore 2
+ jump LABEL434
+LABEL387:
+ iload 1
+ iconst 1
+ if_icmpeq LABEL391
+ jump LABEL410
+LABEL391:
+ sload 2
+ sconst "You're marked with a "
+ sconst ""
+ sconst "PK skull"
+ sconst ""
+ sconst ". This reduces the items you keep from "
+ sconst "three"
+ sconst " to zero!"
+ sconst "
"
+ sconst "
"
+ sconst "However, you also have the "
+ sconst ""
+ sconst "Protect Items"
+ sconst ""
+ sconst " prayer active, which saves you one extra item!"
+ join_string 14
+ append
+ sstore 2
+ jump LABEL434
+LABEL410:
+ iload 1
+ iconst 3
+ if_icmpeq LABEL414
+ jump LABEL419
+LABEL414:
+ sload 2
+ sconst "You have no factors affecting the items you keep."
+ append
+ sstore 2
+ jump LABEL434
+LABEL419:
+ iload 1
+ iconst 3
+ iconst 1
+ add
+ if_icmpeq LABEL425
+ jump LABEL434
+LABEL425:
+ sload 2
+ sconst "You have the "
+ sconst ""
+ sconst "Protect Items"
+ sconst ""
+ sconst " prayer active, which saves you one extra item!"
+ join_string 5
+ append
+ sstore 2
+LABEL434:
+ iload 8
+ iconst 1
+ if_icmpeq LABEL441
+ iload 9
+ iconst 1
+ if_icmpeq LABEL441
+ jump LABEL492
+LABEL441:
+ iload 8
+ iconst 1
+ if_icmpeq LABEL445
+ jump LABEL466
+LABEL445:
+ iload 9
+ iconst 1
+ if_icmpeq LABEL449
+ jump LABEL466
+LABEL449:
+ sload 2
+ sconst "
"
+ sconst "
"
+ sconst "Items with a "
+ sconst ""
+ sconst "white outline"
+ sconst ""
+ sconst " will always be lost."
+ sconst "
"
+ sconst ""
+ sconst "Bonds"
+ sconst ""
+ sconst " are always protected."
+ join_string 12
+ append
+ sstore 2
+ jump LABEL492
+LABEL466:
+ iload 8
+ iconst 1
+ if_icmpeq LABEL470
+ jump LABEL482
+LABEL470:
+ sload 2
+ sconst "
"
+ sconst "
"
+ sconst "Items with a "
+ sconst ""
+ sconst "white outline"
+ sconst ""
+ sconst " will always be lost."
+ join_string 7
+ append
+ sstore 2
+ jump LABEL492
+LABEL482:
+ sload 2
+ sconst "
"
+ sconst "
"
+ sconst ""
+ sconst "Bonds"
+ sconst ""
+ sconst " are always protected, so are not shown here."
+ join_string 6
+ append
+ sstore 2
+LABEL492:
+ sload 2
+ iconst 262173
+ if_settext
+ sconst ""
+ sconst "Max items kept on death :"
+ sconst "
"
+ sconst "
"
+ sconst ""
+ sconst "~ "
+ iload 1
+ tostring
+ sconst " ~"
+ join_string 8
+ iconst 262174
+ if_settext
+ iload 2
+ iconst 0
+ if_icmpgt LABEL511
+ jump LABEL518
+LABEL511:
+ sconst "Items you will keep on death:"
+ iconst 262161
+ if_settext
+ sconst "Items you will lose on death:"
+ iconst 262164
+ if_settext
+ jump LABEL524
+LABEL518:
+ sconst "Items you will keep on death if not skulled:"
+ iconst 262161
+ if_settext
+ sconst "Items you will lose on death if not skulled:"
+ iconst 262164
+ if_settext
+LABEL524:
+ jump LABEL565
+LABEL525:
+ iconst 1
+ iconst 262165
+ if_sethide
+ iconst 1
+ iconst 262162
+ if_sethide
+ iconst 0
+ iconst 262175
+ if_sethide
+ sload 0
+ iconst 262176
+ if_settext
+ sconst "The normal amount of items kept is "
+ sconst "three"
+ sconst "."
+ sconst "
"
+ sconst "
"
+ join_string 5
+ sstore 2
+ sload 2
+ sconst "You're in a "
+ sconst ""
+ sconst "safe area"
+ sconst ""
+ sconst ". See information to the left for a more detailed description."
+ join_string 5
+ append
+ sstore 2
+ sload 2
+ iconst 262173
+ if_settext
+ sconst ""
+ sconst "Max items kept on death :"
+ sconst "
"
+ sconst "
"
+ sconst ""
+ sconst "All items!"
+ join_string 6
+ iconst 262174
+ if_settext
+LABEL565:
+ sconst "itemsKeptOnDeath" ; push event name
+ runelite_callback ; invoke callback
+ return