Kept on death plugin (#59)

* Add Kept on Death Plugin

Modifies the Items Kept on Death widget to be more accurate

* Fix WidgetType import

* Account for stackable kept items

* Remove WidgetButtonRunnable

* Ignore DMM worlds

* Add open looting bag to always lost

* Update script to the new OpCodes

* Add plugin type
This commit is contained in:
sdburns1998
2019-04-23 10:53:25 +02:00
committed by Kyleeld
parent 0c35d18711
commit 729001291b
12 changed files with 1724 additions and 1 deletions

View File

@@ -491,6 +491,12 @@ public interface Client extends GameEngine
*/
int[] getWidgetPositionsY();
/**
* Creates a new widget element
* @return
*/
Widget createWidget();
/**
* Gets the current run energy of the logged in player.
*

View File

@@ -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
* <ul>
* <li> int (boolean) Item kept on death </li>
* <li> int Item Quantity </li>
* <li> String Item Name </li>
* </ul>
*/
public static final int KEPT_LOST_ITEM_EXAMINE = 1603;
/**
* Queries the completion state of a quest by its struct id
* <ul>

View File

@@ -821,4 +821,24 @@ public interface Widget
* Can widgets under this widgets be scrolled in this widgets bounding box
*/
void setNoScrollThrough(boolean noScrollThrough);
/**
* Changes the parent ID for the widget
*/
void setParentId(int id);
/**
* Changes the ID of the widget
*/
void setId(int id);
/**
* Sets the index of this element
*/
void setIndex(int index);
/**
* Seems like this needs to set to true when creating new widgets
*/
void setIsIf3(boolean isIf3);
}

View File

@@ -134,6 +134,7 @@ public class WidgetID
public static final int MUSIC_GROUP_ID = 239;
public static final int MUSICTAB_GROUP_ID = 239;
public static final int BARROWS_PUZZLE_GROUP_ID = 25;
public static final int ITEMS_KEPT_ON_DEATH_GROUP_ID = 4;
static class WorldMap
{
@@ -382,6 +383,7 @@ public class WidgetID
static class ResizableViewport
{
static final int ITEMS_KEPT_ON_DEATH = 13;
static final int CLAN_CHAT_TAB = 35;
static final int FRIENDS_TAB = 37;
static final int IGNORES_TAB = 36;
@@ -987,4 +989,16 @@ static final int WIND_STRIKE = 5;
static final int ANSWER3_CONTAINER = 16;
static final int ANSWER3 = 17;
}
static class KeptOnDeath
{
static final int KEPT_ITEMS_CONTAINER = 18;
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;
static final int CUSTOM_TEXT_CONTAINER = 33;
}
}

View File

@@ -251,6 +251,7 @@ public enum WidgetInfo
RESIZABLE_VIEWPORT_OPTIONS_ICON(WidgetID.RESIZABLE_VIEWPORT_OLD_SCHOOL_BOX_GROUP_ID, WidgetID.ResizableViewport.OPTIONS_ICON),
RESIZABLE_VIEWPORT_EMOTES_ICON(WidgetID.RESIZABLE_VIEWPORT_OLD_SCHOOL_BOX_GROUP_ID, WidgetID.ResizableViewport.EMOTES_ICON),
RESIZABLE_VIEWPORT_MUSIC_ICON(WidgetID.RESIZABLE_VIEWPORT_OLD_SCHOOL_BOX_GROUP_ID, WidgetID.ResizableViewport.MUSIC_ICON),
RESIZABLE_VIEWPORT_KEPT_ON_DEATH(WidgetID.RESIZABLE_VIEWPORT_OLD_SCHOOL_BOX_GROUP_ID, WidgetID.ResizableViewport.ITEMS_KEPT_ON_DEATH),
RESIZABLE_VIEWPORT_BOTTOM_LINE(WidgetID.RESIZABLE_VIEWPORT_BOTTOM_LINE_GROUP_ID, WidgetID.Viewport.RESIZABLE_VIEWPORT_BOTTOM_LINE),
RESIZABLE_VIEWPORT_BOTTOM_LINE_LOGOUT_BUTTON(WidgetID.RESIZABLE_VIEWPORT_BOTTOM_LINE_GROUP_ID, WidgetID.ResizableViewportBottomLine.LOGOUT_BUTTON_OVERLAY),
@@ -562,7 +563,15 @@ public enum WidgetInfo
EQUIPMENT_MELEE_STRENGTH(WidgetID.EQUIPMENT_PAGE_GROUP_ID, WidgetID.EquipmentWidgetIdentifiers.MELEE_STRENGTH),
EQUIPMENT_RANGED_STRENGTH(WidgetID.EQUIPMENT_PAGE_GROUP_ID, WidgetID.EquipmentWidgetIdentifiers.RANGED_STRENGTH),
EQUIPMENT_MAGIC_DAMAGE(WidgetID.EQUIPMENT_PAGE_GROUP_ID, WidgetID.EquipmentWidgetIdentifiers.MAGIC_DAMAGE),
EQUIP_YOUR_CHARACTER(WidgetID.EQUIPMENT_PAGE_GROUP_ID, WidgetID.EquipmentWidgetIdentifiers.EQUIP_YOUR_CHARACTER);
EQUIP_YOUR_CHARACTER(WidgetID.EQUIPMENT_PAGE_GROUP_ID, WidgetID.EquipmentWidgetIdentifiers.EQUIP_YOUR_CHARACTER),
ITEMS_KEPT_ON_DEATH_CONTAINER(WidgetID.ITEMS_KEPT_ON_DEATH_GROUP_ID, WidgetID.KeptOnDeath.KEPT_ITEMS_CONTAINER),
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_KEPT_CUSTOM_TEXT_CONTAINER(WidgetID.ITEMS_KEPT_ON_DEATH_GROUP_ID, WidgetID.KeptOnDeath.CUSTOM_TEXT_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;

View File

@@ -0,0 +1,87 @@
/*
* 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.keptondeath;
import java.util.HashSet;
import static net.runelite.api.ItemID.*;
/**
* Certain items aren't tradeable via the GE but can be traded between players.
* The {@link net.runelite.api.ItemComposition}'s `isTradeable` value is based on GE trade-ability so we need
* to account for these items. These items should only be kept if protected based on item value.
*/
public enum ActuallyTradeableItem
{
// Item Packs
RUNE_PACKS(AIR_RUNE_PACK, WATER_RUNE_PACK, EARTH_RUNE_PACK, FIRE_RUNE_PACK, CHAOS_RUNE_PACK, MIND_RUNE_PACK),
TZHAAR_PACKS(TZHAAR_AIR_RUNE_PACK, TZHAAR_WATER_RUNE_PACK, TZHAAR_EARTH_RUNE_PACK, TZHAAR_FIRE_RUNE_PACK),
OTHER_PACKS(BASKET_PACK, FEATHER_PACK, PLANT_POT_PACK, SACK_PACK, UNFINISHED_BROAD_BOLT_PACK),
// Equipment
BLACK_MASK(BLACK_MASK_1, BLACK_MASK_2, BLACK_MASK_3, BLACK_MASK_4, BLACK_MASK_5, BLACK_MASK_6, BLACK_MASK_7, BLACK_MASK_8, BLACK_MASK_9),
SATCHELS(BLACK_SATCHEL, GOLD_SATCHEL, GREEN_SATCHEL, PLAIN_SATCHEL, RED_SATCHEL, RUNE_SATCHEL),
FIRE_ARROWS(BRONZE_FIRE_ARROWS, IRON_FIRE_ARROWS, STEEL_FIRE_ARROWS, MITHRIL_FIRE_ARROWS, ADAMANT_FIRE_ARROWS, RUNE_FIRE_ARROWS, AMETHYST_FIRE_ARROWS, DRAGON_FIRE_ARROWS),
FIRE_ARROWS_2(BRONZE_FIRE_ARROWS_942, IRON_FIRE_ARROWS_2533, STEEL_FIRE_ARROWS_2535, MITHRIL_FIRE_ARROWS_2537, ADAMANT_FIRE_ARROWS_2539, RUNE_FIRE_ARROWS_2541, AMETHYST_FIRE_ARROWS_21330, DRAGON_FIRE_ARROWS_11222),
// Food Items
HALF_A(HALF_A_GARDEN_PIE, HALF_A_MEAT_PIE, HALF_A_MUSHROOM_PIE, HALF_A_REDBERRY_PIE, HALF_A_BOTANICAL_PIE, HALF_A_FISH_PIE, HALF_A_SUMMER_PIE, HALF_A_WILD_PIE, HALF_AN_ADMIRAL_PIE, HALF_AN_APPLE_PIE),
PIZZA(_12_ANCHOVY_PIZZA, _12_MEAT_PIZZA, _12_PINEAPPLE_PIZZA, _12_PLAIN_PIZZA),
CAKES(CAKE, _23_CAKE, SLICE_OF_CAKE, CHOCOLATE_CAKE, _23_CHOCOLATE_CAKE, CHOCOLATE_SLICE),
BASKETS(APPLES1, APPLES2, APPLES3, APPLES4, BANANAS1, BANANAS2, BANANAS3, BANANAS4, ORANGES1, ORANGES2, ORANGES3, ORANGES4, STRAWBERRIES1, STRAWBERRIES2, STRAWBERRIES3, STRAWBERRIES4, TOMATOES1, TOMATOES2, TOMATOES3, TOMATOES4),
// Charged Jewelery
BURNING_AMULET(BURNING_AMULET1, BURNING_AMULET2, BURNING_AMULET3, BURNING_AMULET4),
NECKLACE_OF_PASSAGE(NECKLACE_OF_PASSAGE1, NECKLACE_OF_PASSAGE2, NECKLACE_OF_PASSAGE3, NECKLACE_OF_PASSAGE4),
RING_OF_DUELING(RING_OF_DUELING1, RING_OF_DUELING2, RING_OF_DUELING3, RING_OF_DUELING4, RING_OF_DUELING5, RING_OF_DUELING6, RING_OF_DUELING7),
GAMES_NECKLACE(GAMES_NECKLACE1, GAMES_NECKLACE2, GAMES_NECKLACE3, GAMES_NECKLACE4, GAMES_NECKLACE5, GAMES_NECKLACE6, GAMES_NECKLACE7),
COMBAT_BRACELET(COMBAT_BRACELET1, COMBAT_BRACELET2, COMBAT_BRACELET3, COMBAT_BRACELET5),
RING_OF_WEALTH(RING_OF_WEALTH_I, RING_OF_WEALTH_1, RING_OF_WEALTH_I1, RING_OF_WEALTH_2, RING_OF_WEALTH_I2, RING_OF_WEALTH_3, RING_OF_WEALTH_I3, RING_OF_WEALTH_4, RING_OF_WEALTH_I4, RING_OF_WEALTH_I5),
AMULET_OF_GLORY(AMULET_OF_GLORY1, AMULET_OF_GLORY2, AMULET_OF_GLORY3, AMULET_OF_GLORY5),
AMULET_OF_GLORY_T(AMULET_OF_GLORY_T1, AMULET_OF_GLORY_T2, AMULET_OF_GLORY_T3, AMULET_OF_GLORY_T5),
SKILLS_NECKLACE(SKILLS_NECKLACE1, SKILLS_NECKLACE2, SKILLS_NECKLACE3, SKILLS_NECKLACE5),
;
private final int[] ids;
private static final HashSet<Integer> ID_SET;
static
{
ID_SET = new HashSet<>();
for (ActuallyTradeableItem p : values())
{
for (int id : p.ids)
{
ID_SET.add(id);
}
}
}
ActuallyTradeableItem(int... ids)
{
this.ids = ids;
}
public static Boolean check(int id)
{
return ID_SET.contains(id);
}
}

View File

@@ -0,0 +1,69 @@
/*
* 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.keptondeath;
import com.google.common.collect.ImmutableMap;
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.
*/
public enum AlwaysLostItem
{
RUNE_POUCH(ItemID.RUNE_POUCH, true),
LOOTING_BAG(ItemID.LOOTING_BAG, false),
LOOTING_BAG_22586(ItemID.LOOTING_BAG_22586, false),
CLUE_BOX(ItemID.CLUE_BOX, false);
private final int itemID;
@Getter
private final boolean kept;
private static final ImmutableMap<Integer, AlwaysLostItem> ID_MAP;
static
{
ImmutableMap.Builder<Integer, AlwaysLostItem> map = ImmutableMap.builder();
for (AlwaysLostItem p : values())
{
map.put(p.itemID, p);
}
ID_MAP = map.build();
}
AlwaysLostItem(int itemID, boolean kept)
{
this.itemID = itemID;
this.kept = kept;
}
public static AlwaysLostItem getByItemID(int itemID)
{
return ID_MAP.get(itemID);
}
}

View File

@@ -0,0 +1,112 @@
/*
* 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.keptondeath;
import java.util.HashSet;
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.
*/
public 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 HashSet<Integer> ID_SET;
static
{
ID_SET = new HashSet<>();
for (BrokenOnDeathItem p : values())
{
ID_SET.add(p.itemID);
}
}
BrokenOnDeathItem(int itemID)
{
this.itemID = itemID;
}
public static boolean check(int itemID)
{
return ID_SET.contains(itemID);
}
}

View File

@@ -0,0 +1,598 @@
/*
* 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.keptondeath;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.LinkedHashMap;
import java.util.List;
import javax.inject.Inject;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
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.game.ItemVariationMapping;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.plugins.PluginType;
@PluginDescriptor(
name = "Kept on Death",
description = "Reworks the Items Kept on Death interface to be more accurate",
enabledByDefault = false,
type = PluginType.UTILITY
)
@Slf4j
public class KeptOnDeathPlugin extends Plugin
{
// Handles Clicking on items in Kept on Death Interface
private static final int SCRIPT_ID = ScriptID.KEPT_LOST_ITEM_EXAMINE;
private static final double HIGH_ALCH = 0.6;
// Item Container helpers
private static final int MAX_ROW_ITEMS = 8;
private static final int STARTING_X = 5;
private static final int STARTING_Y = 25;
private static final int X_INCREMENT = 40;
private static final int Y_INCREMENT = 38;
private static final int ORIGINAL_WIDTH = 36;
private static final int ORIGINAL_HEIGHT = 32;
private static final int ORIGINAL_LOST_HEIGHT = 209;
private static final int ORIGINAL_LOST_Y = 107;
// Information panel text helpers
private static final DecimalFormat NUMBER_FORMAT = new DecimalFormat("#,###");
private static final String MAX_KEPT_ITEMS_FORMAT = "<col=ffcc33>Max items kept on death :<br><br><col=ffcc33>~ %s ~";
private static final String ACTION_TEXT = "Item: <col=ff981f>%s";
private static final String DEFAULT = "<col=FFFFFF>3<col=FF981F> items protected by default";
private static final String IS_SKULLED = "<col=ff3333>PK skull<col=ff981f> -3";
private static final String PROTECTING_ITEM = "<col=ff3333>Protect Item prayer<col=ff981f> +1";
private static final String ACTUAL = "Actually protecting <col=FFFFFF>%s<col=FF981F> items";
private static final String WHITE_OUTLINE = "Items with a <col=ffffff>white outline<col=ff981f> will always be lost.";
private static final String CHANGED_MECHANICS = "Untradeable items are kept on death in non-pvp scenarios.";
private static final String NON_PVP = "You will have 1 hour to retrieve your lost items.";
private static final String LINE_BREAK = "<br>";
private static final String UIM_DEFAULT = "You are an <col=FFFFFF>UIM<col=FF981F> which means <col=FFFFFF>0<col=FF981F> items are protected by default";
private static final int ORIGINAL_INFO_HEIGHT = 183;
private static final int FONT_COLOR = 0xFF981F;
// Button Names and Images
private static final String PROTECT_ITEM_BUTTON_NAME = "Protect Item Prayer";
private static final String SKULLED_BUTTON_NAME = "Skulled";
private static final String LOW_WILDY_BUTTON_NAME = "Low Wildy (1-20)";
private static final String DEEP_WILDY_BUTTON_NAME = "Deep Wildy (21+)";
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;
@Getter
private boolean widgetVisible = false;
private LinkedHashMap<String, WidgetButton> buttonMap = new LinkedHashMap<>();
private boolean isSkulled = false;
private boolean protectingItem = false;
private boolean hasAlwaysLost = false;
private int wildyLevel = -1;
@Subscribe
protected void onScriptCallbackEvent(ScriptCallbackEvent event)
{
if (event.getEventName().equals("deathKeepBuild"))
{
// 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) & playing DMM see the default interface
if (isInSafeArea() || client.getWorldType().contains(WorldType.DEADMAN))
{
return;
}
syncSettings();
createWidgetButtons();
recreateItemsKeptOnDeathWidget();
}
}
// Sync user settings
private void syncSettings()
{
SkullIcon s = client.getLocalPlayer().getSkullIcon();
// Ultimate iron men deaths are treated like they are always skulled
isSkulled = (s != null && s.equals(SkullIcon.SKULL)) || isUltimateIronman();
protectingItem = client.getVar(Varbits.PRAYER_PROTECT_ITEM) == 1;
syncCurrentWildyLevel();
}
private void syncCurrentWildyLevel()
{
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;
}
int y = client.getLocalPlayer().getWorldLocation().getY();
// Credits to atomicint_#5069 (Discord)
int underLevel = ((y - 9920) / 8) + 1;
int upperLevel = ((y - 3520) / 8) + 1;
wildyLevel = (y > 6400 ? underLevel : upperLevel);
}
private boolean isInPvpWorld()
{
EnumSet<WorldType> world = client.getWorldType();
return world.contains(WorldType.PVP) || world.contains(WorldType.PVP_HIGH_RISK);
}
private boolean isInPvPSafeZone()
{
Widget w = client.getWidget(WidgetInfo.PVP_WORLD_SAFE_ZONE);
return w != null && !w.isHidden();
}
private boolean isInSafeArea()
{
Widget w = client.getWidget(WidgetInfo.ITEMS_KEPT_SAFE_ZONE_CONTAINER);
return w != null && !w.isHidden();
}
private boolean isUltimateIronman()
{
return client.getAccountType().equals(AccountType.ULTIMATE_IRONMAN);
}
private int getDefaultItemsKept()
{
int count = isSkulled ? 0 : 3;
if (protectingItem)
{
count++;
}
return count;
}
private void recreateItemsKeptOnDeathWidget()
{
// Text flags based on items should be reset everytime the widget is recreated
hasAlwaysLost = false;
Widget lost = client.getWidget(WidgetInfo.ITEMS_LOST_ON_DEATH_CONTAINER);
Widget kept = client.getWidget(WidgetInfo.ITEMS_KEPT_ON_DEATH_CONTAINER);
if (lost != null && kept != null)
{
// Grab all items on player and sort by price.
List<Item> items = new ArrayList<>();
ItemContainer inventory = client.getItemContainer(InventoryID.INVENTORY);
Item[] inv = inventory == null ? new Item[0] : inventory.getItems();
ItemContainer equipment = client.getItemContainer(InventoryID.EQUIPMENT);
Item[] equip = equipment == null ? new Item[0] : equipment.getItems();
Collections.addAll(items, inv);
Collections.addAll(items, equip);
// Sort by item price
items.sort((o1, o2) ->
{
int o1ID = ItemVariationMapping.map(itemManager.canonicalize(o1.getId()));
int o2ID = ItemVariationMapping.map(itemManager.canonicalize(o2.getId()));
ItemComposition c1 = itemManager.getItemComposition(o1ID);
ItemComposition c2 = itemManager.getItemComposition(o2ID);
int exchangePrice1 = c1.isTradeable() ? itemManager.getItemPrice(c1.getId()) : c1.getPrice();
int exchangePrice2 = c2.isTradeable() ? itemManager.getItemPrice(c2.getId()) : c2.getPrice();
return exchangePrice2 - exchangePrice1;
});
int keepCount = getDefaultItemsKept();
List<Widget> keptItems = new ArrayList<>();
List<Widget> lostItems = new ArrayList<>();
for (Item i : items)
{
int id = i.getId();
if (id == -1)
{
continue;
}
ItemComposition c = itemManager.getItemComposition(i.getId());
Widget itemWidget = createItemWidget(i.getQuantity(), c);
// Bonds are always kept and do not count towards the limit.
if (id == ItemID.OLD_SCHOOL_BOND || id == ItemID.OLD_SCHOOL_BOND_UNTRADEABLE)
{
keptItems.add(itemWidget);
continue;
}
// Certain items are always lost on death and have a white outline which we need to readd
AlwaysLostItem item = AlwaysLostItem.getByItemID(i.getId());
if (item != null)
{
// Some of these items are kept on death (outside wildy), like the Rune pouch. Ignore them
if (!item.isKept() || wildyLevel > 0)
{
itemWidget.setOnOpListener(SCRIPT_ID, 0, i.getQuantity(), c.getName());
itemWidget.setBorderType(2);
lostItems.add(itemWidget);
hasAlwaysLost = true;
continue;
}
}
// Keep most valuable items regardless of trade-ability.
if (keepCount > 0)
{
if (i.getQuantity() > keepCount)
{
keptItems.add(createItemWidget(keepCount, c));
itemWidget.setItemQuantity(i.getQuantity() - keepCount);
keepCount = 0;
}
else
{
keptItems.add(itemWidget);
keepCount -= i.getQuantity();
continue;
}
}
if (!checkTradeable(i.getId(), c) && wildyLevel < 21)
{
// Certain items are turned into broken variants inside the wilderness.
if (BrokenOnDeathItem.check(i.getId()))
{
keptItems.add(itemWidget);
continue;
}
// Ignore all non tradeables in wildy except for the above case(s).
if (wildyLevel > 0)
{
lostItems.add(itemWidget);
continue;
}
keptItems.add(itemWidget);
}
else
{
itemWidget.setOnOpListener(SCRIPT_ID, 0, i.getQuantity(), c.getName());
lostItems.add(itemWidget);
}
}
int rows = keptItems.size() > MAX_ROW_ITEMS ? keptItems.size() / MAX_ROW_ITEMS : 0;
// Adjust items lost container position if new rows were added to kept items container
lost.setOriginalY(ORIGINAL_LOST_Y + (rows * Y_INCREMENT));
lost.setOriginalHeight(ORIGINAL_LOST_HEIGHT - (rows * Y_INCREMENT));
setWidgetChildren(kept, keptItems);
setWidgetChildren(lost, lostItems);
updateKeptWidgetInfoText();
}
}
/**
* Wrapper for widget.setChildren() but updates the child index and original positions
* Used for Items Kept and Lost containers
*
* @param parent Widget to override children
* @param widgets Children to set on parent
*/
private void setWidgetChildren(Widget parent, List<Widget> widgets)
{
Widget[] children = parent.getChildren();
if (children == null)
{
// Create a child so we can copy the returned Widget[] and avoid hn casting issues from creating a new Widget[]
parent.createChild(0, WidgetType.GRAPHIC);
children = parent.getChildren();
}
Widget[] itemsArray = Arrays.copyOf(children, widgets.size());
int parentId = parent.getId();
int startingIndex = 0;
for (Widget w : widgets)
{
int originalX = STARTING_X + ((startingIndex % MAX_ROW_ITEMS) * X_INCREMENT);
int originalY = STARTING_Y + ((startingIndex / MAX_ROW_ITEMS) * Y_INCREMENT);
w.setParentId(parentId);
w.setId(parentId);
w.setIndex(startingIndex);
w.setOriginalX(originalX);
w.setOriginalY(originalY);
w.revalidate();
itemsArray[startingIndex] = w;
startingIndex++;
}
parent.setChildren(itemsArray);
parent.revalidate();
}
/**
* Creates the text to be displayed in the right side of the interface based on current selections
*/
private String getUpdatedInfoText()
{
String textToAdd = DEFAULT;
if (isUltimateIronman())
{
textToAdd = UIM_DEFAULT;
}
else
{
if (isSkulled)
{
textToAdd += LINE_BREAK + IS_SKULLED;
}
if (protectingItem)
{
textToAdd += LINE_BREAK + PROTECTING_ITEM;
}
textToAdd += LINE_BREAK + String.format(ACTUAL, getDefaultItemsKept());
}
if (wildyLevel < 1)
{
textToAdd += LINE_BREAK + LINE_BREAK + NON_PVP;
}
if (hasAlwaysLost)
{
textToAdd += LINE_BREAK + LINE_BREAK + WHITE_OUTLINE;
}
textToAdd += LINE_BREAK + LINE_BREAK + CHANGED_MECHANICS;
return textToAdd;
}
/**
* Corrects the Information panel based on the item containers
*/
private void updateKeptWidgetInfoText()
{
// Add Information text widget
createNewTextWidget();
// Update Items lost total value
Widget lost = client.getWidget(WidgetInfo.ITEMS_LOST_ON_DEATH_CONTAINER);
double total = 0;
for (Widget w : lost.getChildren())
{
if (w.getItemId() == -1)
{
continue;
}
double price = itemManager.getItemPrice(w.getItemId());
if (price == 0)
{
// Default to alch price
price = itemManager.getItemComposition(w.getItemId()).getPrice() * HIGH_ALCH;
}
total += price;
}
Widget lostValue = client.getWidget(WidgetInfo.ITEMS_LOST_VALUE);
lostValue.setText(NUMBER_FORMAT.format(total) + " gp");
// Update Max items kept
Widget kept = client.getWidget(WidgetInfo.ITEMS_KEPT_ON_DEATH_CONTAINER);
Widget max = client.getWidget(WidgetInfo.ITEMS_KEPT_MAX);
max.setText(String.format(MAX_KEPT_ITEMS_FORMAT, kept.getChildren().length));
}
// isTradeable checks if they are traded on the grand exchange, some items are trade-able but not via GE
private boolean checkTradeable(int id, ItemComposition c)
{
// If the item is a note check the unnoted variants trade ability
if (c.getNote() != -1)
{
return checkTradeable(c.getLinkedNoteId(), itemManager.getItemComposition(c.getLinkedNoteId()));
}
switch (id)
{
case ItemID.COINS_995:
case ItemID.PLATINUM_TOKEN:
return true;
default:
if (ActuallyTradeableItem.check(id))
{
return true;
}
}
return c.isTradeable();
}
private void createNewTextWidget()
{
// The text use to be put inside this container but since we can't create LAYER widgets
// We needed to edit this to be a layer for adding buttons
Widget old = client.getWidget(WidgetInfo.ITEMS_KEPT_INFORMATION_CONTAINER);
// Update the existing TEXT container if it exists. It should be the last child of the old text widget
// client.getWidget() seems to not find indexed child widgets
Widget[] children = old.getChildren();
if (children != null && children.length > 0)
{
Widget x = old.getChild(children.length - 1);
if (x.getId() == WidgetInfo.ITEMS_KEPT_CUSTOM_TEXT_CONTAINER.getId())
{
x.setText(getUpdatedInfoText());
x.revalidate();
return;
}
}
Widget w = old.createChild(-1, WidgetType.TEXT);
// Position under buttons taking remaining space
w.setOriginalWidth(old.getOriginalWidth());
w.setOriginalHeight(ORIGINAL_INFO_HEIGHT - old.getOriginalHeight());
w.setOriginalY(old.getOriginalHeight());
w.setFontId(FontID.PLAIN_11);
w.setTextShadowed(true);
w.setTextColor(FONT_COLOR);
w.setText(getUpdatedInfoText());
w.setId(WidgetInfo.ITEMS_KEPT_CUSTOM_TEXT_CONTAINER.getId());
w.revalidate();
// Need to reset height so text is visible?
old.setOriginalHeight(ORIGINAL_INFO_HEIGHT);
old.revalidate();
}
private void createWidgetButtons()
{
buttonMap.clear();
// Ultimate Iron men are always skulled and can't use the protect item prayer
if (!isUltimateIronman())
{
createButton(PROTECT_ITEM_BUTTON_NAME, PROTECT_ITEM_SPRITE_ID, protectingItem);
createButton(SKULLED_BUTTON_NAME, SKULL_SPRITE_ID, isSkulled);
}
createButton(LOW_WILDY_BUTTON_NAME, SWORD_SPRITE_ID, wildyLevel > 0 && wildyLevel <= 20);
createButton(DEEP_WILDY_BUTTON_NAME, SKULL_2_SPRITE_ID, wildyLevel > 20);
Widget parent = client.getWidget(WidgetInfo.ITEMS_KEPT_INFORMATION_CONTAINER);
parent.setType(WidgetType.LAYER);
parent.revalidate();
WidgetButton.addButtonsToContainerWidget(parent, buttonMap.values());
}
private void createButton(String name, int spriteID, boolean startingFlag)
{
WidgetButton button = new WidgetButton(name, spriteID, startingFlag, this::buttonCallback, client);
buttonMap.put(name, button);
}
private void buttonCallback(String name, boolean selected)
{
log.debug("Clicked Widget Button {}. New value: {}", name, selected);
switch (name)
{
case PROTECT_ITEM_BUTTON_NAME:
protectingItem = selected;
break;
case SKULLED_BUTTON_NAME:
isSkulled = selected;
break;
case LOW_WILDY_BUTTON_NAME:
if (!selected)
{
syncCurrentWildyLevel();
break;
}
wildyLevel = 1;
buttonMap.get(DEEP_WILDY_BUTTON_NAME).setSelected(false);
break;
case DEEP_WILDY_BUTTON_NAME:
if (!selected)
{
syncCurrentWildyLevel();
break;
}
wildyLevel = 21;
buttonMap.get(LOW_WILDY_BUTTON_NAME).setSelected(false);
break;
default:
log.warn("Unhandled Button Name: {}", name);
return;
}
recreateItemsKeptOnDeathWidget();
}
/**
* Creates an Item Widget for use inside the Kept on Death Interface
* @param qty Amount of item
* @param c Items Composition
* @return
*/
private Widget createItemWidget(int qty, ItemComposition c)
{
Widget itemWidget = client.createWidget();
itemWidget.setType(WidgetType.GRAPHIC);
itemWidget.setItemId(c.getId());
itemWidget.setItemQuantity(qty);
itemWidget.setHasListener(true);
itemWidget.setIsIf3(true);
itemWidget.setOriginalWidth(ORIGINAL_WIDTH);
itemWidget.setOriginalHeight(ORIGINAL_HEIGHT);
itemWidget.setBorderType(1);
itemWidget.setAction(1, String.format(ACTION_TEXT, c.getName()));
itemWidget.setOnOpListener(SCRIPT_ID, 1, qty, c.getName());
return itemWidget;
}
}

View File

@@ -0,0 +1,175 @@
/*
* 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.keptondeath;
import java.util.Arrays;
import java.util.Collection;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.SpriteID;
import net.runelite.api.widgets.JavaScriptCallback;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetType;
@Slf4j
public 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;
public interface WidgetButtonCallback
{
void run(String name, boolean newState);
}
private String name;
private int spriteID;
@Getter
private Widget icon;
@Getter
private Widget background;
private boolean selected;
private WidgetButtonCallback callback;
WidgetButton(String name, int spriteID, boolean selectedStartState, WidgetButtonCallback callback, Client client)
{
this.name = name;
this.spriteID = spriteID;
this.selected = selectedStartState;
this.callback = callback;
createBackgroundWidget(client);
createIconWidget(client);
}
private void createBackgroundWidget(Client client)
{
background = createWidget(client);
background.setOriginalWidth(BACKGROUND_WIDTH);
background.setOriginalHeight(BACKGROUND_HEIGHT);
syncBackgroundSprite();
}
private void createIconWidget(Client client)
{
icon = createWidget(client);
icon.setAction(1, "Toggle:");
icon.setOnOpListener((JavaScriptCallback) ev -> onButtonClicked());
icon.setHasListener(true);
icon.setSpriteId(spriteID);
}
private Widget createWidget(Client client)
{
Widget w = client.createWidget();
w.setType(WidgetType.GRAPHIC);
w.setOriginalWidth(ICON_WIDTH);
w.setOriginalHeight(ICON_HEIGHT);
w.setName("<col=ff981f>" + this.name);
w.setIsIf3(true);
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 addButtonsToContainerWidget(Widget container, Collection<WidgetButton> buttons)
{
Widget[] children = container.getChildren();
if (children == null)
{
// Create a child so we can copy the returned Widget[] and avoid hn casting issues from creating a new Widget[]
container.createChild(0, WidgetType.GRAPHIC);
children = container.getChildren();
}
// Each button has two widgets, Icon and Background
Widget[] itemsArray = Arrays.copyOf(children, buttons.size() * 2);
int parentId = container.getId();
int xIncrement = BACKGROUND_WIDTH + PADDING;
int yIncrement = BACKGROUND_HEIGHT + PADDING;
int maxRowItems = container.getWidth() / xIncrement;
// Ensure at least 1 button per row
maxRowItems = maxRowItems < 1 ? 1 : maxRowItems;
int startingIndex = 0;
for (WidgetButton w : buttons)
{
int originalX = (((startingIndex / 2) % maxRowItems) * xIncrement);
int originalY = (((startingIndex / 2) / maxRowItems) * yIncrement);
Widget background = updateWidgetPosition(w.getBackground(), parentId, startingIndex, originalX, originalY);
itemsArray[startingIndex] = background;
startingIndex++;
// Icon must be padded to center inside image
Widget icon = updateWidgetPosition(w.getIcon(), parentId, startingIndex, originalX + ICON_PADDING, originalY + ICON_PADDING);
itemsArray[startingIndex] = icon;
startingIndex++;
}
int rows = 1 + (buttons.size() > maxRowItems ? buttons.size() / maxRowItems : 0);
container.setOriginalHeight(yIncrement * rows);
container.setChildren(itemsArray);
container.revalidate();
}
private static Widget updateWidgetPosition(Widget w, int id, int index, int originalX, int originalY)
{
w.setParentId(id);
w.setId(id);
w.setIndex(index);
w.setOriginalX(originalX);
w.setOriginalY(originalY);
w.revalidate();
return w;
}
private void onButtonClicked()
{
setSelected(!selected);
callback.run(name, selected);
}
}

View File

@@ -0,0 +1 @@
15F58F5939D9311F3D76FA2F0F3441B7B0DA1E8EAE23C654948095A7D51E07F0

View File

@@ -0,0 +1,622 @@
.id 1601
.int_stack_count 4
.string_stack_count 2
.int_var_count 13
.string_var_count 3
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
iload 1
define_array 111
iconst 0
istore 11
iconst 0
istore 12
iload 0
iconst 0
if_icmpeq LABEL29
jump LABEL517
LABEL29:
iconst 93
iconst 13190
inv_total
iconst 0
if_icmpgt LABEL40
iconst 93
iconst 13192
inv_total
iconst 0
if_icmpgt LABEL40
jump LABEL42
LABEL40:
iconst 1
istore 9
LABEL42:
iload 10
iload 1
if_icmplt LABEL46
jump LABEL82
LABEL46:
iconst 584
iload 10
inv_getobj
istore 6
iload 6
iconst -1
if_icmpne LABEL54
jump LABEL79
LABEL54:
iconst 584
iload 10
inv_getnum
istore 7
LABEL58:
iload 10
iload 1
if_icmplt LABEL62
jump LABEL78
LABEL62:
iload 7
iconst 0
if_icmpgt LABEL66
jump LABEL78
LABEL66:
iload 10
iload 6
set_array_int
iload 7
iconst 1
sub
istore 7
iload 10
iconst 1
add
istore 10
jump LABEL58
LABEL78:
jump LABEL81
LABEL79:
iload 1
istore 10
LABEL81:
jump LABEL42
LABEL82:
iload 4
iload 1
if_icmplt LABEL86
jump LABEL141
LABEL86:
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 LABEL111
jump LABEL138
LABEL111:
iload 6
iconst 1
1200
sconst "<col=ff981f>"
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 LABEL140
LABEL138:
iload 1
istore 4
LABEL140:
jump LABEL82
LABEL141:
iconst 0
istore 4
LABEL143:
iload 4
iconst 468
inv_size
if_icmplt LABEL148
jump LABEL342
LABEL148:
iconst 468
iload 4
inv_getobj
istore 6
iload 6
iconst -1
if_icmpne LABEL156
jump LABEL337
LABEL156:
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
1200
sconst "<col=ff981f>"
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
enum
iconst 1
if_icmpeq LABEL214
jump LABEL219
LABEL214:
iconst 2
cc_setoutline
iconst 1
istore 8
jump LABEL221
LABEL219:
iconst 1
cc_setoutline
LABEL221:
iload 5
iconst 1
add
istore 5
iload 6
oc_stackable
iconst 1
if_icmpeq LABEL230
jump LABEL337
LABEL230:
iconst 0
istore 10
iconst 0
istore 12
LABEL234:
iload 10
iload 1
if_icmplt LABEL238
jump LABEL252
LABEL238:
iload 10
get_array_int
iload 6
if_icmpeq LABEL243
jump LABEL247
LABEL243:
iload 12
iconst 1
add
istore 12
LABEL247:
iload 10
iconst 1
add
istore 10
jump LABEL234
LABEL252:
iconst 2147483647
iconst 94
iload 6
inv_total
sub
iconst 93
iload 6
inv_total
sub
iload 12
add
istore 11
iconst 0
iload 11
sub
istore 11
iload 11
iconst 0
if_icmpgt LABEL272
jump LABEL337
LABEL272:
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 11
1200
sconst "<col=ff981f>"
iload 6
oc_name
join_string 2
cc_setopbase
iconst 1
sconst "Item:"
cc_setop
iconst 1603
iconst 0
iload 11
iload 6
oc_name
sconst "1is"
cc_setonop
iconst 1118481
cc_setgraphicshadow
iconst 111
iconst 49
iconst 879
iload 6
enum
iconst 1
if_icmpeq LABEL326
jump LABEL331
LABEL326:
iconst 2
cc_setoutline
iconst 1
istore 8
jump LABEL333
LABEL331:
iconst 1
cc_setoutline
LABEL333:
iload 5
iconst 1
add
istore 5
LABEL337:
iload 4
iconst 1
add
istore 4
jump LABEL143
LABEL342:
sconst "The normal amount of items kept is "
sconst "three"
sconst "."
sconst "<br>"
sconst "<br>"
join_string 5
sstore 2
iload 3
iconst 1
if_icmpeq LABEL353
jump LABEL363
LABEL353:
sload 2
sconst "You're an "
sconst "<col=ff3333>"
sconst "Ultimate Iron Man"
sconst "<col=ff981f>"
sconst ", so you will always keep zero items."
join_string 5
append
sstore 2
jump LABEL426
LABEL363:
iload 1
iconst 0
if_icmpeq LABEL367
jump LABEL379
LABEL367:
sload 2
sconst "You're marked with a "
sconst "<col=ff3333>"
sconst "PK skull"
sconst "<col=ff981f>"
sconst ". This reduces the items you keep from "
sconst "three"
sconst " to zero!"
join_string 7
append
sstore 2
jump LABEL426
LABEL379:
iload 1
iconst 1
if_icmpeq LABEL383
jump LABEL402
LABEL383:
sload 2
sconst "You're marked with a "
sconst "<col=ff3333>"
sconst "PK skull"
sconst "<col=ff981f>"
sconst ". This reduces the items you keep from "
sconst "three"
sconst " to zero!"
sconst "<br>"
sconst "<br>"
sconst "However, you also have the "
sconst "<col=ff3333>"
sconst "Protect Items"
sconst "<col=ff981f>"
sconst " prayer active, which saves you one extra item!"
join_string 14
append
sstore 2
jump LABEL426
LABEL402:
iload 1
iconst 3
if_icmpeq LABEL406
jump LABEL411
LABEL406:
sload 2
sconst "You have no factors affecting the items you keep."
append
sstore 2
jump LABEL426
LABEL411:
iload 1
iconst 3
iconst 1
add
if_icmpeq LABEL417
jump LABEL426
LABEL417:
sload 2
sconst "You have the "
sconst "<col=ff3333>"
sconst "Protect Items"
sconst "<col=ff981f>"
sconst " prayer active, which saves you one extra item!"
join_string 5
append
sstore 2
LABEL426:
iload 8
iconst 1
if_icmpeq LABEL433
iload 9
iconst 1
if_icmpeq LABEL433
jump LABEL484
LABEL433:
iload 8
iconst 1
if_icmpeq LABEL437
jump LABEL458
LABEL437:
iload 9
iconst 1
if_icmpeq LABEL441
jump LABEL458
LABEL441:
sload 2
sconst "<br>"
sconst "<br>"
sconst "Items with a "
sconst "<col=ffffff>"
sconst "white outline"
sconst "<col=ff981f>"
sconst " will always be lost."
sconst "<br>"
sconst "<col=00ff00>"
sconst "Bonds"
sconst "</col>"
sconst " are always protected."
join_string 12
append
sstore 2
jump LABEL484
LABEL458:
iload 8
iconst 1
if_icmpeq LABEL462
jump LABEL474
LABEL462:
sload 2
sconst "<br>"
sconst "<br>"
sconst "Items with a "
sconst "<col=ffffff>"
sconst "white outline"
sconst "<col=ff981f>"
sconst " will always be lost."
join_string 7
append
sstore 2
jump LABEL484
LABEL474:
sload 2
sconst "<br>"
sconst "<br>"
sconst "<col=00ff00>"
sconst "Bonds"
sconst "</col>"
sconst " are always protected, so are not shown here."
join_string 6
append
sstore 2
LABEL484:
sload 2
iconst 262173
if_settext
sconst "<col=ffcc33>"
sconst "Max items kept on death :"
sconst "<br>"
sconst "<br>"
sconst "<col=ffcc33>"
sconst "~ "
iload 1
tostring
sconst " ~"
join_string 8
iconst 262174
if_settext
iload 2
iconst 0
if_icmpgt LABEL503
jump LABEL510
LABEL503:
sconst "Items you will keep on death:"
iconst 262161
if_settext
sconst "Items you will lose on death:"
iconst 262164
if_settext
jump LABEL516
LABEL510:
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
LABEL516:
jump LABEL557
LABEL517:
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 "<br>"
sconst "<br>"
join_string 5
sstore 2
sload 2
sconst "You're in a "
sconst "<col=ff3333>"
sconst "safe area"
sconst "<col=ff981f>"
sconst ". See information to the left for a more detailed description."
join_string 5
append
sstore 2
sload 2
iconst 262173
if_settext
sconst "<col=ffcc33>"
sconst "Max items kept on death :"
sconst "<br>"
sconst "<br>"
sconst "<col=ffcc33>"
sconst "All items!"
join_string 6
iconst 262174
if_settext
LABEL557:
sconst "deathKeepBuild" ; push event name
runelite_callback ; invoke callback
return