Merge branch 'master' into maven

This commit is contained in:
Tyler Bochard
2019-07-11 00:48:18 -04:00
committed by GitHub
96 changed files with 6320 additions and 3754 deletions

View File

@@ -290,6 +290,16 @@
<version>3.2.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.11</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.5.9</version>
</dependency>
</dependencies>
<build>

View File

@@ -385,6 +385,18 @@ public class ItemManager
* @return item price
*/
public int getItemPrice(int itemID)
{
return getItemPrice(itemID, false);
}
/**
* Look up an item's price
*
* @param itemID item id
* @param ignoreUntradeableMap should the price returned ignore the {@link UntradeableItemMapping}
* @return item price
*/
public int getItemPrice(int itemID, boolean ignoreUntradeableMap)
{
if (itemID == ItemID.COINS_995)
{
@@ -395,10 +407,13 @@ public class ItemManager
return 1000;
}
UntradeableItemMapping p = UntradeableItemMapping.map(ItemVariationMapping.map(itemID));
if (p != null)
if (!ignoreUntradeableMap)
{
return getItemPrice(p.getPriceID()) * p.getQuantity();
UntradeableItemMapping p = UntradeableItemMapping.map(ItemVariationMapping.map(itemID));
if (p != null)
{
return getItemPrice(p.getPriceID()) * p.getQuantity();
}
}
int price = 0;

View File

@@ -41,6 +41,7 @@ import java.nio.file.WatchService;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.extern.slf4j.Slf4j;
import net.runelite.client.RuneLite;
import net.runelite.client.config.Config;
@@ -154,7 +155,6 @@ public class PluginWatcher extends Thread
{
continue;
}
log.info("Loading plugin from {}", file);
load(file);
}

View File

@@ -65,4 +65,14 @@ public interface AnimationSmoothingConfig extends Config
return true;
}
@ConfigItem(
keyName = "smoothWidgetAnimations",
name = "Smooth Widget Animations",
description = "Configures whether the widget animations are smooth or not",
position = 4
)
default boolean smoothWidgetAnimations()
{
return true;
}
}

View File

@@ -69,6 +69,7 @@ public class AnimationSmoothingPlugin extends Plugin
client.setInterpolatePlayerAnimations(false);
client.setInterpolateNpcAnimations(false);
client.setInterpolateObjectAnimations(false);
client.setInterpolateWidgetAnimations(false);
}
@Subscribe
@@ -85,5 +86,6 @@ public class AnimationSmoothingPlugin extends Plugin
client.setInterpolatePlayerAnimations(config.smoothPlayerAnimations());
client.setInterpolateNpcAnimations(config.smoothNpcAnimations());
client.setInterpolateObjectAnimations(config.smoothObjectAnimations());
client.setInterpolateWidgetAnimations(config.smoothWidgetAnimations());
}
}

View File

@@ -57,7 +57,8 @@ enum Boss
KRAKEN(NpcID.KRAKEN, 8400, ChronoUnit.MILLIS, ItemID.PET_KRAKEN),
KALPHITE_QUEEN(NpcID.KALPHITE_QUEEN_965, 30, ChronoUnit.SECONDS, ItemID.KALPHITE_PRINCESS),
DUSK(NpcID.DUSK_7889, 2, ChronoUnit.MINUTES, ItemID.NOON),
ALCHEMICAL_HYDRA(NpcID.ALCHEMICAL_HYDRA_8622, 25200, ChronoUnit.MILLIS, ItemID.IKKLE_HYDRA);
ALCHEMICAL_HYDRA(NpcID.ALCHEMICAL_HYDRA_8622, 25200, ChronoUnit.MILLIS, ItemID.IKKLE_HYDRA),
SARACHNIS(NpcID.SARACHNIS, 30, ChronoUnit.SECONDS, ItemID.SRARACHA);
private static final Map<Integer, Boss> bosses;

View File

@@ -86,4 +86,15 @@ public interface ChatFilterConfig extends Config
{
return false;
}
@ConfigItem(
keyName = "filterLogin",
name = "Filter Logged In/Out Messages",
description = "Filter your private chat to remove logged in/out messages",
position = 6
)
default boolean filterLogin()
{
return false;
}
}

View File

@@ -133,6 +133,13 @@ public class ChatFilterPlugin extends Plugin
case FRIENDSCHAT:
case GAMEMESSAGE:
break;
case LOGINLOGOUTNOTIFICATION:
if (config.filterLogin())
{
// Block the message
intStack[intStackSize - 3] = 0;
}
return;
default:
return;
}

View File

@@ -25,11 +25,14 @@
package net.runelite.client.plugins.config;
import java.awt.image.BufferedImage;
import java.lang.reflect.Method;
import java.util.concurrent.ScheduledExecutorService;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.swing.SwingUtilities;
import net.runelite.api.MenuAction;
import net.runelite.client.RuneLite;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.config.ChatColorConfig;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.config.RuneLiteConfig;
@@ -41,6 +44,7 @@ import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.plugins.PluginManager;
import net.runelite.client.ui.ClientToolbar;
import net.runelite.client.ui.ClientUI;
import net.runelite.client.ui.NavigationButton;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayMenuEntry;
@@ -97,9 +101,25 @@ public class ConfigPlugin extends Plugin
}
@Override
protected void shutDown() throws Exception
public void shutDown() throws Exception
{
clientToolbar.removeNavigation(navButton);
RuneLite.getInjector().getInstance(ClientThread.class).invokeLater(() ->
{
try
{
ConfigPanel.pluginList.clear();
pluginManager.setPluginEnabled(this, true);
pluginManager.startPlugin(this);
Method expand = ClientUI.class.getDeclaredMethod("expand", NavigationButton.class);
expand.setAccessible(true);
expand.invoke(RuneLite.getInjector().getInstance(ClientUI.class), navButton);
}
catch (Exception e)
{
System.out.println(e.getMessage());
}
});
}
@Subscribe

View File

@@ -253,7 +253,12 @@ public class IdleNotifierPlugin extends Plugin
case USING_GILDED_ALTAR:
/* Farming */
case FARMING_MIX_ULTRACOMPOST:
/* Misc */
case FARMING_HARVEST_BUSH:
case FARMING_HARVEST_HERB:
case FARMING_HARVEST_FRUIT_TREE:
case FARMING_HARVEST_FLOWER:
case FARMING_HARVEST_ALLOTMENT:
/* Misc */
case PISCARILIUS_CRANE_REPAIR:
case HOME_MAKE_TABLET:
case SAND_COLLECTION:

View File

@@ -69,7 +69,7 @@ class InventoryGridOverlay extends Overlay
final Widget if1DraggingWidget = client.getIf1DraggedWidget();
final Widget inventoryWidget = client.getWidget(WidgetInfo.INVENTORY);
if (if1DraggingWidget == null || if1DraggingWidget.equals(inventoryWidget)
if (if1DraggingWidget == null || if1DraggingWidget != inventoryWidget
|| client.getItemPressedDuration() < plugin.getDragDelay() / Constants.CLIENT_TICK_LENGTH)
{
return null;

View File

@@ -42,7 +42,9 @@ enum AlwaysLostItem
{
RUNE_POUCH(ItemID.RUNE_POUCH, true),
LOOTING_BAG(ItemID.LOOTING_BAG, false),
CLUE_BOX(ItemID.CLUE_BOX, false);
CLUE_BOX(ItemID.CLUE_BOX, false),
BRACELET_OF_ETHEREUM(ItemID.BRACELET_OF_ETHEREUM, false),
BRACELET_OF_ETHEREUM_UNCHARGED(ItemID.BRACELET_OF_ETHEREUM_UNCHARGED, false);
private final int itemID;
private final boolean keptOutsideOfWilderness;

View File

@@ -0,0 +1,107 @@
/*
* Copyright (c) 2019, TheStonedTurtle <https://github.com/TheStonedTurtle>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.itemskeptondeath;
import com.google.common.collect.ImmutableMap;
import java.util.Map;
import javax.annotation.Nullable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.runelite.api.ItemID;
/**
* Degradable/Non-rechargeable Jewelry death prices are usually determined by the amount of charges the item has left.
* The price of each charge is based on the GE price of the fully charged item divided by the maximum item charges
* Charge price = GE Price / Max Charges
* Death Price = Charge price * Current Charges
*/
@AllArgsConstructor
@Getter
enum DynamicPriceItem
{
GAMES_NECKLACE1(ItemID.GAMES_NECKLACE1, 1, 8, ItemID.GAMES_NECKLACE8),
GAMES_NECKLACE2(ItemID.GAMES_NECKLACE2, 2, 8, ItemID.GAMES_NECKLACE8),
GAMES_NECKLACE3(ItemID.GAMES_NECKLACE3, 3, 8, ItemID.GAMES_NECKLACE8),
GAMES_NECKLACE4(ItemID.GAMES_NECKLACE4, 4, 8, ItemID.GAMES_NECKLACE8),
GAMES_NECKLACE5(ItemID.GAMES_NECKLACE5, 5, 8, ItemID.GAMES_NECKLACE8),
GAMES_NECKLACE6(ItemID.GAMES_NECKLACE6, 6, 8, ItemID.GAMES_NECKLACE8),
GAMES_NECKLACE7(ItemID.GAMES_NECKLACE7, 7, 8, ItemID.GAMES_NECKLACE8),
RING_OF_DUELING1(ItemID.RING_OF_DUELING1, 1, 8, ItemID.RING_OF_DUELING8),
RING_OF_DUELING2(ItemID.RING_OF_DUELING2, 2, 8, ItemID.RING_OF_DUELING8),
RING_OF_DUELING3(ItemID.RING_OF_DUELING3, 3, 8, ItemID.RING_OF_DUELING8),
RING_OF_DUELING4(ItemID.RING_OF_DUELING4, 4, 8, ItemID.RING_OF_DUELING8),
RING_OF_DUELING5(ItemID.RING_OF_DUELING5, 5, 8, ItemID.RING_OF_DUELING8),
RING_OF_DUELING6(ItemID.RING_OF_DUELING6, 6, 8, ItemID.RING_OF_DUELING8),
RING_OF_DUELING7(ItemID.RING_OF_DUELING7, 7, 8, ItemID.RING_OF_DUELING8),
RING_OF_RETURNING1(ItemID.RING_OF_RETURNING1, 1, 5, ItemID.RING_OF_RETURNING5),
RING_OF_RETURNING2(ItemID.RING_OF_RETURNING2, 2, 5, ItemID.RING_OF_RETURNING5),
RING_OF_RETURNING3(ItemID.RING_OF_RETURNING3, 3, 5, ItemID.RING_OF_RETURNING5),
RING_OF_RETURNING4(ItemID.RING_OF_RETURNING4, 4, 5, ItemID.RING_OF_RETURNING5),
NECKLACE_OF_PASSAGE1(ItemID.NECKLACE_OF_PASSAGE1, 1, 5, ItemID.NECKLACE_OF_PASSAGE5),
NECKLACE_OF_PASSAGE2(ItemID.NECKLACE_OF_PASSAGE2, 2, 5, ItemID.NECKLACE_OF_PASSAGE5),
NECKLACE_OF_PASSAGE3(ItemID.NECKLACE_OF_PASSAGE3, 3, 5, ItemID.NECKLACE_OF_PASSAGE5),
NECKLACE_OF_PASSAGE4(ItemID.NECKLACE_OF_PASSAGE4, 4, 5, ItemID.NECKLACE_OF_PASSAGE5),
BURNING_AMULET1(ItemID.BURNING_AMULET1, 1, 5, ItemID.BURNING_AMULET5),
BURNING_AMULET2(ItemID.BURNING_AMULET2, 2, 5, ItemID.BURNING_AMULET5),
BURNING_AMULET3(ItemID.BURNING_AMULET3, 3, 5, ItemID.BURNING_AMULET5),
BURNING_AMULET4(ItemID.BURNING_AMULET4, 4, 5, ItemID.BURNING_AMULET5);
private final int itemId;
private final int currentCharges;
private final int maxCharges;
private final int chargedId;
private static final Map<Integer, DynamicPriceItem> DYNAMIC_ITEMS;
static
{
final ImmutableMap.Builder<Integer, DynamicPriceItem> map = ImmutableMap.builder();
for (final DynamicPriceItem p : values())
{
map.put(p.itemId, p);
}
DYNAMIC_ITEMS = map.build();
}
/**
* Calculates the price off the partially charged jewelry based on the base items price
* @param basePrice price of the base item, usually the trade-able variant
* @return death price of the current DynamicPriceItem
*/
int calculateDeathPrice(final int basePrice)
{
return (basePrice / maxCharges) * currentCharges;
}
@Nullable
static DynamicPriceItem find(int itemId)
{
return DYNAMIC_ITEMS.get(itemId);
}
}

View File

@@ -28,8 +28,6 @@ package net.runelite.client.plugins.itemskeptondeath;
import com.google.common.collect.ImmutableMap;
import java.util.Map;
import javax.annotation.Nullable;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.runelite.api.ItemID;
@@ -37,8 +35,7 @@ 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(AccessLevel.PACKAGE)
@Getter
enum FixedPriceItem
{
IMBUED_BLACK_MASK_I(ItemID.BLACK_MASK_I, 5000),
@@ -67,10 +64,161 @@ enum FixedPriceItem
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);
IMBUED_TYRANNICAL_RING_I(ItemID.TYRANNICAL_RING_I, 2000),
GRACEFUL_HOOD(ItemID.GRACEFUL_HOOD, 1965),
GRACEFUL_CAPE(ItemID.GRACEFUL_CAPE, 2460),
GRACEFUL_TOP(ItemID.GRACEFUL_TOP, 2345),
GRACEFUL_LEGS(ItemID.GRACEFUL_LEGS, 2290),
GRACEFUL_GLOVES(ItemID.GRACEFUL_GLOVES, 1970),
GRACEFUL_BOOTS(ItemID.GRACEFUL_BOOTS, 2060),
ANGLER_HAT(ItemID.ANGLER_HAT, 2600),
ANGLER_TOP(ItemID.ANGLER_TOP, 3550),
ANGLER_WADERS(ItemID.ANGLER_WADERS, 4400),
ANGLER_BOOTS(ItemID.ANGLER_BOOTS, 5300),
PROSPECTOR_HELMET(ItemID.PROSPECTOR_HELMET, 2640),
PROSPECTOR_JACKET(ItemID.PROSPECTOR_JACKET, 3550),
PROSPECTOR_LEGS(ItemID.PROSPECTOR_LEGS, 4460),
PROSPECTOR_BOOTS(ItemID.PROSPECTOR_BOOTS, 5370),
LUMBERJACK_HAT(ItemID.LUMBERJACK_HAT, 19950),
LUMBERJACK_TOP(ItemID.LUMBERJACK_TOP, 19950),
LUMBERJACK_LEGS(ItemID.LUMBERJACK_LEGS, 19950),
LUMBERJACK_BOOTS(ItemID.LUMBERJACK_BOOTS, 19950),
ROGUE_MASK(ItemID.ROGUE_MASK, 725),
ROGUE_TOP(ItemID.ROGUE_TOP, 575),
ROGUE_TROUSERS(ItemID.ROGUE_TROUSERS, 500),
ROGUE_GLOVES(ItemID.ROGUE_GLOVES, 650),
ROGUE_BOOTS(ItemID.ROGUE_BOOTS, 650),
RING_OF_WEALTH_1(ItemID.RING_OF_WEALTH_1, 500, ItemID.RING_OF_WEALTH),
RING_OF_WEALTH_2(ItemID.RING_OF_WEALTH_2, 1000, ItemID.RING_OF_WEALTH),
RING_OF_WEALTH_3(ItemID.RING_OF_WEALTH_3, 1500, ItemID.RING_OF_WEALTH),
RING_OF_WEALTH_4(ItemID.RING_OF_WEALTH_4, 2000, ItemID.RING_OF_WEALTH),
AMULET_OF_GLORY1(ItemID.AMULET_OF_GLORY1, 500, ItemID.AMULET_OF_GLORY),
AMULET_OF_GLORY2(ItemID.AMULET_OF_GLORY2, 1000, ItemID.AMULET_OF_GLORY),
AMULET_OF_GLORY3(ItemID.AMULET_OF_GLORY3, 1500, ItemID.AMULET_OF_GLORY),
AMULET_OF_GLORY5(ItemID.AMULET_OF_GLORY5, 2500, ItemID.AMULET_OF_GLORY),
COMBAT_BRACELET1(ItemID.COMBAT_BRACELET1, 500, ItemID.COMBAT_BRACELET),
COMBAT_BRACELET2(ItemID.COMBAT_BRACELET2, 1000, ItemID.COMBAT_BRACELET),
COMBAT_BRACELET3(ItemID.COMBAT_BRACELET3, 1500, ItemID.COMBAT_BRACELET),
COMBAT_BRACELET5(ItemID.COMBAT_BRACELET5, 2500, ItemID.COMBAT_BRACELET),
SKILLS_NECKLACE1(ItemID.SKILLS_NECKLACE1, 500, ItemID.SKILLS_NECKLACE),
SKILLS_NECKLACE2(ItemID.SKILLS_NECKLACE2, 1000, ItemID.SKILLS_NECKLACE),
SKILLS_NECKLACE3(ItemID.SKILLS_NECKLACE3, 1500, ItemID.SKILLS_NECKLACE),
SKILLS_NECKLACE4(ItemID.SKILLS_NECKLACE5, 2500, ItemID.SKILLS_NECKLACE),
AHRIMS_HOOD_25(ItemID.AHRIMS_HOOD_25, 2500, ItemID.AHRIMS_HOOD_0),
AHRIMS_HOOD_50(ItemID.AHRIMS_HOOD_50, 5000, ItemID.AHRIMS_HOOD_0),
AHRIMS_HOOD_75(ItemID.AHRIMS_HOOD_75, 7500, ItemID.AHRIMS_HOOD_0),
AHRIMS_HOOD_100(ItemID.AHRIMS_HOOD_100, 10000, ItemID.AHRIMS_HOOD_0),
AHRIMS_ROBETOP_25(ItemID.AHRIMS_ROBETOP_25, 2500, ItemID.AHRIMS_ROBETOP_0),
AHRIMS_ROBETOP_50(ItemID.AHRIMS_ROBETOP_50, 5000, ItemID.AHRIMS_ROBETOP_0),
AHRIMS_ROBETOP_75(ItemID.AHRIMS_ROBETOP_75, 7500, ItemID.AHRIMS_ROBETOP_0),
AHRIMS_ROBETOP_100(ItemID.AHRIMS_ROBETOP_100, 10000, ItemID.AHRIMS_ROBETOP_0),
AHRIMS_ROBESKIRT_25(ItemID.AHRIMS_ROBESKIRT_25, 2500, ItemID.AHRIMS_ROBESKIRT_0),
AHRIMS_ROBESKIRT_50(ItemID.AHRIMS_ROBESKIRT_50, 5000, ItemID.AHRIMS_ROBESKIRT_0),
AHRIMS_ROBESKIRT_75(ItemID.AHRIMS_ROBESKIRT_75, 7500, ItemID.AHRIMS_ROBESKIRT_0),
AHRIMS_ROBESKIRT_100(ItemID.AHRIMS_ROBESKIRT_100, 10000, ItemID.AHRIMS_ROBESKIRT_0),
AHRIMS_STAFF_25(ItemID.AHRIMS_STAFF_25, 2500, ItemID.AHRIMS_STAFF_0),
AHRIMS_STAFF_50(ItemID.AHRIMS_STAFF_50, 5000, ItemID.AHRIMS_STAFF_0),
AHRIMS_STAFF_75(ItemID.AHRIMS_STAFF_75, 7500, ItemID.AHRIMS_STAFF_0),
AHRIMS_STAFF_100(ItemID.AHRIMS_STAFF_100, 10000, ItemID.AHRIMS_STAFF_0),
KARILS_COIF_25(ItemID.KARILS_COIF_25, 2500, ItemID.KARILS_COIF_0),
KARILS_COIF_50(ItemID.KARILS_COIF_50, 5000, ItemID.KARILS_COIF_0),
KARILS_COIF_75(ItemID.KARILS_COIF_75, 7500, ItemID.KARILS_COIF_0),
KARILS_COIF_100(ItemID.KARILS_COIF_100, 10000, ItemID.KARILS_COIF_0),
KARILS_LEATHERTOP_25(ItemID.KARILS_LEATHERTOP_25, 2500, ItemID.KARILS_LEATHERTOP_0),
KARILS_LEATHERTOP_50(ItemID.KARILS_LEATHERTOP_50, 5000, ItemID.KARILS_LEATHERTOP_0),
KARILS_LEATHERTOP_75(ItemID.KARILS_LEATHERTOP_75, 7500, ItemID.KARILS_LEATHERTOP_0),
KARILS_LEATHERTOP_100(ItemID.KARILS_LEATHERTOP_100, 10000, ItemID.KARILS_LEATHERTOP_0),
KARILS_LEATHERSKIRT_25(ItemID.KARILS_LEATHERSKIRT_25, 2500, ItemID.KARILS_LEATHERSKIRT_0),
KARILS_LEATHERSKIRT_50(ItemID.KARILS_LEATHERSKIRT_50, 5000, ItemID.KARILS_LEATHERSKIRT_0),
KARILS_LEATHERSKIRT_75(ItemID.KARILS_LEATHERSKIRT_75, 7500, ItemID.KARILS_LEATHERSKIRT_0),
KARILS_LEATHERSKIRT_100(ItemID.KARILS_LEATHERSKIRT_100, 10000, ItemID.KARILS_LEATHERSKIRT_0),
KARILS_CROSSBOW_25(ItemID.KARILS_CROSSBOW_25, 2500, ItemID.KARILS_CROSSBOW_0),
KARILS_CROSSBOW_50(ItemID.KARILS_CROSSBOW_50, 5000, ItemID.KARILS_CROSSBOW_0),
KARILS_CROSSBOW_75(ItemID.KARILS_CROSSBOW_75, 7500, ItemID.KARILS_CROSSBOW_0),
KARILS_CROSSBOW_100(ItemID.KARILS_CROSSBOW_100, 10000, ItemID.KARILS_CROSSBOW_0),
DHAROKS_HELM_25(ItemID.DHAROKS_HELM_25, 2500, ItemID.DHAROKS_HELM_0),
DHAROKS_HELM_50(ItemID.DHAROKS_HELM_50, 5000, ItemID.DHAROKS_HELM_0),
DHAROKS_HELM_75(ItemID.DHAROKS_HELM_75, 7500, ItemID.DHAROKS_HELM_0),
DHAROKS_HELM_100(ItemID.DHAROKS_HELM_100, 10000, ItemID.DHAROKS_HELM_0),
DHAROKS_PLATEBODY_25(ItemID.DHAROKS_PLATEBODY_25, 2500, ItemID.DHAROKS_PLATEBODY_0),
DHAROKS_PLATEBODY_50(ItemID.DHAROKS_PLATEBODY_50, 5000, ItemID.DHAROKS_PLATEBODY_0),
DHAROKS_PLATEBODY_75(ItemID.DHAROKS_PLATEBODY_75, 7500, ItemID.DHAROKS_PLATEBODY_0),
DHAROKS_PLATEBODY_100(ItemID.DHAROKS_PLATEBODY_100, 10000, ItemID.DHAROKS_PLATEBODY_0),
DHAROKS_PLATELEGS_25(ItemID.DHAROKS_PLATELEGS_25, 2500, ItemID.DHAROKS_PLATELEGS_0),
DHAROKS_PLATELEGS_50(ItemID.DHAROKS_PLATELEGS_50, 5000, ItemID.DHAROKS_PLATELEGS_0),
DHAROKS_PLATELEGS_75(ItemID.DHAROKS_PLATELEGS_75, 7500, ItemID.DHAROKS_PLATELEGS_0),
DHAROKS_PLATELEGS_100(ItemID.DHAROKS_PLATELEGS_100, 10000, ItemID.DHAROKS_PLATELEGS_0),
DHAROKS_GREATAXE_25(ItemID.DHAROKS_GREATAXE_25, 2500, ItemID.DHAROKS_GREATAXE_0),
DHAROKS_GREATAXE_50(ItemID.DHAROKS_GREATAXE_50, 5000, ItemID.DHAROKS_GREATAXE_0),
DHAROKS_GREATAXE_75(ItemID.DHAROKS_GREATAXE_75, 7500, ItemID.DHAROKS_GREATAXE_0),
DHAROKS_GREATAXE_100(ItemID.DHAROKS_GREATAXE_100, 10000, ItemID.DHAROKS_GREATAXE_0),
GUTHANS_HELM_25(ItemID.GUTHANS_HELM_25, 2500, ItemID.GUTHANS_HELM_0),
GUTHANS_HELM_50(ItemID.GUTHANS_HELM_50, 5000, ItemID.GUTHANS_HELM_0),
GUTHANS_HELM_75(ItemID.GUTHANS_HELM_75, 7500, ItemID.GUTHANS_HELM_0),
GUTHANS_HELM_100(ItemID.GUTHANS_HELM_100, 10000, ItemID.GUTHANS_HELM_0),
GUTHANS_PLATEBODY_25(ItemID.GUTHANS_PLATEBODY_25, 2500, ItemID.GUTHANS_PLATEBODY_0),
GUTHANS_PLATEBODY_50(ItemID.GUTHANS_PLATEBODY_50, 5000, ItemID.GUTHANS_PLATEBODY_0),
GUTHANS_PLATEBODY_75(ItemID.GUTHANS_PLATEBODY_75, 7500, ItemID.GUTHANS_PLATEBODY_0),
GUTHANS_PLATEBODY_100(ItemID.GUTHANS_PLATEBODY_100, 10000, ItemID.GUTHANS_PLATEBODY_0),
GUTHANS_CHAINSKIRT_25(ItemID.GUTHANS_CHAINSKIRT_25, 2500, ItemID.GUTHANS_CHAINSKIRT_0),
GUTHANS_CHAINSKIRT_50(ItemID.GUTHANS_CHAINSKIRT_50, 5000, ItemID.GUTHANS_CHAINSKIRT_0),
GUTHANS_CHAINSKIRT_75(ItemID.GUTHANS_CHAINSKIRT_75, 7500, ItemID.GUTHANS_CHAINSKIRT_0),
GUTHANS_CHAINSKIRT_100(ItemID.GUTHANS_CHAINSKIRT_100, 10000, ItemID.GUTHANS_CHAINSKIRT_0),
GUTHANS_WARSPEAR_25(ItemID.GUTHANS_WARSPEAR_25, 2500, ItemID.GUTHANS_WARSPEAR_0),
GUTHANS_WARSPEAR_50(ItemID.GUTHANS_WARSPEAR_50, 5000, ItemID.GUTHANS_WARSPEAR_0),
GUTHANS_WARSPEAR_75(ItemID.GUTHANS_WARSPEAR_75, 7500, ItemID.GUTHANS_WARSPEAR_0),
GUTHANS_WARSPEAR_100(ItemID.GUTHANS_WARSPEAR_100, 10000, ItemID.GUTHANS_WARSPEAR_0),
TORAGS_HELM_25(ItemID.TORAGS_HELM_25, 2500, ItemID.TORAGS_HELM_0),
TORAGS_HELM_50(ItemID.TORAGS_HELM_50, 5000, ItemID.TORAGS_HELM_0),
TORAGS_HELM_75(ItemID.TORAGS_HELM_75, 7500, ItemID.TORAGS_HELM_0),
TORAGS_HELM_100(ItemID.TORAGS_HELM_100, 10000, ItemID.TORAGS_HELM_0),
TORAGS_PLATEBODY_25(ItemID.TORAGS_PLATEBODY_25, 2500, ItemID.TORAGS_PLATEBODY_0),
TORAGS_PLATEBODY_50(ItemID.TORAGS_PLATEBODY_50, 5000, ItemID.TORAGS_PLATEBODY_0),
TORAGS_PLATEBODY_75(ItemID.TORAGS_PLATEBODY_75, 7500, ItemID.TORAGS_PLATEBODY_0),
TORAGS_PLATEBODY_100(ItemID.TORAGS_PLATEBODY_100, 10000, ItemID.TORAGS_PLATEBODY_0),
TORAGS_PLATELEGS_25(ItemID.TORAGS_PLATELEGS_25, 2500, ItemID.TORAGS_PLATELEGS_0),
TORAGS_PLATELEGS_50(ItemID.TORAGS_PLATELEGS_50, 5000, ItemID.TORAGS_PLATELEGS_0),
TORAGS_PLATELEGS_75(ItemID.TORAGS_PLATELEGS_75, 7500, ItemID.TORAGS_PLATELEGS_0),
TORAGS_PLATELEGS_100(ItemID.TORAGS_PLATELEGS_100, 10000, ItemID.TORAGS_PLATELEGS_0),
TORAGS_HAMMERS_25(ItemID.TORAGS_HAMMERS_25, 2500, ItemID.TORAGS_HAMMERS_0),
TORAGS_HAMMERS_50(ItemID.TORAGS_HAMMERS_50, 5000, ItemID.TORAGS_HAMMERS_0),
TORAGS_HAMMERS_75(ItemID.TORAGS_HAMMERS_75, 7500, ItemID.TORAGS_HAMMERS_0),
TORAGS_HAMMERS_100(ItemID.TORAGS_HAMMERS_100, 10000, ItemID.TORAGS_HAMMERS_0),
VERACS_HELM_25(ItemID.VERACS_HELM_25, 2500, ItemID.VERACS_HELM_0),
VERACS_HELM_50(ItemID.VERACS_HELM_50, 5000, ItemID.VERACS_HELM_0),
VERACS_HELM_75(ItemID.VERACS_HELM_75, 7500, ItemID.VERACS_HELM_0),
VERACS_HELM_100(ItemID.VERACS_HELM_100, 10000, ItemID.VERACS_HELM_0),
VERACS_BRASSARD_25(ItemID.VERACS_BRASSARD_25, 2500, ItemID.VERACS_BRASSARD_0),
VERACS_BRASSARD_50(ItemID.VERACS_BRASSARD_50, 5000, ItemID.VERACS_BRASSARD_0),
VERACS_BRASSARD_75(ItemID.VERACS_BRASSARD_75, 7500, ItemID.VERACS_BRASSARD_0),
VERACS_BRASSARD_100(ItemID.VERACS_BRASSARD_100, 10000, ItemID.VERACS_BRASSARD_0),
VERACS_PLATESKIRT_25(ItemID.VERACS_PLATESKIRT_25, 2500, ItemID.VERACS_PLATESKIRT_0),
VERACS_PLATESKIRT_50(ItemID.VERACS_PLATESKIRT_50, 5000, ItemID.VERACS_PLATESKIRT_0),
VERACS_PLATESKIRT_75(ItemID.VERACS_PLATESKIRT_75, 7500, ItemID.VERACS_PLATESKIRT_0),
VERACS_PLATESKIRT_100(ItemID.VERACS_PLATESKIRT_100, 10000, ItemID.VERACS_PLATESKIRT_0),
VERACS_FLAIL_25(ItemID.VERACS_FLAIL_25, 2500, ItemID.VERACS_FLAIL_0),
VERACS_FLAIL_50(ItemID.VERACS_FLAIL_50, 5000, ItemID.VERACS_FLAIL_0),
VERACS_FLAIL_75(ItemID.VERACS_FLAIL_75, 7500, ItemID.VERACS_FLAIL_0),
VERACS_FLAIL_100(ItemID.VERACS_FLAIL_100, 10000, ItemID.VERACS_FLAIL_0);
private final int itemId;
private final int offset;
private final int baseId;
private static final Map<Integer, FixedPriceItem> FIXED_ITEMS;
@@ -84,6 +232,18 @@ enum FixedPriceItem
FIXED_ITEMS = map.build();
}
FixedPriceItem(final int itemId, final int offset, final int baseId)
{
this.itemId = itemId;
this.offset = offset;
this.baseId = baseId;
}
FixedPriceItem(final int itemId, final int offset)
{
this(itemId, offset, -1);
}
@Nullable
static FixedPriceItem find(int itemId)
{

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Sean Dewar <https://github.com/seandewar>
* Copyright (c) 2019, TheStonedTurtle <https://github.com/TheStonedTurtle>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -22,22 +22,15 @@
* (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.runenergy;
package net.runelite.client.plugins.itemskeptondeath;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
import lombok.AllArgsConstructor;
import lombok.Data;
@ConfigGroup("runenergy")
public interface RunEnergyConfig extends Config
@Data
@AllArgsConstructor
class ItemStack
{
@ConfigItem(
keyName = "replaceOrbText",
name = "Replace orb text with run time left",
description = "Show the remaining run time (in seconds) next in the energy orb."
)
default boolean replaceOrbText()
{
return false;
}
private int id;
private int qty;
}

View File

@@ -25,6 +25,7 @@
*/
package net.runelite.client.plugins.itemskeptondeath;
import com.google.common.annotations.VisibleForTesting;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -32,8 +33,11 @@ import java.util.EnumSet;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.Constants;
@@ -55,6 +59,7 @@ 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.ItemMapping;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.util.StackFormatter;
@@ -71,6 +76,16 @@ public class ItemsKeptOnDeathPlugin extends Plugin
private static final int DEEP_WILDY = 20;
private static final Pattern WILDERNESS_LEVEL_PATTERN = Pattern.compile("^Level: (\\d+).*");
@AllArgsConstructor
@Getter
@VisibleForTesting
static class DeathItems
{
private final List<ItemStack> keptItems;
private final List<ItemStack> lostItems;
private final boolean hasAlwaysLost;
}
// Item Container helpers
private static final int MAX_ROW_ITEMS = 8;
private static final int ITEM_X_OFFSET = 5;
@@ -100,9 +115,12 @@ public class ItemsKeptOnDeathPlugin extends Plugin
private WidgetButton deepWildyButton;
private WidgetButton lowWildyButton;
private boolean isSkulled;
private boolean protectingItem;
private int wildyLevel;
@VisibleForTesting
boolean isSkulled;
@VisibleForTesting
boolean protectingItem;
@VisibleForTesting
int wildyLevel;
@Subscribe
public void onScriptCallbackEvent(ScriptCallbackEvent event)
@@ -225,97 +243,12 @@ public class ItemsKeptOnDeathPlugin extends Plugin
final ItemContainer equipment = client.getItemContainer(InventoryID.EQUIPMENT);
final Item[] equip = equipment == null ? new Item[0] : equipment.getItems();
final List<Item> items = new ArrayList<>();
Collections.addAll(items, inv);
Collections.addAll(items, equip);
final DeathItems deathItems = calculateKeptLostItems(inv, equip);
// Sort by item price
items.sort(Comparator.comparing(this::getDeathPrice).reversed());
boolean hasAlwaysLost = false;
int keepCount = getDefaultItemsKept();
final List<Widget> keptItems = new ArrayList<>();
final List<Widget> lostItems = new ArrayList<>();
for (final Item i : items)
{
final int id = i.getId();
int itemQuantity = i.getQuantity();
if (id == -1)
{
continue;
}
final ItemDefinition c = itemManager.getItemDefinition(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);
}
}
final List<Widget> keptItems = deathItems.getKeptItems().stream()
.map(item -> createItemWidget(kept, item, true)).collect(Collectors.toList());
final List<Widget> lostItems = deathItems.getLostItems().stream()
.map(item -> createItemWidget(lost, item, false)).collect(Collectors.toList());
int rows = (keptItems.size() + MAX_ROW_ITEMS - 1) / MAX_ROW_ITEMS;
// Show an empty row if there isn't anything
@@ -330,36 +263,209 @@ public class ItemsKeptOnDeathPlugin extends Plugin
positionWidgetItems(kept, keptItems);
positionWidgetItems(lost, lostItems);
updateKeptWidgetInfoText(hasAlwaysLost, keptItems, lostItems);
updateKeptWidgetInfoText(deathItems.isHasAlwaysLost(), keptItems, lostItems);
}
/**
* Calculates which items will be kept/lost. first list is kept items, second is lost.
*
* @param inv players inventory
* @param equip players equipement
* @return list of items kept followed by a list of items lost
*/
@VisibleForTesting
DeathItems calculateKeptLostItems(final Item[] inv, final Item[] equip)
{
final List<Item> items = new ArrayList<>();
Collections.addAll(items, inv);
Collections.addAll(items, equip);
// Sort by item price
items.sort(Comparator.comparing(this::getDeathPrice).reversed());
boolean hasClueBox = false;
boolean hasAlwaysLost = false;
int keepCount = getDefaultItemsKept();
final List<ItemStack> keptItems = new ArrayList<>();
final List<ItemStack> lostItems = new ArrayList<>();
for (final Item i : items)
{
final int id = i.getId();
int qty = i.getQuantity();
if (id == -1)
{
continue;
}
final ItemDefinition c = itemManager.getItemDefinition(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)
{
keptItems.add(new ItemStack(id, qty));
continue;
}
final AlwaysLostItem alwaysLostItem = AlwaysLostItem.getByItemID(id);
if (alwaysLostItem != null && (!alwaysLostItem.isKeptOutsideOfWilderness() || wildyLevel > 0))
{
hasAlwaysLost = true;
hasClueBox = hasClueBox || id == ItemID.CLUE_BOX;
lostItems.add(new ItemStack(id, qty));
continue;
}
if (keepCount > 0)
{
// Keep most valuable items regardless of trade-ability.
if (i.getQuantity() > keepCount)
{
keptItems.add(new ItemStack(id, keepCount));
qty -= keepCount;
keepCount = 0;
// Fall through to determine if the rest of the stack should drop
}
else
{
keptItems.add(new ItemStack(id, qty));
keepCount -= qty;
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)
&& !LostIfNotProtected.isLostIfNotProtected(id)
&& !isTradeable(itemManager.getItemDefinition(id)) && wildyLevel <= DEEP_WILDY
&& (wildyLevel <= 0 || BrokenOnDeathItem.isBrokenOnDeath(i.getId())))
{
keptItems.add(new ItemStack(id, qty));
}
else
{
// Otherwise, the item is lost
lostItems.add(new ItemStack(id, qty));
}
}
if (hasClueBox)
{
boolean alreadyProtectingClue = false;
for (final ItemStack item : keptItems)
{
if (isClueBoxable(item.getId()))
{
alreadyProtectingClue = true;
break;
}
}
if (!alreadyProtectingClue)
{
int clueId = -1;
// Clue box protects the last clue in your inventory so loop over the players inv
for (final Item i : inv)
{
final int id = i.getId();
if (id != -1 && isClueBoxable(id))
{
clueId = id;
}
}
if (clueId != -1)
{
// Move the boxed item to the kept items container and remove it from the lost items container
for (final ItemStack boxableItem : lostItems)
{
if (boxableItem.getId() == clueId)
{
if (boxableItem.getQty() > 1)
{
boxableItem.setQty(boxableItem.getQty() - 1);
keptItems.add(new ItemStack(clueId, 1));
}
else
{
lostItems.remove(boxableItem);
keptItems.add(boxableItem);
}
break;
}
}
}
}
}
return new DeathItems(keptItems, lostItems, hasAlwaysLost);
}
@VisibleForTesting
boolean isClueBoxable(final int itemID)
{
final String name = itemManager.getItemDefinition(itemID).getName();
return name.contains("Clue scroll (") || name.contains("Reward casket (");
}
/**
* Get the price of an item
*
* @param item
* @return
*/
private int getDeathPrice(Item item)
@VisibleForTesting
int getDeathPrice(Item item)
{
// 1) Check if the death price is dynamically calculated, if so return that value
// 2) If death price is based off another item default to that price, otherwise apply normal ItemMapping GE price
// 3) If still no price, default to store price
// 4) Apply fixed price offset if applicable
int itemId = item.getId();
// Unnote/unplaceholder item
int canonicalizedItemId = itemManager.canonicalize(itemId);
int exchangePrice = itemManager.getItemPrice(canonicalizedItemId);
int exchangePrice = 0;
final DynamicPriceItem dynamicPrice = DynamicPriceItem.find(canonicalizedItemId);
if (dynamicPrice != null)
{
final ItemDefinition c1 = itemManager.getItemDefinition(canonicalizedItemId);
exchangePrice = c1.getPrice();
final int basePrice = itemManager.getItemPrice(dynamicPrice.getChargedId(), true);
return dynamicPrice.calculateDeathPrice(basePrice);
}
// Some items have artificially offset death prices - such as ring imbues
// which are +2k over the non imbues. Check if the item has a fixed price offset
final FixedPriceItem fixedPrice = FixedPriceItem.find(canonicalizedItemId);
if (fixedPrice != null && fixedPrice.getBaseId() != -1)
{
// Grab base item price
exchangePrice = itemManager.getItemPrice(fixedPrice.getBaseId(), true);
}
else
{
// Account for items whose death value comes from their tradeable variant (barrows) or components (ornate kits)
for (final int mappedID : ItemMapping.map(canonicalizedItemId))
{
exchangePrice += itemManager.getItemPrice(mappedID, true);
}
}
if (exchangePrice == 0)
{
final ItemDefinition c1 = itemManager.getItemDefinition(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();
}
}
// Apply fixed price offset
exchangePrice += fixedPrice == null ? 0 : fixedPrice.getOffset();
return exchangePrice;
}
@@ -591,21 +697,29 @@ public class ItemsKeptOnDeathPlugin extends Plugin
/**
* Creates an Item Widget for use inside the Kept on Death Interface
*
* @param qty Amount of item
* @param c Items Composition
* @return
* @param parent Widget to add element too as a child
* @param item the TempItem representing the item
* @param kept is the item being shown in the kept items container
* @return the Widget that was added to the `parent`
*/
private static Widget createItemWidget(final Widget parent, final int qty, final ItemDefinition c)
private Widget createItemWidget(final Widget parent, final ItemStack item, boolean kept)
{
final int id = item.getId();
final int qty = item.getQty();
final ItemDefinition c = itemManager.getItemDefinition(id);
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.setItemId(id);
itemWidget.setItemQuantity(qty);
itemWidget.setAction(1, String.format("Item: <col=ff981f>%s", c.getName()));
itemWidget.setOnOpListener(ScriptID.DEATH_KEEP_ITEM_EXAMINE, kept ? 1 : 0, qty, c.getName());
itemWidget.setHasListener(true);
final AlwaysLostItem alwaysLostItem = AlwaysLostItem.getByItemID(id);
final boolean whiteBorder = alwaysLostItem != null && (!alwaysLostItem.isKeptOutsideOfWilderness() || wildyLevel > 0);
itemWidget.setBorderType(whiteBorder ? 2 : 1);
return itemWidget;
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (c) 2019, TheStonedTurtle <https://github.com/TheStonedTurtle>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.itemskeptondeath;
import com.google.common.collect.ImmutableSet;
import java.util.Set;
import net.runelite.api.ItemID;
final class LostIfNotProtected
{
private static final Set<Integer> ITEMS = ImmutableSet.of(
ItemID.AMULET_OF_THE_DAMNED,
ItemID.RING_OF_CHAROS, ItemID.RING_OF_CHAROSA,
ItemID.LUNAR_STAFF,
ItemID.SHADOW_SWORD,
ItemID.KERIS, ItemID.KERISP, ItemID.KERISP_10583, ItemID.KERISP_10584
);
public static boolean isLostIfNotProtected(int id)
{
return ITEMS.contains(id);
}
}

View File

@@ -103,10 +103,153 @@ public interface KeyRemappingConfig extends Config
position = 6,
keyName = "fkeyRemap",
name = "Remap F Keys",
description = "Configures whether F-Keys are Remapped to 1 (F1) through 0 (F10), '-' (F11), and '=' (F12)"
description = "Configures whether F-Keys use remapped keys"
)
default boolean fkeyRemap()
{
return false;
}
@ConfigItem(
position = 7,
keyName = "f1",
name = "F1",
description = "The key which will replace {F1}."
)
default ModifierlessKeybind f1()
{
return new ModifierlessKeybind(KeyEvent.VK_1, 0);
}
@ConfigItem(
position = 8,
keyName = "f2",
name = "F2",
description = "The key which will replace {F2}."
)
default ModifierlessKeybind f2()
{
return new ModifierlessKeybind(KeyEvent.VK_2, 0);
}
@ConfigItem(
position = 9,
keyName = "f3",
name = "F3",
description = "The key which will replace {F3}."
)
default ModifierlessKeybind f3()
{
return new ModifierlessKeybind(KeyEvent.VK_3, 0);
}
@ConfigItem(
position = 10,
keyName = "f4",
name = "F4",
description = "The key which will replace {F4}."
)
default ModifierlessKeybind f4()
{
return new ModifierlessKeybind(KeyEvent.VK_4, 0);
}
@ConfigItem(
position = 11,
keyName = "f5",
name = "F5",
description = "The key which will replace {F5}."
)
default ModifierlessKeybind f5()
{
return new ModifierlessKeybind(KeyEvent.VK_5, 0);
}
@ConfigItem(
position = 12,
keyName = "f6",
name = "F6",
description = "The key which will replace {F6}."
)
default ModifierlessKeybind f6()
{
return new ModifierlessKeybind(KeyEvent.VK_6, 0);
}
@ConfigItem(
position = 13,
keyName = "f7",
name = "F7",
description = "The key which will replace {F7}."
)
default ModifierlessKeybind f7()
{
return new ModifierlessKeybind(KeyEvent.VK_7, 0);
}
@ConfigItem(
position = 14,
keyName = "f8",
name = "F8",
description = "The key which will replace {F8}."
)
default ModifierlessKeybind f8()
{
return new ModifierlessKeybind(KeyEvent.VK_8, 0);
}
@ConfigItem(
position = 15,
keyName = "f9",
name = "F9",
description = "The key which will replace {F9}."
)
default ModifierlessKeybind f9()
{
return new ModifierlessKeybind(KeyEvent.VK_9, 0);
}
@ConfigItem(
position = 16,
keyName = "f10",
name = "F10",
description = "The key which will replace {F10}."
)
default ModifierlessKeybind f10()
{
return new ModifierlessKeybind(KeyEvent.VK_0, 0);
}
@ConfigItem(
position = 17,
keyName = "f11",
name = "F11",
description = "The key which will replace {F11}."
)
default ModifierlessKeybind f11()
{
return new ModifierlessKeybind(KeyEvent.VK_MINUS, 0);
}
@ConfigItem(
position = 18,
keyName = "f12",
name = "F12",
description = "The key which will replace {F12}."
)
default ModifierlessKeybind f12()
{
return new ModifierlessKeybind(KeyEvent.VK_EQUALS, 0);
}
@ConfigItem(
position = 19,
keyName = "esc",
name = "ESC",
description = "The key which will replace {ESC}."
)
default ModifierlessKeybind esc()
{
return new ModifierlessKeybind(KeyEvent.VK_ESCAPE, 0);
}
}

View File

@@ -35,30 +35,19 @@ import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.VarClientStr;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.config.Keybind;
import net.runelite.client.config.ModifierlessKeybind;
import net.runelite.client.input.KeyListener;
import net.runelite.client.input.MouseAdapter;
@Singleton
class KeyRemappingListener extends MouseAdapter implements KeyListener
{
private static final Keybind ONE = new ModifierlessKeybind(KeyEvent.VK_1, 0);
private static final Keybind TWO = new ModifierlessKeybind(KeyEvent.VK_2, 0);
private static final Keybind THREE = new ModifierlessKeybind(KeyEvent.VK_3, 0);
private static final Keybind FOUR = new ModifierlessKeybind(KeyEvent.VK_4, 0);
private static final Keybind FIVE = new ModifierlessKeybind(KeyEvent.VK_5, 0);
private static final Keybind SIX = new ModifierlessKeybind(KeyEvent.VK_6, 0);
private static final Keybind SEVEN = new ModifierlessKeybind(KeyEvent.VK_7, 0);
private static final Keybind EIGHT = new ModifierlessKeybind(KeyEvent.VK_8, 0);
private static final Keybind NINE = new ModifierlessKeybind(KeyEvent.VK_9, 0);
private static final Keybind ZERO = new ModifierlessKeybind(KeyEvent.VK_0, 0);
private static final Keybind MINUS = new ModifierlessKeybind(KeyEvent.VK_MINUS, 0);
private static final Keybind EQUALS = new ModifierlessKeybind(KeyEvent.VK_EQUALS, 0);
@Inject
private KeyRemappingPlugin plugin;
@Inject
private KeyRemappingConfig config;
@Inject
private Client client;
@@ -111,66 +100,71 @@ class KeyRemappingListener extends MouseAdapter implements KeyListener
// to select options
if (plugin.isFkeyRemap() && !plugin.isDialogOpen())
{
if (ONE.matches(e))
if (config.f1().matches(e))
{
modified.put(e.getKeyCode(), KeyEvent.VK_F1);
e.setKeyCode(KeyEvent.VK_F1);
}
else if (TWO.matches(e))
else if (config.f2().matches(e))
{
modified.put(e.getKeyCode(), KeyEvent.VK_F2);
e.setKeyCode(KeyEvent.VK_F2);
}
else if (THREE.matches(e))
else if (config.f3().matches(e))
{
modified.put(e.getKeyCode(), KeyEvent.VK_F3);
e.setKeyCode(KeyEvent.VK_F3);
}
else if (FOUR.matches(e))
else if (config.f4().matches(e))
{
modified.put(e.getKeyCode(), KeyEvent.VK_F4);
e.setKeyCode(KeyEvent.VK_F4);
}
else if (FIVE.matches(e))
else if (config.f5().matches(e))
{
modified.put(e.getKeyCode(), KeyEvent.VK_F5);
e.setKeyCode(KeyEvent.VK_F5);
}
else if (SIX.matches(e))
else if (config.f6().matches(e))
{
modified.put(e.getKeyCode(), KeyEvent.VK_F6);
e.setKeyCode(KeyEvent.VK_F6);
}
else if (SEVEN.matches(e))
else if (config.f7().matches(e))
{
modified.put(e.getKeyCode(), KeyEvent.VK_F7);
e.setKeyCode(KeyEvent.VK_F7);
}
else if (EIGHT.matches(e))
else if (config.f8().matches(e))
{
modified.put(e.getKeyCode(), KeyEvent.VK_F8);
e.setKeyCode(KeyEvent.VK_F8);
}
else if (NINE.matches(e))
else if (config.f9().matches(e))
{
modified.put(e.getKeyCode(), KeyEvent.VK_F9);
e.setKeyCode(KeyEvent.VK_F9);
}
else if (ZERO.matches(e))
else if (config.f10().matches(e))
{
modified.put(e.getKeyCode(), KeyEvent.VK_F10);
e.setKeyCode(KeyEvent.VK_F10);
}
else if (MINUS.matches(e))
else if (config.f11().matches(e))
{
modified.put(e.getKeyCode(), KeyEvent.VK_F11);
e.setKeyCode(KeyEvent.VK_F11);
}
else if (EQUALS.matches(e))
else if (config.f12().matches(e))
{
modified.put(e.getKeyCode(), KeyEvent.VK_F12);
e.setKeyCode(KeyEvent.VK_F12);
}
else if (config.esc().matches(e))
{
modified.put(e.getKeyCode(), KeyEvent.VK_ESCAPE);
e.setKeyCode(KeyEvent.VK_ESCAPE);
}
}
switch (e.getKeyCode())
@@ -189,8 +183,12 @@ class KeyRemappingListener extends MouseAdapter implements KeyListener
{
switch (e.getKeyCode())
{
case KeyEvent.VK_ENTER:
case KeyEvent.VK_ESCAPE:
// When existing typing mode, block the escape key
// so that it doesn't trigger the in-game hotkeys
e.consume();
// FALLTHROUGH
case KeyEvent.VK_ENTER:
plugin.setTyping(false);
clientThread.invoke(plugin::lockChat);
break;
@@ -240,54 +238,58 @@ class KeyRemappingListener extends MouseAdapter implements KeyListener
if (plugin.isFkeyRemap())
{
if (ONE.matches(e))
if (config.f1().matches(e))
{
e.setKeyCode(KeyEvent.VK_F1);
}
else if (TWO.matches(e))
else if (config.f2().matches(e))
{
e.setKeyCode(KeyEvent.VK_F2);
}
else if (THREE.matches(e))
else if (config.f3().matches(e))
{
e.setKeyCode(KeyEvent.VK_F3);
}
else if (FOUR.matches(e))
else if (config.f4().matches(e))
{
e.setKeyCode(KeyEvent.VK_F4);
}
else if (FIVE.matches(e))
else if (config.f5().matches(e))
{
e.setKeyCode(KeyEvent.VK_F5);
}
else if (SIX.matches(e))
else if (config.f6().matches(e))
{
e.setKeyCode(KeyEvent.VK_F6);
}
else if (SEVEN.matches(e))
else if (config.f7().matches(e))
{
e.setKeyCode(KeyEvent.VK_F7);
}
else if (EIGHT.matches(e))
else if (config.f8().matches(e))
{
e.setKeyCode(KeyEvent.VK_F8);
}
else if (NINE.matches(e))
else if (config.f9().matches(e))
{
e.setKeyCode(KeyEvent.VK_F9);
}
else if (ZERO.matches(e))
else if (config.f10().matches(e))
{
e.setKeyCode(KeyEvent.VK_F10);
}
else if (MINUS.matches(e))
else if (config.f11().matches(e))
{
e.setKeyCode(KeyEvent.VK_F11);
}
else if (EQUALS.matches(e))
else if (config.f12().matches(e))
{
e.setKeyCode(KeyEvent.VK_F12);
}
else if (config.esc().matches(e))
{
e.setKeyCode(KeyEvent.VK_ESCAPE);
}
}
}
else

View File

@@ -34,7 +34,6 @@ import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Actor;
import static net.runelite.api.AnimationID.LIZARDMAN_SHAMAN_SPAWN;
import net.runelite.api.ChatMessageType;
import net.runelite.api.coords.LocalPoint;
import net.runelite.api.events.AnimationChanged;
import net.runelite.api.events.ChatMessage;
@@ -104,7 +103,8 @@ public class LizardmenShamanPlugin extends Plugin
@Subscribe
public void onChatMessage(ChatMessage event)
{
if (this.notifyOnSpawn && event.getType() == ChatMessageType.GAMEMESSAGE && event.getMessage().contains(MESSAGE))
if (this.notifyOnSpawn && /* event.getType() == ChatMessageType.GAMEMESSAGE && */event.getMessage().contains(MESSAGE))
// ChatMessageType should probably be SPAM <- should be tested first though
{
notifier.notify(MESSAGE);
}

View File

@@ -1,126 +0,0 @@
/*
* 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.regenmeter;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.geom.Arc2D;
import javax.inject.Inject;
import javax.inject.Singleton;
import net.runelite.api.Client;
import net.runelite.api.VarPlayer;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer;
import net.runelite.client.ui.overlay.OverlayPosition;
@Singleton
public class RegenMeterOverlay extends Overlay
{
private static final Color HITPOINTS_COLOR = brighter(0x9B0703);
private static final Color SPECIAL_COLOR = brighter(0x1E95B0);
private static final Color OVERLAY_COLOR = new Color(255, 255, 255, 60);
private static final double DIAMETER = 26D;
private static final int OFFSET = 27;
private static final Stroke STROKE = new BasicStroke(2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER);
private final Client client;
private final RegenMeterPlugin plugin;
private Rectangle getBounds(WidgetInfo widgetInfo)
{
Widget widget = client.getWidget(widgetInfo);
if (widget == null || widget.isHidden())
{
return null;
}
return widget.getBounds();
}
private static Color brighter(int color)
{
float[] hsv = new float[3];
Color.RGBtoHSB(color >>> 16, (color >> 8) & 0xFF, color & 0xFF, hsv);
return Color.getHSBColor(hsv[0], 1.f, 1.f);
}
@Inject
public RegenMeterOverlay(final Client client, final RegenMeterPlugin plugin)
{
setPosition(OverlayPosition.DYNAMIC);
setLayer(OverlayLayer.ABOVE_WIDGETS);
this.client = client;
this.plugin = plugin;
}
@Override
public Dimension render(Graphics2D g)
{
g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
if (plugin.isShowHitpoints())
{
renderRegen(g, WidgetInfo.MINIMAP_HEALTH_ORB, plugin.getHitpointsPercentage(), HITPOINTS_COLOR);
}
if (plugin.isShowSpecial())
{
if (client.getVar(VarPlayer.SPECIAL_ATTACK_ENABLED) == 1)
{
final Rectangle bounds = getBounds(WidgetInfo.MINIMAP_SPEC_ORB);
if (bounds != null)
{
g.setColor(RegenMeterOverlay.OVERLAY_COLOR);
g.fillOval(
bounds.x + OFFSET,
bounds.y + (int) (bounds.height / 2D - (DIAMETER) / 2D),
(int) DIAMETER, (int) DIAMETER);
}
}
renderRegen(g, WidgetInfo.MINIMAP_SPEC_ORB, plugin.getSpecialPercentage(), SPECIAL_COLOR);
}
return null;
}
private void renderRegen(Graphics2D g, WidgetInfo widgetInfo, double percent, Color color)
{
final Rectangle bounds = getBounds(widgetInfo);
if (bounds != null)
{
Arc2D.Double arc = new Arc2D.Double(bounds.x + OFFSET, bounds.y + (bounds.height / 2 - DIAMETER / 2), DIAMETER, DIAMETER, 90.d, -360.d * percent, Arc2D.OPEN);
g.setStroke(STROKE);
g.setColor(color);
g.draw(arc);
}
}
}

View File

@@ -1,201 +0,0 @@
/*
* Copyright (c) 2019, Sean Dewar <https://github.com/seandewar>
* Copyright (c) 2018, Abex
* Copyright (c) 2018, Zimaya <https://github.com/Zimaya>
* Copyright (c) 2017, Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.regenmeter;
import com.google.inject.Provides;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.AccessLevel;
import lombok.Getter;
import net.runelite.api.Client;
import net.runelite.api.Constants;
import net.runelite.api.GameState;
import net.runelite.api.Prayer;
import net.runelite.api.Skill;
import net.runelite.api.VarPlayer;
import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.GameTick;
import net.runelite.api.events.VarbitChanged;
import net.runelite.client.Notifier;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.overlay.OverlayManager;
@PluginDescriptor(
name = "Regeneration Meter",
description = "Track and show the hitpoints and special attack regeneration timers",
tags = {"combat", "health", "hitpoints", "special", "attack", "overlay", "notifications"}
)
@Singleton
public class RegenMeterPlugin extends Plugin
{
private static final int SPEC_REGEN_TICKS = 50;
private static final int NORMAL_HP_REGEN_TICKS = 100;
@Inject
private Client client;
@Inject
private OverlayManager overlayManager;
@Inject
private Notifier notifier;
@Inject
private RegenMeterOverlay overlay;
@Inject
private RegenMeterConfig config;
@Getter(AccessLevel.PACKAGE)
private double hitpointsPercentage;
@Getter(AccessLevel.PACKAGE)
private double specialPercentage;
private int ticksSinceSpecRegen;
private int ticksSinceHPRegen;
private boolean wasRapidHeal;
@Getter(AccessLevel.PACKAGE)
private boolean showHitpoints;
@Getter(AccessLevel.PACKAGE)
private boolean showSpecial;
private boolean showWhenNoChange;
private int getNotifyBeforeHpRegenSeconds;
@Provides
RegenMeterConfig provideConfig(ConfigManager configManager)
{
return configManager.getConfig(RegenMeterConfig.class);
}
@Override
protected void startUp() throws Exception
{
updateConfig();
overlayManager.add(overlay);
}
@Override
protected void shutDown() throws Exception
{
overlayManager.remove(overlay);
}
@Subscribe
private void onGameStateChanged(GameStateChanged ev)
{
if (ev.getGameState() == GameState.HOPPING || ev.getGameState() == GameState.LOGIN_SCREEN)
{
ticksSinceHPRegen = -2; // For some reason this makes this accurate
ticksSinceSpecRegen = 0;
}
}
@Subscribe
private void onVarbitChanged(VarbitChanged ev)
{
boolean isRapidHeal = client.isPrayerActive(Prayer.RAPID_HEAL);
if (wasRapidHeal != isRapidHeal)
{
ticksSinceHPRegen = 0;
}
wasRapidHeal = isRapidHeal;
}
@Subscribe
public void onGameTick(GameTick event)
{
if (client.getVar(VarPlayer.SPECIAL_ATTACK_PERCENT) == 1000)
{
// The recharge doesn't tick when at 100%
ticksSinceSpecRegen = 0;
}
else
{
ticksSinceSpecRegen = (ticksSinceSpecRegen + 1) % SPEC_REGEN_TICKS;
}
specialPercentage = ticksSinceSpecRegen / (double) SPEC_REGEN_TICKS;
int ticksPerHPRegen = NORMAL_HP_REGEN_TICKS;
if (client.isPrayerActive(Prayer.RAPID_HEAL))
{
ticksPerHPRegen /= 2;
}
ticksSinceHPRegen = (ticksSinceHPRegen + 1) % ticksPerHPRegen;
hitpointsPercentage = ticksSinceHPRegen / (double) ticksPerHPRegen;
int currentHP = client.getBoostedSkillLevel(Skill.HITPOINTS);
int maxHP = client.getRealSkillLevel(Skill.HITPOINTS);
if (currentHP == maxHP && !this.showWhenNoChange)
{
hitpointsPercentage = 0;
}
else if (currentHP > maxHP)
{
// Show it going down
hitpointsPercentage = 1 - hitpointsPercentage;
}
if (this.getNotifyBeforeHpRegenSeconds > 0 && currentHP < maxHP && shouldNotifyHpRegenThisTick(ticksPerHPRegen))
{
notifier.notify("[" + client.getLocalPlayer().getName() + "] regenerates their next hitpoint soon!");
}
}
private boolean shouldNotifyHpRegenThisTick(int ticksPerHPRegen)
{
// if the configured duration lies between two ticks, choose the earlier tick
final int ticksBeforeHPRegen = ticksPerHPRegen - ticksSinceHPRegen;
final int notifyTick = (int) Math.ceil(this.getNotifyBeforeHpRegenSeconds * 1000d / Constants.GAME_TICK_LENGTH);
return ticksBeforeHPRegen == notifyTick;
}
@Subscribe
public void onConfigChanged(ConfigChanged event)
{
if (event.getGroup().equals("regenmeter"))
{
updateConfig();
}
}
private void updateConfig()
{
this.showHitpoints = config.showHitpoints();
this.showSpecial = config.showSpecial();
this.showWhenNoChange = config.showWhenNoChange();
this.getNotifyBeforeHpRegenSeconds = config.getNotifyBeforeHpRegenSeconds();
}
}

View File

@@ -1,109 +0,0 @@
/*
* Copyright (c) 2018, Sean Dewar <https://github.com/seandewar>
* 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.runenergy;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.inject.Inject;
import javax.inject.Singleton;
import net.runelite.api.Client;
import net.runelite.api.Point;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer;
import net.runelite.client.ui.overlay.OverlayPosition;
import net.runelite.client.ui.overlay.tooltip.Tooltip;
import net.runelite.client.ui.overlay.tooltip.TooltipManager;
import org.apache.commons.lang3.StringUtils;
@Singleton
class RunEnergyOverlay extends Overlay
{
private final RunEnergyPlugin plugin;
private final Client client;
private final RunEnergyConfig config;
private final TooltipManager tooltipManager;
@Inject
private RunEnergyOverlay(final RunEnergyPlugin plugin, final Client client, final RunEnergyConfig config, final TooltipManager tooltipManager)
{
this.plugin = plugin;
this.client = client;
this.config = config;
this.tooltipManager = tooltipManager;
setPosition(OverlayPosition.DYNAMIC);
setLayer(OverlayLayer.ABOVE_WIDGETS);
}
@Override
public Dimension render(Graphics2D graphics)
{
final Widget runOrb = client.getWidget(WidgetInfo.MINIMAP_TOGGLE_RUN_ORB);
if (runOrb == null || runOrb.isHidden())
{
return null;
}
final Rectangle bounds = runOrb.getBounds();
if (bounds.getX() <= 0)
{
return null;
}
final Point mousePosition = client.getMouseCanvasPosition();
if (bounds.contains(mousePosition.getX(), mousePosition.getY()))
{
StringBuilder sb = new StringBuilder();
sb.append("Weight: ").append(client.getWeight()).append(" kg</br>");
if (config.replaceOrbText())
{
sb.append("Run Energy: ").append(client.getEnergy()).append("%");
}
else
{
sb.append("Run Time Remaining: ").append(plugin.getEstimatedRunTimeRemaining(false));
}
int secondsUntil100 = plugin.getEstimatedRecoverTimeRemaining();
if (secondsUntil100 > 0)
{
final int minutes = (int) Math.floor(secondsUntil100 / 60.0);
final int seconds = (int) Math.floor(secondsUntil100 - (minutes * 60.0));
sb.append("</br>").append("100% Energy In: ").append(minutes).append(':').append(StringUtils.leftPad(Integer.toString(seconds), 2, "0"));
}
tooltipManager.add(new Tooltip(sb.toString()));
}
return null;
}
}

View File

@@ -1,340 +0,0 @@
/*
* Copyright (c) 2018, Sean Dewar <https://github.com/seandewar>
* 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.runenergy;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Provides;
import javax.inject.Inject;
import javax.inject.Singleton;
import net.runelite.api.Client;
import net.runelite.api.Constants;
import net.runelite.api.EquipmentInventorySlot;
import net.runelite.api.InventoryID;
import net.runelite.api.Item;
import net.runelite.api.ItemContainer;
import static net.runelite.api.ItemID.AGILITY_CAPE;
import static net.runelite.api.ItemID.AGILITY_CAPET;
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_11861;
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13589;
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13590;
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13601;
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13602;
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13613;
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13614;
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13625;
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13626;
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13637;
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13638;
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13677;
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13678;
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_21076;
import static net.runelite.api.ItemID.GRACEFUL_BOOTS_21078;
import static net.runelite.api.ItemID.GRACEFUL_CAPE_11853;
import static net.runelite.api.ItemID.GRACEFUL_CAPE_13581;
import static net.runelite.api.ItemID.GRACEFUL_CAPE_13582;
import static net.runelite.api.ItemID.GRACEFUL_CAPE_13593;
import static net.runelite.api.ItemID.GRACEFUL_CAPE_13594;
import static net.runelite.api.ItemID.GRACEFUL_CAPE_13605;
import static net.runelite.api.ItemID.GRACEFUL_CAPE_13606;
import static net.runelite.api.ItemID.GRACEFUL_CAPE_13617;
import static net.runelite.api.ItemID.GRACEFUL_CAPE_13618;
import static net.runelite.api.ItemID.GRACEFUL_CAPE_13629;
import static net.runelite.api.ItemID.GRACEFUL_CAPE_13630;
import static net.runelite.api.ItemID.GRACEFUL_CAPE_13669;
import static net.runelite.api.ItemID.GRACEFUL_CAPE_13670;
import static net.runelite.api.ItemID.GRACEFUL_CAPE_21064;
import static net.runelite.api.ItemID.GRACEFUL_CAPE_21066;
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_11859;
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13587;
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13588;
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13599;
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13600;
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13611;
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13612;
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13623;
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13624;
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13635;
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13636;
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13675;
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13676;
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_21073;
import static net.runelite.api.ItemID.GRACEFUL_GLOVES_21075;
import static net.runelite.api.ItemID.GRACEFUL_HOOD_11851;
import static net.runelite.api.ItemID.GRACEFUL_HOOD_13579;
import static net.runelite.api.ItemID.GRACEFUL_HOOD_13580;
import static net.runelite.api.ItemID.GRACEFUL_HOOD_13591;
import static net.runelite.api.ItemID.GRACEFUL_HOOD_13592;
import static net.runelite.api.ItemID.GRACEFUL_HOOD_13603;
import static net.runelite.api.ItemID.GRACEFUL_HOOD_13604;
import static net.runelite.api.ItemID.GRACEFUL_HOOD_13615;
import static net.runelite.api.ItemID.GRACEFUL_HOOD_13616;
import static net.runelite.api.ItemID.GRACEFUL_HOOD_13627;
import static net.runelite.api.ItemID.GRACEFUL_HOOD_13628;
import static net.runelite.api.ItemID.GRACEFUL_HOOD_13667;
import static net.runelite.api.ItemID.GRACEFUL_HOOD_13668;
import static net.runelite.api.ItemID.GRACEFUL_HOOD_21061;
import static net.runelite.api.ItemID.GRACEFUL_HOOD_21063;
import static net.runelite.api.ItemID.GRACEFUL_LEGS_11857;
import static net.runelite.api.ItemID.GRACEFUL_LEGS_13585;
import static net.runelite.api.ItemID.GRACEFUL_LEGS_13586;
import static net.runelite.api.ItemID.GRACEFUL_LEGS_13597;
import static net.runelite.api.ItemID.GRACEFUL_LEGS_13598;
import static net.runelite.api.ItemID.GRACEFUL_LEGS_13609;
import static net.runelite.api.ItemID.GRACEFUL_LEGS_13610;
import static net.runelite.api.ItemID.GRACEFUL_LEGS_13621;
import static net.runelite.api.ItemID.GRACEFUL_LEGS_13622;
import static net.runelite.api.ItemID.GRACEFUL_LEGS_13633;
import static net.runelite.api.ItemID.GRACEFUL_LEGS_13634;
import static net.runelite.api.ItemID.GRACEFUL_LEGS_13673;
import static net.runelite.api.ItemID.GRACEFUL_LEGS_13674;
import static net.runelite.api.ItemID.GRACEFUL_LEGS_21070;
import static net.runelite.api.ItemID.GRACEFUL_LEGS_21072;
import static net.runelite.api.ItemID.GRACEFUL_TOP_11855;
import static net.runelite.api.ItemID.GRACEFUL_TOP_13583;
import static net.runelite.api.ItemID.GRACEFUL_TOP_13584;
import static net.runelite.api.ItemID.GRACEFUL_TOP_13595;
import static net.runelite.api.ItemID.GRACEFUL_TOP_13596;
import static net.runelite.api.ItemID.GRACEFUL_TOP_13607;
import static net.runelite.api.ItemID.GRACEFUL_TOP_13608;
import static net.runelite.api.ItemID.GRACEFUL_TOP_13619;
import static net.runelite.api.ItemID.GRACEFUL_TOP_13620;
import static net.runelite.api.ItemID.GRACEFUL_TOP_13631;
import static net.runelite.api.ItemID.GRACEFUL_TOP_13632;
import static net.runelite.api.ItemID.GRACEFUL_TOP_13671;
import static net.runelite.api.ItemID.GRACEFUL_TOP_13672;
import static net.runelite.api.ItemID.GRACEFUL_TOP_21067;
import static net.runelite.api.ItemID.GRACEFUL_TOP_21069;
import static net.runelite.api.ItemID.MAX_CAPE;
import net.runelite.api.Skill;
import net.runelite.api.Varbits;
import net.runelite.api.coords.WorldPoint;
import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.GameTick;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.overlay.OverlayManager;
import org.apache.commons.lang3.StringUtils;
@PluginDescriptor(
name = "Run Energy",
description = "Show various information related to run energy",
tags = {"overlay", "stamina"}
)
@Singleton
public class RunEnergyPlugin extends Plugin
{
// TODO It would be nice if we have the IDs for just the equipped variants of the Graceful set items.
private static final ImmutableSet<Integer> ALL_GRACEFUL_HOODS = ImmutableSet.of(
GRACEFUL_HOOD_11851, GRACEFUL_HOOD_13579, GRACEFUL_HOOD_13580, GRACEFUL_HOOD_13591, GRACEFUL_HOOD_13592,
GRACEFUL_HOOD_13603, GRACEFUL_HOOD_13604, GRACEFUL_HOOD_13615, GRACEFUL_HOOD_13616, GRACEFUL_HOOD_13627,
GRACEFUL_HOOD_13628, GRACEFUL_HOOD_13667, GRACEFUL_HOOD_13668, GRACEFUL_HOOD_21061, GRACEFUL_HOOD_21063
);
private static final ImmutableSet<Integer> ALL_GRACEFUL_TOPS = ImmutableSet.of(
GRACEFUL_TOP_11855, GRACEFUL_TOP_13583, GRACEFUL_TOP_13584, GRACEFUL_TOP_13595, GRACEFUL_TOP_13596,
GRACEFUL_TOP_13607, GRACEFUL_TOP_13608, GRACEFUL_TOP_13619, GRACEFUL_TOP_13620, GRACEFUL_TOP_13631,
GRACEFUL_TOP_13632, GRACEFUL_TOP_13671, GRACEFUL_TOP_13672, GRACEFUL_TOP_21067, GRACEFUL_TOP_21069
);
private static final ImmutableSet<Integer> ALL_GRACEFUL_LEGS = ImmutableSet.of(
GRACEFUL_LEGS_11857, GRACEFUL_LEGS_13585, GRACEFUL_LEGS_13586, GRACEFUL_LEGS_13597, GRACEFUL_LEGS_13598,
GRACEFUL_LEGS_13609, GRACEFUL_LEGS_13610, GRACEFUL_LEGS_13621, GRACEFUL_LEGS_13622, GRACEFUL_LEGS_13633,
GRACEFUL_LEGS_13634, GRACEFUL_LEGS_13673, GRACEFUL_LEGS_13674, GRACEFUL_LEGS_21070, GRACEFUL_LEGS_21072
);
private static final ImmutableSet<Integer> ALL_GRACEFUL_GLOVES = ImmutableSet.of(
GRACEFUL_GLOVES_11859, GRACEFUL_GLOVES_13587, GRACEFUL_GLOVES_13588, GRACEFUL_GLOVES_13599, GRACEFUL_GLOVES_13600,
GRACEFUL_GLOVES_13611, GRACEFUL_GLOVES_13612, GRACEFUL_GLOVES_13623, GRACEFUL_GLOVES_13624, GRACEFUL_GLOVES_13635,
GRACEFUL_GLOVES_13636, GRACEFUL_GLOVES_13675, GRACEFUL_GLOVES_13676, GRACEFUL_GLOVES_21073, GRACEFUL_GLOVES_21075
);
private static final ImmutableSet<Integer> ALL_GRACEFUL_BOOTS = ImmutableSet.of(
GRACEFUL_BOOTS_11861, GRACEFUL_BOOTS_13589, GRACEFUL_BOOTS_13590, GRACEFUL_BOOTS_13601, GRACEFUL_BOOTS_13602,
GRACEFUL_BOOTS_13613, GRACEFUL_BOOTS_13614, GRACEFUL_BOOTS_13625, GRACEFUL_BOOTS_13626, GRACEFUL_BOOTS_13637,
GRACEFUL_BOOTS_13638, GRACEFUL_BOOTS_13677, GRACEFUL_BOOTS_13678, GRACEFUL_BOOTS_21076, GRACEFUL_BOOTS_21078
);
// Agility skill capes and the non-cosmetic Max capes also count for the Graceful set effect
private static final ImmutableSet<Integer> ALL_GRACEFUL_CAPES = ImmutableSet.of(
GRACEFUL_CAPE_11853, GRACEFUL_CAPE_13581, GRACEFUL_CAPE_13582, GRACEFUL_CAPE_13593, GRACEFUL_CAPE_13594,
GRACEFUL_CAPE_13605, GRACEFUL_CAPE_13606, GRACEFUL_CAPE_13617, GRACEFUL_CAPE_13618, GRACEFUL_CAPE_13629,
GRACEFUL_CAPE_13630, GRACEFUL_CAPE_13669, GRACEFUL_CAPE_13670, GRACEFUL_CAPE_21064, GRACEFUL_CAPE_21066,
AGILITY_CAPE, AGILITY_CAPET, MAX_CAPE
);
@Inject
private Client client;
@Inject
private OverlayManager overlayManager;
@Inject
private RunEnergyOverlay energyOverlay;
@Inject
private RunEnergyConfig energyConfig;
private boolean localPlayerRunningToDestination;
private WorldPoint prevLocalPlayerLocation;
@Provides
RunEnergyConfig getConfig(ConfigManager configManager)
{
return configManager.getConfig(RunEnergyConfig.class);
}
@Override
protected void startUp() throws Exception
{
overlayManager.add(energyOverlay);
}
@Override
protected void shutDown() throws Exception
{
overlayManager.remove(energyOverlay);
localPlayerRunningToDestination = false;
prevLocalPlayerLocation = null;
resetRunOrbText();
}
@Subscribe
public void onGameTick(GameTick event)
{
localPlayerRunningToDestination =
prevLocalPlayerLocation != null &&
client.getLocalDestinationLocation() != null &&
prevLocalPlayerLocation.distanceTo(client.getLocalPlayer().getWorldLocation()) > 1;
prevLocalPlayerLocation = client.getLocalPlayer().getWorldLocation();
if (energyConfig.replaceOrbText())
{
setRunOrbText(getEstimatedRunTimeRemaining(true));
}
}
@Subscribe
public void onConfigChanged(ConfigChanged event)
{
if (event.getGroup().equals("runenergy") && !energyConfig.replaceOrbText())
{
resetRunOrbText();
}
}
private void setRunOrbText(String text)
{
Widget runOrbText = client.getWidget(WidgetInfo.MINIMAP_RUN_ORB_TEXT);
if (runOrbText != null)
{
runOrbText.setText(text);
}
}
private void resetRunOrbText()
{
setRunOrbText(Integer.toString(client.getEnergy()));
}
String getEstimatedRunTimeRemaining(boolean inSeconds)
{
// Calculate the amount of energy lost every tick.
// Negative weight has the same depletion effect as 0 kg.
final int effectiveWeight = Math.max(client.getWeight(), 0);
double lossRate = (Math.min(effectiveWeight, 64) / 100.0) + 0.64;
if (client.getVar(Varbits.RUN_SLOWED_DEPLETION_ACTIVE) != 0)
{
lossRate *= 0.3; // Stamina effect reduces energy depletion to 30%
}
// Calculate the number of seconds left
final double secondsLeft = (client.getEnergy() * Constants.GAME_TICK_LENGTH) / (lossRate * 1000.0);
// Return the text
if (inSeconds)
{
return (int) Math.floor(secondsLeft) + "s";
}
else
{
final int minutes = (int) Math.floor(secondsLeft / 60.0);
final int seconds = (int) Math.floor(secondsLeft - (minutes * 60.0));
return minutes + ":" + StringUtils.leftPad(Integer.toString(seconds), 2, "0");
}
}
private boolean isLocalPlayerWearingFullGraceful()
{
final ItemContainer equipment = client.getItemContainer(InventoryID.EQUIPMENT);
if (equipment == null)
{
return false;
}
final Item[] items = equipment.getItems();
// Check that the local player is wearing enough items to be using full Graceful
// (the Graceful boots will have the highest slot index in the worn set).
if (items == null || items.length <= EquipmentInventorySlot.BOOTS.getSlotIdx())
{
return false;
}
return (ALL_GRACEFUL_HOODS.contains(items[EquipmentInventorySlot.HEAD.getSlotIdx()].getId()) &&
ALL_GRACEFUL_TOPS.contains(items[EquipmentInventorySlot.BODY.getSlotIdx()].getId()) &&
ALL_GRACEFUL_LEGS.contains(items[EquipmentInventorySlot.LEGS.getSlotIdx()].getId()) &&
ALL_GRACEFUL_GLOVES.contains(items[EquipmentInventorySlot.GLOVES.getSlotIdx()].getId()) &&
ALL_GRACEFUL_BOOTS.contains(items[EquipmentInventorySlot.BOOTS.getSlotIdx()].getId()) &&
ALL_GRACEFUL_CAPES.contains(items[EquipmentInventorySlot.CAPE.getSlotIdx()].getId()));
}
int getEstimatedRecoverTimeRemaining()
{
if (localPlayerRunningToDestination)
{
return -1;
}
// Calculate the amount of energy recovered every second
double recoverRate = (48 + client.getBoostedSkillLevel(Skill.AGILITY)) / 360.0;
if (isLocalPlayerWearingFullGraceful())
{
recoverRate *= 1.3; // 30% recover rate increase from Graceful set effect
}
// Calculate the number of seconds left
return (int) ((100 - client.getEnergy()) / recoverRate);
}
}

View File

@@ -1,675 +0,0 @@
/*
* 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.skillcalculator;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.inject.Singleton;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.Experience;
import net.runelite.api.Skill;
import net.runelite.client.game.ItemManager;
import net.runelite.client.plugins.skillcalculator.banked.CriticalItem;
import net.runelite.client.plugins.skillcalculator.banked.beans.Activity;
import net.runelite.client.plugins.skillcalculator.banked.beans.SecondaryItem;
import net.runelite.client.plugins.skillcalculator.banked.ui.CriticalItemPanel;
import net.runelite.client.plugins.skillcalculator.beans.SkillDataBonus;
import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.DynamicGridLayout;
import net.runelite.client.ui.FontManager;
@Slf4j
@Singleton
public class BankedCalculator extends JPanel
{
private static final DecimalFormat XP_FORMAT_COMMA = new DecimalFormat("#,###.#");
private final SkillCalculatorPanel parent;
private final Client client;
private final UICalculatorInputArea uiInput;
private final SkillCalculatorConfig config;
private final ItemManager itemManager;
private final CacheSkillData skillData = new CacheSkillData();
private final List<JCheckBox> bonusCheckBoxes = new ArrayList<>();
// UI Input data
private float xpFactor = 1.0f;
private CalculatorType currentCalc;
private Skill currentSkill;
private double totalBankedXp = 0.0f;
private final JLabel totalLabel = new JLabel();
private final JPanel detailConfigContainer;
private final JPanel detailContainer;
// Banked Experience magic
private Map<Integer, Integer> bankMap = new HashMap<>();
private final Map<String, Boolean> categoryMap = new HashMap<>(); // Check if CriticalItem Category is enabled
private final Map<CriticalItem, CriticalItemPanel> panelMap = new HashMap<>();
private final Map<CriticalItem, Integer> criticalMap = new HashMap<>(); // Quantity of CriticalItem inside bankMap
private final Map<CriticalItem, Activity> activityMap = new HashMap<>(); // Selected Activity used for calculating xp
private final Map<CriticalItem, Integer> linkedMap = new HashMap<>(); // ItemID of item that links to the CriticalItem
BankedCalculator(
final SkillCalculatorPanel parent,
final Client client,
final UICalculatorInputArea uiInput,
final SkillCalculatorConfig config,
final ItemManager itemManager)
{
this.parent = parent;
this.client = client;
this.uiInput = uiInput;
this.config = config;
this.itemManager = itemManager;
setLayout(new DynamicGridLayout(0, 1, 0, 5));
detailContainer = new JPanel();
detailContainer.setLayout(new BoxLayout(detailContainer, BoxLayout.Y_AXIS));
detailConfigContainer = new JPanel();
detailConfigContainer.setLayout(new BoxLayout(detailConfigContainer, BoxLayout.Y_AXIS));
}
private void reset()
{
criticalMap.clear();
linkedMap.clear();
xpFactor = 1f;
}
/**
* Update target Xp and Level inputs to match current Xp + total banked XP
*/
private void syncInputFields()
{
// Update Target XP & Level to include total banked xp
int newTotal = (int) (uiInput.getCurrentXPInput() + totalBankedXp);
uiInput.setTargetXPInput(newTotal);
uiInput.setTargetLevelInput(Experience.getLevelForXp(newTotal));
}
/*
* Banked Experience Logic
*/
/**
* Shows the Banked Xp tab for the CalculatorType
*
* @param calculatorType Selected Calculator Type
*/
void openBanked(CalculatorType calculatorType)
{
// clean slate for creating the required panel
removeAll();
reset();
if (calculatorType.getSkill() != currentSkill)
{
// Only clear Category and Activity map on skill change.
activityMap.clear();
categoryMap.clear();
}
currentCalc = calculatorType;
currentSkill = calculatorType.getSkill();
bankMap = parent.getBankMap();
uiInput.setCurrentLevelInput(client.getRealSkillLevel(currentSkill));
uiInput.setCurrentXPInput(client.getSkillExperience(currentSkill));
// Only adds Banked Experience portion if enabled for this SkillCalc and have seen their bank
if (!calculatorType.isBankedXpFlag())
{
add(new JLabel("<html><div style='text-align: center;'>Banked Experience is not enabled for this skill.</div></html>", JLabel.CENTER));
}
else if (bankMap.size() <= 0)
{
add(new JLabel("Please visit a bank!", JLabel.CENTER));
}
else
{
// Prevent editing of the target level/exp since we automagically adjust them
uiInput.getUiFieldTargetLevel().setEditable(false);
uiInput.getUiFieldTargetXP().setEditable(false);
// Now we can actually show the Banked Experience Panel
// Adds Config Options for this panel
renderBankedXpOptions();
renderBonusXpOptions();
// sprite 202
calculatedBankedMaps();
// Calculate total banked experience and create detail container
refreshDetailContainer();
// Add back all necessary content
add(detailConfigContainer);
add(totalLabel);
add(detailContainer);
}
revalidate();
repaint();
// Update the input fields.
syncInputFields();
}
/**
* Add the config options for toggling each Item Category
*/
private void renderBankedXpOptions()
{
Set<String> categories = CriticalItem.getSkillCategories(currentSkill);
if (categories == null)
{
return;
}
add(new JLabel("Configs:"));
for (String category : categories)
{
JPanel uiOption = new JPanel(new BorderLayout());
JLabel uiLabel = new JLabel(category);
JCheckBox uiCheckbox = new JCheckBox();
uiLabel.setForeground(Color.WHITE);
uiLabel.setFont(FontManager.getRunescapeSmallFont());
uiOption.setBorder(BorderFactory.createEmptyBorder(3, 7, 3, 0));
uiOption.setBackground(ColorScheme.DARKER_GRAY_COLOR);
// Everything is enabled by default
uiCheckbox.setSelected(true);
categoryMap.put(category, true);
// Adjust Total Banked XP check-state of the box.
uiCheckbox.addActionListener(e -> toggleCategory(category, uiCheckbox.isSelected()));
uiCheckbox.setBackground(ColorScheme.MEDIUM_GRAY_COLOR);
uiOption.add(uiLabel, BorderLayout.WEST);
uiOption.add(uiCheckbox, BorderLayout.EAST);
add(uiOption);
add(Box.createRigidArea(new Dimension(0, 5)));
}
}
/**
* Used to toggle Categories of Items inside the Banked Xp tab
*
* @param category Category Name
* @param enabled is enabled
*/
private void toggleCategory(String category, boolean enabled)
{
categoryMap.put(category, enabled);
refreshDetailContainer();
}
/**
* Creates the Maps used for easy access when calculating Banked Xp
*/
private void calculatedBankedMaps()
{
// Grab all CriticalItems for this skill
List<CriticalItem> items = CriticalItem.getBySkillName(currentSkill);
// Loop over all Critical Items for this skill and determine how many are in the bank
for (CriticalItem item : items)
{
Integer qty = bankMap.get(item.getItemID());
if (qty != null && qty > 0)
{
if (criticalMap.containsKey(item))
{
criticalMap.put(item, criticalMap.get(item) + qty);
}
else
{
criticalMap.put(item, qty);
}
// Ensure the item this is linked to maps back to us.
if (item.getLinkedItemId() != -1)
{
CriticalItem i = CriticalItem.getByItemId(item.getLinkedItemId());
if (i != null)
{
linkedMap.put(i, item.getItemID());
}
}
}
}
}
/**
* Populates the detailContainer with the necessary CriticalItemPanels
*/
private void refreshDetailContainer()
{
detailContainer.removeAll();
panelMap.clear();
Map<CriticalItem, Integer> map = getBankedXpBreakdown();
for (Map.Entry<CriticalItem, Integer> entry : map.entrySet())
{
CriticalItem item = entry.getKey();
createItemPanel(item);
}
detailContainer.revalidate();
detailContainer.repaint();
calculateBankedXpTotal();
}
/**
* Creates an Individual Item Panel if it should be displayed
*
* @param item CriticalItem this information is tied too
*/
private void createItemPanel(CriticalItem item)
{
// Category Included?
if (categoryMap.get(item.getCategory()))
{
// Get possible activities limited to current level
List<Activity> activities = Activity.getByCriticalItem(item, uiInput.getCurrentLevelInput());
// Check if this should count as another item.
if (item.getLinkedItemId() != -1)
{
// Ensure the linked item panel is created even if there are none in bank.
CriticalItem linked = CriticalItem.getByItemId(item.getLinkedItemId());
if (!criticalMap.containsKey(linked))
{
createItemPanel(linked);
}
// One activity and rewards no xp ignore.
if (activities.size() == 1 && activities.get(0).getXp() <= 0)
{
return;
}
}
// If it doesn't have any activities ignore it in the breakdown.
if (activities.size() <= 0)
{
return;
}
// Either this item has multiple activities or the single activity rewards xp, create the item panel.
// Determine xp rate for this item
Activity a = getSelectedActivity(item);
double activityXp = a == null ? 0 : a.getXp();
double xp = activityXp * (item.isIgnoreBonus() ? 1.0f : xpFactor);
int amount = 0;
// If it has linked items figure out the working total.
Map<CriticalItem, Integer> links = getLinkedTotalMap(item);
for (Integer num : links.values())
{
amount += num;
}
// Actually create the panel displaying banked experience for this item
CriticalItemPanel panel = new CriticalItemPanel(this, itemManager, item, xp, amount, links);
// Limit to Banked Secondaries
if (config.limitedBankedSecondaries() && a != null)
{
panel.updateAmount(limitToActivitySecondaries(a, amount), true);
panel.recalculate();
}
panelMap.put(item, panel);
detailContainer.add(panel);
}
}
/**
* Return the Activity the player selected for this Item. Defaults to First activity
*
* @param i CriticalItem to check for
* @return selected Activity
*/
public Activity getSelectedActivity(CriticalItem i)
{
// Pull from memory if available
Activity a = activityMap.get(i);
if (a != null)
{
return a;
}
// If not in memory select the first Activity and add to memory
List<Activity> activities = Activity.getByCriticalItem(i);
if (activities.size() == 0)
{
// If you can't find an activity it means this item must link to one and give 0 xp
return null;
}
Activity selected = activities.get(0);
activityMap.put(i, selected);
return selected;
}
/**
* Creates a Map of Item ID and QTY for this Skill by Category. Keeps order for better UI display
*
* @return Map of Item ID and QTY for this Skill by Category
*/
private Map<CriticalItem, Integer> getBankedXpBreakdown()
{
Map<CriticalItem, Integer> map = new LinkedHashMap<>();
for (String category : CriticalItem.getSkillCategories(currentSkill))
{
List<CriticalItem> items = CriticalItem.getItemsForSkillCategories(currentSkill, category);
for (CriticalItem item : items)
{
Integer amount = bankMap.get(item.getItemID());
if (amount != null && amount > 0)
{
map.put(item, amount);
}
}
}
return map;
}
/**
* Used to select an Activity for an item
*
* @param i CriticalItem
* @param a Activity selected
*/
public void activitySelected(CriticalItem i, Activity a)
{
// This is triggered on every click so don't update if activity didn't actually change
Activity cur = activityMap.get(i);
if (cur != null && cur.equals(a))
{
return;
}
// Update selected activity in map
activityMap.put(i, a);
// If had a previous selection and this item links to another check for item prevention change.
// If there are changes adjust the Linked panel quantity as well
if (cur != null && i.getLinkedItemId() != -1 && cur.isPreventLinked() != a.isPreventLinked())
{
CriticalItem linked = CriticalItem.getByItemId(i.getLinkedItemId());
CriticalItemPanel l = panelMap.get(linked);
if (l != null)
{
l.updateLinkedMap(getLinkedTotalMap(linked));
int amount = config.limitedBankedSecondaries() ? limitToActivitySecondaries(a, l.getAmount()) : l.getAmount();
l.updateAmount(amount, false);
l.recalculate();
}
}
// Total banked experience
CriticalItemPanel p = panelMap.get(i);
if (p != null)
{
p.updateLinkedMap(getLinkedTotalMap(i));
int amount = config.limitedBankedSecondaries() ? limitToActivitySecondaries(a, p.getAmount()) : p.getAmount();
p.updateAmount(amount, true);
p.updateXp(a.getXp() * (i.isIgnoreBonus() ? 1.0f : xpFactor));
}
// Update total banked xp value based on updated panels
calculateBankedXpTotal();
}
private Map<CriticalItem, Integer> getLinkedTotalMap(CriticalItem i)
{
return getLinkedTotalMap(i, true);
}
/**
* Creates a Map of CriticalItem and Qty for all items that link to the passed CriticalItem
*
* @param i CriticalItem to base Map off of
* @param first Since this is called recursively we want to ensure the original CriticalItem is always added
* @return Map of Linked CriticalItems and their Qty
*/
private Map<CriticalItem, Integer> getLinkedTotalMap(CriticalItem i, boolean first)
{
Map<CriticalItem, Integer> map = new LinkedHashMap<>();
if (!categoryMap.get(i.getCategory()))
{
return map;
}
// This item has an activity selected and its preventing linked functionality?
Activity selected = activityMap.get(i);
if (selected != null && selected.isPreventLinked()
// If initial request is for this item
&& !first)
{
return map;
}
// Add self to map
int amount = criticalMap.getOrDefault(i, 0);
if (amount > 0)
{
map.put(i, amount);
}
// This item doesn't link to anything, all done.
if (linkedMap.get(i) == null)
{
return map;
}
CriticalItem item = CriticalItem.getByItemId(linkedMap.get(i));
if (item == null)
{
log.warn("Error finding Critical Item for Item ID: {}", linkedMap.get(i));
return map;
}
map.putAll(getLinkedTotalMap(item, false));
return map;
}
/**
* SkillCalculatorPlugin sends the Bank Map when the bank contents change
*
* @param map Map of Item IDs and Quantity
*/
void updateBankMap(Map<Integer, Integer> map)
{
boolean oldMapFlag = (bankMap.size() <= 0);
bankMap = map;
// Refresh entire panel if old map was empty
if (oldMapFlag)
{
CalculatorType calc = CalculatorType.getBySkill(currentSkill);
SwingUtilities.invokeLater(() ->
{
if (calc != null)
{
openBanked(calc);
}
});
return;
}
// recalculate all data related to banked experience except for activity selections
criticalMap.clear();
linkedMap.clear();
calculatedBankedMaps();
// Update the Total XP banked and the details panel
SwingUtilities.invokeLater(this::refreshDetailContainer);
}
/**
* Loops over all ItemPanels too sum their total xp and updates the label with the new value
*/
private void calculateBankedXpTotal()
{
double total = 0.0;
for (CriticalItemPanel p : panelMap.values())
{
total += p.getTotal();
}
totalBankedXp = total;
syncBankedXp();
}
/**
* Used to update the UI to reflect the new Banked XP amount
*/
private void syncBankedXp()
{
totalLabel.setText("Total Banked xp: " + XP_FORMAT_COMMA.format(totalBankedXp));
syncInputFields();
revalidate();
repaint();
}
/**
* Check Bank for Activity Secondaries and Limits to possible Activity amounts
*
* @param a Selected Activity
* @param possible Amount of Critical Item available
* @return possible Limited to Banked Secondaries
*/
private int limitToActivitySecondaries(Activity a, int possible)
{
for (SecondaryItem i : a.getSecondaries())
{
int banked = bankMap.getOrDefault(i.getId(), 0);
int newPossible = banked / i.getQty();
possible = newPossible < possible ? newPossible : possible;
}
return possible;
}
/**
* Renders the Xp Modifier options
*/
private void renderBonusXpOptions()
{
SkillDataBonus[] bonuses = skillData.getSkillData(currentCalc.getDataFile()).getBonuses();
if (bonuses != null)
{
add(new JLabel("Bonus Experience:"));
for (SkillDataBonus bonus : bonuses)
{
JPanel checkboxPanel = buildCheckboxPanel(bonus);
add(checkboxPanel);
add(Box.createRigidArea(new Dimension(0, 5)));
}
}
}
private JPanel buildCheckboxPanel(SkillDataBonus bonus)
{
JPanel uiOption = new JPanel(new BorderLayout());
JLabel uiLabel = new JLabel(bonus.getName());
JCheckBox uiCheckbox = new JCheckBox();
uiLabel.setForeground(Color.WHITE);
uiLabel.setFont(FontManager.getRunescapeSmallFont());
uiOption.setBorder(BorderFactory.createEmptyBorder(3, 7, 3, 0));
uiOption.setBackground(ColorScheme.DARKER_GRAY_COLOR);
// Adjust XP bonus depending on check-state of the boxes.
uiCheckbox.addActionListener(event -> adjustCheckboxes(uiCheckbox, bonus));
uiCheckbox.setBackground(ColorScheme.MEDIUM_GRAY_COLOR);
uiOption.add(uiLabel, BorderLayout.WEST);
uiOption.add(uiCheckbox, BorderLayout.EAST);
bonusCheckBoxes.add(uiCheckbox);
return uiOption;
}
private void adjustCheckboxes(JCheckBox target, SkillDataBonus bonus)
{
adjustXPBonus(0);
bonusCheckBoxes.forEach(otherSelectedCheckbox ->
{
if (otherSelectedCheckbox != target)
{
otherSelectedCheckbox.setSelected(false);
}
});
if (target.isSelected())
{
adjustXPBonus(bonus.getValue());
}
}
private void adjustXPBonus(float value)
{
xpFactor = 1f + value;
refreshDetailContainer();
}
}

View File

@@ -35,7 +35,7 @@ class CacheSkillData
{
private final Map<String, SkillData> cache = new HashMap<>();
SkillData getSkillData(final String dataFile)
SkillData getSkillData(String dataFile)
{
if (cache.containsKey(dataFile))
{

View File

@@ -1,6 +1,5 @@
/*
* Copyright (c) 2018, Kruithne <kruithne@gmail.com>
* Copyright (c) 2018, TheStonedTurtle <https://github.com/TheStonedTurtle>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,47 +24,32 @@
*/
package net.runelite.client.plugins.skillcalculator;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.runelite.api.Skill;
@AllArgsConstructor
@Getter(AccessLevel.PACKAGE)
public enum CalculatorType
@Getter
enum CalculatorType
{
AGILITY(Skill.AGILITY, "skill_agility.json", false),
CONSTRUCTION(Skill.CONSTRUCTION, "skill_construction.json", true),
COOKING(Skill.COOKING, "skill_cooking.json", true),
CRAFTING(Skill.CRAFTING, "skill_crafting.json", true),
FARMING(Skill.FARMING, "skill_farming.json", true),
FIREMAKING(Skill.FIREMAKING, "skill_firemaking.json", false),
FLETCHING(Skill.FLETCHING, "skill_fletching.json", false),
FISHING(Skill.FISHING, "skill_fishing.json", false),
HERBLORE(Skill.HERBLORE, "skill_herblore.json", true),
HUNTER(Skill.HUNTER, "skill_hunter.json", false),
MAGIC(Skill.MAGIC, "skill_magic.json", false),
MINING(Skill.MINING, "skill_mining.json", false),
PRAYER(Skill.PRAYER, "skill_prayer.json", true),
RUNECRAFT(Skill.RUNECRAFT, "skill_runecraft.json", false),
SMITHING(Skill.SMITHING, "skill_smithing.json", true),
THIEVING(Skill.THIEVING, "skill_thieving.json", false),
WOODCUTTING(Skill.WOODCUTTING, "skill_woodcutting.json", false);
MINING(Skill.MINING, "skill_mining.json"),
AGILITY(Skill.AGILITY, "skill_agility.json"),
SMITHING(Skill.SMITHING, "skill_smithing.json"),
HERBLORE(Skill.HERBLORE, "skill_herblore.json"),
FISHING(Skill.FISHING, "skill_fishing.json"),
THIEVING(Skill.THIEVING, "skill_thieving.json"),
COOKING(Skill.COOKING, "skill_cooking.json"),
PRAYER(Skill.PRAYER, "skill_prayer.json"),
CRAFTING(Skill.CRAFTING, "skill_crafting.json"),
FIREMAKING(Skill.FIREMAKING, "skill_firemaking.json"),
MAGIC(Skill.MAGIC, "skill_magic.json"),
FLETCHING(Skill.FLETCHING, "skill_fletching.json"),
WOODCUTTING(Skill.WOODCUTTING, "skill_woodcutting.json"),
RUNECRAFT(Skill.RUNECRAFT, "skill_runecraft.json"),
FARMING(Skill.FARMING, "skill_farming.json"),
CONSTRUCTION(Skill.CONSTRUCTION, "skill_construction.json"),
HUNTER(Skill.HUNTER, "skill_hunter.json");
private final Skill skill;
private final String dataFile;
private final boolean bankedXpFlag;
public static CalculatorType getBySkill(Skill skill)
{
for (CalculatorType c : values())
{
if (c.getSkill().equals(skill))
{
return c;
}
}
return null;
}
}

View File

@@ -34,18 +34,13 @@ import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import javax.inject.Singleton;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import lombok.AccessLevel;
import lombok.Getter;
import net.runelite.api.Client;
import net.runelite.api.Experience;
import net.runelite.api.Skill;
import net.runelite.client.game.ItemManager;
import net.runelite.client.game.SpriteManager;
import net.runelite.client.plugins.skillcalculator.beans.SkillData;
@@ -59,7 +54,6 @@ import net.runelite.client.ui.components.IconTextField;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
@Singleton
class SkillCalculator extends JPanel
{
private static final int MAX_XP = 200_000_000;
@@ -71,9 +65,7 @@ class SkillCalculator extends JPanel
private final ItemManager itemManager;
private final List<UIActionSlot> uiActionSlots = new ArrayList<>();
private final CacheSkillData cacheSkillData = new CacheSkillData();
@Getter(AccessLevel.PACKAGE)
private final UICombinedActionSlot combinedActionSlot;
@Getter(AccessLevel.PACKAGE)
private final List<UIActionSlot> combinedActionSlots = new ArrayList<>();
private final List<JCheckBox> bonusCheckBoxes = new ArrayList<>();
private final IconTextField searchBar = new IconTextField();
@@ -85,9 +77,8 @@ class SkillCalculator extends JPanel
private int targetXP = Experience.getXpForLevel(targetLevel);
private float xpFactor = 1.0f;
private float lastBonus = 0.0f;
private CalculatorType calculatorType;
SkillCalculator(final Client client, final UICalculatorInputArea uiInput, final SpriteManager spriteManager, final ItemManager itemManager)
SkillCalculator(Client client, UICalculatorInputArea uiInput, SpriteManager spriteManager, ItemManager itemManager)
{
this.client = client;
this.uiInput = uiInput;
@@ -123,8 +114,6 @@ class SkillCalculator extends JPanel
void openCalculator(CalculatorType calculatorType)
{
this.calculatorType = calculatorType;
// Load the skill data.
skillData = cacheSkillData.getSkillData(calculatorType.getDataFile());
@@ -132,11 +121,10 @@ class SkillCalculator extends JPanel
xpFactor = 1.0f;
// Update internal skill/XP values.
updateInternalValues();
// BankedCalculator prevents these from being editable so just ensure they are editable.
uiInput.getUiFieldTargetLevel().setEditable(true);
uiInput.getUiFieldTargetXP().setEditable(true);
currentXP = client.getSkillExperience(calculatorType.getSkill());
currentLevel = Experience.getLevelForXp(currentXP);
targetLevel = enforceSkillBounds(currentLevel + 1);
targetXP = Experience.getXpForLevel(targetLevel);
// Remove all components (action slots) from this panel.
removeAll();
@@ -144,9 +132,6 @@ class SkillCalculator extends JPanel
// Clear the search bar
searchBar.setText(null);
// Clear the search bar
searchBar.setText(null);
// Add in checkboxes for available skill bonuses.
renderBonusOptions();
@@ -163,24 +148,6 @@ class SkillCalculator extends JPanel
updateInputFields();
}
private void updateInternalValues()
{
updateCurrentValues();
updateTargetValues();
}
private void updateCurrentValues()
{
currentXP = client.getSkillExperience(calculatorType.getSkill());
currentLevel = Experience.getLevelForXp(currentXP);
}
private void updateTargetValues()
{
targetLevel = enforceSkillBounds(currentLevel + 1);
targetXP = Experience.getXpForLevel(targetLevel);
}
private void updateCombinedAction()
{
int size = combinedActionSlots.size();
@@ -254,7 +221,7 @@ class SkillCalculator extends JPanel
JCheckBox uiCheckbox = new JCheckBox();
uiLabel.setForeground(Color.WHITE);
uiLabel.setFont(FontManager.getSmallFont(getFont()));
uiLabel.setFont(FontManager.getRunescapeSmallFont());
uiOption.setBorder(BorderFactory.createEmptyBorder(3, 7, 3, 0));
uiOption.setBackground(ColorScheme.DARKER_GRAY_COLOR);
@@ -270,7 +237,7 @@ class SkillCalculator extends JPanel
for (JCheckBox checkBox : uiCheckBoxList)
{
if (checkBox != null && !checkBox.equals(uiCheckBox))
if (checkBox != uiCheckBox)
{
checkBox.setSelected(false);
}
@@ -466,25 +433,4 @@ class SkillCalculator extends JPanel
return slot.getAction().getName().toLowerCase().contains(text.toLowerCase());
}
/**
* Updates the current skill calculator (if present)
* <p>
* This method is invoked by the {@link SkillCalculatorPlugin} event subscriber
* when an {@link ExperienceChanged} object is posted to the event bus
*/
void updateSkillCalculator(Skill skill)
{
// If the user has selected a calculator, update its fields
Optional.ofNullable(calculatorType).ifPresent(calc ->
{
if (skill.equals(calculatorType.getSkill()))
{
// Update our model "current" values
updateCurrentValues();
// Update the UI to reflect our new model
updateInputFields();
}
});
}
}

View File

@@ -32,24 +32,24 @@ import net.runelite.client.config.ConfigItem;
public interface SkillCalculatorConfig extends Config
{
@ConfigItem(
keyName = "showBankedXp",
name = "Show Banked xp Tab",
description = "Shows the Banked xp tab inside the Calculator Panel",
keyName = "enabledBankedXp",
name = "Add Banked XP Panel",
description = "Adds the Banked XP Panel to the side bar",
position = 0
)
default boolean showBankedXp()
{
return true;
return false;
}
@ConfigItem(
keyName = "limitedBankedSecondaries",
name = "Limit Banked xp to Secondaries",
description = "Limits the Banked xp shown based on secondaries banked as well",
keyName = "cascadeBankedXp",
name = "Include output items",
description = "Includes output items in the item quantity calculations",
position = 1
)
default boolean limitedBankedSecondaries()
default boolean cascadeBankedXp()
{
return false;
return true;
}
}

View File

@@ -1,7 +1,6 @@
/*
* Copyright (c) 2018, Kruithne <kruithne@gmail.com>
* Copyright (c) 2018, Psikoi <https://github.com/psikoi>
* Copyright (c) 2018, TheStonedTurtle <https://github.com/TheStonedTurtle>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,20 +29,10 @@ package net.runelite.client.plugins.skillcalculator;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import javax.inject.Singleton;
import javax.swing.ImageIcon;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.Skill;
import net.runelite.client.game.ItemManager;
import net.runelite.client.game.SkillIconManager;
import net.runelite.client.game.SpriteManager;
@@ -52,43 +41,30 @@ import net.runelite.client.ui.PluginPanel;
import net.runelite.client.ui.components.materialtabs.MaterialTab;
import net.runelite.client.ui.components.materialtabs.MaterialTabGroup;
@Slf4j
@Singleton
class SkillCalculatorPanel extends PluginPanel
{
private final SkillCalculator uiCalculator;
private final SkillIconManager iconManager;
private final SkillCalculatorConfig config;
private final BankedCalculator bankedCalculator;
private CalculatorType currentCalc;
private final MaterialTabGroup skillGroup;
private final MaterialTabGroup tabGroup;
private String currentTab;
private final List<String> tabs = new ArrayList<>();
@Getter
private Map<Integer, Integer> bankMap = new HashMap<>();
private final GridBagConstraints c;
SkillCalculatorPanel(final SkillIconManager iconManager, final Client client, final SkillCalculatorConfig config, final SpriteManager spriteManager, final ItemManager itemManager)
SkillCalculatorPanel(SkillIconManager iconManager, Client client, SpriteManager spriteManager, ItemManager itemManager)
{
super();
getScrollPane().setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
this.iconManager = iconManager;
this.config = config;
setBorder(new EmptyBorder(10, 10, 10, 10));
setLayout(new GridBagLayout());
c = new GridBagConstraints();
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 1;
c.gridx = 0;
c.gridy = 0;
skillGroup = new MaterialTabGroup();
skillGroup.setLayout(new GridLayout(0, 6, 7, 7));
tabGroup = new MaterialTabGroup();
tabGroup.setLayout(new GridLayout(0, 6, 7, 7));
addCalculatorButtons();
@@ -97,23 +73,14 @@ class SkillCalculatorPanel extends PluginPanel
uiInput.setBackground(ColorScheme.DARK_GRAY_COLOR);
uiCalculator = new SkillCalculator(client, uiInput, spriteManager, itemManager);
bankedCalculator = new BankedCalculator(this, client, uiInput, config, itemManager);
tabGroup = new MaterialTabGroup();
tabGroup.setBorder(new EmptyBorder(0, 0, 10, 0));
addTabButtons();
add(skillGroup, c);
add(tabGroup, c);
c.gridy++;
add(uiInput, c);
c.gridy++;
add(tabGroup, c);
c.gridy++;
add(uiCalculator, c);
c.gridy++;
}
private void addCalculatorButtons()
@@ -121,126 +88,14 @@ class SkillCalculatorPanel extends PluginPanel
for (CalculatorType calculatorType : CalculatorType.values())
{
ImageIcon icon = new ImageIcon(iconManager.getSkillImage(calculatorType.getSkill(), true));
MaterialTab tab = new MaterialTab(icon, skillGroup, null);
MaterialTab tab = new MaterialTab(icon, tabGroup, null);
tab.setOnSelectEvent(() ->
{
if (currentCalc != null && currentCalc.equals(calculatorType))
{
return true;
}
currentCalc = calculatorType;
selectedTab(currentTab, true);
uiCalculator.openCalculator(calculatorType);
return true;
});
skillGroup.addTab(tab);
tabGroup.addTab(tab);
}
}
private void addTabButtons()
{
tabGroup.removeAll();
tabs.clear();
tabs.add("Calculator");
if (config.showBankedXp())
{
tabs.add("Banked Xp");
}
// Only show if both options are visible
tabGroup.setVisible(tabs.size() > 1);
tabGroup.setLayout(new GridLayout(0, tabs.size(), 7, 7));
for (String s : tabs)
{
MaterialTab matTab = new MaterialTab(s, tabGroup, null);
matTab.setHorizontalAlignment(SwingUtilities.CENTER);
// Ensure Background is applied
matTab.setOpaque(true);
matTab.setBackground(ColorScheme.DARKER_GRAY_COLOR);
// When Clicked
matTab.setOnSelectEvent(() ->
{
selectedTab(s, false);
return true;
});
tabGroup.addTab(matTab);
}
MaterialTab selected = tabGroup.getTab(0);
if (tabs.contains(currentTab))
{
selected = tabGroup.getTab(tabs.indexOf(currentTab));
}
tabGroup.select(selected);
currentTab = selected.getText();
}
private void selectedTab(String s, boolean force)
{
// Do not refresh the panel if they clicked the same tab, unless they selected a new skill
if (Objects.equals(currentTab, s) && !force)
{
return;
}
currentTab = s;
// Only open a panel if a skill is selected
if (currentCalc == null)
{
return;
}
switch (s)
{
case "Calculator":
remove(bankedCalculator);
add(uiCalculator, c);
uiCalculator.openCalculator(currentCalc);
break;
case "Banked Xp":
remove(uiCalculator);
add(bankedCalculator, c);
bankedCalculator.openBanked(currentCalc);
break;
}
this.revalidate();
this.repaint();
}
// Refresh entire panel
void refreshPanel()
{
// Recreate Tabs (in case of Config change) and selects the first tab
addTabButtons();
// Ensure reload
selectedTab(currentTab, true);
this.revalidate();
this.repaint();
}
// Wrapper function for updating SkillCalculator's bankMap
void updateBankMap(Map<Integer, Integer> bank)
{
bankMap = bank;
if (currentCalc != null & currentTab.equals("Banked Xp"))
{
bankedCalculator.updateBankMap(bankMap);
}
}
void updateSkillCalculator(Skill skill)
{
uiCalculator.updateSkillCalculator(skill);
}
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018, Kruithne <kruithne@gmail.com>
* Copyright (c) 2018, TheStonedTurtle <https://github.com/TheStonedTurtle>
* Copyright (c) 2019, TheStonedTurtle <https://github.com/TheStonedTurtle>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,18 +31,13 @@ import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.swing.SwingUtilities;
import lombok.Getter;
import net.runelite.api.Client;
import net.runelite.api.InventoryID;
import net.runelite.api.Item;
import net.runelite.api.ItemContainer;
import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.ExperienceChanged;
import net.runelite.api.events.GameTick;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.api.events.ScriptCallbackEvent;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
@@ -51,7 +46,9 @@ import net.runelite.client.game.SkillIconManager;
import net.runelite.client.game.SpriteManager;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.plugins.skillcalculator.banked.CriticalItem;
import net.runelite.client.plugins.skillcalculator.banked.BankedCalculatorPanel;
import net.runelite.client.plugins.skillcalculator.banked.beans.Activity;
import net.runelite.client.plugins.skillcalculator.banked.beans.CriticalItem;
import net.runelite.client.ui.ClientToolbar;
import net.runelite.client.ui.NavigationButton;
import net.runelite.client.util.ImageUtil;
@@ -61,7 +58,6 @@ import net.runelite.client.util.ImageUtil;
description = "Enable the Skill Calculator panel",
tags = {"panel", "skilling"}
)
@Singleton
public class SkillCalculatorPlugin extends Plugin
{
@Inject
@@ -86,12 +82,10 @@ public class SkillCalculatorPlugin extends Plugin
private SkillCalculatorConfig skillCalculatorConfig;
private NavigationButton uiNavigationButton;
private SkillCalculatorPanel uiPanel;
private NavigationButton bankedUiNavigationButton;
@Getter
private Map<Integer, Integer> bankMap = new HashMap<>();
private int bankHash;
private BankedCalculatorPanel bankedUiPanel;
private int bankHash = -1;
@Provides
SkillCalculatorConfig getConfig(ConfigManager configManager)
@@ -103,7 +97,7 @@ public class SkillCalculatorPlugin extends Plugin
protected void startUp() throws Exception
{
final BufferedImage icon = ImageUtil.getResourceStreamFromClass(getClass(), "calc.png");
this.uiPanel = new SkillCalculatorPanel(skillIconManager, client, skillCalculatorConfig, spriteManager, itemManager);
final SkillCalculatorPanel uiPanel = new SkillCalculatorPanel(skillIconManager, client, spriteManager, itemManager);
uiNavigationButton = NavigationButton.builder()
.tooltip("Skill Calculator")
@@ -114,56 +108,32 @@ public class SkillCalculatorPlugin extends Plugin
clientToolbar.addNavigation(uiNavigationButton);
clientThread.invokeLater(() ->
{
switch (client.getGameState())
{
case STARTING:
case UNKNOWN:
return false;
}
CriticalItem.prepareItemDefinitions(itemManager);
return true;
});
toggleBankedXpPanel();
}
@Override
protected void shutDown() throws Exception
{
clientToolbar.removeNavigation(uiNavigationButton);
bankMap.clear();
bankHash = -1;
if (bankedUiNavigationButton != null)
{
clientToolbar.removeNavigation(bankedUiNavigationButton);
}
}
@Subscribe
public void onConfigChanged(ConfigChanged event)
{
if (event.getGroup().equals("skillCalculator"))
if (event.getGroup().equals("skillCalculator") && event.getKey().equals("enabledBankedXp"))
{
if (event.getKey().equals("showBankedXp"))
{
bankMap.clear();
bankHash = -1;
}
SwingUtilities.invokeLater(() -> uiPanel.refreshPanel());
toggleBankedXpPanel();
}
}
// Pulled from bankvalue plugin to check if bank is open
@Subscribe
public void onGameTick(GameTick event)
public void onScriptCallbackEvent(ScriptCallbackEvent event)
{
if (!skillCalculatorConfig.showBankedXp())
{
return;
}
Widget widgetBankTitleBar = client.getWidget(WidgetInfo.BANK_TITLE_BAR);
// Don't update on a search because rs seems to constantly update the title
if (widgetBankTitleBar == null || widgetBankTitleBar.isHidden() || widgetBankTitleBar.getText().contains("Showing"))
if (!event.getEventName().equals("setBankTitle") || !skillCalculatorConfig.showBankedXp())
{
return;
}
@@ -171,54 +141,80 @@ public class SkillCalculatorPlugin extends Plugin
updateBankItems();
}
private void toggleBankedXpPanel()
{
if (skillCalculatorConfig.showBankedXp())
{
final BufferedImage icon = ImageUtil.getResourceStreamFromClass(getClass(), "banked.png");
bankedUiPanel = new BankedCalculatorPanel(client, skillCalculatorConfig, skillIconManager, itemManager);
bankedUiNavigationButton = NavigationButton.builder()
.tooltip("Banked XP")
.icon(icon)
.priority(6)
.panel(bankedUiPanel)
.build();
clientToolbar.addNavigation(bankedUiNavigationButton);
clientThread.invoke(() ->
{
switch (client.getGameState())
{
case LOGIN_SCREEN:
case LOGIN_SCREEN_AUTHENTICATOR:
case LOGGING_IN:
case LOADING:
case LOGGED_IN:
case CONNECTION_LOST:
case HOPPING:
CriticalItem.prepareItemDefinitions(itemManager);
Activity.prepareItemDefinitions(itemManager);
return true;
default:
return false;
}
});
}
else
{
if (bankedUiNavigationButton == null)
{
return;
}
clientToolbar.removeNavigation(bankedUiNavigationButton);
bankedUiNavigationButton = null;
}
}
// Check if bank contents changed and if so send to UI
private void updateBankItems()
{
ItemContainer c = client.getItemContainer(InventoryID.BANK);
Item[] widgetItems = (c == null ? new Item[0] : c.getItems());
final ItemContainer c = client.getItemContainer(InventoryID.BANK);
if (c == null)
{
return;
}
// Couldn't find any items in bank, do nothing.
final Item[] widgetItems = c.getItems();
if (widgetItems == null || widgetItems.length == 0)
{
return;
}
Map<Integer, Integer> newBankMap = getBankMapIfDiff(widgetItems);
// Bank didn't change
if (newBankMap.size() == 0)
{
return;
}
bankMap = newBankMap;
// send updated bank map to ui
uiPanel.updateBankMap(bankMap);
}
// Recreates the bankMap and checks if the hashCode is different (the map has changed). Sends an empty map if no changes
private Map<Integer, Integer> getBankMapIfDiff(Item[] widgetItems)
{
Map<Integer, Integer> mapCheck = new HashMap<>();
final Map<Integer, Integer> m = new HashMap<>();
for (Item widgetItem : widgetItems)
{
mapCheck.put(widgetItem.getId(), widgetItem.getQuantity());
m.put(widgetItem.getId(), widgetItem.getQuantity());
}
int curHash = mapCheck.hashCode();
if (curHash != bankHash)
final int curHash = m.hashCode();
if (bankHash != curHash)
{
bankHash = curHash;
return mapCheck;
SwingUtilities.invokeLater(() -> bankedUiPanel.setBankMap(m));
}
return new HashMap<>();
}
@Subscribe
public void onExperienceChanged(ExperienceChanged changeEvent)
{
uiPanel.updateSkillCalculator(changeEvent.getSkill());
}
}

View File

@@ -33,7 +33,6 @@ import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.inject.Singleton;
import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JPanel;
@@ -48,7 +47,6 @@ import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.FontManager;
import net.runelite.client.ui.components.shadowlabel.JShadowedLabel;
@Singleton
class UIActionSlot extends JPanel
{
private static final Border GREEN_BORDER = new CompoundBorder(
@@ -127,7 +125,7 @@ class UIActionSlot extends JPanel
uiLabelName.setForeground(Color.WHITE);
uiLabelActions = new JShadowedLabel("Unknown");
uiLabelActions.setFont(FontManager.getSmallFont(getFont()));
uiLabelActions.setFont(FontManager.getRunescapeSmallFont());
uiLabelActions.setForeground(ColorScheme.LIGHT_GRAY_COLOR);
uiInfo.add(uiLabelName);

View File

@@ -28,27 +28,24 @@ package net.runelite.client.plugins.skillcalculator;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import javax.inject.Singleton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;
import lombok.AccessLevel;
import lombok.Getter;
import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.FontManager;
import net.runelite.client.ui.components.FlatTextField;
@Getter(AccessLevel.PACKAGE)
@Singleton
class UICalculatorInputArea extends JPanel
@Getter
public class UICalculatorInputArea extends JPanel
{
private final JTextField uiFieldCurrentLevel;
private final JTextField uiFieldCurrentXP;
private final JTextField uiFieldTargetLevel;
private final JTextField uiFieldTargetXP;
UICalculatorInputArea()
public UICalculatorInputArea()
{
setLayout(new GridLayout(2, 2, 7, 7));
uiFieldCurrentLevel = addComponent("Current Level");
@@ -62,7 +59,7 @@ class UICalculatorInputArea extends JPanel
return getInput(uiFieldCurrentLevel);
}
void setCurrentLevelInput(int value)
public void setCurrentLevelInput(int value)
{
setInput(uiFieldCurrentLevel, value);
}
@@ -72,7 +69,7 @@ class UICalculatorInputArea extends JPanel
return getInput(uiFieldCurrentXP);
}
void setCurrentXPInput(Object value)
public void setCurrentXPInput(Object value)
{
setInput(uiFieldCurrentXP, value);
}
@@ -82,7 +79,7 @@ class UICalculatorInputArea extends JPanel
return getInput(uiFieldTargetLevel);
}
void setTargetLevelInput(Object value)
public void setTargetLevelInput(Object value)
{
setInput(uiFieldTargetLevel, value);
}
@@ -92,7 +89,7 @@ class UICalculatorInputArea extends JPanel
return getInput(uiFieldTargetXP);
}
void setTargetXPInput(Object value)
public void setTargetXPInput(Object value)
{
setInput(uiFieldTargetXP, value);
}
@@ -126,7 +123,7 @@ class UICalculatorInputArea extends JPanel
uiInput.setHoverBackgroundColor(ColorScheme.DARK_GRAY_HOVER_COLOR);
uiInput.setBorder(new EmptyBorder(5, 7, 5, 7));
uiLabel.setFont(FontManager.getSmallFont(getFont()));
uiLabel.setFont(FontManager.getRunescapeSmallFont());
uiLabel.setBorder(new EmptyBorder(0, 0, 4, 0));
uiLabel.setForeground(Color.WHITE);
@@ -137,4 +134,4 @@ class UICalculatorInputArea extends JPanel
return uiInput.getTextField();
}
}
}

View File

@@ -30,7 +30,6 @@ import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.inject.Singleton;
import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JPanel;
@@ -40,14 +39,13 @@ import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.FontManager;
import net.runelite.client.ui.components.shadowlabel.JShadowedLabel;
@Singleton
class UICombinedActionSlot extends JPanel
{
private static final Dimension ICON_SIZE = new Dimension(32, 32);
private final JShadowedLabel uiLabelActions;
private final JShadowedLabel uiLabelTitle;
UICombinedActionSlot(final SpriteManager spriteManager)
UICombinedActionSlot(SpriteManager spriteManager)
{
setLayout(new BorderLayout());
setBackground(ColorScheme.DARKER_GRAY_COLOR);
@@ -70,7 +68,7 @@ class UICombinedActionSlot extends JPanel
uiLabelTitle.setForeground(Color.WHITE);
uiLabelActions = new JShadowedLabel("Shift-click to select multiple");
uiLabelActions.setFont(FontManager.getSmallFont(getFont()));
uiLabelActions.setFont(FontManager.getRunescapeSmallFont());
uiLabelActions.setForeground(ColorScheme.LIGHT_GRAY_COLOR);
uiInfo.add(uiLabelTitle);

View File

@@ -0,0 +1,462 @@
/*
* Copyright (c) 2019, TheStonedTurtle <https://github.com/TheStonedTurtle>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.skillcalculator.banked;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ItemEvent;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.swing.BorderFactory;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.Experience;
import net.runelite.api.Skill;
import net.runelite.client.game.AsyncBufferedImage;
import net.runelite.client.game.ItemManager;
import net.runelite.client.plugins.skillcalculator.SkillCalculatorConfig;
import net.runelite.client.plugins.skillcalculator.UICalculatorInputArea;
import net.runelite.client.plugins.skillcalculator.banked.beans.Activity;
import net.runelite.client.plugins.skillcalculator.banked.beans.BankedItem;
import net.runelite.client.plugins.skillcalculator.banked.beans.CriticalItem;
import net.runelite.client.plugins.skillcalculator.banked.beans.XpModifiers;
import net.runelite.client.plugins.skillcalculator.banked.components.GridItem;
import net.runelite.client.plugins.skillcalculator.banked.components.ModifyPanel;
import net.runelite.client.plugins.skillcalculator.banked.components.SelectionGrid;
import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.DynamicGridLayout;
import net.runelite.client.ui.FontManager;
@Slf4j
public class BankedCalculator extends JPanel
{
public static final DecimalFormat XP_FORMAT_COMMA = new DecimalFormat("#,###.#");
private final Client client;
@Getter
private final SkillCalculatorConfig config;
private final UICalculatorInputArea uiInput;
private final ItemManager itemManager;
// Some activities output a CriticalItem and may need to be included in the calculable qty
// Using multimap for cases where there are multiple items linked directly to one item, use recursion for otherwise
private final Multimap<CriticalItem, BankedItem> linkedMap = ArrayListMultimap.create();
private final Map<CriticalItem, BankedItem> bankedItemMap = new LinkedHashMap<>();
private final JLabel totalXpLabel = new JLabel();
private final ModifyPanel modifyPanel;
private SelectionGrid itemGrid;
@Setter
private Map<Integer, Integer> bankMap = new HashMap<>();
@Getter
private Skill currentSkill;
@Getter
private int skillLevel, skillExp, endLevel, endExp;
private final Collection<JCheckBox> xpModifierButtons = new ArrayList<>();
@Getter
private float xpFactor = 1.0f;
BankedCalculator(UICalculatorInputArea uiInput, Client client, SkillCalculatorConfig config, ItemManager itemManager)
{
this.uiInput = uiInput;
this.client = client;
this.config = config;
this.itemManager = itemManager;
setLayout(new DynamicGridLayout(0, 1, 0, 5));
// Panel used to modify banked item values
this.modifyPanel = new ModifyPanel(this, itemManager);
}
/**
* opens the Banked Calculator for this skill
*/
void open(final Skill newSkill)
{
if (newSkill.equals(currentSkill))
{
return;
}
this.currentSkill = newSkill;
removeAll();
xpFactor = 1.0f;
if (bankMap.size() <= 0)
{
add(new JLabel("Please visit a bank!", JLabel.CENTER));
revalidate();
repaint();
return;
}
skillLevel = client.getRealSkillLevel(currentSkill);
skillExp = client.getSkillExperience(currentSkill);
endLevel = skillLevel;
endExp = skillExp;
uiInput.setCurrentLevelInput(skillLevel);
uiInput.setCurrentXPInput(skillExp);
uiInput.setTargetLevelInput(endLevel);
uiInput.setTargetXPInput(endExp);
recreateBankedItemMap();
final Collection<XpModifiers> modifiers = XpModifiers.getModifiersBySkill(this.currentSkill);
for (final XpModifiers modifier : modifiers)
{
JPanel uiOption = new JPanel(new BorderLayout());
JLabel uiLabel = new JLabel(modifier.getName());
JCheckBox btn = new JCheckBox();
uiLabel.setForeground(Color.WHITE);
uiLabel.setFont(FontManager.getRunescapeSmallFont());
uiLabel.setHorizontalAlignment(SwingConstants.CENTER);
uiOption.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 0));
uiOption.setBackground(ColorScheme.DARKER_GRAY_COLOR);
btn.addItemListener((event) ->
{
switch (event.getStateChange())
{
case ItemEvent.DESELECTED:
xpFactor = 1.0f;
break;
case ItemEvent.SELECTED:
// Deselects all but the current item
final JCheckBox box = (JCheckBox) event.getItem();
xpModifierButtons.forEach(b -> b.setSelected(b == box));
xpFactor = modifier.getModifier();
break;
default:
return;
}
modifierUpdated();
});
xpModifierButtons.add(btn);
uiOption.add(uiLabel, BorderLayout.WEST);
uiOption.add(btn, BorderLayout.EAST);
add(uiOption);
}
recreateItemGrid();
// This should only be null if there are no items in their bank for this skill
if (itemGrid.getSelectedItem() == null)
{
add(new JLabel("Couldn't find any items for this skill.", JLabel.CENTER));
}
else
{
add(totalXpLabel);
add(modifyPanel);
add(itemGrid);
}
revalidate();
repaint();
}
private void recreateBankedItemMap()
{
bankedItemMap.clear();
linkedMap.clear();
final Collection<CriticalItem> items = CriticalItem.getBySkill(currentSkill);
log.debug("Critical Items for the {} Skill: {}", currentSkill.getName(), items);
for (final CriticalItem item : items)
{
final BankedItem banked = new BankedItem(item, bankMap.getOrDefault(item.getItemID(), 0));
bankedItemMap.put(item, banked);
Activity a = item.getSelectedActivity();
if (a == null)
{
final List<Activity> activities = Activity.getByCriticalItem(item);
if (activities.size() == 0)
{
continue;
}
item.setSelectedActivity(activities.get(0));
a = activities.get(0);
}
if (a.getLinkedItem() != null)
{
linkedMap.put(a.getLinkedItem(), banked);
}
}
log.debug("Banked Item Map: {}", bankedItemMap);
log.debug("Linked Map: {}", linkedMap);
}
/**
* Populates the detailContainer with the necessary BankedItemPanels
*/
private void recreateItemGrid()
{
// Selection grid will only display values with > 0 items
itemGrid = new SelectionGrid(this, bankedItemMap.values(), itemManager);
itemGrid.setOnSelectEvent(() ->
{
modifyPanel.setBankedItem(itemGrid.getSelectedItem());
return true;
});
itemGrid.setOnIgnoreEvent(() ->
{
CriticalItem item = itemGrid.getLastIgnoredItem().getItem();
updateLinkedItems(item.getSelectedActivity());
calculateBankedXpTotal();
return true;
});
// Select the first item in the list
modifyPanel.setBankedItem(itemGrid.getSelectedItem());
calculateBankedXpTotal();
}
public double getItemXpRate(final BankedItem bankedItem)
{
return bankedItem.getXpRate() * (bankedItem.getItem().isIgnoreBonus() ? 1.0f : xpFactor);
}
/**
* Calculates total item quantity accounting for backwards linked items
*
* @param item starting item
* @return item qty including linked items
*/
public int getItemQty(final BankedItem item)
{
int qty = item.getQty();
if (!config.cascadeBankedXp())
{
return qty;
}
final Map<CriticalItem, Integer> linked = createLinksMap(item);
final int linkedQty = linked.values().stream().mapToInt(Integer::intValue).sum();
return qty + linkedQty;
}
private void calculateBankedXpTotal()
{
double total = 0.0;
for (final GridItem i : itemGrid.getPanelMap().values())
{
if (i.isIgnored())
{
continue;
}
final BankedItem bi = i.getBankedItem();
total += getItemQty(bi) * getItemXpRate(bi);
}
endExp = (int) (skillExp + total);
endLevel = Experience.getLevelForXp(endExp);
totalXpLabel.setText("Total Banked xp: " + XP_FORMAT_COMMA.format(total));
uiInput.setTargetLevelInput(endLevel);
uiInput.setTargetXPInput(Math.min(Experience.MAX_SKILL_XP, endExp));
revalidate();
repaint();
}
/**
* Used to select an Activity for an item
*
* @param i BankedItem item the activity is tied to
* @param a Activity the selected activity
*/
public void activitySelected(final BankedItem i, final Activity a)
{
final CriticalItem item = i.getItem();
final Activity old = item.getSelectedActivity();
if (a.equals(old))
{
return;
}
item.setSelectedActivity(a);
// Cascade activity changes if necessary.
if (config.cascadeBankedXp() && (old.getLinkedItem() != a.getLinkedItem()))
{
// Update Linked Map
linkedMap.remove(old.getLinkedItem(), i);
linkedMap.put(a.getLinkedItem(), i);
// Update all items the old activity effects
updateLinkedItems(old);
// Update all the items the new activity effects
updateLinkedItems(a);
}
modifyPanel.setBankedItem(i);
itemGrid.getPanelMap().get(i).updateToolTip();
// recalculate total xp
calculateBankedXpTotal();
}
/**
* Updates the item quantities of all forward linked items
*
* @param activity the starting {@link Activity} to start the cascade from
*/
private void updateLinkedItems(final Activity activity)
{
if (activity == null)
{
return;
}
boolean foundSelected = false;
boolean panelAmountChange = false;
CriticalItem i = activity.getLinkedItem();
while (i != null)
{
final BankedItem bi = bankedItemMap.get(i);
if (bi == null)
{
break;
}
final int qty = getItemQty(bi);
final boolean stackable = bi.getItem().getItemInfo().isStackable() || qty > 1;
final AsyncBufferedImage img = itemManager.getImage(bi.getItem().getItemID(), qty, stackable);
final GridItem gridItem = itemGrid.getPanelMap().get(bi);
final int oldQty = gridItem.getAmount();
panelAmountChange = panelAmountChange || ((oldQty == 0 && qty > 0) || (oldQty > 0 && qty == 0));
gridItem.updateIcon(img, qty);
gridItem.updateToolTip();
foundSelected = foundSelected || itemGrid.getSelectedItem().equals(bi);
final Activity a = bi.getItem().getSelectedActivity();
if (a == null)
{
break;
}
i = a.getLinkedItem();
}
if (panelAmountChange)
{
itemGrid.refreshGridDisplay();
}
if (foundSelected)
{
// Refresh current modify panel if the cascade effects it
modifyPanel.setBankedItem(itemGrid.getSelectedItem());
}
}
/**
* Creates a Map of CriticalItem to bank qty for all items that are being linked to this one
*
* @param item starting item
* @return Map of CriticalItem to bank qty
*/
public Map<CriticalItem, Integer> createLinksMap(final BankedItem item)
{
final Map<CriticalItem, Integer> qtyMap = new HashMap<>();
final Activity a = item.getItem().getSelectedActivity();
if (a == null)
{
return qtyMap;
}
final Collection<BankedItem> linkedBank = linkedMap.get(item.getItem());
if (linkedBank == null || linkedBank.size() == 0)
{
return qtyMap;
}
for (final BankedItem linked : linkedBank)
{
// Check if the item is ignored in the grid
if (itemGrid != null)
{
final GridItem grid = itemGrid.getPanelMap().get(linked);
if (grid != null && grid.isIgnored())
{
continue;
}
}
final int qty = linked.getQty();
if (qty > 0)
{
qtyMap.put(linked.getItem(), qty);
}
qtyMap.putAll(createLinksMap(linked));
}
return qtyMap;
}
private void modifierUpdated()
{
itemGrid.getPanelMap().values().forEach(GridItem::updateToolTip);
modifyPanel.setBankedItem(modifyPanel.getBankedItem());
calculateBankedXpTotal();
}
}

View File

@@ -0,0 +1,120 @@
/*
* Copyright (c) 2019, TheStonedTurtle <https://github.com/TheStonedTurtle>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.skillcalculator.banked;
import com.google.common.collect.ImmutableSet;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ItemEvent;
import java.awt.image.BufferedImage;
import java.util.Map;
import javax.swing.ImageIcon;
import javax.swing.JComboBox;
import javax.swing.border.EmptyBorder;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.Skill;
import net.runelite.client.game.ItemManager;
import net.runelite.client.game.SkillIconManager;
import net.runelite.client.plugins.skillcalculator.SkillCalculatorConfig;
import net.runelite.client.plugins.skillcalculator.UICalculatorInputArea;
import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.PluginPanel;
import net.runelite.client.ui.components.ComboBoxIconEntry;
import net.runelite.client.ui.components.ComboBoxListRenderer;
@Slf4j
public class BankedCalculatorPanel extends PluginPanel
{
private final static ImmutableSet<Skill> BANKABLE_SKILLS = ImmutableSet.of(
Skill.CONSTRUCTION, Skill.COOKING, Skill.CRAFTING, Skill.FARMING, Skill.HERBLORE, Skill.PRAYER, Skill.SMITHING
);
private final BankedCalculator calculator;
public BankedCalculatorPanel(Client client, SkillCalculatorConfig config, SkillIconManager skillIconManager, ItemManager itemManager)
{
super();
setBorder(new EmptyBorder(10, 10, 10, 10));
setLayout(new GridBagLayout());
final UICalculatorInputArea inputs = new UICalculatorInputArea();
inputs.setBorder(new EmptyBorder(15, 0, 15, 0));
inputs.setBackground(ColorScheme.DARK_GRAY_COLOR);
inputs.getUiFieldTargetXP().setEditable(false);
inputs.getUiFieldTargetLevel().setEditable(false);
calculator = new BankedCalculator(inputs, client, config, itemManager);
// Create the Skill dropdown with icons
final JComboBox<ComboBoxIconEntry> dropdown = new JComboBox<>();
final ComboBoxListRenderer renderer = new ComboBoxListRenderer();
renderer.setDefaultText("Select a Skill...");
dropdown.setRenderer(renderer);
for (final Skill skill : BANKABLE_SKILLS)
{
final BufferedImage img = skillIconManager.getSkillImage(skill, true);
final ComboBoxIconEntry entry = new ComboBoxIconEntry(new ImageIcon(img), skill.getName(), skill);
dropdown.addItem(entry);
}
// Add click event handler now to prevent above code from triggering it.
dropdown.addItemListener(e ->
{
if (e.getStateChange() == ItemEvent.SELECTED)
{
final ComboBoxIconEntry source = (ComboBoxIconEntry) e.getItem();
if (source.getData() instanceof Skill)
{
final Skill skill = (Skill) source.getData();
this.calculator.open(skill);
}
}
});
dropdown.setSelectedIndex(-1);
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 1;
c.gridx = 0;
c.gridy = 0;
add(dropdown, c);
c.gridy++;
add(inputs, c);
c.gridy++;
add(calculator, c);
}
public void setBankMap(final Map<Integer, Integer> bankMap)
{
calculator.setBankMap(bankMap);
}
}

View File

@@ -1,418 +0,0 @@
/*
* 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.skillcalculator.banked;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import lombok.Getter;
import net.runelite.api.ItemDefinition;
import net.runelite.api.ItemID;
import net.runelite.api.Skill;
import net.runelite.client.game.ItemManager;
public enum CriticalItem
{
/**
* Construction Items
*/
// Planks
PLANK(ItemID.PLANK, "Planks", Skill.CONSTRUCTION),
OAK_PLANK(ItemID.OAK_PLANK, "Planks", Skill.CONSTRUCTION),
TEAK_PLANK(ItemID.TEAK_PLANK, "Planks", Skill.CONSTRUCTION),
MAHOGANY_PLANK(ItemID.MAHOGANY_PLANK, "Planks", Skill.CONSTRUCTION),
// Logs
LOGS(ItemID.LOGS, "Logs", Skill.CONSTRUCTION, ItemID.PLANK),
OAK_LOGS(ItemID.OAK_LOGS, "Logs", Skill.CONSTRUCTION, ItemID.OAK_PLANK),
TEAK_LOGS(ItemID.TEAK_LOGS, "Logs", Skill.CONSTRUCTION, ItemID.TEAK_PLANK),
MAHOGANY_LOGS(ItemID.MAHOGANY_LOGS, "Logs", Skill.CONSTRUCTION, ItemID.MAHOGANY_PLANK),
/**
* Herblore Items
*/
// Grimy Herbs
GRIMY_GUAM_LEAF(ItemID.GRIMY_GUAM_LEAF, "Grimy Herbs", Skill.HERBLORE, ItemID.GUAM_LEAF),
GRIMY_MARRENTILL(ItemID.GRIMY_MARRENTILL, "Grimy Herbs", Skill.HERBLORE, ItemID.MARRENTILL),
GRIMY_TARROMIN(ItemID.GRIMY_TARROMIN, "Grimy Herbs", Skill.HERBLORE, ItemID.TARROMIN),
GRIMY_HARRALANDER(ItemID.GRIMY_HARRALANDER, "Grimy Herbs", Skill.HERBLORE, ItemID.HARRALANDER),
GRIMY_RANARR_WEED(ItemID.GRIMY_RANARR_WEED, "Grimy Herbs", Skill.HERBLORE, ItemID.RANARR_WEED),
GRIMY_TOADFLAX(ItemID.GRIMY_TOADFLAX, "Grimy Herbs", Skill.HERBLORE, ItemID.TOADFLAX),
GRIMY_IRIT_LEAF(ItemID.GRIMY_IRIT_LEAF, "Grimy Herbs", Skill.HERBLORE, ItemID.IRIT_LEAF),
GRIMY_AVANTOE(ItemID.GRIMY_AVANTOE, "Grimy Herbs", Skill.HERBLORE, ItemID.AVANTOE),
GRIMY_KWUARM(ItemID.GRIMY_KWUARM, "Grimy Herbs", Skill.HERBLORE, ItemID.KWUARM),
GRIMY_SNAPDRAGON(ItemID.GRIMY_SNAPDRAGON, "Grimy Herbs", Skill.HERBLORE, ItemID.SNAPDRAGON),
GRIMY_CADANTINE(ItemID.GRIMY_CADANTINE, "Grimy Herbs", Skill.HERBLORE, ItemID.CADANTINE),
GRIMY_LANTADYME(ItemID.GRIMY_LANTADYME, "Grimy Herbs", Skill.HERBLORE, ItemID.LANTADYME),
GRIMY_DWARF_WEED(ItemID.GRIMY_DWARF_WEED, "Grimy Herbs", Skill.HERBLORE, ItemID.DWARF_WEED),
GRIMY_TORSTOL(ItemID.GRIMY_TORSTOL, "Grimy Herbs", Skill.HERBLORE, ItemID.TORSTOL),
// Clean Herbs
GUAM_LEAF(ItemID.GUAM_LEAF, "Cleaned Herbs", Skill.HERBLORE, ItemID.GUAM_POTION_UNF),
MARRENTILL(ItemID.MARRENTILL, "Cleaned Herbs", Skill.HERBLORE, ItemID.MARRENTILL_POTION_UNF),
TARROMIN(ItemID.TARROMIN, "Cleaned Herbs", Skill.HERBLORE, ItemID.TARROMIN_POTION_UNF),
HARRALANDER(ItemID.HARRALANDER, "Cleaned Herbs", Skill.HERBLORE, ItemID.HARRALANDER_POTION_UNF),
RANARR_WEED(ItemID.RANARR_WEED, "Cleaned Herbs", Skill.HERBLORE, ItemID.RANARR_POTION_UNF),
TOADFLAX(ItemID.TOADFLAX, "Cleaned Herbs", Skill.HERBLORE, ItemID.TOADFLAX_POTION_UNF),
IRIT_LEAF(ItemID.IRIT_LEAF, "Cleaned Herbs", Skill.HERBLORE, ItemID.IRIT_POTION_UNF),
AVANTOE(ItemID.AVANTOE, "Cleaned Herbs", Skill.HERBLORE, ItemID.AVANTOE_POTION_UNF),
KWUARM(ItemID.KWUARM, "Cleaned Herbs", Skill.HERBLORE, ItemID.KWUARM_POTION_UNF),
SNAPDRAGON(ItemID.SNAPDRAGON, "Cleaned Herbs", Skill.HERBLORE, ItemID.SNAPDRAGON_POTION_UNF),
CADANTINE(ItemID.CADANTINE, "Cleaned Herbs", Skill.HERBLORE, ItemID.CADANTINE_POTION_UNF),
LANTADYME(ItemID.LANTADYME, "Cleaned Herbs", Skill.HERBLORE, ItemID.LANTADYME_POTION_UNF),
DWARF_WEED(ItemID.DWARF_WEED, "Cleaned Herbs", Skill.HERBLORE, ItemID.DWARF_WEED_POTION_UNF),
TORSTOL(ItemID.TORSTOL, "Cleaned Herbs", Skill.HERBLORE, ItemID.TORSTOL_POTION_UNF),
// Unfinished Potions
GUAM_LEAF_POTION_UNF(ItemID.GUAM_POTION_UNF, "Unfinished Potions", Skill.HERBLORE),
MARRENTILL_POTION_UNF(ItemID.MARRENTILL_POTION_UNF, "Unfinished Potions", Skill.HERBLORE),
TARROMIN_POTION_UNF(ItemID.TARROMIN_POTION_UNF, "Unfinished Potions", Skill.HERBLORE),
HARRALANDER_POTION_UNF(ItemID.HARRALANDER_POTION_UNF, "Unfinished Potions", Skill.HERBLORE),
RANARR_POTION_UNF(ItemID.RANARR_POTION_UNF, "Unfinished Potions", Skill.HERBLORE),
TOADFLAX_POTION_UNF(ItemID.TOADFLAX_POTION_UNF, "Unfinished Potions", Skill.HERBLORE),
IRIT_POTION_UNF(ItemID.IRIT_POTION_UNF, "Unfinished Potions", Skill.HERBLORE),
AVANTOE_POTION_UNF(ItemID.AVANTOE_POTION_UNF, "Unfinished Potions", Skill.HERBLORE),
KWUARM_POTION_UNF(ItemID.KWUARM_POTION_UNF, "Unfinished Potions", Skill.HERBLORE),
SNAPDRAGON_POTION_UNF(ItemID.SNAPDRAGON_POTION_UNF, "Unfinished Potions", Skill.HERBLORE),
CADANTINE_POTION_UNF(ItemID.CADANTINE_POTION_UNF, "Unfinished Potions", Skill.HERBLORE),
LANTADYME_POTION_UNF(ItemID.LANTADYME_POTION_UNF, "Unfinished Potions", Skill.HERBLORE),
DWARF_WEED_POTION_UNF(ItemID.DWARF_WEED_POTION_UNF, "Unfinished Potions", Skill.HERBLORE),
TORSTOL_POTION_UNF(ItemID.TORSTOL_POTION_UNF, "Unfinished Potions", Skill.HERBLORE),
/**
* Prayer Items
*/
// Bones
BONES(ItemID.BONES, "Bones", Skill.PRAYER),
WOLF_BONES(ItemID.WOLF_BONES, "Bones", Skill.PRAYER),
BURNT_BONES(ItemID.BURNT_BONES, "Bones", Skill.PRAYER),
MONKEY_BONES(ItemID.MONKEY_BONES, "Bones", Skill.PRAYER),
BAT_BONES(ItemID.BAT_BONES, "Bones", Skill.PRAYER),
JOGRE_BONES(ItemID.JOGRE_BONES, "Bones", Skill.PRAYER),
BIG_BONES(ItemID.BIG_BONES, "Bones", Skill.PRAYER),
ZOGRE_BONES(ItemID.ZOGRE_BONES, "Bones", Skill.PRAYER),
SHAIKAHAN_BONES(ItemID.SHAIKAHAN_BONES, "Bones", Skill.PRAYER),
BABYDRAGON_BONES(ItemID.BABYDRAGON_BONES, "Bones", Skill.PRAYER),
WYVERN_BONES(ItemID.WYVERN_BONES, "Bones", Skill.PRAYER),
DRAGON_BONES(ItemID.DRAGON_BONES, "Bones", Skill.PRAYER),
FAYRG_BONES(ItemID.FAYRG_BONES, "Bones", Skill.PRAYER),
LAVA_DRAGON_BONES(ItemID.LAVA_DRAGON_BONES, "Bones", Skill.PRAYER),
RAURG_BONES(ItemID.RAURG_BONES, "Bones", Skill.PRAYER),
DAGANNOTH_BONES(ItemID.DAGANNOTH_BONES, "Bones", Skill.PRAYER),
OURG_BONES(ItemID.OURG_BONES, "Bones", Skill.PRAYER),
SUPERIOR_DRAGON_BONES(ItemID.SUPERIOR_DRAGON_BONES, "Bones", Skill.PRAYER),
// Shade Remains (Pyre Logs)
LOAR_REMAINS(ItemID.LOAR_REMAINS, "Shades", Skill.PRAYER, true),
PHRIN_REMAINS(ItemID.PHRIN_REMAINS, "Shades", Skill.PRAYER, true),
RIYL_REMAINS(ItemID.RIYL_REMAINS, "Shades", Skill.PRAYER, true),
ASYN_REMAINS(ItemID.ASYN_REMAINS, "Shades", Skill.PRAYER, true),
FIYR_REMAINS(ItemID.FIYR_REMAINS, "Shades", Skill.PRAYER, true),
// Ensouled Heads
ENSOULED_GOBLIN_HEAD(ItemID.ENSOULED_GOBLIN_HEAD_13448, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_MONKEY_HEAD(ItemID.ENSOULED_MONKEY_HEAD_13451, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_IMP_HEAD(ItemID.ENSOULED_IMP_HEAD_13454, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_MINOTAUR_HEAD(ItemID.ENSOULED_MINOTAUR_HEAD_13457, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_SCORPION_HEAD(ItemID.ENSOULED_SCORPION_HEAD_13460, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_BEAR_HEAD(ItemID.ENSOULED_BEAR_HEAD_13463, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_UNICORN_HEAD(ItemID.ENSOULED_UNICORN_HEAD_13466, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_DOG_HEAD(ItemID.ENSOULED_DOG_HEAD_13469, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_CHAOS_DRUID_HEAD(ItemID.ENSOULED_CHAOS_DRUID_HEAD_13472, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_GIANT_HEAD(ItemID.ENSOULED_GIANT_HEAD_13475, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_OGRE_HEAD(ItemID.ENSOULED_OGRE_HEAD_13478, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_ELF_HEAD(ItemID.ENSOULED_ELF_HEAD_13481, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_TROLL_HEAD(ItemID.ENSOULED_TROLL_HEAD_13484, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_HORROR_HEAD(ItemID.ENSOULED_HORROR_HEAD_13487, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_KALPHITE_HEAD(ItemID.ENSOULED_KALPHITE_HEAD_13490, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_DAGANNOTH_HEAD(ItemID.ENSOULED_DAGANNOTH_HEAD_13493, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_BLOODVELD_HEAD(ItemID.ENSOULED_BLOODVELD_HEAD_13496, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_TZHAAR_HEAD(ItemID.ENSOULED_TZHAAR_HEAD_13499, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_DEMON_HEAD(ItemID.ENSOULED_DEMON_HEAD_13502, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_AVIANSIE_HEAD(ItemID.ENSOULED_AVIANSIE_HEAD_13505, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_ABYSSAL_HEAD(ItemID.ENSOULED_ABYSSAL_HEAD_13508, "Ensouled Heads", Skill.PRAYER, true),
ENSOULED_DRAGON_HEAD(ItemID.ENSOULED_DRAGON_HEAD_13511, "Ensouled Heads", Skill.PRAYER, true),
/**
* Cooking Items
*/
RAW_HERRING(ItemID.RAW_HERRING, "Fish", Skill.COOKING),
RAW_MACKEREL(ItemID.RAW_MACKEREL, "Fish", Skill.COOKING),
RAW_TROUT(ItemID.RAW_TROUT, "Fish", Skill.COOKING),
RAW_COD(ItemID.RAW_COD, "Fish", Skill.COOKING),
RAW_PIKE(ItemID.RAW_PIKE, "Fish", Skill.COOKING),
RAW_SALMON(ItemID.RAW_SALMON, "Fish", Skill.COOKING),
RAW_TUNA(ItemID.RAW_TUNA, "Fish", Skill.COOKING),
RAW_KARAMBWAN(ItemID.RAW_KARAMBWAN, "Fish", Skill.COOKING),
RAW_LOBSTER(ItemID.RAW_LOBSTER, "Fish", Skill.COOKING),
RAW_BASS(ItemID.RAW_BASS, "Fish", Skill.COOKING),
RAW_SWORDFISH(ItemID.RAW_SWORDFISH, "Fish", Skill.COOKING),
RAW_MONKFISH(ItemID.RAW_MONKFISH, "Fish", Skill.COOKING),
RAW_SHARK(ItemID.RAW_SHARK, "Fish", Skill.COOKING),
RAW_SEA_TURTLE(ItemID.RAW_SEA_TURTLE, "Fish", Skill.COOKING),
RAW_ANGLERFISH(ItemID.RAW_ANGLERFISH, "Fish", Skill.COOKING),
RAW_DARK_CRAB(ItemID.RAW_DARK_CRAB, "Fish", Skill.COOKING),
RAW_MANTA_RAY(ItemID.RAW_MANTA_RAY, "Fish", Skill.COOKING),
GRAPES(ItemID.GRAPES, "Other", Skill.COOKING),
/**
* Crafting Items
*/
WOOL(ItemID.WOOL, "Misc", Skill.CRAFTING),
FLAX(ItemID.FLAX, "Misc", Skill.CRAFTING),
MOLTEN_GLASS(ItemID.MOLTEN_GLASS, "Misc", Skill.CRAFTING),
BATTLESTAFF(ItemID.BATTLESTAFF, "Misc", Skill.CRAFTING),
// D'hide/Dragon Leather
GREEN_DRAGONHIDE(ItemID.GREEN_DRAGONHIDE, "D'hide", Skill.CRAFTING, ItemID.GREEN_DRAGON_LEATHER),
GREEN_DRAGON_LEATHER(ItemID.GREEN_DRAGON_LEATHER, "D'hide", Skill.CRAFTING),
BLUE_DRAGONHIDE(ItemID.BLUE_DRAGONHIDE, "D'hide", Skill.CRAFTING, ItemID.BLUE_DRAGON_LEATHER),
BLUE_DRAGON_LEATHER(ItemID.BLUE_DRAGON_LEATHER, "D'hide", Skill.CRAFTING),
RED_DRAGONHIDE(ItemID.RED_DRAGONHIDE, "D'hide", Skill.CRAFTING, ItemID.RED_DRAGON_LEATHER),
RED_DRAGON_LEATHER(ItemID.RED_DRAGON_LEATHER, "D'hide", Skill.CRAFTING),
BLACK_DRAGONHIDE(ItemID.BLACK_DRAGONHIDE, "D'hide", Skill.CRAFTING, ItemID.BLACK_DRAGON_LEATHER),
BLACK_DRAGON_LEATHER(ItemID.BLACK_DRAGON_LEATHER, "D'hide", Skill.CRAFTING),
// Uncut Gems
UNCUT_OPAL(ItemID.UNCUT_OPAL, "Gems", Skill.CRAFTING, ItemID.OPAL),
UNCUT_JADE(ItemID.UNCUT_JADE, "Gems", Skill.CRAFTING, ItemID.JADE),
UNCUT_RED_TOPAZ(ItemID.UNCUT_RED_TOPAZ, "Gems", Skill.CRAFTING, ItemID.RED_TOPAZ),
UNCUT_SAPPHIRE(ItemID.UNCUT_SAPPHIRE, "Gems", Skill.CRAFTING, ItemID.SAPPHIRE),
UNCUT_EMERALD(ItemID.UNCUT_EMERALD, "Gems", Skill.CRAFTING, ItemID.EMERALD),
UNCUT_RUBY(ItemID.UNCUT_RUBY, "Gems", Skill.CRAFTING, ItemID.RUBY),
UNCUT_DIAMOND(ItemID.UNCUT_DIAMOND, "Gems", Skill.CRAFTING, ItemID.DIAMOND),
UNCUT_DRAGONSTONE(ItemID.UNCUT_DRAGONSTONE, "Gems", Skill.CRAFTING, ItemID.DRAGONSTONE),
UNCUT_ONYX(ItemID.UNCUT_ONYX, "Gems", Skill.CRAFTING, ItemID.ONYX),
UNCUT_ZENYTE(ItemID.UNCUT_ZENYTE, "Gems", Skill.CRAFTING, ItemID.ZENYTE),
// Cut Gems
OPAL(ItemID.OPAL, "Gems", Skill.CRAFTING),
JADE(ItemID.JADE, "Gems", Skill.CRAFTING),
RED_TOPAZ(ItemID.RED_TOPAZ, "Gems", Skill.CRAFTING),
SAPPHIRE(ItemID.SAPPHIRE, "Gems", Skill.CRAFTING),
EMERALD(ItemID.EMERALD, "Gems", Skill.CRAFTING),
RUBY(ItemID.RUBY, "Gems", Skill.CRAFTING),
DIAMOND(ItemID.DIAMOND, "Gems", Skill.CRAFTING),
DRAGONSTONE(ItemID.DRAGONSTONE, "Gems", Skill.CRAFTING),
ONYX(ItemID.ONYX, "Gems", Skill.CRAFTING),
ZENYTE(ItemID.ZENYTE, "Gems", Skill.CRAFTING),
/**
* Smithing Items
*/
// Ores
IRON_ORE(ItemID.IRON_ORE, "Ore", Skill.SMITHING),
SILVER_ORE(ItemID.SILVER_ORE, "Ore", Skill.SMITHING),
GOLD_ORE(ItemID.GOLD_ORE, "Ore", Skill.SMITHING),
MITHRIL_ORE(ItemID.MITHRIL_ORE, "Ore", Skill.SMITHING),
ADAMANTITE_ORE(ItemID.ADAMANTITE_ORE, "Ore", Skill.SMITHING),
RUNITE_ORE(ItemID.RUNITE_ORE, "Ore", Skill.SMITHING),
// Bars
BRONZE_BAR(ItemID.BRONZE_BAR, "Bars", Skill.SMITHING),
IRON_BAR(ItemID.IRON_BAR, "Bars", Skill.SMITHING),
STEEL_BAR(ItemID.STEEL_BAR, "Bars", Skill.SMITHING),
MITHRIL_BAR(ItemID.MITHRIL_BAR, "Bars", Skill.SMITHING),
ADAMANTITE_BAR(ItemID.ADAMANTITE_BAR, "Bars", Skill.SMITHING),
RUNITE_BAR(ItemID.RUNITE_BAR, "Bars", Skill.SMITHING),
/**
* Farming Items
*/
// Seeds
ACORN(ItemID.ACORN, "Seeds", Skill.FARMING),
WILLOW_SEED(ItemID.WILLOW_SEED, "Seeds", Skill.FARMING),
MAPLE_SEED(ItemID.MAPLE_SEED, "Seeds", Skill.FARMING),
YEW_SEED(ItemID.YEW_SEED, "Seeds", Skill.FARMING),
MAGIC_SEED(ItemID.MAGIC_SEED, "Seeds", Skill.FARMING),
APPLE_TREE_SEED(ItemID.APPLE_TREE_SEED, "Seeds", Skill.FARMING),
BANANA_TREE_SEED(ItemID.BANANA_TREE_SEED, "Seeds", Skill.FARMING),
ORANGE_TREE_SEED(ItemID.ORANGE_TREE_SEED, "Seeds", Skill.FARMING),
CURRY_TREE_SEED(ItemID.CURRY_TREE_SEED, "Seeds", Skill.FARMING),
PINEAPPLE_SEED(ItemID.PINEAPPLE_SEED, "Seeds", Skill.FARMING),
PAPAYA_TREE_SEED(ItemID.PAPAYA_TREE_SEED, "Seeds", Skill.FARMING),
PALM_TREE_SEED(ItemID.PALM_TREE_SEED, "Seeds", Skill.FARMING),
CALQUAT_TREE_SEED(ItemID.CALQUAT_TREE_SEED, "Seeds", Skill.FARMING),
TEAK_SEED(ItemID.TEAK_SEED, "Seeds", Skill.FARMING),
MAHOGANY_SEED(ItemID.MAHOGANY_SEED, "Seeds", Skill.FARMING),
SPIRIT_SEED(ItemID.SPIRIT_SEED, "Seeds", Skill.FARMING),
// Saplings
OAK_SAPLING(ItemID.OAK_SAPLING, "Saplings", Skill.FARMING, ItemID.ACORN),
WILLOW_SAPLING(ItemID.WILLOW_SAPLING, "Saplings", Skill.FARMING, ItemID.WILLOW_SEED),
MAPLE_SAPLING(ItemID.MAPLE_SAPLING, "Saplings", Skill.FARMING, ItemID.MAPLE_SEED),
YEW_SAPLING(ItemID.YEW_SAPLING, "Saplings", Skill.FARMING, ItemID.YEW_SEED),
MAGIC_SAPLING(ItemID.MAGIC_SAPLING, "Saplings", Skill.FARMING, ItemID.MAGIC_SEED),
APPLE_TREE_SAPLING(ItemID.APPLE_SAPLING, "Saplings", Skill.FARMING, ItemID.APPLE_TREE_SEED),
BANANA_TREE_SAPLING(ItemID.BANANA_SAPLING, "Saplings", Skill.FARMING, ItemID.BANANA_TREE_SEED),
ORANGE_TREE_SAPLING(ItemID.ORANGE_SAPLING, "Saplings", Skill.FARMING, ItemID.ORANGE_TREE_SEED),
CURRY_TREE_SAPLING(ItemID.CURRY_SAPLING, "Saplings", Skill.FARMING, ItemID.CURRY_TREE_SEED),
PINEAPPLE_SAPLING(ItemID.PINEAPPLE_SAPLING, "Saplings", Skill.FARMING, ItemID.PINEAPPLE_SEED),
PAPAYA_TREE_SAPLING(ItemID.PAPAYA_SAPLING, "Saplings", Skill.FARMING, ItemID.PAPAYA_TREE_SEED),
PALM_TREE_SAPLING(ItemID.PALM_SAPLING, "Saplings", Skill.FARMING, ItemID.PALM_TREE_SEED),
CALQUAT_TREE_SAPLING(ItemID.CALQUAT_SAPLING, "Saplings", Skill.FARMING, ItemID.CALQUAT_TREE_SEED),
TEAK_SAPLING(ItemID.TEAK_SAPLING, "Saplings", Skill.FARMING, ItemID.TEAK_SEED),
MAHOGANY_SAPLING(ItemID.MAHOGANY_SAPLING, "Saplings", Skill.FARMING, ItemID.MAHOGANY_SEED),
SPIRIT_SAPLING(ItemID.SPIRIT_SAPLING, "Saplings", Skill.FARMING, ItemID.SPIRIT_SEED),
;
@Getter
private final int itemID;
@Getter
private final String category;
@Getter
private final Skill skill;
/**
* Should be operated on and then treated like this item or does nothing if null.
* Used mostly for things like herblore where you want Grimy, Clean, and UNF to count for creating potions.
* To do this GRIMY links to CLEAN which links to UNFINISHED which links to null
*/
@Getter
private final int linkedItemId;
@Getter
private boolean ignoreBonus;
@Getter
private ItemDefinition definition;
CriticalItem(int itemID, String category, Skill skill, int linkedItem)
{
this.itemID = itemID;
this.category = category;
this.skill = skill;
this.linkedItemId = linkedItem;
this.definition = null;
this.ignoreBonus = false;
}
CriticalItem(int itemID, String category, Skill skill)
{
this(itemID, category, skill, -1);
}
CriticalItem(int itemID, String category, Skill skill, boolean ignoreBonusXp)
{
this(itemID, category, skill, -1);
this.ignoreBonus = ignoreBonusXp;
}
// Builds a Map to reduce looping frequency
private static Map<Skill, List<CriticalItem>> buildSkillItemMap()
{
Map<Skill, List<CriticalItem>> map = new HashMap<>();
for (CriticalItem item : values())
{
map.computeIfAbsent(item.getSkill(), e -> new ArrayList<>()).add(item);
}
return map;
}
private static final Map<Skill, List<CriticalItem>> bySkillName = buildSkillItemMap();
public static List<CriticalItem> getBySkillName(Skill skill)
{
return bySkillName.get(skill);
}
// Builds a Map to reduce looping frequency
private static Map<Skill, Set<String>> buildSkillCategoryMap()
{
Map<Skill, Set<String>> map = new HashMap<>();
for (CriticalItem item : values())
{
map.computeIfAbsent(item.getSkill(), k -> new HashSet<>()).add(item.category);
}
return map;
}
private static final Map<Skill, Set<String>> bySkillCategory = buildSkillCategoryMap();
public static Set<String> getSkillCategories(Skill skill)
{
return bySkillCategory.get(skill);
}
// Builds a Map to reduce looping frequency
private static Map<String, List<CriticalItem>> buildItemSkillCategoryMap()
{
Map<String, List<CriticalItem>> map = new HashMap<>();
for (CriticalItem item : values())
{
String key = item.getCategory() + item.skill.getName();
map.computeIfAbsent(key, e -> new ArrayList<>()).add(item);
}
return map;
}
private static final Map<String, List<CriticalItem>> itemsBySkillCategory = buildItemSkillCategoryMap();
public static List<CriticalItem> getItemsForSkillCategories(Skill skill, String category)
{
return itemsBySkillCategory.get(category + skill.getName());
}
// Builds a Map to reduce looping frequency
private static Map<Integer, CriticalItem> buildItemsByIdMap()
{
Map<Integer, CriticalItem> map = new HashMap<>();
for (CriticalItem item : values())
{
map.put(item.getItemID(), item);
}
return map;
}
private static final Map<Integer, CriticalItem> itemsById = buildItemsByIdMap();
public static CriticalItem getByItemId(int id)
{
return itemsById.get(id);
}
/**
* Attaches the Item Composition to each Critical Item on client initial load
*
* @param m ItemManager
*/
public static void prepareItemDefinitions(ItemManager m)
{
for (CriticalItem i : values())
{
i.definition = m.getItemDefinition(i.getItemID());
}
}
@Override
public String toString()
{
return "CriticalItem=(name=" + this.name() + ",id=" + this.itemID + ",category=" + this.category + ")";
}
}

View File

@@ -24,17 +24,19 @@
*/
package net.runelite.client.plugins.skillcalculator.banked.beans;
import com.google.common.collect.ImmutableMultimap;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import lombok.AccessLevel;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import lombok.Getter;
import net.runelite.api.ItemDefinition;
import net.runelite.api.ItemID;
import net.runelite.api.Skill;
import net.runelite.client.plugins.skillcalculator.banked.CriticalItem;
import net.runelite.client.game.ItemManager;
@Getter(AccessLevel.PUBLIC)
@Getter
public enum Activity
{
/**
@@ -42,372 +44,679 @@ public enum Activity
*/
// Creating Potions
// Guam
GUAM_POTION_UNF(ItemID.GUAM_POTION_UNF, "Unfinished Potion", Skill.HERBLORE, 1, 0, CriticalItem.GUAM_LEAF, ActivitySecondaries.UNFINISHED_POTION),
GUAM_TAR(ItemID.GUAM_TAR, "Guam tar", Skill.HERBLORE, 19, 30, CriticalItem.GUAM_LEAF, ActivitySecondaries.SWAMP_TAR, true),
GUAM_POTION_UNF(ItemID.GUAM_POTION_UNF, "Unfinished Potion", Skill.HERBLORE, 1, 0,
CriticalItem.GUAM_LEAF, Secondaries.UNFINISHED_POTION, new ItemStack(ItemID.GUAM_POTION_UNF, 1)),
GUAM_TAR(ItemID.GUAM_TAR, "Guam tar", Skill.HERBLORE, 19, 30,
CriticalItem.GUAM_LEAF, Secondaries.SWAMP_TAR, new ItemStack(ItemID.GUAM_TAR, 15)),
ATTACK_POTION(ItemID.ATTACK_POTION4, "Attack Potion", Skill.HERBLORE, 3, 25, CriticalItem.GUAM_LEAF_POTION_UNF, ActivitySecondaries.ATTACK_POTION),
ATTACK_POTION(ItemID.ATTACK_POTION3, "Attack potion", Skill.HERBLORE, 3, 25,
CriticalItem.GUAM_LEAF_POTION_UNF, Secondaries.ATTACK_POTION, new ItemStack(ItemID.ATTACK_POTION3, 1)),
// Marrentil
MARRENTILL_POTION_UNF(ItemID.MARRENTILL_POTION_UNF, "Unfinished Potion", Skill.HERBLORE, 1, 0, CriticalItem.MARRENTILL, ActivitySecondaries.UNFINISHED_POTION),
MARRENTILL_TAR(ItemID.MARRENTILL_TAR, "Marrentill tar", Skill.HERBLORE, 31, 42.5, CriticalItem.MARRENTILL, ActivitySecondaries.SWAMP_TAR, true),
MARRENTILL_POTION_UNF(ItemID.MARRENTILL_POTION_UNF, "Unfinished potion", Skill.HERBLORE, 1, 0,
CriticalItem.MARRENTILL, Secondaries.UNFINISHED_POTION, new ItemStack(ItemID.MARRENTILL_POTION_UNF, 1)),
MARRENTILL_TAR(ItemID.MARRENTILL_TAR, "Marrentill tar", Skill.HERBLORE, 31, 42.5,
CriticalItem.MARRENTILL, Secondaries.SWAMP_TAR, new ItemStack(ItemID.MARRENTILL_TAR, 15)),
ANTIPOISON(ItemID.ANTIPOISON4, "Antipoison", Skill.HERBLORE, 5, 37.5, CriticalItem.MARRENTILL_POTION_UNF, ActivitySecondaries.ANTIPOISON),
ANTIPOISON(ItemID.ANTIPOISON3, "Antipoison", Skill.HERBLORE, 5, 37.5,
CriticalItem.MARRENTILL_POTION_UNF, Secondaries.ANTIPOISON, new ItemStack(ItemID.ANTIPOISON3, 1)),
// Tarromin
TARROMIN_POTION_UNF(ItemID.TARROMIN_POTION_UNF, "Unfinished Potion", Skill.HERBLORE, 1, 0, CriticalItem.TARROMIN, ActivitySecondaries.UNFINISHED_POTION),
TARROMIN_TAR(ItemID.TARROMIN_TAR, "Tarromin tar", Skill.HERBLORE, 39, 55, CriticalItem.TARROMIN, ActivitySecondaries.SWAMP_TAR, true),
TARROMIN_POTION_UNF(ItemID.TARROMIN_POTION_UNF, "Unfinished potion", Skill.HERBLORE, 1, 0,
CriticalItem.TARROMIN, Secondaries.UNFINISHED_POTION, new ItemStack(ItemID.TARROMIN_POTION_UNF, 1)),
TARROMIN_TAR(ItemID.TARROMIN_TAR, "Tarromin tar", Skill.HERBLORE, 39, 55,
CriticalItem.TARROMIN, Secondaries.SWAMP_TAR, new ItemStack(ItemID.TARROMIN_TAR, 15)),
STRENGTH_POTION(ItemID.STRENGTH_POTION4, "Strength potion", Skill.HERBLORE, 12, 50, CriticalItem.TARROMIN_POTION_UNF, ActivitySecondaries.STRENGTH_POTION),
SERUM_207(ItemID.SERUM_207_4, "Serum 207", Skill.HERBLORE, 15, 50, CriticalItem.TARROMIN_POTION_UNF, ActivitySecondaries.SERUM_207),
STRENGTH_POTION(ItemID.STRENGTH_POTION3, "Strength potion", Skill.HERBLORE, 12, 50,
CriticalItem.TARROMIN_POTION_UNF, Secondaries.STRENGTH_POTION, new ItemStack(ItemID.STRENGTH_POTION3, 1)),
SERUM_207(ItemID.SERUM_207_3, "Serum 207", Skill.HERBLORE, 15, 50,
CriticalItem.TARROMIN_POTION_UNF, Secondaries.SERUM_207, new ItemStack(ItemID.SERUM_207_3, 1)),
// Harralander
HARRALANDER_POTION_UNF(ItemID.HARRALANDER_POTION_UNF, "Unfinished Potion", Skill.HERBLORE, 1, 0, CriticalItem.HARRALANDER, ActivitySecondaries.UNFINISHED_POTION),
HARRALANDER_TAR(ItemID.HARRALANDER_TAR, "Harralander tar", Skill.HERBLORE, 44, 72.5, CriticalItem.HARRALANDER, ActivitySecondaries.SWAMP_TAR, true),
HARRALANDER_POTION_UNF(ItemID.HARRALANDER_POTION_UNF, "Unfinished potion", Skill.HERBLORE, 1, 0,
CriticalItem.HARRALANDER, Secondaries.UNFINISHED_POTION, new ItemStack(ItemID.HARRALANDER_POTION_UNF, 1)),
HARRALANDER_TAR(ItemID.HARRALANDER_TAR, "Harralander tar", Skill.HERBLORE, 44, 72.5,
CriticalItem.HARRALANDER, Secondaries.SWAMP_TAR, new ItemStack(ItemID.HARRALANDER_TAR, 15)),
COMPOST_POTION(ItemID.COMPOST_POTION4, "Compost potion", Skill.HERBLORE, 21, 60, CriticalItem.HARRALANDER_POTION_UNF, ActivitySecondaries.COMPOST_POTION),
RESTORE_POTION(ItemID.RESTORE_POTION4, "Restore potion", Skill.HERBLORE, 22, 62.5, CriticalItem.HARRALANDER_POTION_UNF, ActivitySecondaries.RESTORE_POTION),
ENERGY_POTION(ItemID.ENERGY_POTION4, "Energy potion", Skill.HERBLORE, 26, 67.5, CriticalItem.HARRALANDER_POTION_UNF, ActivitySecondaries.ENERGY_POTION),
COMBAT_POTION(ItemID.COMBAT_POTION4, "Combat potion", Skill.HERBLORE, 36, 84, CriticalItem.HARRALANDER_POTION_UNF, ActivitySecondaries.COMBAT_POTION),
COMPOST_POTION(ItemID.COMPOST_POTION3, "Compost potion", Skill.HERBLORE, 21, 60,
CriticalItem.HARRALANDER_POTION_UNF, Secondaries.COMPOST_POTION, new ItemStack(ItemID.COMPOST_POTION3, 1)),
RESTORE_POTION(ItemID.RESTORE_POTION3, "Restore potion", Skill.HERBLORE, 22, 62.5,
CriticalItem.HARRALANDER_POTION_UNF, Secondaries.RESTORE_POTION, new ItemStack(ItemID.RESTORE_POTION3, 1)),
ENERGY_POTION(ItemID.ENERGY_POTION3, "Energy potion", Skill.HERBLORE, 26, 67.5,
CriticalItem.HARRALANDER_POTION_UNF, Secondaries.ENERGY_POTION, new ItemStack(ItemID.ENERGY_POTION3, 1)),
COMBAT_POTION(ItemID.COMBAT_POTION3, "Combat potion", Skill.HERBLORE, 36, 84,
CriticalItem.HARRALANDER_POTION_UNF, Secondaries.COMBAT_POTION, new ItemStack(ItemID.COMBAT_POTION3, 1)),
// Ranarr Weed
DEFENCE_POTION(ItemID.DEFENCE_POTION4, "Defence potion", Skill.HERBLORE, 30, 75, CriticalItem.RANARR_POTION_UNF, ActivitySecondaries.DEFENCE_POTION),
PRAYER_POTION(ItemID.PRAYER_POTION4, "Prayer potion", Skill.HERBLORE, 38, 87.5, CriticalItem.RANARR_POTION_UNF, ActivitySecondaries.PRAYER_POTION),
RANARR_POTION_UNF(ItemID.RANARR_POTION_UNF, "Unfinished potion", Skill.HERBLORE, 30, 0,
CriticalItem.RANARR_WEED, Secondaries.UNFINISHED_POTION, new ItemStack(ItemID.RANARR_POTION_UNF, 1)),
DEFENCE_POTION(ItemID.DEFENCE_POTION3, "Defence potion", Skill.HERBLORE, 30, 75,
CriticalItem.RANARR_POTION_UNF, Secondaries.DEFENCE_POTION, new ItemStack(ItemID.DEFENCE_POTION3, 1)),
PRAYER_POTION(ItemID.PRAYER_POTION3, "Prayer potion", Skill.HERBLORE, 38, 87.5,
CriticalItem.RANARR_POTION_UNF, Secondaries.PRAYER_POTION, new ItemStack(ItemID.PRAYER_POTION3, 1)),
// Toadflax
AGILITY_POTION(ItemID.AGILITY_POTION4, "Agility potion", Skill.HERBLORE, 34, 80, CriticalItem.TOADFLAX_POTION_UNF, ActivitySecondaries.AGILITY_POTION),
SARADOMIN_BREW(ItemID.SARADOMIN_BREW4, "Saradomin brew", Skill.HERBLORE, 81, 180, CriticalItem.TOADFLAX_POTION_UNF, ActivitySecondaries.SARADOMIN_BREW),
TOADFLAX_POTION_UNF(ItemID.TOADFLAX_POTION_UNF, "Unfinished potion", Skill.HERBLORE, 34, 0,
CriticalItem.TOADFLAX, Secondaries.UNFINISHED_POTION, new ItemStack(ItemID.TOADFLAX_POTION_UNF, 1)),
AGILITY_POTION(ItemID.AGILITY_POTION3, "Agility potion", Skill.HERBLORE, 34, 80,
CriticalItem.TOADFLAX_POTION_UNF, Secondaries.AGILITY_POTION, new ItemStack(ItemID.AGILITY_POTION3, 1)),
SARADOMIN_BREW(ItemID.SARADOMIN_BREW3, "Saradomin brew", Skill.HERBLORE, 81, 180,
CriticalItem.TOADFLAX_POTION_UNF, Secondaries.SARADOMIN_BREW, new ItemStack(ItemID.SARADOMIN_BREW3, 1)),
// Irit
SUPER_ATTACK(ItemID.SUPER_ATTACK4, "Super attack", Skill.HERBLORE, 45, 100, CriticalItem.IRIT_POTION_UNF, ActivitySecondaries.SUPER_ATTACK),
SUPERANTIPOISON(ItemID.SUPERANTIPOISON4, "Superantipoison", Skill.HERBLORE, 48, 106.3, CriticalItem.IRIT_POTION_UNF, ActivitySecondaries.SUPERANTIPOISON),
IRIT_POTION_UNF(ItemID.IRIT_POTION_UNF, "Unfinished potion", Skill.HERBLORE, 45, 0,
CriticalItem.IRIT_LEAF, Secondaries.UNFINISHED_POTION, new ItemStack(ItemID.IRIT_POTION_UNF, 1)),
SUPER_ATTACK(ItemID.SUPER_ATTACK3, "Super attack", Skill.HERBLORE, 45, 100,
CriticalItem.IRIT_POTION_UNF, Secondaries.SUPER_ATTACK, new ItemStack(ItemID.SUPER_ATTACK3, 1)),
SUPERANTIPOISON(ItemID.SUPERANTIPOISON3, "Superantipoison", Skill.HERBLORE, 48, 106.3,
CriticalItem.IRIT_POTION_UNF, Secondaries.SUPERANTIPOISON, new ItemStack(ItemID.SUPERANTIPOISON3, 1)),
// Avantoe
FISHING_POTION(ItemID.FISHING_POTION4, "Fishing potion", Skill.HERBLORE, 50, 112.5, CriticalItem.AVANTOE_POTION_UNF, ActivitySecondaries.FISHING_POTION),
SUPER_ENERGY_POTION(ItemID.SUPER_ENERGY3_20549, "Super energy potion", Skill.HERBLORE, 52, 117.5, CriticalItem.AVANTOE_POTION_UNF, ActivitySecondaries.SUPER_ENERGY_POTION),
HUNTER_POTION(ItemID.HUNTER_POTION4, "Hunter potion", Skill.HERBLORE, 53, 120, CriticalItem.AVANTOE_POTION_UNF, ActivitySecondaries.HUNTER_POTION),
AVANTOE_POTION_UNF(ItemID.AVANTOE_POTION_UNF, "Unfinished potion", Skill.HERBLORE, 50, 0,
CriticalItem.AVANTOE, Secondaries.UNFINISHED_POTION, new ItemStack(ItemID.AVANTOE_POTION_UNF, 1)),
FISHING_POTION(ItemID.FISHING_POTION3, "Fishing potion", Skill.HERBLORE, 50, 112.5,
CriticalItem.AVANTOE_POTION_UNF, Secondaries.FISHING_POTION, new ItemStack(ItemID.FISHING_POTION3, 1)),
SUPER_ENERGY_POTION(ItemID.SUPER_ENERGY3_20549, "Super energy potion", Skill.HERBLORE, 52, 117.5,
CriticalItem.AVANTOE_POTION_UNF, Secondaries.SUPER_ENERGY_POTION, new ItemStack(ItemID.SUPER_ENERGY3_20549, 1)),
HUNTER_POTION(ItemID.HUNTER_POTION3, "Hunter potion", Skill.HERBLORE, 53, 120,
CriticalItem.AVANTOE_POTION_UNF, Secondaries.HUNTER_POTION, new ItemStack(ItemID.HUNTER_POTION3, 1)),
// Kwuarm
SUPER_STRENGTH(ItemID.SUPER_STRENGTH4, "Super strength", Skill.HERBLORE, 55, 125, CriticalItem.KWUARM_POTION_UNF, ActivitySecondaries.SUPER_STRENGTH),
KWUARM_POTION_UNF(ItemID.KWUARM_POTION_UNF, "Unfinished potion", Skill.HERBLORE, 55, 0,
CriticalItem.KWUARM, Secondaries.UNFINISHED_POTION, new ItemStack(ItemID.KWUARM_POTION_UNF, 1)),
SUPER_STRENGTH(ItemID.SUPER_STRENGTH3, "Super strength", Skill.HERBLORE, 55, 125,
CriticalItem.KWUARM_POTION_UNF, Secondaries.SUPER_STRENGTH, new ItemStack(ItemID.SUPER_STRENGTH3, 1)),
// Snapdragon
SUPER_RESTORE(ItemID.SUPER_RESTORE4, "Super restore", Skill.HERBLORE, 63, 142.5, CriticalItem.SNAPDRAGON_POTION_UNF, ActivitySecondaries.SUPER_RESTORE),
SANFEW_SERUM(ItemID.SANFEW_SERUM4, "Sanfew serum", Skill.HERBLORE, 65, 160, CriticalItem.SNAPDRAGON_POTION_UNF, ActivitySecondaries.SANFEW_SERUM),
SNAPDRAGON_POTION_UNF(ItemID.SNAPDRAGON_POTION_UNF, "Unfinished potion", Skill.HERBLORE, 63, 0,
CriticalItem.SNAPDRAGON, Secondaries.UNFINISHED_POTION, new ItemStack(ItemID.SNAPDRAGON_POTION_UNF, 1)),
SUPER_RESTORE(ItemID.SUPER_RESTORE3, "Super restore", Skill.HERBLORE, 63, 142.5,
CriticalItem.SNAPDRAGON_POTION_UNF, Secondaries.SUPER_RESTORE, new ItemStack(ItemID.SUPER_RESTORE3, 1)),
SANFEW_SERUM(ItemID.SANFEW_SERUM3, "Sanfew serum", Skill.HERBLORE, 65, 160,
CriticalItem.SNAPDRAGON_POTION_UNF, Secondaries.SANFEW_SERUM, new ItemStack(ItemID.SANFEW_SERUM3, 1)),
// Cadantine
SUPER_DEFENCE_POTION(ItemID.SUPER_DEFENCE4, "Super defence", Skill.HERBLORE, 66, 150, CriticalItem.CADANTINE_POTION_UNF, ActivitySecondaries.SUPER_DEFENCE_POTION),
CADANTINE_POTION_UNF(ItemID.CADANTINE_POTION_UNF, "Unfinished potion", Skill.HERBLORE, 66, 0,
CriticalItem.CADANTINE, Secondaries.UNFINISHED_POTION, new ItemStack(ItemID.CADANTINE_POTION_UNF, 1)),
SUPER_DEFENCE_POTION(ItemID.SUPER_DEFENCE3, "Super defence", Skill.HERBLORE, 66, 150,
CriticalItem.CADANTINE_POTION_UNF, Secondaries.SUPER_DEFENCE_POTION, new ItemStack(ItemID.SUPER_DEFENCE3, 1)),
// Lantadyme
ANTIFIRE_POTION(ItemID.ANTIFIRE_POTION4, "Anti-fire potion", Skill.HERBLORE, 69, 157.5, CriticalItem.LANTADYME_POTION_UNF, ActivitySecondaries.ANTIFIRE_POTION),
MAGIC_POTION(ItemID.MAGIC_POTION4, "Magic potion", Skill.HERBLORE, 76, 172.5, CriticalItem.LANTADYME_POTION_UNF, ActivitySecondaries.MAGIC_POTION),
LANTADYME_POTION_UNF(ItemID.LANTADYME_POTION_UNF, "Unfinished potion", Skill.HERBLORE, 69, 0,
CriticalItem.LANTADYME, Secondaries.UNFINISHED_POTION, new ItemStack(ItemID.LANTADYME_POTION_UNF, 1)),
ANTIFIRE_POTION(ItemID.ANTIFIRE_POTION3, "Anti-fire potion", Skill.HERBLORE, 69, 157.5,
CriticalItem.LANTADYME_POTION_UNF, Secondaries.ANTIFIRE_POTION, new ItemStack(ItemID.ANTIFIRE_POTION3, 1)),
MAGIC_POTION(ItemID.MAGIC_POTION3, "Magic potion", Skill.HERBLORE, 76, 172.5,
CriticalItem.LANTADYME_POTION_UNF, Secondaries.MAGIC_POTION, new ItemStack(ItemID.MAGIC_POTION3, 1)),
// Dwarf Weed
RANGING_POTION(ItemID.RANGING_POTION4, "Ranging potion", Skill.HERBLORE, 72, 162.5, CriticalItem.DWARF_WEED_POTION_UNF, ActivitySecondaries.RANGING_POTION),
DWARF_WEED_POTION_UNF(ItemID.DWARF_WEED_POTION_UNF, "Unfinished potion", Skill.HERBLORE, 72, 0,
CriticalItem.DWARF_WEED, Secondaries.UNFINISHED_POTION, new ItemStack(ItemID.DWARF_WEED_POTION_UNF, 1)),
RANGING_POTION(ItemID.RANGING_POTION3, "Ranging potion", Skill.HERBLORE, 72, 162.5,
CriticalItem.DWARF_WEED_POTION_UNF, Secondaries.RANGING_POTION, new ItemStack(ItemID.RANGING_POTION3, 1)),
// Torstol
TORSTOL_POTION_UNF(ItemID.TORSTOL_POTION_UNF, "Unfinished Potion", Skill.HERBLORE, 78, 0, CriticalItem.TORSTOL, ActivitySecondaries.UNFINISHED_POTION),
SUPER_COMBAT_POTION(ItemID.SUPER_COMBAT_POTION4, "Super combat", Skill.HERBLORE, 90, 150, CriticalItem.TORSTOL, ActivitySecondaries.SUPER_COMBAT_POTION, true),
ANTIVENOM_PLUS(ItemID.ANTIVENOM4_12913, "Anti-venom+", Skill.HERBLORE, 94, 125, CriticalItem.TORSTOL, ActivitySecondaries.ANTIVENOM_PLUS, true),
TORSTOL_POTION_UNF(ItemID.TORSTOL_POTION_UNF, "Unfinished potion", Skill.HERBLORE, 78, 0,
CriticalItem.TORSTOL, Secondaries.UNFINISHED_POTION, new ItemStack(ItemID.TORSTOL_POTION_UNF, 1)),
SUPER_COMBAT_POTION(ItemID.SUPER_COMBAT_POTION4, "Super combat", Skill.HERBLORE, 90, 150,
CriticalItem.TORSTOL, Secondaries.SUPER_COMBAT_POTION, new ItemStack(ItemID.SUPER_COMBAT_POTION4, 1)),
ANTIVENOM_PLUS(ItemID.ANTIVENOM3_12915, "Anti-venom+", Skill.HERBLORE, 94, 125,
CriticalItem.TORSTOL, Secondaries.ANTIVENOM_PLUS, new ItemStack(ItemID.ANTIVENOM3_12915, 1)),
ZAMORAK_BREW(ItemID.ZAMORAK_BREW4, "Zamorak brew", Skill.HERBLORE, 78, 175, CriticalItem.TORSTOL_POTION_UNF, ActivitySecondaries.ZAMORAK_BREW),
ZAMORAK_BREW(ItemID.ZAMORAK_BREW3, "Zamorak brew", Skill.HERBLORE, 78, 175,
CriticalItem.TORSTOL_POTION_UNF, Secondaries.ZAMORAK_BREW, new ItemStack(ItemID.ZAMORAK_BREW3, 1)),
// Cleaning Grimy Herbs
CLEAN_GUAM(ItemID.GUAM_LEAF, "Clean guam", Skill.HERBLORE, 3, 2.5, CriticalItem.GRIMY_GUAM_LEAF),
CLEAN_MARRENTILL(ItemID.MARRENTILL, "Clean marrentill", Skill.HERBLORE, 5, 3.8, CriticalItem.GRIMY_MARRENTILL),
CLEAN_TARROMIN(ItemID.TARROMIN, "Clean tarromin", Skill.HERBLORE, 11, 5, CriticalItem.GRIMY_TARROMIN),
CLEAN_HARRALANDER(ItemID.HARRALANDER, "Clean harralander", Skill.HERBLORE, 20, 6.3, CriticalItem.GRIMY_HARRALANDER),
CLEAN_RANARR_WEED(ItemID.RANARR_WEED, "Clean ranarr weed", Skill.HERBLORE, 25, 7.5, CriticalItem.GRIMY_RANARR_WEED),
CLEAN_TOADFLAX(ItemID.TOADFLAX, "Clean toadflax", Skill.HERBLORE, 30, 8, CriticalItem.GRIMY_TOADFLAX),
CLEAN_IRIT_LEAF(ItemID.IRIT_LEAF, "Clean irit leaf", Skill.HERBLORE, 40, 8.8, CriticalItem.GRIMY_IRIT_LEAF),
CLEAN_AVANTOE(ItemID.AVANTOE, "Clean avantoe", Skill.HERBLORE, 48, 10, CriticalItem.GRIMY_AVANTOE),
CLEAN_KWUARM(ItemID.KWUARM, "Clean kwuarm", Skill.HERBLORE, 54, 11.3, CriticalItem.GRIMY_KWUARM),
CLEAN_SNAPDRAGON(ItemID.SNAPDRAGON, "Clean snapdragon", Skill.HERBLORE, 59, 11.8, CriticalItem.GRIMY_SNAPDRAGON),
CLEAN_CADANTINE(ItemID.CADANTINE, "Clean cadantine", Skill.HERBLORE, 65, 12.5, CriticalItem.GRIMY_CADANTINE),
CLEAN_LANTADYME(ItemID.LANTADYME, "Clean lantadyme", Skill.HERBLORE, 67, 13.1, CriticalItem.GRIMY_LANTADYME),
CLEAN_DWARF_WEED(ItemID.DWARF_WEED, "Clean dwarf weed", Skill.HERBLORE, 70, 13.8, CriticalItem.GRIMY_DWARF_WEED),
CLEAN_TORSTOL(ItemID.TORSTOL, "Clean torstol", Skill.HERBLORE, 75, 15, CriticalItem.GRIMY_TORSTOL),
CLEAN_GUAM(ItemID.GUAM_LEAF, "Clean guam", Skill.HERBLORE, 3, 2.5,
CriticalItem.GRIMY_GUAM_LEAF, null, new ItemStack(ItemID.GUAM_LEAF, 1)),
CLEAN_MARRENTILL(ItemID.MARRENTILL, "Clean marrentill", Skill.HERBLORE, 5, 3.8,
CriticalItem.GRIMY_MARRENTILL, null, new ItemStack(ItemID.MARRENTILL, 1)),
CLEAN_TARROMIN(ItemID.TARROMIN, "Clean tarromin", Skill.HERBLORE, 11, 5,
CriticalItem.GRIMY_TARROMIN, null, new ItemStack(ItemID.TARROMIN, 1)),
CLEAN_HARRALANDER(ItemID.HARRALANDER, "Clean harralander", Skill.HERBLORE, 20, 6.3,
CriticalItem.GRIMY_HARRALANDER, null, new ItemStack(ItemID.HARRALANDER, 1)),
CLEAN_RANARR_WEED(ItemID.RANARR_WEED, "Clean ranarr weed", Skill.HERBLORE, 25, 7.5,
CriticalItem.GRIMY_RANARR_WEED, null, new ItemStack(ItemID.RANARR_WEED, 1)),
CLEAN_TOADFLAX(ItemID.TOADFLAX, "Clean toadflax", Skill.HERBLORE, 30, 8,
CriticalItem.GRIMY_TOADFLAX, null, new ItemStack(ItemID.TOADFLAX, 1)),
CLEAN_IRIT_LEAF(ItemID.IRIT_LEAF, "Clean irit leaf", Skill.HERBLORE, 40, 8.8,
CriticalItem.GRIMY_IRIT_LEAF, null, new ItemStack(ItemID.IRIT_LEAF, 1)),
CLEAN_AVANTOE(ItemID.AVANTOE, "Clean avantoe", Skill.HERBLORE, 48, 10,
CriticalItem.GRIMY_AVANTOE, null, new ItemStack(ItemID.AVANTOE, 1)),
CLEAN_KWUARM(ItemID.KWUARM, "Clean kwuarm", Skill.HERBLORE, 54, 11.3,
CriticalItem.GRIMY_KWUARM, null, new ItemStack(ItemID.KWUARM, 1)),
CLEAN_SNAPDRAGON(ItemID.SNAPDRAGON, "Clean snapdragon", Skill.HERBLORE, 59, 11.8,
CriticalItem.GRIMY_SNAPDRAGON, null, new ItemStack(ItemID.SNAPDRAGON, 1)),
CLEAN_CADANTINE(ItemID.CADANTINE, "Clean cadantine", Skill.HERBLORE, 65, 12.5,
CriticalItem.GRIMY_CADANTINE, null, new ItemStack(ItemID.CADANTINE, 1)),
CLEAN_LANTADYME(ItemID.LANTADYME, "Clean lantadyme", Skill.HERBLORE, 67, 13.1,
CriticalItem.GRIMY_LANTADYME, null, new ItemStack(ItemID.LANTADYME, 1)),
CLEAN_DWARF_WEED(ItemID.DWARF_WEED, "Clean dwarf weed", Skill.HERBLORE, 70, 13.8,
CriticalItem.GRIMY_DWARF_WEED, null, new ItemStack(ItemID.DWARF_WEED, 1)),
CLEAN_TORSTOL(ItemID.TORSTOL, "Clean torstol", Skill.HERBLORE, 75, 15,
CriticalItem.GRIMY_TORSTOL, null, new ItemStack(ItemID.TORSTOL, 1)),
/**
* Construction Options
*/
PLANKS(ItemID.PLANK, "Normal Plank Products", Skill.CONSTRUCTION, 1, 29, CriticalItem.PLANK),
OAK_PLANKS(ItemID.OAK_PLANK, "Normal Oak Products", Skill.CONSTRUCTION, 1, 60, CriticalItem.OAK_PLANK),
TEAK_PLANKS(ItemID.TEAK_PLANK, "Normal Teak Products", Skill.CONSTRUCTION, 1, 90, CriticalItem.TEAK_PLANK),
MYTHICAL_CAPE(ItemID.MYTHICAL_CAPE, "Mythical Cape Rakes", Skill.CONSTRUCTION, 1, 123.33, CriticalItem.TEAK_PLANK),
MAHOGANY_PLANKS(ItemID.MAHOGANY_PLANK, "Normal Mahogany Products", Skill.CONSTRUCTION, 1, 140, CriticalItem.MAHOGANY_PLANK),
PLANK(ItemID.PLANK, "Regular Plank", Skill.CONSTRUCTION, 1, 0,
CriticalItem.LOGS, Secondaries.COINS_100, new ItemStack(ItemID.PLANK, 1)),
PLANKS(ItemID.PLANK, "Regular plank products", Skill.CONSTRUCTION, 1, 29,
CriticalItem.PLANK, null, null),
OAK_PLANK(ItemID.OAK_PLANK, "Oak Plank", Skill.CONSTRUCTION, 1, 0,
CriticalItem.OAK_LOGS, Secondaries.COINS_250, new ItemStack(ItemID.OAK_PLANK, 1)),
OAK_PLANKS(ItemID.OAK_PLANK, "Oak products", Skill.CONSTRUCTION, 1, 60,
CriticalItem.OAK_PLANK, null, null),
TEAK_PLANK(ItemID.TEAK_PLANK, "Teak Plank", Skill.CONSTRUCTION, 1, 0,
CriticalItem.TEAK_LOGS, Secondaries.COINS_500, new ItemStack(ItemID.TEAK_PLANK, 1)),
TEAK_PLANKS(ItemID.TEAK_PLANK, "Teak products", Skill.CONSTRUCTION, 1, 90,
CriticalItem.TEAK_PLANK, null, null),
MYTHICAL_CAPE(ItemID.MYTHICAL_CAPE, "Mythical cape rakes", Skill.CONSTRUCTION, 1, 123.33,
CriticalItem.TEAK_PLANK, null, null),
MAHOGANY_PLANK(ItemID.MAHOGANY_PLANK, "Mahogany Plank", Skill.CONSTRUCTION, 1, 0,
CriticalItem.MAHOGANY_LOGS, Secondaries.COINS_1500, new ItemStack(ItemID.MAHOGANY_PLANK, 1)),
MAHOGANY_PLANKS(ItemID.MAHOGANY_PLANK, "Mahogany products", Skill.CONSTRUCTION, 1, 140,
CriticalItem.MAHOGANY_PLANK, null, null),
/**
* Prayer Options
*/
BONES(ItemID.BONES, "Bones", Skill.PRAYER, 1, 4.5, CriticalItem.BONES),
WOLF_BONES(ItemID.WOLF_BONES, "Bones", Skill.PRAYER, 1, 4.5, CriticalItem.WOLF_BONES),
BURNT_BONES(ItemID.BURNT_BONES, "Bones", Skill.PRAYER, 1, 4.5, CriticalItem.BURNT_BONES),
MONKEY_BONES(ItemID.MONKEY_BONES, "Bones", Skill.PRAYER, 1, 5.0, CriticalItem.MONKEY_BONES),
BAT_BONES(ItemID.BAT_BONES, "Bones", Skill.PRAYER, 1, 5.3, CriticalItem.BAT_BONES),
JOGRE_BONES(ItemID.JOGRE_BONES, "Bones", Skill.PRAYER, 1, 15.0, CriticalItem.JOGRE_BONES),
BIG_BONES(ItemID.BIG_BONES, "Bones", Skill.PRAYER, 1, 15.0, CriticalItem.BIG_BONES),
ZOGRE_BONES(ItemID.ZOGRE_BONES, "Bones", Skill.PRAYER, 1, 22.5, CriticalItem.ZOGRE_BONES),
SHAIKAHAN_BONES(ItemID.SHAIKAHAN_BONES, "Bones", Skill.PRAYER, 1, 25.0, CriticalItem.SHAIKAHAN_BONES),
BABYDRAGON_BONES(ItemID.BABYDRAGON_BONES, "Bones", Skill.PRAYER, 1, 30.0, CriticalItem.BABYDRAGON_BONES),
WYVERN_BONES(ItemID.WYVERN_BONES, "Bones", Skill.PRAYER, 1, 72.0, CriticalItem.WYVERN_BONES),
DRAGON_BONES(ItemID.DRAGON_BONES, "Bones", Skill.PRAYER, 1, 72.0, CriticalItem.DRAGON_BONES),
FAYRG_BONES(ItemID.FAYRG_BONES, "Bones", Skill.PRAYER, 1, 84.0, CriticalItem.FAYRG_BONES),
LAVA_DRAGON_BONES(ItemID.LAVA_DRAGON_BONES, "Bones", Skill.PRAYER, 1, 85.0, CriticalItem.LAVA_DRAGON_BONES),
RAURG_BONES(ItemID.RAURG_BONES, "Bones", Skill.PRAYER, 1, 96.0, CriticalItem.RAURG_BONES),
DAGANNOTH_BONES(ItemID.DAGANNOTH_BONES, "Bones", Skill.PRAYER, 1, 125.0, CriticalItem.DAGANNOTH_BONES),
OURG_BONES(ItemID.OURG_BONES, "Bones", Skill.PRAYER, 1, 140.0, CriticalItem.OURG_BONES),
SUPERIOR_DRAGON_BONES(ItemID.SUPERIOR_DRAGON_BONES, "Bones", Skill.PRAYER, 1, 150.0, CriticalItem.SUPERIOR_DRAGON_BONES),
BONES(ItemID.BONES, "Bones", Skill.PRAYER, 1, 4.5,
CriticalItem.BONES, null, null),
WOLF_BONES(ItemID.WOLF_BONES, "Wolf bones", Skill.PRAYER, 1, 4.5,
CriticalItem.WOLF_BONES, null, null),
BURNT_BONES(ItemID.BURNT_BONES, "Burnt bones", Skill.PRAYER, 1, 4.5,
CriticalItem.BURNT_BONES, null, null),
MONKEY_BONES(ItemID.MONKEY_BONES, "Monkey bones", Skill.PRAYER, 1, 5.0,
CriticalItem.MONKEY_BONES, null, null),
BAT_BONES(ItemID.BAT_BONES, "Bat bones", Skill.PRAYER, 1, 5.3,
CriticalItem.BAT_BONES, null, null),
JOGRE_BONES(ItemID.JOGRE_BONES, "Jogre bones", Skill.PRAYER, 1, 15.0,
CriticalItem.JOGRE_BONES, null, null),
BIG_BONES(ItemID.BIG_BONES, "Big bones", Skill.PRAYER, 1, 15.0,
CriticalItem.BIG_BONES, null, null),
ZOGRE_BONES(ItemID.ZOGRE_BONES, "Zogre bones", Skill.PRAYER, 1, 22.5,
CriticalItem.ZOGRE_BONES, null, null),
SHAIKAHAN_BONES(ItemID.SHAIKAHAN_BONES, "Shaikahan bones", Skill.PRAYER, 1, 25.0,
CriticalItem.SHAIKAHAN_BONES, null, null),
BABYDRAGON_BONES(ItemID.BABYDRAGON_BONES, "Babydragon bones", Skill.PRAYER, 1, 30.0,
CriticalItem.BABYDRAGON_BONES, null, null),
WYVERN_BONES(ItemID.WYVERN_BONES, "Wyvern bones", Skill.PRAYER, 1, 72.0,
CriticalItem.WYVERN_BONES, null, null),
DRAGON_BONES(ItemID.DRAGON_BONES, "Dragon bones", Skill.PRAYER, 1, 72.0,
CriticalItem.DRAGON_BONES, null, null),
FAYRG_BONES(ItemID.FAYRG_BONES, "Fayrg bones", Skill.PRAYER, 1, 84.0,
CriticalItem.FAYRG_BONES, null, null),
LAVA_DRAGON_BONES(ItemID.LAVA_DRAGON_BONES, "Lava dragon bones", Skill.PRAYER, 1, 85.0,
CriticalItem.LAVA_DRAGON_BONES, null, null),
RAURG_BONES(ItemID.RAURG_BONES, "Raurg bones", Skill.PRAYER, 1, 96.0,
CriticalItem.RAURG_BONES, null, null),
DAGANNOTH_BONES(ItemID.DAGANNOTH_BONES, "Dagannoth bones", Skill.PRAYER, 1, 125.0,
CriticalItem.DAGANNOTH_BONES, null, null),
OURG_BONES(ItemID.OURG_BONES, "Ourg bones", Skill.PRAYER, 1, 140.0,
CriticalItem.OURG_BONES, null, null),
SUPERIOR_DRAGON_BONES(ItemID.SUPERIOR_DRAGON_BONES, "Superior dragon bones", Skill.PRAYER, 1, 150.0,
CriticalItem.SUPERIOR_DRAGON_BONES, null, null),
// Shade Remains (Pyre Logs)
LOAR_REMAINS(ItemID.LOAR_REMAINS, "Shades", Skill.PRAYER, 1, 33.0, CriticalItem.LOAR_REMAINS),
PHRIN_REMAINS(ItemID.PHRIN_REMAINS, "Shades", Skill.PRAYER, 1, 46.5, CriticalItem.PHRIN_REMAINS),
RIYL_REMAINS(ItemID.RIYL_REMAINS, "Shades", Skill.PRAYER, 1, 59.5, CriticalItem.RIYL_REMAINS),
ASYN_REMAINS(ItemID.ASYN_REMAINS, "Shades", Skill.PRAYER, 1, 82.5, CriticalItem.ASYN_REMAINS),
FIYR_REMAINS(ItemID.FIYR_REMAINS, "Shades", Skill.PRAYER, 1, 84.0, CriticalItem.FIYR_REMAINS),
LOAR_REMAINS(ItemID.LOAR_REMAINS, "Loar remains", Skill.PRAYER, 1, 33.0,
CriticalItem.LOAR_REMAINS, null, null),
PHRIN_REMAINS(ItemID.PHRIN_REMAINS, "Phrin remains", Skill.PRAYER, 1, 46.5,
CriticalItem.PHRIN_REMAINS, null, null),
RIYL_REMAINS(ItemID.RIYL_REMAINS, "Riyl remains", Skill.PRAYER, 1, 59.5,
CriticalItem.RIYL_REMAINS, null, null),
ASYN_REMAINS(ItemID.ASYN_REMAINS, "Asyn remains", Skill.PRAYER, 1, 82.5,
CriticalItem.ASYN_REMAINS, null, null),
FIYR_REMAINS(ItemID.FIYR_REMAINS, "Fiyre remains", Skill.PRAYER, 1, 84.0,
CriticalItem.FIYR_REMAINS, null, null),
// Ensouled Heads
ENSOULED_GOBLIN_HEAD(ItemID.ENSOULED_GOBLIN_HEAD_13448, "Ensouled Heads", Skill.PRAYER, 1, 130.0, CriticalItem.ENSOULED_GOBLIN_HEAD),
ENSOULED_MONKEY_HEAD(ItemID.ENSOULED_MONKEY_HEAD_13451, "Ensouled Heads", Skill.PRAYER, 1, 182.0, CriticalItem.ENSOULED_MONKEY_HEAD),
ENSOULED_IMP_HEAD(ItemID.ENSOULED_IMP_HEAD_13454, "Ensouled Heads", Skill.PRAYER, 1, 286.0, CriticalItem.ENSOULED_IMP_HEAD),
ENSOULED_MINOTAUR_HEAD(ItemID.ENSOULED_MINOTAUR_HEAD_13457, "Ensouled Heads", Skill.PRAYER, 1, 364.0, CriticalItem.ENSOULED_MINOTAUR_HEAD),
ENSOULED_SCORPION_HEAD(ItemID.ENSOULED_SCORPION_HEAD_13460, "Ensouled Heads", Skill.PRAYER, 1, 454.0, CriticalItem.ENSOULED_SCORPION_HEAD),
ENSOULED_BEAR_HEAD(ItemID.ENSOULED_BEAR_HEAD_13463, "Ensouled Heads", Skill.PRAYER, 1, 480.0, CriticalItem.ENSOULED_BEAR_HEAD),
ENSOULED_UNICORN_HEAD(ItemID.ENSOULED_UNICORN_HEAD_13466, "Ensouled Heads", Skill.PRAYER, 1, 494.0, CriticalItem.ENSOULED_UNICORN_HEAD),
ENSOULED_DOG_HEAD(ItemID.ENSOULED_DOG_HEAD_13469, "Ensouled Heads", Skill.PRAYER, 1, 520.0, CriticalItem.ENSOULED_DOG_HEAD),
ENSOULED_CHAOS_DRUID_HEAD(ItemID.ENSOULED_CHAOS_DRUID_HEAD_13472, "Ensouled Heads", Skill.PRAYER, 1, 584.0, CriticalItem.ENSOULED_CHAOS_DRUID_HEAD),
ENSOULED_GIANT_HEAD(ItemID.ENSOULED_GIANT_HEAD_13475, "Ensouled Heads", Skill.PRAYER, 1, 650.0, CriticalItem.ENSOULED_GIANT_HEAD),
ENSOULED_OGRE_HEAD(ItemID.ENSOULED_OGRE_HEAD_13478, "Ensouled Heads", Skill.PRAYER, 1, 716.0, CriticalItem.ENSOULED_OGRE_HEAD),
ENSOULED_ELF_HEAD(ItemID.ENSOULED_ELF_HEAD_13481, "Ensouled Heads", Skill.PRAYER, 1, 754.0, CriticalItem.ENSOULED_ELF_HEAD),
ENSOULED_TROLL_HEAD(ItemID.ENSOULED_TROLL_HEAD_13484, "Ensouled Heads", Skill.PRAYER, 1, 780.0, CriticalItem.ENSOULED_TROLL_HEAD),
ENSOULED_HORROR_HEAD(ItemID.ENSOULED_HORROR_HEAD_13487, "Ensouled Heads", Skill.PRAYER, 1, 832.0, CriticalItem.ENSOULED_HORROR_HEAD),
ENSOULED_KALPHITE_HEAD(ItemID.ENSOULED_KALPHITE_HEAD_13490, "Ensouled Heads", Skill.PRAYER, 1, 884.0, CriticalItem.ENSOULED_KALPHITE_HEAD),
ENSOULED_DAGANNOTH_HEAD(ItemID.ENSOULED_DAGANNOTH_HEAD_13493, "Ensouled Heads", Skill.PRAYER, 1, 936.0, CriticalItem.ENSOULED_DAGANNOTH_HEAD),
ENSOULED_BLOODVELD_HEAD(ItemID.ENSOULED_BLOODVELD_HEAD_13496, "Ensouled Heads", Skill.PRAYER, 1, 1040.0, CriticalItem.ENSOULED_BLOODVELD_HEAD),
ENSOULED_TZHAAR_HEAD(ItemID.ENSOULED_TZHAAR_HEAD_13499, "Ensouled Heads", Skill.PRAYER, 1, 1104.0, CriticalItem.ENSOULED_TZHAAR_HEAD),
ENSOULED_DEMON_HEAD(ItemID.ENSOULED_DEMON_HEAD_13502, "Ensouled Heads", Skill.PRAYER, 1, 1170.0, CriticalItem.ENSOULED_DEMON_HEAD),
ENSOULED_AVIANSIE_HEAD(ItemID.ENSOULED_AVIANSIE_HEAD_13505, "Ensouled Heads", Skill.PRAYER, 1, 1234.0, CriticalItem.ENSOULED_AVIANSIE_HEAD),
ENSOULED_ABYSSAL_HEAD(ItemID.ENSOULED_ABYSSAL_HEAD_13508, "Ensouled Heads", Skill.PRAYER, 1, 1300.0, CriticalItem.ENSOULED_ABYSSAL_HEAD),
ENSOULED_DRAGON_HEAD(ItemID.ENSOULED_DRAGON_HEAD_13511, "Ensouled Heads", Skill.PRAYER, 1, 1560.0, CriticalItem.ENSOULED_DRAGON_HEAD),
ENSOULED_GOBLIN_HEAD(ItemID.ENSOULED_GOBLIN_HEAD_13448, "Ensouled goblin head", Skill.PRAYER, 1, 130.0,
CriticalItem.ENSOULED_GOBLIN_HEAD, null, null),
ENSOULED_MONKEY_HEAD(ItemID.ENSOULED_MONKEY_HEAD_13451, "Ensouled monkey head", Skill.PRAYER, 1, 182.0,
CriticalItem.ENSOULED_MONKEY_HEAD, null, null),
ENSOULED_IMP_HEAD(ItemID.ENSOULED_IMP_HEAD_13454, "Ensouled imp head", Skill.PRAYER, 1, 286.0,
CriticalItem.ENSOULED_IMP_HEAD, null, null),
ENSOULED_MINOTAUR_HEAD(ItemID.ENSOULED_MINOTAUR_HEAD_13457, "Ensouled minotaur head", Skill.PRAYER, 1, 364.0,
CriticalItem.ENSOULED_MINOTAUR_HEAD, null, null),
ENSOULED_SCORPION_HEAD(ItemID.ENSOULED_SCORPION_HEAD_13460, "Ensouled scorpion head", Skill.PRAYER, 1, 454.0,
CriticalItem.ENSOULED_SCORPION_HEAD, null, null),
ENSOULED_BEAR_HEAD(ItemID.ENSOULED_BEAR_HEAD_13463, "Ensouled bear head", Skill.PRAYER, 1, 480.0,
CriticalItem.ENSOULED_BEAR_HEAD, null, null),
ENSOULED_UNICORN_HEAD(ItemID.ENSOULED_UNICORN_HEAD_13466, "Ensouled unicorn head", Skill.PRAYER, 1, 494.0,
CriticalItem.ENSOULED_UNICORN_HEAD, null, null),
ENSOULED_DOG_HEAD(ItemID.ENSOULED_DOG_HEAD_13469, "Ensouled dog head", Skill.PRAYER, 1, 520.0,
CriticalItem.ENSOULED_DOG_HEAD, null, null),
ENSOULED_CHAOS_DRUID_HEAD(ItemID.ENSOULED_CHAOS_DRUID_HEAD_13472, "Ensouled druid head", Skill.PRAYER, 1, 584.0,
CriticalItem.ENSOULED_CHAOS_DRUID_HEAD, null, null),
ENSOULED_GIANT_HEAD(ItemID.ENSOULED_GIANT_HEAD_13475, "Ensouled giant head", Skill.PRAYER, 1, 650.0,
CriticalItem.ENSOULED_GIANT_HEAD, null, null),
ENSOULED_OGRE_HEAD(ItemID.ENSOULED_OGRE_HEAD_13478, "Ensouled ogre head", Skill.PRAYER, 1, 716.0,
CriticalItem.ENSOULED_OGRE_HEAD, null, null),
ENSOULED_ELF_HEAD(ItemID.ENSOULED_ELF_HEAD_13481, "Ensouled elf head", Skill.PRAYER, 1, 754.0,
CriticalItem.ENSOULED_ELF_HEAD, null, null),
ENSOULED_TROLL_HEAD(ItemID.ENSOULED_TROLL_HEAD_13484, "Ensouled troll head", Skill.PRAYER, 1, 780.0,
CriticalItem.ENSOULED_TROLL_HEAD, null, null),
ENSOULED_HORROR_HEAD(ItemID.ENSOULED_HORROR_HEAD_13487, "Ensouled horror head", Skill.PRAYER, 1, 832.0,
CriticalItem.ENSOULED_HORROR_HEAD, null, null),
ENSOULED_KALPHITE_HEAD(ItemID.ENSOULED_KALPHITE_HEAD_13490, "Ensouled kalphite head", Skill.PRAYER, 1, 884.0,
CriticalItem.ENSOULED_KALPHITE_HEAD, null, null),
ENSOULED_DAGANNOTH_HEAD(ItemID.ENSOULED_DAGANNOTH_HEAD_13493, "Ensouled dagannoth head", Skill.PRAYER, 1, 936.0,
CriticalItem.ENSOULED_DAGANNOTH_HEAD, null, null),
ENSOULED_BLOODVELD_HEAD(ItemID.ENSOULED_BLOODVELD_HEAD_13496, "Ensouled bloodveld head", Skill.PRAYER, 1, 1040.0,
CriticalItem.ENSOULED_BLOODVELD_HEAD, null, null),
ENSOULED_TZHAAR_HEAD(ItemID.ENSOULED_TZHAAR_HEAD_13499, "Ensouled tzhaar head", Skill.PRAYER, 1, 1104.0,
CriticalItem.ENSOULED_TZHAAR_HEAD, null, null),
ENSOULED_DEMON_HEAD(ItemID.ENSOULED_DEMON_HEAD_13502, "Ensouled demon head", Skill.PRAYER, 1, 1170.0,
CriticalItem.ENSOULED_DEMON_HEAD, null, null),
ENSOULED_AVIANSIE_HEAD(ItemID.ENSOULED_AVIANSIE_HEAD_13505, "Ensouled aviansie head", Skill.PRAYER, 1, 1234.0,
CriticalItem.ENSOULED_AVIANSIE_HEAD, null, null),
ENSOULED_ABYSSAL_HEAD(ItemID.ENSOULED_ABYSSAL_HEAD_13508, "Ensouled abyssal head", Skill.PRAYER, 1, 1300.0,
CriticalItem.ENSOULED_ABYSSAL_HEAD, null, null),
ENSOULED_DRAGON_HEAD(ItemID.ENSOULED_DRAGON_HEAD_13511, "Ensouled dragon head", Skill.PRAYER, 1, 1560.0,
CriticalItem.ENSOULED_DRAGON_HEAD, null, null),
/*
* Cooking Items
*/
RAW_HERRING(ItemID.RAW_HERRING, "Fish", Skill.COOKING, 5, 50.0, CriticalItem.RAW_HERRING),
RAW_MACKEREL(ItemID.RAW_MACKEREL, "Fish", Skill.COOKING, 10, 60.0, CriticalItem.RAW_MACKEREL),
RAW_TROUT(ItemID.RAW_TROUT, "Fish", Skill.COOKING, 15, 70.0, CriticalItem.RAW_TROUT),
RAW_COD(ItemID.RAW_COD, "Fish", Skill.COOKING, 18, 75.0, CriticalItem.RAW_COD),
RAW_PIKE(ItemID.RAW_PIKE, "Fish", Skill.COOKING, 20, 80.0, CriticalItem.RAW_PIKE),
RAW_SALMON(ItemID.RAW_SALMON, "Fish", Skill.COOKING, 25, 90.0, CriticalItem.RAW_SALMON),
RAW_TUNA(ItemID.RAW_TUNA, "Fish", Skill.COOKING, 30, 100.0, CriticalItem.RAW_TUNA),
RAW_KARAMBWAN(ItemID.RAW_KARAMBWAN, "Fish", Skill.COOKING, 30, 190.0, CriticalItem.RAW_KARAMBWAN),
RAW_LOBSTER(ItemID.RAW_LOBSTER, "Fish", Skill.COOKING, 40, 120.0, CriticalItem.RAW_LOBSTER),
RAW_BASS(ItemID.RAW_BASS, "Fish", Skill.COOKING, 43, 130.0, CriticalItem.RAW_BASS),
RAW_SWORDFISH(ItemID.RAW_SWORDFISH, "Fish", Skill.COOKING, 45, 140.0, CriticalItem.RAW_SWORDFISH),
RAW_MONKFISH(ItemID.RAW_MONKFISH, "Fish", Skill.COOKING, 62, 150.0, CriticalItem.RAW_MONKFISH),
RAW_SHARK(ItemID.RAW_SHARK, "Fish", Skill.COOKING, 80, 210.0, CriticalItem.RAW_SHARK),
RAW_SEA_TURTLE(ItemID.RAW_SEA_TURTLE, "Fish", Skill.COOKING, 82, 211.3, CriticalItem.RAW_SEA_TURTLE),
RAW_ANGLERFISH(ItemID.RAW_ANGLERFISH, "Fish", Skill.COOKING, 84, 230.0, CriticalItem.RAW_ANGLERFISH),
RAW_DARK_CRAB(ItemID.RAW_DARK_CRAB, "Fish", Skill.COOKING, 90, 215.0, CriticalItem.RAW_DARK_CRAB),
RAW_MANTA_RAY(ItemID.RAW_MANTA_RAY, "Fish", Skill.COOKING, 91, 216.2, CriticalItem.RAW_MANTA_RAY),
COOK_HERRING(ItemID.HERRING, "Herring", Skill.COOKING, 5, 50.0,
CriticalItem.RAW_HERRING, null, new ItemStack(ItemID.HERRING, 1)),
COOK_MACKEREL(ItemID.MACKEREL, "Mackerel", Skill.COOKING, 10, 60.0,
CriticalItem.RAW_MACKEREL, null, new ItemStack(ItemID.MACKEREL, 1)),
COOK_TROUT(ItemID.TROUT, "Trout", Skill.COOKING, 15, 70.0,
CriticalItem.RAW_TROUT, null, new ItemStack(ItemID.TROUT, 1)),
COOK_COD(ItemID.COD, "Cod", Skill.COOKING, 18, 75.0,
CriticalItem.RAW_COD, null, new ItemStack(ItemID.COD, 1)),
COOK_PIKE(ItemID.PIKE, "Pike", Skill.COOKING, 20, 80.0,
CriticalItem.RAW_PIKE, null, new ItemStack(ItemID.PIKE, 1)),
COOK_SALMON(ItemID.SALMON, "Salmon", Skill.COOKING, 25, 90.0,
CriticalItem.RAW_SALMON, null, new ItemStack(ItemID.SALMON, 1)),
COOK_TUNA(ItemID.TUNA, "Tuna", Skill.COOKING, 30, 100.0,
CriticalItem.RAW_TUNA, null, new ItemStack(ItemID.TUNA, 1)),
COOK_KARAMBWAN(ItemID.COOKED_KARAMBWAN, "Cooked Karambwan", Skill.COOKING, 30, 190.0,
CriticalItem.RAW_KARAMBWAN, null, new ItemStack(ItemID.COOKED_KARAMBWAN, 1)),
COOK_LOBSTER(ItemID.LOBSTER, "Lobster", Skill.COOKING, 40, 120.0,
CriticalItem.RAW_LOBSTER, null, new ItemStack(ItemID.LOBSTER, 1)),
COOK_BASS(ItemID.BASS, "Bass", Skill.COOKING, 43, 130.0,
CriticalItem.RAW_BASS, null, new ItemStack(ItemID.BASS, 1)),
COOK_SWORDFISH(ItemID.SWORDFISH, "Swordfish", Skill.COOKING, 45, 140.0,
CriticalItem.RAW_SWORDFISH, null, new ItemStack(ItemID.SWORDFISH, 1)),
COOK_MONKFISH(ItemID.MONKFISH, "Monkfish", Skill.COOKING, 62, 150.0,
CriticalItem.RAW_MONKFISH, null, new ItemStack(ItemID.MONKFISH, 1)),
COOK_SHARK(ItemID.SHARK, "Shark", Skill.COOKING, 80, 210.0,
CriticalItem.RAW_SHARK, null, new ItemStack(ItemID.SHARK, 1)),
COOK_SEA_TURTLE(ItemID.SEA_TURTLE, "Sea turtle", Skill.COOKING, 82, 211.3,
CriticalItem.RAW_SEA_TURTLE, null, new ItemStack(ItemID.SEA_TURTLE, 1)),
COOK_ANGLERFISH(ItemID.ANGLERFISH, "Anglerfish", Skill.COOKING, 84, 230.0,
CriticalItem.RAW_ANGLERFISH, null, new ItemStack(ItemID.ANGLERFISH, 1)),
COOK_DARK_CRAB(ItemID.DARK_CRAB, "Dark crab", Skill.COOKING, 90, 215.0,
CriticalItem.RAW_DARK_CRAB, null, new ItemStack(ItemID.DARK_CRAB, 1)),
COOK_MANTA_RAY(ItemID.MANTA_RAY, "Manta ray", Skill.COOKING, 91, 216.2,
CriticalItem.RAW_MANTA_RAY, null, new ItemStack(ItemID.MANTA_RAY, 1)),
WINE(ItemID.JUG_OF_WINE, "Other", Skill.COOKING, 35, 200, CriticalItem.GRAPES, ActivitySecondaries.JUG_OF_WATER),
WINE(ItemID.JUG_OF_WINE, "Jug of wine", Skill.COOKING, 35, 200,
CriticalItem.GRAPES, Secondaries.JUG_OF_WATER, new ItemStack(ItemID.JUG_OF_WINE, 1)),
/*
* Crafting Items
*/
// Spinning
BALL_OF_WOOL(ItemID.WOOL, "Misc", Skill.CRAFTING, 1, 2.5, CriticalItem.WOOL),
BOW_STRING(ItemID.BOW_STRING, "Misc", Skill.CRAFTING, 1, 15, CriticalItem.FLAX),
BALL_OF_WOOL(ItemID.BALL_OF_WOOL, "Ball of wool", Skill.CRAFTING, 1, 2.5,
CriticalItem.WOOL, null, new ItemStack(ItemID.BALL_OF_WOOL, 1)),
BOW_STRING(ItemID.BOW_STRING, "Bow string", Skill.CRAFTING, 1, 15,
CriticalItem.FLAX, null, new ItemStack(ItemID.BOW_STRING, 1)),
// Glass Blowing
BEER_GLASS(ItemID.BEER_GLASS, "Beer Glass", Skill.CRAFTING, 1, 17.5, CriticalItem.MOLTEN_GLASS),
CANDLE_LANTERN(ItemID.CANDLE_LANTERN, "Candle Lantern", Skill.CRAFTING, 4, 19, CriticalItem.MOLTEN_GLASS),
OIL_LAMP(ItemID.OIL_LAMP, "Oil Lamp", Skill.CRAFTING, 12, 25, CriticalItem.MOLTEN_GLASS),
VIAL(ItemID.VIAL, "Vial", Skill.CRAFTING, 33, 35, CriticalItem.MOLTEN_GLASS),
EMPTY_FISHBOWL(ItemID.EMPTY_FISHBOWL, "Empty fishbowl", Skill.CRAFTING, 42, 42.5, CriticalItem.MOLTEN_GLASS),
UNPOWERED_ORB(ItemID.UNPOWERED_ORB, "Unpowered orb", Skill.CRAFTING, 46, 52.5, CriticalItem.MOLTEN_GLASS),
LANTERN_LENS(ItemID.LANTERN_LENS, "Lantern lens", Skill.CRAFTING, 49, 55, CriticalItem.MOLTEN_GLASS),
LIGHT_ORB(ItemID.LIGHT_ORB, "Light orb", Skill.CRAFTING, 87, 70, CriticalItem.MOLTEN_GLASS),
BEER_GLASS(ItemID.BEER_GLASS, "Beer glass", Skill.CRAFTING, 1, 17.5,
CriticalItem.MOLTEN_GLASS, null, new ItemStack(ItemID.BEER_GLASS, 1)),
CANDLE_LANTERN(ItemID.CANDLE_LANTERN, "Candle lantern", Skill.CRAFTING, 4, 19,
CriticalItem.MOLTEN_GLASS, null, new ItemStack(ItemID.CANDLE_LANTERN, 1)),
OIL_LAMP(ItemID.OIL_LAMP, "Oil lamp", Skill.CRAFTING, 12, 25,
CriticalItem.MOLTEN_GLASS, null, new ItemStack(ItemID.OIL_LAMP, 1)),
VIAL(ItemID.VIAL, "Vial", Skill.CRAFTING, 33, 35,
CriticalItem.MOLTEN_GLASS, null, new ItemStack(ItemID.VIAL, 1)),
EMPTY_FISHBOWL(ItemID.EMPTY_FISHBOWL, "Empty fishbowl", Skill.CRAFTING, 42, 42.5,
CriticalItem.MOLTEN_GLASS, null, new ItemStack(ItemID.EMPTY_FISHBOWL, 1)),
UNPOWERED_ORB(ItemID.UNPOWERED_ORB, "Unpowered orb", Skill.CRAFTING, 46, 52.5,
CriticalItem.MOLTEN_GLASS, null, new ItemStack(ItemID.UNPOWERED_ORB, 1)),
LANTERN_LENS(ItemID.LANTERN_LENS, "Lantern lens", Skill.CRAFTING, 49, 55,
CriticalItem.MOLTEN_GLASS, null, new ItemStack(ItemID.LANTERN_LENS, 1)),
LIGHT_ORB(ItemID.LIGHT_ORB, "Light orb", Skill.CRAFTING, 87, 70,
CriticalItem.MOLTEN_GLASS, null, new ItemStack(ItemID.LIGHT_ORB, 1)),
// D'hide/Dragon Leather
GREEN_DRAGON_LEATHER(ItemID.GREEN_DRAGON_LEATHER, "D'hide", Skill.CRAFTING, 57, 62.0, CriticalItem.GREEN_DRAGON_LEATHER),
BLUE_DRAGON_LEATHER(ItemID.BLUE_DRAGON_LEATHER, "D'hide", Skill.CRAFTING, 66, 70.0, CriticalItem.BLUE_DRAGON_LEATHER),
RED_DRAGON_LEATHER(ItemID.RED_DRAGON_LEATHER, "D'hide", Skill.CRAFTING, 73, 78.0, CriticalItem.RED_DRAGON_LEATHER),
BLACK_DRAGON_LEATHER(ItemID.BLACK_DRAGON_LEATHER, "D'hide", Skill.CRAFTING, 79, 86.0, CriticalItem.BLACK_DRAGON_LEATHER),
GREEN_DRAGONHIDE(ItemID.GREEN_DRAGON_LEATHER, "Tan Green D'hide", Skill.CRAFTING, 57, 0,
CriticalItem.GREEN_DRAGONHIDE, null, new ItemStack(ItemID.GREEN_DRAGON_LEATHER, 1)),
BLUE_DRAGONHIDE(ItemID.BLUE_DRAGON_LEATHER, "Tan Blue D'hide", Skill.CRAFTING, 66, 0,
CriticalItem.BLUE_DRAGONHIDE, null, new ItemStack(ItemID.BLUE_DRAGON_LEATHER, 1)),
RED_DRAGONHIDE(ItemID.RED_DRAGON_LEATHER, "Tan Red D'hide", Skill.CRAFTING, 73, 0,
CriticalItem.RED_DRAGONHIDE, null, new ItemStack(ItemID.RED_DRAGON_LEATHER, 1)),
BLACK_DRAGONHIDE(ItemID.BLACK_DRAGON_LEATHER, "Tan Black D'hide", Skill.CRAFTING, 79, 0,
CriticalItem.BLACK_DRAGONHIDE, null, new ItemStack(ItemID.BLACK_DRAGON_LEATHER, 1)),
GREEN_DRAGON_LEATHER(ItemID.GREEN_DHIDE_VAMB, "Green D'hide product", Skill.CRAFTING, 57, 62.0,
CriticalItem.GREEN_DRAGON_LEATHER, null, null),
BLUE_DRAGON_LEATHER(ItemID.BLUE_DHIDE_VAMB, "Blue D'hide product", Skill.CRAFTING, 66, 70.0,
CriticalItem.BLUE_DRAGON_LEATHER, null, null),
RED_DRAGON_LEATHER(ItemID.RED_DHIDE_VAMB, "Red D'hide product", Skill.CRAFTING, 73, 78.0,
CriticalItem.RED_DRAGON_LEATHER, null, null),
BLACK_DRAGON_LEATHER(ItemID.BLACK_DHIDE_VAMB, "Black D'hide product", Skill.CRAFTING, 79, 86.0,
CriticalItem.BLACK_DRAGON_LEATHER, null, null),
// Uncut Gems
UNCUT_OPAL(ItemID.UNCUT_OPAL, "Gems", Skill.CRAFTING, 1, 15.0, CriticalItem.UNCUT_OPAL),
UNCUT_JADE(ItemID.UNCUT_JADE, "Gems", Skill.CRAFTING, 13, 20.0, CriticalItem.UNCUT_JADE),
UNCUT_RED_TOPAZ(ItemID.UNCUT_RED_TOPAZ, "Gems", Skill.CRAFTING, 16, 25.0, CriticalItem.UNCUT_RED_TOPAZ),
UNCUT_SAPPHIRE(ItemID.UNCUT_SAPPHIRE, "Gems", Skill.CRAFTING, 20, 50.0, CriticalItem.UNCUT_SAPPHIRE),
UNCUT_EMERALD(ItemID.UNCUT_EMERALD, "Gems", Skill.CRAFTING, 27, 67.5, CriticalItem.UNCUT_EMERALD),
UNCUT_RUBY(ItemID.UNCUT_RUBY, "Gems", Skill.CRAFTING, 34, 85, CriticalItem.UNCUT_RUBY),
UNCUT_DIAMOND(ItemID.UNCUT_DIAMOND, "Gems", Skill.CRAFTING, 43, 107.5, CriticalItem.UNCUT_DIAMOND),
UNCUT_DRAGONSTONE(ItemID.UNCUT_DRAGONSTONE, "Gems", Skill.CRAFTING, 55, 137.5, CriticalItem.UNCUT_DRAGONSTONE),
UNCUT_ONYX(ItemID.UNCUT_ONYX, "Gems", Skill.CRAFTING, 67, 167.5, CriticalItem.UNCUT_ONYX),
UNCUT_ZENYTE(ItemID.UNCUT_ZENYTE, "Gems", Skill.CRAFTING, 89, 200.0, CriticalItem.UNCUT_ZENYTE),
UNCUT_OPAL(ItemID.OPAL, "Cut opal", Skill.CRAFTING, 1, 15.0,
CriticalItem.UNCUT_OPAL, null, new ItemStack(ItemID.OPAL, 1)),
UNCUT_JADE(ItemID.JADE, "Cut jade", Skill.CRAFTING, 13, 20.0,
CriticalItem.UNCUT_JADE, null, new ItemStack(ItemID.JADE, 1)),
UNCUT_RED_TOPAZ(ItemID.RED_TOPAZ, "Cut red topaz", Skill.CRAFTING, 16, 25.0,
CriticalItem.UNCUT_RED_TOPAZ, null, new ItemStack(ItemID.RED_TOPAZ, 1)),
UNCUT_SAPPHIRE(ItemID.SAPPHIRE, "Cut sapphire", Skill.CRAFTING, 20, 50.0,
CriticalItem.UNCUT_SAPPHIRE, null, new ItemStack(ItemID.SAPPHIRE, 1)),
UNCUT_EMERALD(ItemID.EMERALD, "Cut emerald", Skill.CRAFTING, 27, 67.5,
CriticalItem.UNCUT_EMERALD, null, new ItemStack(ItemID.EMERALD, 1)),
UNCUT_RUBY(ItemID.RUBY, "Cut ruby", Skill.CRAFTING, 34, 85,
CriticalItem.UNCUT_RUBY, null, new ItemStack(ItemID.RUBY, 1)),
UNCUT_DIAMOND(ItemID.DIAMOND, "Cut diamond", Skill.CRAFTING, 43, 107.5,
CriticalItem.UNCUT_DIAMOND, null, new ItemStack(ItemID.DIAMOND, 1)),
UNCUT_DRAGONSTONE(ItemID.DRAGONSTONE, "Cut dragonstone", Skill.CRAFTING, 55, 137.5,
CriticalItem.UNCUT_DRAGONSTONE, null, new ItemStack(ItemID.DRAGONSTONE, 1)),
UNCUT_ONYX(ItemID.ONYX, "Cut onyx", Skill.CRAFTING, 67, 167.5,
CriticalItem.UNCUT_ONYX, null, new ItemStack(ItemID.ONYX, 1)),
UNCUT_ZENYTE(ItemID.ZENYTE, "Cut zenyte", Skill.CRAFTING, 89, 200.0,
CriticalItem.UNCUT_ZENYTE, null, new ItemStack(ItemID.ZENYTE, 1)),
// Silver Jewelery
OPAL_RING(ItemID.OPAL_RING, "Opal ring", Skill.CRAFTING, 1, 10, CriticalItem.OPAL, ActivitySecondaries.SILVER_BAR),
OPAL_NECKLACE(ItemID.OPAL_NECKLACE, "Opal necklace", Skill.CRAFTING, 16, 35, CriticalItem.OPAL, ActivitySecondaries.SILVER_BAR),
OPAL_BRACELET(ItemID.OPAL_BRACELET, "Opal bracelet", Skill.CRAFTING, 22, 45, CriticalItem.OPAL, ActivitySecondaries.SILVER_BAR),
OPAL_AMULET(ItemID.OPAL_AMULET, "Opal amulet", Skill.CRAFTING, 27, 55, CriticalItem.OPAL, ActivitySecondaries.SILVER_BAR),
JADE_RING(ItemID.JADE_RING, "Jade ring", Skill.CRAFTING, 13, 32, CriticalItem.JADE, ActivitySecondaries.SILVER_BAR),
JADE_NECKLACE(ItemID.JADE_NECKLACE, "Jade necklace", Skill.CRAFTING, 25, 54, CriticalItem.JADE, ActivitySecondaries.SILVER_BAR),
JADE_BRACELET(ItemID.JADE_BRACELET, "Jade bracelet", Skill.CRAFTING, 29, 60, CriticalItem.JADE, ActivitySecondaries.SILVER_BAR),
JADE_AMULET(ItemID.JADE_AMULET, "Jade amulet", Skill.CRAFTING, 34, 70, CriticalItem.JADE, ActivitySecondaries.SILVER_BAR),
TOPAZ_RING(ItemID.TOPAZ_RING, "Topaz ring", Skill.CRAFTING, 16, 35, CriticalItem.RED_TOPAZ, ActivitySecondaries.SILVER_BAR),
TOPAZ_NECKLACE(ItemID.TOPAZ_NECKLACE, "Topaz necklace", Skill.CRAFTING, 32, 70, CriticalItem.RED_TOPAZ, ActivitySecondaries.SILVER_BAR),
TOPAZ_BRACELET(ItemID.TOPAZ_BRACELET, "Topaz bracelet", Skill.CRAFTING, 38, 75, CriticalItem.RED_TOPAZ, ActivitySecondaries.SILVER_BAR),
TOPAZ_AMULET(ItemID.TOPAZ_AMULET, "Topaz amulet", Skill.CRAFTING, 45, 80, CriticalItem.RED_TOPAZ, ActivitySecondaries.SILVER_BAR),
OPAL_RING(ItemID.OPAL_RING, "Opal ring", Skill.CRAFTING, 1, 10,
CriticalItem.OPAL, Secondaries.SILVER_BAR, new ItemStack(ItemID.OPAL_RING, 1)),
OPAL_NECKLACE(ItemID.OPAL_NECKLACE, "Opal necklace", Skill.CRAFTING, 16, 35,
CriticalItem.OPAL, Secondaries.SILVER_BAR, new ItemStack(ItemID.OPAL_NECKLACE, 1)),
OPAL_BRACELET(ItemID.OPAL_BRACELET, "Opal bracelet", Skill.CRAFTING, 22, 45,
CriticalItem.OPAL, Secondaries.SILVER_BAR, new ItemStack(ItemID.OPAL_BRACELET, 1)),
OPAL_AMULET(ItemID.OPAL_AMULET, "Opal amulet", Skill.CRAFTING, 27, 55,
CriticalItem.OPAL, Secondaries.SILVER_BAR, new ItemStack(ItemID.OPAL_AMULET, 1)),
JADE_RING(ItemID.JADE_RING, "Jade ring", Skill.CRAFTING, 13, 32,
CriticalItem.JADE, Secondaries.SILVER_BAR, new ItemStack(ItemID.JADE_RING, 1)),
JADE_NECKLACE(ItemID.JADE_NECKLACE, "Jade necklace", Skill.CRAFTING, 25, 54,
CriticalItem.JADE, Secondaries.SILVER_BAR, new ItemStack(ItemID.JADE_NECKLACE, 1)),
JADE_BRACELET(ItemID.JADE_BRACELET, "Jade bracelet", Skill.CRAFTING, 29, 60,
CriticalItem.JADE, Secondaries.SILVER_BAR, new ItemStack(ItemID.JADE_BRACELET, 1)),
JADE_AMULET(ItemID.JADE_AMULET, "Jade amulet", Skill.CRAFTING, 34, 70,
CriticalItem.JADE, Secondaries.SILVER_BAR, new ItemStack(ItemID.JADE_AMULET, 1)),
TOPAZ_RING(ItemID.TOPAZ_RING, "Topaz ring", Skill.CRAFTING, 16, 35,
CriticalItem.RED_TOPAZ, Secondaries.SILVER_BAR, new ItemStack(ItemID.TOPAZ_RING, 1)),
TOPAZ_NECKLACE(ItemID.TOPAZ_NECKLACE, "Topaz necklace", Skill.CRAFTING, 32, 70,
CriticalItem.RED_TOPAZ, Secondaries.SILVER_BAR, new ItemStack(ItemID.TOPAZ_NECKLACE, 1)),
TOPAZ_BRACELET(ItemID.TOPAZ_BRACELET, "Topaz bracelet", Skill.CRAFTING, 38, 75,
CriticalItem.RED_TOPAZ, Secondaries.SILVER_BAR, new ItemStack(ItemID.TOPAZ_BRACELET, 1)),
TOPAZ_AMULET(ItemID.TOPAZ_AMULET, "Topaz amulet", Skill.CRAFTING, 45, 80,
CriticalItem.RED_TOPAZ, Secondaries.SILVER_BAR, new ItemStack(ItemID.TOPAZ_AMULET, 1)),
// Gold Jewelery
SAPPHIRE_RING(ItemID.SAPPHIRE_RING, "Sapphire ring", Skill.CRAFTING, 20, 40, CriticalItem.SAPPHIRE, ActivitySecondaries.GOLD_BAR),
SAPPHIRE_NECKLACE(ItemID.SAPPHIRE_NECKLACE, "Sapphire necklace", Skill.CRAFTING, 22, 55, CriticalItem.SAPPHIRE, ActivitySecondaries.GOLD_BAR),
SAPPHIRE_BRACELET(ItemID.SAPPHIRE_BRACELET, "Sapphire bracelet", Skill.CRAFTING, 23, 60, CriticalItem.SAPPHIRE, ActivitySecondaries.GOLD_BAR),
SAPPHIRE_AMULET(ItemID.SAPPHIRE_AMULET, "Sapphire amulet", Skill.CRAFTING, 24, 65, CriticalItem.SAPPHIRE, ActivitySecondaries.GOLD_BAR),
EMERALD_RING(ItemID.EMERALD_RING, "Emerald ring", Skill.CRAFTING, 27, 55, CriticalItem.EMERALD, ActivitySecondaries.GOLD_BAR),
EMERALD_NECKLACE(ItemID.EMERALD_NECKLACE, "Emerald necklace", Skill.CRAFTING, 29, 60, CriticalItem.EMERALD, ActivitySecondaries.GOLD_BAR),
EMERALD_BRACELET(ItemID.EMERALD_BRACELET, "Emerald bracelet", Skill.CRAFTING, 30, 65, CriticalItem.EMERALD, ActivitySecondaries.GOLD_BAR),
EMERALD_AMULET(ItemID.EMERALD_AMULET, "Emerald amulet", Skill.CRAFTING, 31, 70, CriticalItem.EMERALD, ActivitySecondaries.GOLD_BAR),
RUBY_RING(ItemID.RUBY_RING, "Ruby ring", Skill.CRAFTING, 34, 70, CriticalItem.RUBY, ActivitySecondaries.GOLD_BAR),
RUBY_NECKLACE(ItemID.RUBY_NECKLACE, "Ruby necklace", Skill.CRAFTING, 40, 75, CriticalItem.RUBY, ActivitySecondaries.GOLD_BAR),
RUBY_BRACELET(ItemID.RUBY_BRACELET, "Ruby bracelet", Skill.CRAFTING, 42, 80, CriticalItem.RUBY, ActivitySecondaries.GOLD_BAR),
RUBY_AMULET(ItemID.RUBY_AMULET, "Ruby amulet", Skill.CRAFTING, 50, 85, CriticalItem.RUBY, ActivitySecondaries.GOLD_BAR),
DIAMOND_RING(ItemID.DIAMOND_RING, "Diamond ring", Skill.CRAFTING, 43, 85, CriticalItem.DIAMOND, ActivitySecondaries.GOLD_BAR),
DIAMOND_NECKLACE(ItemID.DIAMOND_NECKLACE, "Diamond necklace", Skill.CRAFTING, 56, 90, CriticalItem.DIAMOND, ActivitySecondaries.GOLD_BAR),
DIAMOND_BRACELET(ItemID.DIAMOND_BRACELET, "Diamond bracelet", Skill.CRAFTING, 58, 95, CriticalItem.DIAMOND, ActivitySecondaries.GOLD_BAR),
DIAMOND_AMULET(ItemID.DIAMOND_AMULET, "Diamond amulet", Skill.CRAFTING, 70, 100, CriticalItem.DIAMOND, ActivitySecondaries.GOLD_BAR),
DRAGONSTONE_RING(ItemID.DRAGONSTONE_RING, "Dragonstone ring", Skill.CRAFTING, 55, 100, CriticalItem.DRAGONSTONE, ActivitySecondaries.GOLD_BAR),
DRAGON_NECKLACE(ItemID.DRAGON_NECKLACE, "Dragon necklace", Skill.CRAFTING, 72, 105, CriticalItem.DRAGONSTONE, ActivitySecondaries.GOLD_BAR),
DRAGONSTONE_BRACELET(ItemID.DRAGONSTONE_BRACELET, "Dragonstone bracelet", Skill.CRAFTING, 74, 110, CriticalItem.DRAGONSTONE, ActivitySecondaries.GOLD_BAR),
DRAGONSTONE_AMULET(ItemID.DRAGONSTONE_AMULET, "Dragonstone amulet", Skill.CRAFTING, 80, 150, CriticalItem.DRAGONSTONE, ActivitySecondaries.GOLD_BAR),
ONYX_RING(ItemID.ONYX_RING, "Onyx ring", Skill.CRAFTING, 67, 115, CriticalItem.ONYX, ActivitySecondaries.GOLD_BAR),
ONYX_NECKLACE(ItemID.ONYX_NECKLACE, "Onyx necklace", Skill.CRAFTING, 82, 120, CriticalItem.ONYX, ActivitySecondaries.GOLD_BAR),
REGEN_BRACELET(ItemID.REGEN_BRACELET, "Regen bracelet", Skill.CRAFTING, 84, 125, CriticalItem.ONYX, ActivitySecondaries.GOLD_BAR),
ONYX_AMULET(ItemID.ONYX_AMULET, "Onyx amulet", Skill.CRAFTING, 90, 165, CriticalItem.ONYX, ActivitySecondaries.GOLD_BAR),
ZENYTE_RING(ItemID.ZENYTE_RING, "Zenyte ring", Skill.CRAFTING, 89, 150, CriticalItem.ZENYTE, ActivitySecondaries.GOLD_BAR),
ZENYTE_NECKLACE(ItemID.ZENYTE_NECKLACE, "Zenyte necklace", Skill.CRAFTING, 92, 165, CriticalItem.ZENYTE, ActivitySecondaries.GOLD_BAR),
ZENYTE_BRACELET(ItemID.ZENYTE_BRACELET, "Zenyte bracelet", Skill.CRAFTING, 95, 180, CriticalItem.ZENYTE, ActivitySecondaries.GOLD_BAR),
ZENYTE_AMULET(ItemID.ZENYTE_AMULET, "Zenyte amulet", Skill.CRAFTING, 98, 200, CriticalItem.ZENYTE, ActivitySecondaries.GOLD_BAR),
SAPPHIRE_RING(ItemID.SAPPHIRE_RING, "Sapphire ring", Skill.CRAFTING, 20, 40,
CriticalItem.SAPPHIRE, Secondaries.GOLD_BAR, new ItemStack(ItemID.SAPPHIRE_RING, 1)),
SAPPHIRE_NECKLACE(ItemID.SAPPHIRE_NECKLACE, "Sapphire necklace", Skill.CRAFTING, 22, 55,
CriticalItem.SAPPHIRE, Secondaries.GOLD_BAR, new ItemStack(ItemID.SAPPHIRE_NECKLACE, 1)),
SAPPHIRE_BRACELET(ItemID.SAPPHIRE_BRACELET, "Sapphire bracelet", Skill.CRAFTING, 23, 60,
CriticalItem.SAPPHIRE, Secondaries.GOLD_BAR, new ItemStack(ItemID.SAPPHIRE_BRACELET, 1)),
SAPPHIRE_AMULET(ItemID.SAPPHIRE_AMULET, "Sapphire amulet", Skill.CRAFTING, 24, 65,
CriticalItem.SAPPHIRE, Secondaries.GOLD_BAR, new ItemStack(ItemID.SAPPHIRE_AMULET, 1)),
EMERALD_RING(ItemID.EMERALD_RING, "Emerald ring", Skill.CRAFTING, 27, 55,
CriticalItem.EMERALD, Secondaries.GOLD_BAR, new ItemStack(ItemID.EMERALD_RING, 1)),
EMERALD_NECKLACE(ItemID.EMERALD_NECKLACE, "Emerald necklace", Skill.CRAFTING, 29, 60,
CriticalItem.EMERALD, Secondaries.GOLD_BAR, new ItemStack(ItemID.EMERALD_NECKLACE, 1)),
EMERALD_BRACELET(ItemID.EMERALD_BRACELET, "Emerald bracelet", Skill.CRAFTING, 30, 65,
CriticalItem.EMERALD, Secondaries.GOLD_BAR, new ItemStack(ItemID.EMERALD_BRACELET, 1)),
EMERALD_AMULET(ItemID.EMERALD_AMULET, "Emerald amulet", Skill.CRAFTING, 31, 70,
CriticalItem.EMERALD, Secondaries.GOLD_BAR, new ItemStack(ItemID.EMERALD_AMULET, 1)),
RUBY_RING(ItemID.RUBY_RING, "Ruby ring", Skill.CRAFTING, 34, 70,
CriticalItem.RUBY, Secondaries.GOLD_BAR, new ItemStack(ItemID.RUBY_RING, 1)),
RUBY_NECKLACE(ItemID.RUBY_NECKLACE, "Ruby necklace", Skill.CRAFTING, 40, 75,
CriticalItem.RUBY, Secondaries.GOLD_BAR, new ItemStack(ItemID.RUBY_NECKLACE, 1)),
RUBY_BRACELET(ItemID.RUBY_BRACELET, "Ruby bracelet", Skill.CRAFTING, 42, 80,
CriticalItem.RUBY, Secondaries.GOLD_BAR, new ItemStack(ItemID.RUBY_BRACELET, 1)),
RUBY_AMULET(ItemID.RUBY_AMULET, "Ruby amulet", Skill.CRAFTING, 50, 85,
CriticalItem.RUBY, Secondaries.GOLD_BAR, new ItemStack(ItemID.RUBY_AMULET, 1)),
DIAMOND_RING(ItemID.DIAMOND_RING, "Diamond ring", Skill.CRAFTING, 43, 85,
CriticalItem.DIAMOND, Secondaries.GOLD_BAR, new ItemStack(ItemID.DIAMOND_RING, 1)),
DIAMOND_NECKLACE(ItemID.DIAMOND_NECKLACE, "Diamond necklace", Skill.CRAFTING, 56, 90,
CriticalItem.DIAMOND, Secondaries.GOLD_BAR, new ItemStack(ItemID.DIAMOND_NECKLACE, 1)),
DIAMOND_BRACELET(ItemID.DIAMOND_BRACELET, "Diamond bracelet", Skill.CRAFTING, 58, 95,
CriticalItem.DIAMOND, Secondaries.GOLD_BAR, new ItemStack(ItemID.DIAMOND_BRACELET, 1)),
DIAMOND_AMULET(ItemID.DIAMOND_AMULET, "Diamond amulet", Skill.CRAFTING, 70, 100,
CriticalItem.DIAMOND, Secondaries.GOLD_BAR, new ItemStack(ItemID.DIAMOND_AMULET, 1)),
DRAGONSTONE_RING(ItemID.DRAGONSTONE_RING, "Dragonstone ring", Skill.CRAFTING, 55, 100,
CriticalItem.DRAGONSTONE, Secondaries.GOLD_BAR, new ItemStack(ItemID.DRAGONSTONE_RING, 1)),
DRAGON_NECKLACE(ItemID.DRAGON_NECKLACE, "Dragon necklace", Skill.CRAFTING, 72, 105,
CriticalItem.DRAGONSTONE, Secondaries.GOLD_BAR, new ItemStack(ItemID.DRAGON_NECKLACE, 1)),
DRAGONSTONE_BRACELET(ItemID.DRAGONSTONE_BRACELET, "Dragonstone bracelet", Skill.CRAFTING, 74, 110,
CriticalItem.DRAGONSTONE, Secondaries.GOLD_BAR, new ItemStack(ItemID.DRAGONSTONE_BRACELET, 1)),
DRAGONSTONE_AMULET(ItemID.DRAGONSTONE_AMULET, "Dragonstone amulet", Skill.CRAFTING, 80, 150,
CriticalItem.DRAGONSTONE, Secondaries.GOLD_BAR, new ItemStack(ItemID.DRAGONSTONE_AMULET, 1)),
ONYX_RING(ItemID.ONYX_RING, "Onyx ring", Skill.CRAFTING, 67, 115,
CriticalItem.ONYX, Secondaries.GOLD_BAR, new ItemStack(ItemID.ONYX_RING, 1)),
ONYX_NECKLACE(ItemID.ONYX_NECKLACE, "Onyx necklace", Skill.CRAFTING, 82, 120,
CriticalItem.ONYX, Secondaries.GOLD_BAR, new ItemStack(ItemID.ONYX_NECKLACE, 1)),
REGEN_BRACELET(ItemID.REGEN_BRACELET, "Regen bracelet", Skill.CRAFTING, 84, 125,
CriticalItem.ONYX, Secondaries.GOLD_BAR, new ItemStack(ItemID.REGEN_BRACELET, 1)),
ONYX_AMULET(ItemID.ONYX_AMULET, "Onyx amulet", Skill.CRAFTING, 90, 165,
CriticalItem.ONYX, Secondaries.GOLD_BAR, new ItemStack(ItemID.ONYX_AMULET, 1)),
ZENYTE_RING(ItemID.ZENYTE_RING, "Zenyte ring", Skill.CRAFTING, 89, 150,
CriticalItem.ZENYTE, Secondaries.GOLD_BAR, new ItemStack(ItemID.ZENYTE_RING, 1)),
ZENYTE_NECKLACE(ItemID.ZENYTE_NECKLACE, "Zenyte necklace", Skill.CRAFTING, 92, 165,
CriticalItem.ZENYTE, Secondaries.GOLD_BAR, new ItemStack(ItemID.ZENYTE_NECKLACE, 1)),
ZENYTE_BRACELET(ItemID.ZENYTE_BRACELET, "Zenyte bracelet", Skill.CRAFTING, 95, 180,
CriticalItem.ZENYTE, Secondaries.GOLD_BAR, new ItemStack(ItemID.ZENYTE_BRACELET, 1)),
ZENYTE_AMULET(ItemID.ZENYTE_AMULET, "Zenyte amulet", Skill.CRAFTING, 98, 200,
CriticalItem.ZENYTE, Secondaries.GOLD_BAR, new ItemStack(ItemID.ZENYTE_AMULET, 1)),
// Battle Staves
WATER_BATTLESTAFF(ItemID.WATER_BATTLESTAFF, "Water battlestaff", Skill.CRAFTING, 54, 100, CriticalItem.BATTLESTAFF, ActivitySecondaries.WATER_ORB),
EARTH_BATTLESTAFF(ItemID.EARTH_BATTLESTAFF, "Earth battlestaff", Skill.CRAFTING, 58, 112.5, CriticalItem.BATTLESTAFF, ActivitySecondaries.EARTH_ORB),
FIRE_BATTLESTAFF(ItemID.FIRE_BATTLESTAFF, "Fire battlestaff", Skill.CRAFTING, 62, 125, CriticalItem.BATTLESTAFF, ActivitySecondaries.FIRE_ORB),
AIR_BATTLESTAFF(ItemID.AIR_BATTLESTAFF, "Air battlestaff", Skill.CRAFTING, 66, 137.5, CriticalItem.BATTLESTAFF, ActivitySecondaries.AIR_ORB),
WATER_BATTLESTAFF(ItemID.WATER_BATTLESTAFF, "Water battlestaff", Skill.CRAFTING, 54, 100,
CriticalItem.BATTLESTAFF, Secondaries.WATER_ORB, new ItemStack(ItemID.WATER_BATTLESTAFF, 1)),
EARTH_BATTLESTAFF(ItemID.EARTH_BATTLESTAFF, "Earth battlestaff", Skill.CRAFTING, 58, 112.5,
CriticalItem.BATTLESTAFF, Secondaries.EARTH_ORB, new ItemStack(ItemID.EARTH_BATTLESTAFF, 1)),
FIRE_BATTLESTAFF(ItemID.FIRE_BATTLESTAFF, "Fire battlestaff", Skill.CRAFTING, 62, 125,
CriticalItem.BATTLESTAFF, Secondaries.FIRE_ORB, new ItemStack(ItemID.FIRE_BATTLESTAFF, 1)),
AIR_BATTLESTAFF(ItemID.AIR_BATTLESTAFF, "Air battlestaff", Skill.CRAFTING, 66, 137.5,
CriticalItem.BATTLESTAFF, Secondaries.AIR_ORB, new ItemStack(ItemID.AIR_BATTLESTAFF, 1)),
/*
* Smithing Items
*/
// Smelting ores (Furnace)
IRON_ORE(ItemID.IRON_BAR, "Iron Bars", Skill.SMITHING, 15, 12.5, CriticalItem.IRON_ORE, ActivitySecondaries.COAL_ORE),
STEEL_ORE(ItemID.STEEL_BAR, "Steel Bars", Skill.SMITHING, 30, 17.5, CriticalItem.IRON_ORE, ActivitySecondaries.COAL_ORE_2),
SILVER_ORE(ItemID.SILVER_ORE, "Bar", Skill.SMITHING, 20, 13.67, CriticalItem.SILVER_ORE),
GOLD_ORE(ItemID.GOLD_BAR, "Regular exp", Skill.SMITHING, 40, 22.5, CriticalItem.GOLD_ORE),
GOLD_ORE_GAUNTLETS(ItemID.GOLDSMITH_GAUNTLETS, "Goldsmith Gauntlets", Skill.SMITHING, 40, 56.2, CriticalItem.GOLD_ORE),
MITHRIL_ORE(ItemID.MITHRIL_ORE, "Bar", Skill.SMITHING, 50, 30, CriticalItem.MITHRIL_ORE, ActivitySecondaries.COAL_ORE_4),
ADAMANTITE_ORE(ItemID.ADAMANTITE_ORE, "Bar", Skill.SMITHING, 70, 37.5, CriticalItem.ADAMANTITE_ORE, ActivitySecondaries.COAL_ORE_6),
RUNITE_ORE(ItemID.RUNITE_ORE, "Bar", Skill.SMITHING, 85, 50, CriticalItem.RUNITE_ORE, ActivitySecondaries.COAL_ORE_8),
IRON_ORE(ItemID.IRON_BAR, "Iron bar", Skill.SMITHING, 15, 12.5,
CriticalItem.IRON_ORE, Secondaries.COAL_ORE, new ItemStack(ItemID.IRON_BAR, 1)),
STEEL_ORE(ItemID.STEEL_BAR, "Steel bar", Skill.SMITHING, 30, 17.5,
CriticalItem.IRON_ORE, Secondaries.COAL_ORE_2, new ItemStack(ItemID.STEEL_BAR, 1)),
SILVER_ORE(ItemID.SILVER_BAR, "Silver Bar", Skill.SMITHING, 20, 13.67,
CriticalItem.SILVER_ORE, null, new ItemStack(ItemID.SILVER_BAR, 1)),
GOLD_ORE(ItemID.GOLD_BAR, "Gold bar", Skill.SMITHING, 40, 22.5,
CriticalItem.GOLD_ORE, null, new ItemStack(ItemID.GOLD_BAR, 1)),
GOLD_ORE_GAUNTLETS(ItemID.GOLDSMITH_GAUNTLETS, "Goldsmith gauntlets", Skill.SMITHING, 40, 56.2,
CriticalItem.GOLD_ORE, null, new ItemStack(ItemID.GOLD_BAR, 1)),
MITHRIL_ORE(ItemID.MITHRIL_BAR, "Mithril bar", Skill.SMITHING, 50, 30,
CriticalItem.MITHRIL_ORE, Secondaries.COAL_ORE_4, new ItemStack(ItemID.MITHRIL_BAR, 1)),
ADAMANTITE_ORE(ItemID.ADAMANTITE_BAR, "Adamantite bar", Skill.SMITHING, 70, 37.5,
CriticalItem.ADAMANTITE_ORE, Secondaries.COAL_ORE_6, new ItemStack(ItemID.ADAMANTITE_BAR, 1)),
RUNITE_ORE(ItemID.RUNITE_BAR, "Runite bar", Skill.SMITHING, 85, 50,
CriticalItem.RUNITE_ORE, Secondaries.COAL_ORE_8, new ItemStack(ItemID.RUNITE_BAR, 1)),
// Smelting bars (Anvil)
BRONZE_BAR(ItemID.BRONZE_BAR, "Bars", Skill.SMITHING, 1, 12.5, CriticalItem.BRONZE_BAR),
IRON_BAR(ItemID.IRON_BAR, "Bars", Skill.SMITHING, 15, 25.0, CriticalItem.IRON_BAR),
STEEL_BAR(ItemID.STEEL_BAR, "Steel Products", Skill.SMITHING, 30, 37.5, CriticalItem.STEEL_BAR),
CANNONBALLS(ItemID.CANNONBALL, "Cannonballs", Skill.SMITHING, 35, 25.5, CriticalItem.STEEL_BAR),
MITHRIL_BAR(ItemID.MITHRIL_BAR, "Bars", Skill.SMITHING, 50, 50.0, CriticalItem.MITHRIL_BAR),
ADAMANTITE_BAR(ItemID.ADAMANTITE_BAR, "Bars", Skill.SMITHING, 70, 62.5, CriticalItem.ADAMANTITE_BAR),
RUNITE_BAR(ItemID.RUNITE_BAR, "Bars", Skill.SMITHING, 85, 75.0, CriticalItem.RUNITE_BAR),
BRONZE_BAR(ItemID.BRONZE_BAR, "Bronze products", Skill.SMITHING, 1, 12.5,
CriticalItem.BRONZE_BAR, null, null),
IRON_BAR(ItemID.IRON_BAR, "Iron products", Skill.SMITHING, 15, 25.0,
CriticalItem.IRON_BAR, null, null),
STEEL_BAR(ItemID.STEEL_BAR, "Steel products", Skill.SMITHING, 30, 37.5,
CriticalItem.STEEL_BAR, null, null),
CANNONBALLS(ItemID.CANNONBALL, "Cannonballs", Skill.SMITHING, 35, 25.5,
CriticalItem.STEEL_BAR, null, new ItemStack(ItemID.CANNONBALL, 4)),
MITHRIL_BAR(ItemID.MITHRIL_BAR, "Mithril products", Skill.SMITHING, 50, 50.0,
CriticalItem.MITHRIL_BAR, null, null),
ADAMANTITE_BAR(ItemID.ADAMANTITE_BAR, "Adamantite products", Skill.SMITHING, 70, 62.5,
CriticalItem.ADAMANTITE_BAR, null, null),
RUNITE_BAR(ItemID.RUNITE_BAR, "Runite products", Skill.SMITHING, 85, 75.0,
CriticalItem.RUNITE_BAR, null, null),
/**
* Farming Items
*/
ACORN(ItemID.ACORN, "Seeds", Skill.FARMING, 15, 481.3, CriticalItem.ACORN),
WILLOW_SEED(ItemID.WILLOW_SEED, "Seeds", Skill.FARMING, 30, 1481.5, CriticalItem.WILLOW_SEED),
MAPLE_SEED(ItemID.MAPLE_SEED, "Seeds", Skill.FARMING, 45, 3448.4, CriticalItem.MAPLE_SEED),
YEW_SEED(ItemID.YEW_SEED, "Seeds", Skill.FARMING, 60, 7150.9, CriticalItem.YEW_SEED),
MAGIC_SEED(ItemID.MAGIC_SEED, "Seeds", Skill.FARMING, 75, 13913.8, CriticalItem.MAGIC_SEED),
APPLE_TREE_SEED(ItemID.APPLE_TREE_SEED, "Seeds", Skill.FARMING, 27, 1272.5, CriticalItem.APPLE_TREE_SEED),
BANANA_TREE_SEED(ItemID.BANANA_TREE_SEED, "Seeds", Skill.FARMING, 33, 1841.5, CriticalItem.BANANA_TREE_SEED),
ORANGE_TREE_SEED(ItemID.ORANGE_TREE_SEED, "Seeds", Skill.FARMING, 39, 2586.7, CriticalItem.ORANGE_TREE_SEED),
CURRY_TREE_SEED(ItemID.CURRY_TREE_SEED, "Seeds", Skill.FARMING, 42, 3036.9, CriticalItem.CURRY_TREE_SEED),
PINEAPPLE_SEED(ItemID.PINEAPPLE_SEED, "Seeds", Skill.FARMING, 51, 4791.7, CriticalItem.PINEAPPLE_SEED),
PAPAYA_TREE_SEED(ItemID.PAPAYA_TREE_SEED, "Seeds", Skill.FARMING, 57, 6380.4, CriticalItem.PAPAYA_TREE_SEED),
PALM_TREE_SEED(ItemID.PALM_TREE_SEED, "Seeds", Skill.FARMING, 68, 10509.6, CriticalItem.PALM_TREE_SEED),
CALQUAT_TREE_SEED(ItemID.CALQUAT_TREE_SEED, "Seeds", Skill.FARMING, 72, 12516.5, CriticalItem.CALQUAT_TREE_SEED),
TEAK_SEED(ItemID.TEAK_SEED, "Seeds", Skill.FARMING, 35, 7325, CriticalItem.TEAK_SEED),
MAHOGANY_SEED(ItemID.MAHOGANY_SEED, "Seeds", Skill.FARMING, 55, 15783, CriticalItem.MAHOGANY_SEED),
SPIRIT_SEED(ItemID.SPIRIT_SEED, "Seeds", Skill.FARMING, 83, 19500, CriticalItem.SPIRIT_SEED),
ACORN(ItemID.OAK_SAPLING, "Oak sapling", Skill.FARMING, 15, 0,
CriticalItem.ACORN, null, new ItemStack(ItemID.OAK_SAPLING, 1)),
WILLOW_SEED(ItemID.WILLOW_SAPLING, "Willow sapling", Skill.FARMING, 30, 0,
CriticalItem.WILLOW_SEED, null, new ItemStack(ItemID.WILLOW_SAPLING, 1)),
MAPLE_SEED(ItemID.MAPLE_SAPLING, "Maple sapling", Skill.FARMING, 45, 0,
CriticalItem.MAPLE_SEED, null, new ItemStack(ItemID.MAPLE_SAPLING, 1)),
YEW_SEED(ItemID.YEW_SAPLING, "Yew sapling", Skill.FARMING, 60, 0,
CriticalItem.YEW_SEED, null, new ItemStack(ItemID.YEW_SAPLING, 1)),
MAGIC_SEED(ItemID.MAGIC_SAPLING, "Magic sapling", Skill.FARMING, 75, 0,
CriticalItem.MAGIC_SEED, null, new ItemStack(ItemID.MAGIC_SAPLING, 1)),
APPLE_TREE_SEED(ItemID.APPLE_SAPLING, "Apple sapling", Skill.FARMING, 27, 0,
CriticalItem.APPLE_TREE_SEED, null, new ItemStack(ItemID.APPLE_SAPLING, 1)),
BANANA_TREE_SEED(ItemID.BANANA_SAPLING, "Banana sapling", Skill.FARMING, 33, 0,
CriticalItem.BANANA_TREE_SEED, null, new ItemStack(ItemID.BANANA_SAPLING, 1)),
ORANGE_TREE_SEED(ItemID.ORANGE_SAPLING, "Orange sapling", Skill.FARMING, 39, 0,
CriticalItem.ORANGE_TREE_SEED, null, new ItemStack(ItemID.ORANGE_SAPLING, 1)),
CURRY_TREE_SEED(ItemID.CURRY_SAPLING, "Curry sapling", Skill.FARMING, 42, 0,
CriticalItem.CURRY_TREE_SEED, null, new ItemStack(ItemID.CURRY_SAPLING, 1)),
PINEAPPLE_SEED(ItemID.PINEAPPLE_SAPLING, "Pineapple sapling", Skill.FARMING, 51, 0,
CriticalItem.PINEAPPLE_SEED, null, new ItemStack(ItemID.PINEAPPLE_SAPLING, 1)),
PAPAYA_TREE_SEED(ItemID.PAPAYA_SAPLING, "Papaya sapling", Skill.FARMING, 57, 0,
CriticalItem.PAPAYA_TREE_SEED, null, new ItemStack(ItemID.PAPAYA_SAPLING, 1)),
PALM_TREE_SEED(ItemID.PALM_SAPLING, "Palm sapling", Skill.FARMING, 68, 0,
CriticalItem.PALM_TREE_SEED, null, new ItemStack(ItemID.PALM_SAPLING, 1)),
CALQUAT_TREE_SEED(ItemID.CALQUAT_SAPLING, "Calquat sapling", Skill.FARMING, 72, 0,
CriticalItem.CALQUAT_TREE_SEED, null, new ItemStack(ItemID.CALQUAT_SAPLING, 1)),
TEAK_SEED(ItemID.TEAK_SAPLING, "Teak sapling", Skill.FARMING, 35, 0,
CriticalItem.TEAK_SEED, null, new ItemStack(ItemID.TEAK_SAPLING, 1)),
MAHOGANY_SEED(ItemID.MAHOGANY_SAPLING, "Mahogany sapling", Skill.FARMING, 55, 0,
CriticalItem.MAHOGANY_SEED, null, new ItemStack(ItemID.MAHOGANY_SAPLING, 1)),
SPIRIT_SEED(ItemID.SPIRIT_SAPLING, "Spirit sapling", Skill.FARMING, 83, 0,
CriticalItem.SPIRIT_SEED, null, new ItemStack(ItemID.SPIRIT_SAPLING, 1)),
OAK_SAPPLING(ItemID.OAK_SAPLING, "Oak tree", Skill.FARMING, 15, 481.3,
CriticalItem.OAK_SAPLING, null, null),
WILLOW_SAPLING(ItemID.WILLOW_SAPLING, "Willow tree", Skill.FARMING, 30, 1481.5,
CriticalItem.WILLOW_SAPLING, null, null),
MAPLE_SAPLING(ItemID.MAPLE_SAPLING, "Maple tree", Skill.FARMING, 45, 3448.4,
CriticalItem.MAPLE_SAPLING, null, null),
YEW_SAPLING(ItemID.YEW_SAPLING, "Yew tree", Skill.FARMING, 60, 7150.9,
CriticalItem.YEW_SAPLING, null, null),
MAGIC_SAPLING(ItemID.MAGIC_SAPLING, "Magic tree", Skill.FARMING, 75, 13913.8,
CriticalItem.MAGIC_SAPLING, null, null),
APPLE_TREE_SAPLING(ItemID.APPLE_SAPLING, "Apple tree", Skill.FARMING, 27, 1272.5,
CriticalItem.APPLE_TREE_SAPLING, null, null),
BANANA_TREE_SAPLING(ItemID.BANANA_SAPLING, "Banana tree", Skill.FARMING, 33, 1841.5,
CriticalItem.BANANA_TREE_SAPLING, null, null),
ORANGE_TREE_SAPLING(ItemID.ORANGE_SAPLING, "Orange tree", Skill.FARMING, 39, 2586.7,
CriticalItem.ORANGE_TREE_SAPLING, null, null),
CURRY_TREE_SAPLING(ItemID.CURRY_SAPLING, "Curry tree", Skill.FARMING, 42, 3036.9,
CriticalItem.CURRY_TREE_SAPLING, null, null),
PINEAPPLE_SAPLING(ItemID.PINEAPPLE_SAPLING, "Pineapple tree", Skill.FARMING, 51, 4791.7,
CriticalItem.PINEAPPLE_SAPLING, null, null),
PAPAYA_TREE_SAPLING(ItemID.PAPAYA_SAPLING, "Papaya tree", Skill.FARMING, 57, 6380.4,
CriticalItem.PAPAYA_TREE_SAPLING, null, null),
PALM_TREE_SAPLING(ItemID.PALM_SAPLING, "Palm tree", Skill.FARMING, 68, 10509.6,
CriticalItem.PALM_TREE_SAPLING, null, null),
CALQUAT_TREE_SAPLING(ItemID.CALQUAT_SAPLING, "Calquat tree", Skill.FARMING, 72, 12516.5,
CriticalItem.CALQUAT_TREE_SAPLING, null, null),
TEAK_SAPLING(ItemID.TEAK_SAPLING, "Teak tree", Skill.FARMING, 35, 7325,
CriticalItem.TEAK_SAPLING, null, null),
MAHOGANY_SAPLING(ItemID.MAHOGANY_SAPLING, "Mahogany tree", Skill.FARMING, 55, 15783,
CriticalItem.MAHOGANY_SAPLING, null, null),
SPIRIT_SAPLING(ItemID.SPIRIT_SAPLING, "Spirit tree", Skill.FARMING, 83, 19500,
CriticalItem.SPIRIT_SAPLING, null, null),
;
private final int icon;
private final String name;
private final CriticalItem criticalItem;
private final Skill skill;
private final int level;
private final double xp;
private final SecondaryItem[] secondaries;
private final CriticalItem criticalItem;
private final boolean preventLinked;
private final ItemStack[] secondaries;
@Nullable
private final ItemStack output;
private ItemInfo outputItemInfo = null;
@Nullable
private final CriticalItem linkedItem;
Activity(int Icon, String name, Skill skill, int level, double xp, CriticalItem criticalItem)
{
this.icon = Icon;
this.name = name;
this.skill = skill;
this.level = level;
this.xp = xp;
this.criticalItem = criticalItem;
this.secondaries = new SecondaryItem[0];
this.preventLinked = false;
}
// Store activity by CriticalItem
private static final ImmutableMultimap<CriticalItem, Activity> CRITICAL_MAP;
Activity(int Icon, String name, Skill skill, int level, double xp, CriticalItem criticalItem, ActivitySecondaries secondaries)
static
{
this.icon = Icon;
this.name = name;
this.skill = skill;
this.level = level;
this.xp = xp;
this.criticalItem = criticalItem;
this.secondaries = secondaries == null ? new SecondaryItem[0] : secondaries.getItems();
this.preventLinked = false;
}
Activity(final int Icon, final String name, final Skill skill, final int level, final double xp, final CriticalItem criticalItem, final ActivitySecondaries secondaries, final boolean preventLinked)
{
this.icon = Icon;
this.name = name;
this.skill = skill;
this.level = level;
this.xp = xp;
this.criticalItem = criticalItem;
this.secondaries = secondaries == null ? new SecondaryItem[0] : secondaries.getItems();
this.preventLinked = preventLinked;
}
// Builds a Map to reduce looping frequency
private static Map<CriticalItem, ArrayList<Activity>> buildItemMap()
{
Map<CriticalItem, ArrayList<Activity>> map = new HashMap<>();
for (Activity item : values())
final ImmutableMultimap.Builder<CriticalItem, Activity> map = ImmutableMultimap.builder();
for (final Activity item : values())
{
map.computeIfAbsent(item.getCriticalItem(), e -> new ArrayList<>()).add(item);
map.put(item.getCriticalItem(), item);
}
return map;
CRITICAL_MAP = map.build();
}
private static final Map<CriticalItem, ArrayList<Activity>> byCriticalItem = buildItemMap();
public static List<Activity> getByCriticalItem(CriticalItem item)
Activity(
final int icon,
final String name,
final Skill skill,
final int level,
final double xp,
final CriticalItem criticalItem,
@Nullable final Secondaries secondaries,
@Nullable final ItemStack output)
{
return byCriticalItem.getOrDefault(item, new ArrayList<>());
this.icon = icon;
this.name = name;
this.skill = skill;
this.level = level;
this.xp = xp;
this.criticalItem = criticalItem;
this.secondaries = secondaries == null ? new ItemStack[0] : secondaries.getItems();
this.output = output;
this.linkedItem = output == null ? null : CriticalItem.getByItemId(output.getId());
}
/**
* Get all Activities for this CriticalItem
*
* @param item CriticalItem to check for
* @param limitLevel Level to check Activitiy requirements against. -1 or 0 value disables limits
* @return an empty list if no activities
* @param item CriticalItem to check for
* @return an empty Collection if no activities
*/
public static List<Activity> getByCriticalItem(CriticalItem item, int limitLevel)
public static List<Activity> getByCriticalItem(CriticalItem item)
{
List<Activity> activities = getByCriticalItem(item);
List<Activity> l = new ArrayList<>();
final Collection<Activity> activities = CRITICAL_MAP.get(item);
if (activities == null)
{
return new ArrayList<>();
}
return new ArrayList<>(activities);
}
/**
* Get all Activities for this CriticalItem limited to level
*
* @param item CriticalItem to check for
* @param limitLevel Level to check Activitiy requirements against. -1/0 value disables limits
* @return an empty Collection if no activities
*/
public static List<Activity> getByCriticalItem(final CriticalItem item, final int limitLevel)
{
// Return as list to allow getting by index
final List<Activity> l = getByCriticalItem(item);
if (limitLevel <= 0)
{
return l;
}
for (Activity a : activities)
{
if (!(a.getLevel() > limitLevel))
{
l.add(a);
}
}
return l;
return l.stream().filter(a -> a.getLevel() <= limitLevel).collect(Collectors.toList());
}
}
/**
* Attaches the Item Composition to each CriticalItem on client initial load
*
* @param m ItemManager
*/
public static void prepareItemDefinitions(ItemManager m)
{
for (Activity a : values())
{
final ItemStack output = a.getOutput();
if (output == null)
{
continue;
}
if (a.getOutputItemInfo() != null)
{
return;
}
final ItemDefinition c = m.getItemDefinition(output.getId());
a.outputItemInfo = new ItemInfo(c.getName(), c.isStackable());
}
}
}

View File

@@ -1,112 +0,0 @@
/*
* 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.skillcalculator.banked.beans;
import lombok.AccessLevel;
import lombok.Getter;
import net.runelite.api.ItemID;
@Getter(AccessLevel.PUBLIC)
public enum ActivitySecondaries
{
/**
* Herblore
*/
UNFINISHED_POTION(new SecondaryItem(ItemID.VIAL_OF_WATER, 1)),
SWAMP_TAR(new SecondaryItem(ItemID.SWAMP_TAR, 15)),
// Guam
ATTACK_POTION(new SecondaryItem(ItemID.EYE_OF_NEWT)),
// Marrentil
ANTIPOISON(new SecondaryItem(ItemID.UNICORN_HORN_DUST)),
// Tarromin
STRENGTH_POTION(new SecondaryItem(ItemID.LIMPWURT_ROOT)),
SERUM_207(new SecondaryItem(ItemID.ASHES)),
// Harralander
COMPOST_POTION(new SecondaryItem(ItemID.VOLCANIC_ASH)),
RESTORE_POTION(new SecondaryItem(ItemID.RED_SPIDERS_EGGS)),
ENERGY_POTION(new SecondaryItem(ItemID.CHOCOLATE_DUST)),
COMBAT_POTION(new SecondaryItem(ItemID.GOAT_HORN_DUST)),
// Ranarr Weed
DEFENCE_POTION(new SecondaryItem(ItemID.WHITE_BERRIES)),
PRAYER_POTION(new SecondaryItem(ItemID.SNAPE_GRASS)),
// Toadflax
AGILITY_POTION(new SecondaryItem(ItemID.TOADS_LEGS)),
SARADOMIN_BREW(new SecondaryItem(ItemID.CRUSHED_NEST)),
// Irit
SUPER_ATTACK(new SecondaryItem(ItemID.EYE_OF_NEWT)),
SUPERANTIPOISON(new SecondaryItem(ItemID.UNICORN_HORN_DUST)),
// Avantoe
FISHING_POTION(new SecondaryItem(ItemID.SNAPE_GRASS)),
SUPER_ENERGY_POTION(new SecondaryItem(ItemID.MORT_MYRE_FUNGUS)),
HUNTER_POTION(new SecondaryItem(ItemID.KEBBIT_TEETH_DUST)),
// Kwuarm
SUPER_STRENGTH(new SecondaryItem(ItemID.LIMPWURT_ROOT)),
// Snapdragon
SUPER_RESTORE(new SecondaryItem(ItemID.RED_SPIDERS_EGGS)),
SANFEW_SERUM(new SecondaryItem(ItemID.SNAKE_WEED), new SecondaryItem(ItemID.UNICORN_HORN_DUST), new SecondaryItem(ItemID.SUPER_RESTORE4), new SecondaryItem(ItemID.NAIL_BEAST_NAILS)),
// Cadantine
SUPER_DEFENCE_POTION(new SecondaryItem(ItemID.WHITE_BERRIES)),
// Lantadyme
ANTIFIRE_POTION(new SecondaryItem(ItemID.DRAGON_SCALE_DUST)),
MAGIC_POTION(new SecondaryItem(ItemID.POTATO_CACTUS)),
// Dwarf Weed
RANGING_POTION(new SecondaryItem(ItemID.WINE_OF_ZAMORAK)),
// Torstol
ZAMORAK_BREW(new SecondaryItem(ItemID.JANGERBERRIES)),
SUPER_COMBAT_POTION(new SecondaryItem(ItemID.SUPER_ATTACK3), new SecondaryItem(ItemID.SUPER_STRENGTH3), new SecondaryItem(ItemID.SUPER_DEFENCE3)),
ANTIVENOM_PLUS(new SecondaryItem(ItemID.ANTIVENOM4)),
/**
* Smithing
*/
COAL_ORE(new SecondaryItem(ItemID.COAL)),
COAL_ORE_2(new SecondaryItem(ItemID.COAL, 2)),
COAL_ORE_4(new SecondaryItem(ItemID.COAL, 4)),
COAL_ORE_6(new SecondaryItem(ItemID.COAL, 6)),
COAL_ORE_8(new SecondaryItem(ItemID.COAL, 8)),
/**
* Crafting
*/
GOLD_BAR(new SecondaryItem(ItemID.GOLD_BAR)),
SILVER_BAR(new SecondaryItem(ItemID.SILVER_BAR)),
WATER_ORB(new SecondaryItem(ItemID.WATER_ORB)),
EARTH_ORB(new SecondaryItem(ItemID.EARTH_ORB)),
FIRE_ORB(new SecondaryItem(ItemID.FIRE_ORB)),
AIR_ORB(new SecondaryItem(ItemID.AIR_ORB)),
/**
* Cooking
*/
JUG_OF_WATER(new SecondaryItem(ItemID.JUG_OF_WATER)),
;
private final SecondaryItem[] items;
ActivitySecondaries(final SecondaryItem... items)
{
this.items = items;
}
}

View File

@@ -0,0 +1,53 @@
/*
* 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.skillcalculator.banked.beans;
import lombok.AllArgsConstructor;
import lombok.Getter;
@AllArgsConstructor
@Getter
public class BankedItem
{
private final CriticalItem item;
private final int qty;
public double getXpRate()
{
final Activity selectedActivity = item.getSelectedActivity();
if (selectedActivity == null)
{
return 0;
}
return selectedActivity.getXp();
}
@Override
public String toString()
{
return item.name() + " x " + qty;
}
}

View File

@@ -0,0 +1,355 @@
/*
* 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.skillcalculator.banked.beans;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import lombok.Getter;
import lombok.Setter;
import net.runelite.api.ItemDefinition;
import net.runelite.api.ItemID;
import net.runelite.api.Skill;
import net.runelite.client.game.ItemManager;
@Getter
public enum CriticalItem
{
/**
* Construction Items
*/
// Logs
LOGS(ItemID.LOGS, Skill.CONSTRUCTION, "Logs"),
OAK_LOGS(ItemID.OAK_LOGS, Skill.CONSTRUCTION, "Logs"),
TEAK_LOGS(ItemID.TEAK_LOGS, Skill.CONSTRUCTION, "Logs"),
MAHOGANY_LOGS(ItemID.MAHOGANY_LOGS, Skill.CONSTRUCTION, "Logs"),
// Planks
PLANK(ItemID.PLANK, Skill.CONSTRUCTION, "Planks"),
OAK_PLANK(ItemID.OAK_PLANK, Skill.CONSTRUCTION, "Planks"),
TEAK_PLANK(ItemID.TEAK_PLANK, Skill.CONSTRUCTION, "Planks"),
MAHOGANY_PLANK(ItemID.MAHOGANY_PLANK, Skill.CONSTRUCTION, "Planks"),
/**
* Herblore Items
*/
// Grimy Herbs
GRIMY_GUAM_LEAF(ItemID.GRIMY_GUAM_LEAF, Skill.HERBLORE, "Grimy Herbs"),
GRIMY_MARRENTILL(ItemID.GRIMY_MARRENTILL, Skill.HERBLORE, "Grimy Herbs"),
GRIMY_TARROMIN(ItemID.GRIMY_TARROMIN, Skill.HERBLORE, "Grimy Herbs"),
GRIMY_HARRALANDER(ItemID.GRIMY_HARRALANDER, Skill.HERBLORE, "Grimy Herbs"),
GRIMY_RANARR_WEED(ItemID.GRIMY_RANARR_WEED, Skill.HERBLORE, "Grimy Herbs"),
GRIMY_TOADFLAX(ItemID.GRIMY_TOADFLAX, Skill.HERBLORE, "Grimy Herbs"),
GRIMY_IRIT_LEAF(ItemID.GRIMY_IRIT_LEAF, Skill.HERBLORE, "Grimy Herbs"),
GRIMY_AVANTOE(ItemID.GRIMY_AVANTOE, Skill.HERBLORE, "Grimy Herbs"),
GRIMY_KWUARM(ItemID.GRIMY_KWUARM, Skill.HERBLORE, "Grimy Herbs"),
GRIMY_SNAPDRAGON(ItemID.GRIMY_SNAPDRAGON, Skill.HERBLORE, "Grimy Herbs"),
GRIMY_CADANTINE(ItemID.GRIMY_CADANTINE, Skill.HERBLORE, "Grimy Herbs"),
GRIMY_LANTADYME(ItemID.GRIMY_LANTADYME, Skill.HERBLORE, "Grimy Herbs"),
GRIMY_DWARF_WEED(ItemID.GRIMY_DWARF_WEED, Skill.HERBLORE, "Grimy Herbs"),
GRIMY_TORSTOL(ItemID.GRIMY_TORSTOL, Skill.HERBLORE, "Grimy Herbs"),
// Clean Herbs
GUAM_LEAF(ItemID.GUAM_LEAF, Skill.HERBLORE, "Cleaned Herbs"),
MARRENTILL(ItemID.MARRENTILL, Skill.HERBLORE, "Cleaned Herbs"),
TARROMIN(ItemID.TARROMIN, Skill.HERBLORE, "Cleaned Herbs"),
HARRALANDER(ItemID.HARRALANDER, Skill.HERBLORE, "Cleaned Herbs"),
RANARR_WEED(ItemID.RANARR_WEED, Skill.HERBLORE, "Cleaned Herbs"),
TOADFLAX(ItemID.TOADFLAX, Skill.HERBLORE, "Cleaned Herbs"),
IRIT_LEAF(ItemID.IRIT_LEAF, Skill.HERBLORE, "Cleaned Herbs"),
AVANTOE(ItemID.AVANTOE, Skill.HERBLORE, "Cleaned Herbs"),
KWUARM(ItemID.KWUARM, Skill.HERBLORE, "Cleaned Herbs"),
SNAPDRAGON(ItemID.SNAPDRAGON, Skill.HERBLORE, "Cleaned Herbs"),
CADANTINE(ItemID.CADANTINE, Skill.HERBLORE, "Cleaned Herbs"),
LANTADYME(ItemID.LANTADYME, Skill.HERBLORE, "Cleaned Herbs"),
DWARF_WEED(ItemID.DWARF_WEED, Skill.HERBLORE, "Cleaned Herbs"),
TORSTOL(ItemID.TORSTOL, Skill.HERBLORE, "Cleaned Herbs"),
// Unfinished Potions
GUAM_LEAF_POTION_UNF(ItemID.GUAM_POTION_UNF, Skill.HERBLORE, "Unfinished Potions"),
MARRENTILL_POTION_UNF(ItemID.MARRENTILL_POTION_UNF, Skill.HERBLORE, "Unfinished Potions"),
TARROMIN_POTION_UNF(ItemID.TARROMIN_POTION_UNF, Skill.HERBLORE, "Unfinished Potions"),
HARRALANDER_POTION_UNF(ItemID.HARRALANDER_POTION_UNF, Skill.HERBLORE, "Unfinished Potions"),
RANARR_POTION_UNF(ItemID.RANARR_POTION_UNF, Skill.HERBLORE, "Unfinished Potions"),
TOADFLAX_POTION_UNF(ItemID.TOADFLAX_POTION_UNF, Skill.HERBLORE, "Unfinished Potions"),
IRIT_POTION_UNF(ItemID.IRIT_POTION_UNF, Skill.HERBLORE, "Unfinished Potions"),
AVANTOE_POTION_UNF(ItemID.AVANTOE_POTION_UNF, Skill.HERBLORE, "Unfinished Potions"),
KWUARM_POTION_UNF(ItemID.KWUARM_POTION_UNF, Skill.HERBLORE, "Unfinished Potions"),
SNAPDRAGON_POTION_UNF(ItemID.SNAPDRAGON_POTION_UNF, Skill.HERBLORE, "Unfinished Potions"),
CADANTINE_POTION_UNF(ItemID.CADANTINE_POTION_UNF, Skill.HERBLORE, "Unfinished Potions"),
LANTADYME_POTION_UNF(ItemID.LANTADYME_POTION_UNF, Skill.HERBLORE, "Unfinished Potions"),
DWARF_WEED_POTION_UNF(ItemID.DWARF_WEED_POTION_UNF, Skill.HERBLORE, "Unfinished Potions"),
TORSTOL_POTION_UNF(ItemID.TORSTOL_POTION_UNF, Skill.HERBLORE, "Unfinished Potions"),
/**
* Prayer Items
*/
// Bones
BONES(ItemID.BONES, Skill.PRAYER, "Bones"),
WOLF_BONES(ItemID.WOLF_BONES, Skill.PRAYER, "Bones"),
BURNT_BONES(ItemID.BURNT_BONES, Skill.PRAYER, "Bones"),
MONKEY_BONES(ItemID.MONKEY_BONES, Skill.PRAYER, "Bones"),
BAT_BONES(ItemID.BAT_BONES, Skill.PRAYER, "Bones"),
JOGRE_BONES(ItemID.JOGRE_BONES, Skill.PRAYER, "Bones"),
BIG_BONES(ItemID.BIG_BONES, Skill.PRAYER, "Bones"),
ZOGRE_BONES(ItemID.ZOGRE_BONES, Skill.PRAYER, "Bones"),
SHAIKAHAN_BONES(ItemID.SHAIKAHAN_BONES, Skill.PRAYER, "Bones"),
BABYDRAGON_BONES(ItemID.BABYDRAGON_BONES, Skill.PRAYER, "Bones"),
WYVERN_BONES(ItemID.WYVERN_BONES, Skill.PRAYER, "Bones"),
DRAGON_BONES(ItemID.DRAGON_BONES, Skill.PRAYER, "Bones"),
FAYRG_BONES(ItemID.FAYRG_BONES, Skill.PRAYER, "Bones"),
LAVA_DRAGON_BONES(ItemID.LAVA_DRAGON_BONES, Skill.PRAYER, "Bones"),
RAURG_BONES(ItemID.RAURG_BONES, Skill.PRAYER, "Bones"),
DAGANNOTH_BONES(ItemID.DAGANNOTH_BONES, Skill.PRAYER, "Bones"),
OURG_BONES(ItemID.OURG_BONES, Skill.PRAYER, "Bones"),
SUPERIOR_DRAGON_BONES(ItemID.SUPERIOR_DRAGON_BONES, Skill.PRAYER, "Bones"),
// Shade Remains (Pyre Logs)
LOAR_REMAINS(ItemID.LOAR_REMAINS, Skill.PRAYER, "Shades", true),
PHRIN_REMAINS(ItemID.PHRIN_REMAINS, Skill.PRAYER, "Shades", true),
RIYL_REMAINS(ItemID.RIYL_REMAINS, Skill.PRAYER, "Shades", true),
ASYN_REMAINS(ItemID.ASYN_REMAINS, Skill.PRAYER, "Shades", true),
FIYR_REMAINS(ItemID.FIYR_REMAINS, Skill.PRAYER, "Shades", true),
// Ensouled Heads
ENSOULED_GOBLIN_HEAD(ItemID.ENSOULED_GOBLIN_HEAD_13448, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_MONKEY_HEAD(ItemID.ENSOULED_MONKEY_HEAD_13451, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_IMP_HEAD(ItemID.ENSOULED_IMP_HEAD_13454, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_MINOTAUR_HEAD(ItemID.ENSOULED_MINOTAUR_HEAD_13457, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_SCORPION_HEAD(ItemID.ENSOULED_SCORPION_HEAD_13460, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_BEAR_HEAD(ItemID.ENSOULED_BEAR_HEAD_13463, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_UNICORN_HEAD(ItemID.ENSOULED_UNICORN_HEAD_13466, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_DOG_HEAD(ItemID.ENSOULED_DOG_HEAD_13469, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_CHAOS_DRUID_HEAD(ItemID.ENSOULED_CHAOS_DRUID_HEAD_13472, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_GIANT_HEAD(ItemID.ENSOULED_GIANT_HEAD_13475, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_OGRE_HEAD(ItemID.ENSOULED_OGRE_HEAD_13478, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_ELF_HEAD(ItemID.ENSOULED_ELF_HEAD_13481, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_TROLL_HEAD(ItemID.ENSOULED_TROLL_HEAD_13484, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_HORROR_HEAD(ItemID.ENSOULED_HORROR_HEAD_13487, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_KALPHITE_HEAD(ItemID.ENSOULED_KALPHITE_HEAD_13490, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_DAGANNOTH_HEAD(ItemID.ENSOULED_DAGANNOTH_HEAD_13493, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_BLOODVELD_HEAD(ItemID.ENSOULED_BLOODVELD_HEAD_13496, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_TZHAAR_HEAD(ItemID.ENSOULED_TZHAAR_HEAD_13499, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_DEMON_HEAD(ItemID.ENSOULED_DEMON_HEAD_13502, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_AVIANSIE_HEAD(ItemID.ENSOULED_AVIANSIE_HEAD_13505, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_ABYSSAL_HEAD(ItemID.ENSOULED_ABYSSAL_HEAD_13508, Skill.PRAYER, "Ensouled Heads", true),
ENSOULED_DRAGON_HEAD(ItemID.ENSOULED_DRAGON_HEAD_13511, Skill.PRAYER, "Ensouled Heads", true),
/**
* Cooking Items
*/
RAW_HERRING(ItemID.RAW_HERRING, Skill.COOKING, "Fish"),
RAW_MACKEREL(ItemID.RAW_MACKEREL, Skill.COOKING, "Fish"),
RAW_TROUT(ItemID.RAW_TROUT, Skill.COOKING, "Fish"),
RAW_COD(ItemID.RAW_COD, Skill.COOKING, "Fish"),
RAW_PIKE(ItemID.RAW_PIKE, Skill.COOKING, "Fish"),
RAW_SALMON(ItemID.RAW_SALMON, Skill.COOKING, "Fish"),
RAW_TUNA(ItemID.RAW_TUNA, Skill.COOKING, "Fish"),
RAW_KARAMBWAN(ItemID.RAW_KARAMBWAN, Skill.COOKING, "Fish"),
RAW_LOBSTER(ItemID.RAW_LOBSTER, Skill.COOKING, "Fish"),
RAW_BASS(ItemID.RAW_BASS, Skill.COOKING, "Fish"),
RAW_SWORDFISH(ItemID.RAW_SWORDFISH, Skill.COOKING, "Fish"),
RAW_MONKFISH(ItemID.RAW_MONKFISH, Skill.COOKING, "Fish"),
RAW_SHARK(ItemID.RAW_SHARK, Skill.COOKING, "Fish"),
RAW_SEA_TURTLE(ItemID.RAW_SEA_TURTLE, Skill.COOKING, "Fish"),
RAW_ANGLERFISH(ItemID.RAW_ANGLERFISH, Skill.COOKING, "Fish"),
RAW_DARK_CRAB(ItemID.RAW_DARK_CRAB, Skill.COOKING, "Fish"),
RAW_MANTA_RAY(ItemID.RAW_MANTA_RAY, Skill.COOKING, "Fish"),
GRAPES(ItemID.GRAPES, Skill.COOKING, "Other"),
/**
* Crafting Items
*/
WOOL(ItemID.WOOL, Skill.CRAFTING, "Misc"),
FLAX(ItemID.FLAX, Skill.CRAFTING, "Misc"),
MOLTEN_GLASS(ItemID.MOLTEN_GLASS, Skill.CRAFTING, "Misc"),
BATTLESTAFF(ItemID.BATTLESTAFF, Skill.CRAFTING, "Misc"),
// D'hide/Dragon Leather
GREEN_DRAGONHIDE(ItemID.GREEN_DRAGONHIDE, Skill.CRAFTING, "D'hide"),
GREEN_DRAGON_LEATHER(ItemID.GREEN_DRAGON_LEATHER, Skill.CRAFTING, "D'hide"),
BLUE_DRAGONHIDE(ItemID.BLUE_DRAGONHIDE, Skill.CRAFTING, "D'hide"),
BLUE_DRAGON_LEATHER(ItemID.BLUE_DRAGON_LEATHER, Skill.CRAFTING, "D'hide"),
RED_DRAGONHIDE(ItemID.RED_DRAGONHIDE, Skill.CRAFTING, "D'hide"),
RED_DRAGON_LEATHER(ItemID.RED_DRAGON_LEATHER, Skill.CRAFTING, "D'hide"),
BLACK_DRAGONHIDE(ItemID.BLACK_DRAGONHIDE, Skill.CRAFTING, "D'hide"),
BLACK_DRAGON_LEATHER(ItemID.BLACK_DRAGON_LEATHER, Skill.CRAFTING, "D'hide"),
// Uncut Gems
UNCUT_OPAL(ItemID.UNCUT_OPAL, Skill.CRAFTING, "Gems"),
UNCUT_JADE(ItemID.UNCUT_JADE, Skill.CRAFTING, "Gems"),
UNCUT_RED_TOPAZ(ItemID.UNCUT_RED_TOPAZ, Skill.CRAFTING, "Gems"),
UNCUT_SAPPHIRE(ItemID.UNCUT_SAPPHIRE, Skill.CRAFTING, "Gems"),
UNCUT_EMERALD(ItemID.UNCUT_EMERALD, Skill.CRAFTING, "Gems"),
UNCUT_RUBY(ItemID.UNCUT_RUBY, Skill.CRAFTING, "Gems"),
UNCUT_DIAMOND(ItemID.UNCUT_DIAMOND, Skill.CRAFTING, "Gems"),
UNCUT_DRAGONSTONE(ItemID.UNCUT_DRAGONSTONE, Skill.CRAFTING, "Gems"),
UNCUT_ONYX(ItemID.UNCUT_ONYX, Skill.CRAFTING, "Gems"),
UNCUT_ZENYTE(ItemID.UNCUT_ZENYTE, Skill.CRAFTING, "Gems"),
// Cut Gems
OPAL(ItemID.OPAL, Skill.CRAFTING, "Gems"),
JADE(ItemID.JADE, Skill.CRAFTING, "Gems"),
RED_TOPAZ(ItemID.RED_TOPAZ, Skill.CRAFTING, "Gems"),
SAPPHIRE(ItemID.SAPPHIRE, Skill.CRAFTING, "Gems"),
EMERALD(ItemID.EMERALD, Skill.CRAFTING, "Gems"),
RUBY(ItemID.RUBY, Skill.CRAFTING, "Gems"),
DIAMOND(ItemID.DIAMOND, Skill.CRAFTING, "Gems"),
DRAGONSTONE(ItemID.DRAGONSTONE, Skill.CRAFTING, "Gems"),
ONYX(ItemID.ONYX, Skill.CRAFTING, "Gems"),
ZENYTE(ItemID.ZENYTE, Skill.CRAFTING, "Gems"),
/**
* Smithing Items
*/
// Ores
IRON_ORE(ItemID.IRON_ORE, Skill.SMITHING, "Ore"),
SILVER_ORE(ItemID.SILVER_ORE, Skill.SMITHING, "Ore"),
GOLD_ORE(ItemID.GOLD_ORE, Skill.SMITHING, "Ore"),
MITHRIL_ORE(ItemID.MITHRIL_ORE, Skill.SMITHING, "Ore"),
ADAMANTITE_ORE(ItemID.ADAMANTITE_ORE, Skill.SMITHING, "Ore"),
RUNITE_ORE(ItemID.RUNITE_ORE, Skill.SMITHING, "Ore"),
// Bars
BRONZE_BAR(ItemID.BRONZE_BAR, Skill.SMITHING, "Bars"),
IRON_BAR(ItemID.IRON_BAR, Skill.SMITHING, "Bars"),
STEEL_BAR(ItemID.STEEL_BAR, Skill.SMITHING, "Bars"),
MITHRIL_BAR(ItemID.MITHRIL_BAR, Skill.SMITHING, "Bars"),
ADAMANTITE_BAR(ItemID.ADAMANTITE_BAR, Skill.SMITHING, "Bars"),
RUNITE_BAR(ItemID.RUNITE_BAR, Skill.SMITHING, "Bars"),
/**
* Farming Items
*/
// Seeds
ACORN(ItemID.ACORN, Skill.FARMING, "Seeds"),
WILLOW_SEED(ItemID.WILLOW_SEED, Skill.FARMING, "Seeds"),
MAPLE_SEED(ItemID.MAPLE_SEED, Skill.FARMING, "Seeds"),
YEW_SEED(ItemID.YEW_SEED, Skill.FARMING, "Seeds"),
MAGIC_SEED(ItemID.MAGIC_SEED, Skill.FARMING, "Seeds"),
APPLE_TREE_SEED(ItemID.APPLE_TREE_SEED, Skill.FARMING, "Seeds"),
BANANA_TREE_SEED(ItemID.BANANA_TREE_SEED, Skill.FARMING, "Seeds"),
ORANGE_TREE_SEED(ItemID.ORANGE_TREE_SEED, Skill.FARMING, "Seeds"),
CURRY_TREE_SEED(ItemID.CURRY_TREE_SEED, Skill.FARMING, "Seeds"),
PINEAPPLE_SEED(ItemID.PINEAPPLE_SEED, Skill.FARMING, "Seeds"),
PAPAYA_TREE_SEED(ItemID.PAPAYA_TREE_SEED, Skill.FARMING, "Seeds"),
PALM_TREE_SEED(ItemID.PALM_TREE_SEED, Skill.FARMING, "Seeds"),
CALQUAT_TREE_SEED(ItemID.CALQUAT_TREE_SEED, Skill.FARMING, "Seeds"),
TEAK_SEED(ItemID.TEAK_SEED, Skill.FARMING, "Seeds"),
MAHOGANY_SEED(ItemID.MAHOGANY_SEED, Skill.FARMING, "Seeds"),
SPIRIT_SEED(ItemID.SPIRIT_SEED, Skill.FARMING, "Seeds"),
// Saplings
OAK_SAPLING(ItemID.OAK_SAPLING, Skill.FARMING, "Saplings"),
WILLOW_SAPLING(ItemID.WILLOW_SAPLING, Skill.FARMING, "Saplings"),
MAPLE_SAPLING(ItemID.MAPLE_SAPLING, Skill.FARMING, "Saplings"),
YEW_SAPLING(ItemID.YEW_SAPLING, Skill.FARMING, "Saplings"),
MAGIC_SAPLING(ItemID.MAGIC_SAPLING, Skill.FARMING, "Saplings"),
APPLE_TREE_SAPLING(ItemID.APPLE_SAPLING, Skill.FARMING, "Saplings"),
BANANA_TREE_SAPLING(ItemID.BANANA_SAPLING, Skill.FARMING, "Saplings"),
ORANGE_TREE_SAPLING(ItemID.ORANGE_SAPLING, Skill.FARMING, "Saplings"),
CURRY_TREE_SAPLING(ItemID.CURRY_SAPLING, Skill.FARMING, "Saplings"),
PINEAPPLE_SAPLING(ItemID.PINEAPPLE_SAPLING, Skill.FARMING, "Saplings"),
PAPAYA_TREE_SAPLING(ItemID.PAPAYA_SAPLING, Skill.FARMING, "Saplings"),
PALM_TREE_SAPLING(ItemID.PALM_SAPLING, Skill.FARMING, "Saplings"),
CALQUAT_TREE_SAPLING(ItemID.CALQUAT_SAPLING, Skill.FARMING, "Saplings"),
TEAK_SAPLING(ItemID.TEAK_SAPLING, Skill.FARMING, "Saplings"),
MAHOGANY_SAPLING(ItemID.MAHOGANY_SAPLING, Skill.FARMING, "Saplings"),
SPIRIT_SAPLING(ItemID.SPIRIT_SAPLING, Skill.FARMING, "Saplings"),
;
private final int itemID;
private final Skill skill;
private final String category;
private boolean ignoreBonus;
@Setter
// Stores the item composition info we use since we don't operate on the game thread
private ItemInfo itemInfo = null;
@Setter
private Activity selectedActivity;
private static final Multimap<Skill, CriticalItem> SKILL_MAP = ArrayListMultimap.create();
private static final Map<Integer, CriticalItem> ITEM_ID_MAP = new HashMap<>();
static
{
for (CriticalItem i : values())
{
Skill s = i.getSkill();
SKILL_MAP.put(s, i);
ITEM_ID_MAP.put(i.getItemID(), i);
}
}
CriticalItem(int itemID, Skill skill, String category, boolean ignoreBonus)
{
this.itemID = itemID;
this.category = category;
this.skill = skill;
this.ignoreBonus = ignoreBonus;
}
CriticalItem(int itemID, Skill skill, String category)
{
this(itemID, skill, category, false);
}
public static Collection<CriticalItem> getBySkill(Skill skill)
{
Collection<CriticalItem> items = SKILL_MAP.get(skill);
if (items == null)
{
items = new ArrayList<>();
}
return items;
}
public static CriticalItem getByItemId(int id)
{
return ITEM_ID_MAP.get(id);
}
/**
* Attaches the Item Composition to each CriticalItem on client initial load
*
* @param m ItemManager
*/
public static void prepareItemDefinitions(ItemManager m)
{
for (CriticalItem i : values())
{
if (i.itemInfo != null)
{
return;
}
final ItemDefinition c = m.getItemDefinition(i.getItemID());
i.itemInfo = new ItemInfo(c.getName(), c.isStackable());
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, TheStonedTurtle <https://github.com/TheStonedTurtle>
* Copyright (c) 2019, TheStonedTurtle <https://github.com/TheStonedTurtle>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -24,23 +24,13 @@
*/
package net.runelite.client.plugins.skillcalculator.banked.beans;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.AllArgsConstructor;
import lombok.Data;
@Getter(AccessLevel.PUBLIC)
public class SecondaryItem
@Data
@AllArgsConstructor
public class ItemInfo
{
private final int id;
private final int qty;
SecondaryItem(int id, int qty)
{
this.id = id;
this.qty = qty;
}
SecondaryItem(int id)
{
this(id, 1);
}
}
private String name;
private boolean stackable;
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright (c) 2019, TheStonedTurtle <https://github.com/TheStonedTurtle>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.skillcalculator.banked.beans;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
class ItemStack
{
private int id;
private int qty;
}

View File

@@ -0,0 +1,118 @@
/*
* 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.skillcalculator.banked.beans;
import lombok.Getter;
import net.runelite.api.ItemID;
@Getter
public enum Secondaries
{
/**
* Herblore
*/
UNFINISHED_POTION(new ItemStack(ItemID.VIAL_OF_WATER, 1)),
SWAMP_TAR(new ItemStack(ItemID.SWAMP_TAR, 15)),
// Guam
ATTACK_POTION(new ItemStack(ItemID.EYE_OF_NEWT, 1)),
// Marrentil
ANTIPOISON(new ItemStack(ItemID.UNICORN_HORN_DUST, 1)),
// Tarromin
STRENGTH_POTION(new ItemStack(ItemID.LIMPWURT_ROOT, 1)),
SERUM_207(new ItemStack(ItemID.ASHES, 1)),
// Harralander
COMPOST_POTION(new ItemStack(ItemID.VOLCANIC_ASH, 1)),
RESTORE_POTION(new ItemStack(ItemID.RED_SPIDERS_EGGS, 1)),
ENERGY_POTION(new ItemStack(ItemID.CHOCOLATE_DUST, 1)),
COMBAT_POTION(new ItemStack(ItemID.GOAT_HORN_DUST, 1)),
// Ranarr Weed
DEFENCE_POTION(new ItemStack(ItemID.WHITE_BERRIES, 1)),
PRAYER_POTION(new ItemStack(ItemID.SNAPE_GRASS, 1)),
// Toadflax
AGILITY_POTION(new ItemStack(ItemID.TOADS_LEGS, 1)),
SARADOMIN_BREW(new ItemStack(ItemID.CRUSHED_NEST, 1)),
// Irit
SUPER_ATTACK(new ItemStack(ItemID.EYE_OF_NEWT, 1)),
SUPERANTIPOISON(new ItemStack(ItemID.UNICORN_HORN_DUST, 1)),
// Avantoe
FISHING_POTION(new ItemStack(ItemID.SNAPE_GRASS, 1)),
SUPER_ENERGY_POTION(new ItemStack(ItemID.MORT_MYRE_FUNGUS, 1)),
HUNTER_POTION(new ItemStack(ItemID.KEBBIT_TEETH_DUST, 1)),
// Kwuarm
SUPER_STRENGTH(new ItemStack(ItemID.LIMPWURT_ROOT, 1)),
// Snapdragon
SUPER_RESTORE(new ItemStack(ItemID.RED_SPIDERS_EGGS, 1)),
SANFEW_SERUM(new ItemStack(ItemID.SNAKE_WEED, 1), new ItemStack(ItemID.UNICORN_HORN_DUST, 1), new ItemStack(ItemID.SUPER_RESTORE4, 1), new ItemStack(ItemID.NAIL_BEAST_NAILS, 1)),
// Cadantine
SUPER_DEFENCE_POTION(new ItemStack(ItemID.WHITE_BERRIES, 1)),
// Lantadyme
ANTIFIRE_POTION(new ItemStack(ItemID.DRAGON_SCALE_DUST, 1)),
MAGIC_POTION(new ItemStack(ItemID.POTATO_CACTUS, 1)),
// Dwarf Weed
RANGING_POTION(new ItemStack(ItemID.WINE_OF_ZAMORAK, 1)),
// Torstol
ZAMORAK_BREW(new ItemStack(ItemID.JANGERBERRIES, 1)),
SUPER_COMBAT_POTION(new ItemStack(ItemID.SUPER_ATTACK4, 1), new ItemStack(ItemID.SUPER_STRENGTH4, 1), new ItemStack(ItemID.SUPER_DEFENCE4, 1)),
ANTIVENOM_PLUS(new ItemStack(ItemID.ANTIVENOM4, 1)),
/**
* Smithing
*/
COAL_ORE(new ItemStack(ItemID.COAL, 1)),
COAL_ORE_2(new ItemStack(ItemID.COAL, 2)),
COAL_ORE_4(new ItemStack(ItemID.COAL, 4)),
COAL_ORE_6(new ItemStack(ItemID.COAL, 6)),
COAL_ORE_8(new ItemStack(ItemID.COAL, 8)),
/**
* Crafting
*/
GOLD_BAR(new ItemStack(ItemID.GOLD_BAR, 1)),
SILVER_BAR(new ItemStack(ItemID.SILVER_BAR, 1)),
WATER_ORB(new ItemStack(ItemID.WATER_ORB, 1)),
EARTH_ORB(new ItemStack(ItemID.EARTH_ORB, 1)),
FIRE_ORB(new ItemStack(ItemID.FIRE_ORB, 1)),
AIR_ORB(new ItemStack(ItemID.AIR_ORB, 1)),
/**
* Construction
*/
COINS_100(new ItemStack(ItemID.COINS_995, 100)),
COINS_250(new ItemStack(ItemID.COINS_995, 250)),
COINS_500(new ItemStack(ItemID.COINS_995, 500)),
COINS_1500(new ItemStack(ItemID.COINS_995, 1500)),
/**
* Cooking
*/
JUG_OF_WATER(new ItemStack(ItemID.JUG_OF_WATER, 1)),
;
private final ItemStack[] items;
Secondaries(ItemStack... items)
{
this.items = items;
}
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright (c) 2019, TheStonedTurtle <https://github.com/TheStonedTurtle>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.skillcalculator.banked.beans;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
import java.util.Collection;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.runelite.api.Skill;
@AllArgsConstructor
@Getter
public enum XpModifiers
{
LIT_GILDER_ALTAR(Skill.PRAYER, "Lit Gilded Altar (350%)", 3.5f),
ECTOFUNTUS(Skill.PRAYER, "Ectofuntus (400%)", 4),
WILDY_ALTAR(Skill.PRAYER, "Wildy Altar (700%)", 7),
FARMERS_OUTFIT(Skill.FARMING, "Farmer's Outfit (+2.5%)", 1.025f);
private final Skill skill;
private final String name;
private final float modifier;
private final static Multimap<Skill, XpModifiers> MODIFIERS_MAP;
static
{
final ImmutableMultimap.Builder<Skill, XpModifiers> map = ImmutableMultimap.builder();
for (final XpModifiers m : values())
{
map.put(m.skill, m);
}
MODIFIERS_MAP = map.build();
}
public static Collection<XpModifiers> getModifiersBySkill(final Skill skill)
{
return MODIFIERS_MAP.get(skill);
}
}

View File

@@ -0,0 +1,201 @@
/*
* Copyright (c) 2019, TheStonedTurtle <https://github.com/TheStonedTurtle>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.skillcalculator.banked.components;
import java.awt.Color;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.function.BooleanSupplier;
import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.SwingConstants;
import javax.swing.border.EmptyBorder;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import net.runelite.client.game.AsyncBufferedImage;
import net.runelite.client.plugins.skillcalculator.banked.BankedCalculator;
import net.runelite.client.plugins.skillcalculator.banked.beans.Activity;
import net.runelite.client.plugins.skillcalculator.banked.beans.BankedItem;
import net.runelite.client.ui.ColorScheme;
@Getter(AccessLevel.PUBLIC)
public class GridItem extends JLabel
{
private final static String IGNORE = "Ignore Item";
private final static String INCLUDE = "Include Item";
private static final Color UNSELECTED_BACKGROUND = ColorScheme.DARKER_GRAY_COLOR;
private static final Color UNSELECTED_HOVER_BACKGROUND = ColorScheme.DARKER_GRAY_HOVER_COLOR;
private static final Color SELECTED_BACKGROUND = new Color(0, 70, 0);
private static final Color SELECTED_HOVER_BACKGROUND = new Color(0, 100, 0);
private static final Color IGNORED_BACKGROUND = new Color(90, 0, 0);
private static final Color IGNORED_HOVER_BACKGROUND = new Color(120, 0, 0);
/* To be executed when this element is clicked */
@Setter(AccessLevel.PUBLIC)
private BooleanSupplier onSelectEvent;
/* To be executed when this element is ignored */
@Setter(AccessLevel.PUBLIC)
private BooleanSupplier onIgnoreEvent;
private final SelectionGrid parent;
private final BankedItem bankedItem;
private int amount;
private boolean selected = false;
private boolean ignored = false;
private final JMenuItem IGNORE_OPTION = new JMenuItem(IGNORE);
GridItem(final SelectionGrid parent, final BankedItem item, final AsyncBufferedImage icon, final int amount)
{
super("");
this.parent = parent;
this.bankedItem = item;
this.setOpaque(true);
this.setBackground(ColorScheme.DARKER_GRAY_COLOR);
this.setBorder(BorderFactory.createEmptyBorder(5, 0, 2, 0));
this.setVerticalAlignment(SwingConstants.CENTER);
this.setHorizontalAlignment(SwingConstants.CENTER);
updateIcon(icon, amount);
updateToolTip();
this.addMouseListener(new MouseAdapter()
{
@Override
public void mousePressed(MouseEvent mouseEvent)
{
if (mouseEvent.getButton() == MouseEvent.BUTTON1)
{
select();
}
}
@Override
public void mouseEntered(MouseEvent e)
{
final GridItem item = (GridItem) e.getSource();
item.setBackground(getHoverBackgroundColor());
}
@Override
public void mouseExited(MouseEvent e)
{
final GridItem item = (GridItem) e.getSource();
item.setBackground(getBackgroundColor());
}
});
IGNORE_OPTION.addActionListener(e ->
{
// Update ignored flag now so event knows new state
this.ignored = !this.ignored;
if (onIgnoreEvent != null && !onIgnoreEvent.getAsBoolean())
{
// Reset state
this.ignored = !this.ignored;
return;
}
IGNORE_OPTION.setText(this.ignored ? INCLUDE : IGNORE);
this.setBackground(getBackgroundColor());
});
final JPopupMenu popupMenu = new JPopupMenu();
popupMenu.setBorder(new EmptyBorder(5, 5, 5, 5));
popupMenu.add(IGNORE_OPTION);
this.setComponentPopupMenu(popupMenu);
}
private Color getBackgroundColor()
{
return ignored ? IGNORED_BACKGROUND : (selected ? SELECTED_BACKGROUND : UNSELECTED_BACKGROUND);
}
private Color getHoverBackgroundColor()
{
return ignored ? IGNORED_HOVER_BACKGROUND : (selected ? SELECTED_HOVER_BACKGROUND : UNSELECTED_HOVER_BACKGROUND);
}
public void select()
{
if (onSelectEvent != null && !onSelectEvent.getAsBoolean())
{
return;
}
selected = true;
setBackground(getBackgroundColor());
}
void unselect()
{
selected = false;
setBackground(getBackgroundColor());
}
public void updateIcon(final AsyncBufferedImage icon, final int amount)
{
icon.addTo(this);
this.amount = amount;
}
public void updateToolTip()
{
this.setToolTipText(buildToolTip());
}
private String buildToolTip()
{
String tip = "<html>" + bankedItem.getItem().getItemInfo().getName();
final Activity a = bankedItem.getItem().getSelectedActivity();
if (a != null)
{
final double xp = parent.getCalc().getItemXpRate(bankedItem);
tip += "<br/>Activity: " + a.getName();
tip += "<br/>Xp/Action: " + BankedCalculator.XP_FORMAT_COMMA.format(xp);
tip += "<br/>Total Xp: " + BankedCalculator.XP_FORMAT_COMMA.format(xp * amount);
}
else
{
tip += "<br/>Outputs: " + bankedItem.getItem().getItemInfo().getName();
}
return tip + "</html>";
}
}

View File

@@ -0,0 +1,354 @@
/*
* 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.skillcalculator.banked.components;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.event.ItemEvent;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.ImageIcon;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import lombok.AccessLevel;
import lombok.Getter;
import net.runelite.api.Constants;
import net.runelite.client.game.AsyncBufferedImage;
import net.runelite.client.game.ItemManager;
import net.runelite.client.plugins.skillcalculator.banked.BankedCalculator;
import net.runelite.client.plugins.skillcalculator.banked.beans.Activity;
import net.runelite.client.plugins.skillcalculator.banked.beans.BankedItem;
import net.runelite.client.plugins.skillcalculator.banked.beans.CriticalItem;
import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.FontManager;
import net.runelite.client.ui.components.ComboBoxIconEntry;
import net.runelite.client.ui.components.ComboBoxListRenderer;
import net.runelite.client.ui.components.shadowlabel.JShadowedLabel;
public class ModifyPanel extends JPanel
{
private static final Dimension ICON_SIZE = new Dimension(Constants.ITEM_SPRITE_WIDTH, Constants.ITEM_SPRITE_HEIGHT);
private static final DecimalFormat FORMAT_COMMA = new DecimalFormat("#,###.#");
private static final Border PANEL_BORDER = new EmptyBorder(3, 0, 3, 0);
private static final Color BACKGROUND_COLOR = ColorScheme.DARKER_GRAY_COLOR;
private final BankedCalculator calc;
private final ItemManager itemManager;
@Getter(AccessLevel.PUBLIC)
private BankedItem bankedItem;
private Map<CriticalItem, Integer> linkedMap;
@Getter(AccessLevel.PUBLIC)
private int amount = 0;
@Getter(AccessLevel.PUBLIC)
private double total = 0;
// Banked item information display
private final JPanel labelContainer;
private final JLabel image;
private final JShadowedLabel labelName;
private final JShadowedLabel labelValue;
// Elements used to adjust banked item
private final JPanel adjustContainer;
public ModifyPanel(final BankedCalculator calc, final ItemManager itemManager)
{
this.calc = calc;
this.itemManager = itemManager;
this.setLayout(new GridBagLayout());
this.setBorder(PANEL_BORDER);
this.setBackground(ColorScheme.DARK_GRAY_COLOR);
// Banked item information display
labelContainer = new JPanel();
labelContainer.setLayout(new BorderLayout());
labelContainer.setBackground(BACKGROUND_COLOR);
labelContainer.setBorder(new EmptyBorder(5, 0, 5, 0));
// Icon
image = new JLabel();
image.setMinimumSize(ICON_SIZE);
image.setMaximumSize(ICON_SIZE);
image.setPreferredSize(ICON_SIZE);
image.setHorizontalAlignment(SwingConstants.CENTER);
image.setBorder(new EmptyBorder(0, 8, 0, 0));
// Wrapper panel for the shadowed labels
final JPanel uiInfo = new JPanel(new GridLayout(2, 1));
uiInfo.setBorder(new EmptyBorder(0, 5, 0, 0));
uiInfo.setBackground(BACKGROUND_COLOR);
labelName = new JShadowedLabel();
labelName.setForeground(Color.WHITE);
labelName.setVerticalAlignment(SwingUtilities.BOTTOM);
labelValue = new JShadowedLabel();
labelValue.setFont(FontManager.getRunescapeSmallFont());
labelValue.setVerticalAlignment(SwingUtilities.TOP);
uiInfo.add(labelName);
uiInfo.add(labelValue);
// Append elements to item info panel
labelContainer.add(image, BorderLayout.LINE_START);
labelContainer.add(uiInfo, BorderLayout.CENTER);
// Container for tools to adjust banked calculation for this item
adjustContainer = new JPanel();
adjustContainer.setLayout(new GridBagLayout());
adjustContainer.setBackground(BACKGROUND_COLOR);
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.BOTH;
c.weightx = 1;
c.gridx = 0;
c.gridy = 0;
c.ipady = 0;
this.add(labelContainer, c);
c.gridy++;
this.add(adjustContainer, c);
}
// Updates the UI for the selected item
public void setBankedItem(final BankedItem bankedItem)
{
if (bankedItem == null)
{
return;
}
this.bankedItem = bankedItem;
if (this.calc.getConfig().cascadeBankedXp())
{
this.linkedMap = this.calc.createLinksMap(bankedItem);
this.amount = bankedItem.getQty();
for (int i : linkedMap.values())
{
this.amount += i;
}
}
else
{
this.linkedMap = new HashMap<>();
this.amount = this.calc.getItemQty(bankedItem);
}
updateImageTooltip();
updateLabelContainer();
updateAdjustContainer();
}
private void updateImageTooltip()
{
final StringBuilder b = new StringBuilder("<html>");
b.append(bankedItem.getQty()).append(" x ").append(bankedItem.getItem().getItemInfo().getName());
for (final Map.Entry<CriticalItem, Integer> e : this.linkedMap.entrySet())
{
b.append("<br/>").append(e.getValue()).append(" x ").append(e.getKey().getItemInfo().getName());
}
b.append("</html>");
this.image.setToolTipText(b.toString());
}
private void updateLabelContainer()
{
final CriticalItem item = bankedItem.getItem();
// Update image icon
final boolean stackable = item.getItemInfo().isStackable() || amount > 1;
final AsyncBufferedImage icon = itemManager.getImage(item.getItemID(), amount, stackable);
final Runnable resize = () -> image.setIcon(new ImageIcon(icon.getScaledInstance(ICON_SIZE.width, ICON_SIZE.height, Image.SCALE_SMOOTH)));
icon.onChanged(resize);
resize.run();
final String itemName = item.getItemInfo().getName();
labelName.setText(itemName);
double xp = calc.getItemXpRate(bankedItem);
total = amount * xp;
final String value = FORMAT_COMMA.format(total) + "xp";
labelValue.setText(value);
labelContainer.setToolTipText("<html>" + itemName
+ "<br/>xp: " + xp
+ "<br/>Total: " + total + "</html");
labelContainer.revalidate();
labelContainer.repaint();
}
private void updateAdjustContainer()
{
adjustContainer.removeAll();
final JLabel label = new JLabel("Output:");
label.setVerticalAlignment(JLabel.CENTER);
label.setHorizontalAlignment(JLabel.CENTER);
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 1;
c.gridx = 0;
c.gridy = 0;
c.ipady = 0;
adjustContainer.add(label, c);
c.gridy++;
final float xpFactor = (bankedItem.getItem().isIgnoreBonus() ? 1.0f : this.calc.getXpFactor());
final List<Activity> activities = Activity.getByCriticalItem(bankedItem.getItem(), calc.getSkillLevel());
if (activities == null || activities.size() == 0)
{
adjustContainer.add(new JLabel("Unknown"));
}
else if (activities.size() == 1)
{
final Activity a = activities.get(0);
final AsyncBufferedImage img = itemManager.getImage(a.getIcon());
final ImageIcon icon = new ImageIcon(img);
final double xp = a.getXp() * xpFactor;
final JPanel container = createShadowedLabel(icon, a.getName(), FORMAT_COMMA.format(xp) + "xp");
img.onChanged(() ->
{
icon.setImage(img);
container.repaint();
});
adjustContainer.add(container, c);
}
else
{
final JComboBox<ComboBoxIconEntry> dropdown = new JComboBox<>();
final ComboBoxListRenderer renderer = new ComboBoxListRenderer();
dropdown.setRenderer(renderer);
for (final Activity option : activities)
{
final double xp = option.getXp() * xpFactor;
String name = option.getName();
if (xp > 0)
{
name += " (" + FORMAT_COMMA.format(xp) + "xp)";
}
final AsyncBufferedImage img = itemManager.getImage(option.getIcon());
final ImageIcon icon = new ImageIcon(img);
final ComboBoxIconEntry entry = new ComboBoxIconEntry(icon, name, option);
dropdown.addItem(entry);
img.onChanged(() ->
{
icon.setImage(img);
dropdown.revalidate();
dropdown.repaint();
});
final Activity selected = bankedItem.getItem().getSelectedActivity();
if (option.equals(selected))
{
dropdown.setSelectedItem(entry);
}
}
// Add click event handler now to prevent above code from triggering it.
dropdown.addItemListener(e ->
{
if (e.getStateChange() == ItemEvent.SELECTED && e.getItem() instanceof ComboBoxIconEntry)
{
final ComboBoxIconEntry source = (ComboBoxIconEntry) e.getItem();
if (source.getData() instanceof Activity)
{
final Activity selectedActivity = ((Activity) source.getData());
calc.activitySelected(bankedItem, selectedActivity);
updateLabelContainer();
}
}
});
adjustContainer.add(dropdown, c);
}
}
private JPanel createShadowedLabel(final ImageIcon icon, final String name, final String value)
{
// Wrapper panel for the shadowed labels
final JPanel wrapper = new JPanel(new GridLayout(2, 1));
wrapper.setBorder(new EmptyBorder(0, 5, 0, 0));
wrapper.setBackground(BACKGROUND_COLOR);
final JShadowedLabel nameLabel = new JShadowedLabel(name);
nameLabel.setForeground(Color.WHITE);
nameLabel.setVerticalAlignment(SwingUtilities.BOTTOM);
final JShadowedLabel valueLabel = new JShadowedLabel(value);
valueLabel.setFont(FontManager.getRunescapeSmallFont());
valueLabel.setVerticalAlignment(SwingUtilities.TOP);
wrapper.add(nameLabel);
wrapper.add(valueLabel);
final JPanel container = new JPanel();
container.setLayout(new BorderLayout());
container.setBackground(BACKGROUND_COLOR);
container.setBorder(new EmptyBorder(5, 0, 5, 0));
final JLabel image = new JLabel();
image.setMinimumSize(ICON_SIZE);
image.setMaximumSize(ICON_SIZE);
image.setPreferredSize(ICON_SIZE);
image.setHorizontalAlignment(SwingConstants.CENTER);
image.setBorder(new EmptyBorder(0, 8, 0, 0));
image.setIcon(icon);
container.add(image, BorderLayout.LINE_START);
container.add(wrapper, BorderLayout.CENTER);
return container;
}
}

View File

@@ -0,0 +1,142 @@
/*
* 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.skillcalculator.banked.components;
import java.awt.GridLayout;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BooleanSupplier;
import java.util.stream.Collectors;
import javax.swing.JPanel;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import net.runelite.client.game.AsyncBufferedImage;
import net.runelite.client.game.ItemManager;
import net.runelite.client.plugins.skillcalculator.banked.BankedCalculator;
import net.runelite.client.plugins.skillcalculator.banked.beans.BankedItem;
/**
* A grid that supports mouse events
*/
public class SelectionGrid extends JPanel
{
private static final int ITEMS_PER_ROW = 5;
@Getter(AccessLevel.PUBLIC)
private final Map<BankedItem, GridItem> panelMap = new LinkedHashMap<>();
@Getter(AccessLevel.PUBLIC)
private BankedItem selectedItem;
@Getter(AccessLevel.PUBLIC)
private BankedItem lastIgnoredItem;
/* To be executed when this element is clicked */
@Setter(AccessLevel.PUBLIC)
private BooleanSupplier onSelectEvent;
/* To be executed when this element is ignored */
@Setter(AccessLevel.PUBLIC)
private BooleanSupplier onIgnoreEvent;
@Getter(AccessLevel.PUBLIC)
private final BankedCalculator calc;
public SelectionGrid(final BankedCalculator calc, final Collection<BankedItem> items, final ItemManager itemManager)
{
this.calc = calc;
// Create a panel for every item
for (final BankedItem item : items)
{
final int qty = calc.getItemQty(item);
final boolean stackable = item.getItem().getItemInfo().isStackable() || qty > 1;
final AsyncBufferedImage img = itemManager.getImage(item.getItem().getItemID(), qty, stackable);
final GridItem gridItem = new GridItem(this, item, img, qty);
gridItem.setOnSelectEvent(() -> selected(item));
gridItem.setOnIgnoreEvent(() -> ignore(item));
panelMap.put(item, gridItem);
}
refreshGridDisplay();
}
public void refreshGridDisplay()
{
this.removeAll();
final List<GridItem> items = panelMap.values().stream().filter(gi -> gi.getAmount() > 0).collect(Collectors.toList());
// Calculates how many rows need to be display to fit all items
final int rowSize = ((items.size() % ITEMS_PER_ROW == 0) ? 0 : 1) + items.size() / ITEMS_PER_ROW;
setLayout(new GridLayout(rowSize, ITEMS_PER_ROW, 1, 1));
for (final GridItem gridItem : items)
{
// Select the first option
if (selectedItem == null)
{
gridItem.select();
}
this.add(gridItem);
}
}
private boolean selected(final BankedItem item)
{
final BankedItem old = this.selectedItem;
if (item.equals(old))
{
return false;
}
// Set selected item now so the boolean can see what was just clicked
this.selectedItem = item;
if (onSelectEvent != null && !onSelectEvent.getAsBoolean())
{
this.selectedItem = old;
return false;
}
final GridItem gridItem = panelMap.get(old);
if (gridItem != null)
{
gridItem.unselect();
}
return true;
}
private boolean ignore(final BankedItem item)
{
this.lastIgnoredItem = item;
return onIgnoreEvent.getAsBoolean();
}
}

View File

@@ -1,402 +0,0 @@
/*
* 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.skillcalculator.banked.ui;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.List;
import java.util.Map;
import javax.imageio.ImageIO;
import javax.inject.Singleton;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.border.MatteBorder;
import lombok.AccessLevel;
import lombok.Getter;
import net.runelite.client.game.AsyncBufferedImage;
import net.runelite.client.game.ItemManager;
import net.runelite.client.plugins.skillcalculator.BankedCalculator;
import net.runelite.client.plugins.skillcalculator.banked.CriticalItem;
import net.runelite.client.plugins.skillcalculator.banked.beans.Activity;
import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.FontManager;
import net.runelite.client.ui.components.materialtabs.MaterialTab;
import net.runelite.client.ui.components.materialtabs.MaterialTabGroup;
import net.runelite.client.ui.components.shadowlabel.JShadowedLabel;
import net.runelite.client.util.StackFormatter;
@Singleton
public class CriticalItemPanel extends JPanel
{
private static final Dimension ICON_SIZE = new Dimension(36, 36);
private static final DecimalFormat FORMAT_COMMA = new DecimalFormat("#,###.#");
private static final BufferedImage ICON_SETTINGS;
private static final Border PANEL_BORDER = new EmptyBorder(3, 0, 3, 0);
private final static Color BACKGROUND_COLOR = ColorScheme.DARKER_GRAY_COLOR;
private final static Color BUTTON_HOVER_COLOR = ColorScheme.DARKER_GRAY_HOVER_COLOR;
static
{
BufferedImage i1;
try
{
synchronized (ImageIO.class)
{
i1 = ImageIO.read(BankedCalculator.class.getResourceAsStream("view-more-white.png"));
}
}
catch (IOException e)
{
throw new RuntimeException(e);
}
ICON_SETTINGS = i1;
}
private final BankedCalculator bankedCalculator;
private final CriticalItem item;
private final ItemManager itemManager;
private double xp;
@Getter(AccessLevel.PUBLIC)
private int amount;
@Getter(AccessLevel.PUBLIC)
private double total;
private Map<CriticalItem, Integer> linkedMap;
private JShadowedLabel labelValue;
private final JPanel infoContainer;
private final JLabel image;
private boolean infoVisibility = false;
public CriticalItemPanel(BankedCalculator bankedCalculator, ItemManager itemManager, CriticalItem item, double xp, int amount, Map<CriticalItem, Integer> linkedMap)
{
this.bankedCalculator = bankedCalculator;
this.item = item;
this.xp = xp;
this.amount = amount;
this.total = xp * amount;
this.itemManager = itemManager;
this.linkedMap = linkedMap;
this.setLayout(new GridBagLayout());
this.setBorder(PANEL_BORDER);
this.setBackground(ColorScheme.DARK_GRAY_COLOR);
this.setVisible(this.amount > 0);
infoContainer = new JPanel();
infoContainer.setLayout(new GridBagLayout());
infoContainer.setVisible(false);
infoContainer.setBackground(BACKGROUND_COLOR);
infoContainer.setBorder(new MatteBorder(1, 0, 0, 0, Color.GRAY));
// Icon
AsyncBufferedImage icon = itemManager.getImage(item.getItemID(), amount, item.getDefinition().isStackable() || amount > 1);
image = new JLabel();
image.setMinimumSize(ICON_SIZE);
image.setMaximumSize(ICON_SIZE);
image.setPreferredSize(ICON_SIZE);
image.setHorizontalAlignment(SwingConstants.CENTER);
image.setBorder(new EmptyBorder(0, 8, 0, 0));
Runnable resize = () ->
image.setIcon(new ImageIcon(icon.getScaledInstance((int) ICON_SIZE.getWidth(), (int) ICON_SIZE.getHeight(), Image.SCALE_SMOOTH)));
icon.onChanged(resize);
resize.run();
// Container for Info
JPanel uiInfo = new JPanel(new GridLayout(2, 1));
uiInfo.setBorder(new EmptyBorder(0, 5, 0, 0));
uiInfo.setBackground(BACKGROUND_COLOR);
JShadowedLabel labelName = new JShadowedLabel(item.getDefinition().getName());
labelName.setForeground(Color.WHITE);
labelName.setVerticalAlignment(SwingUtilities.BOTTOM);
labelValue = new JShadowedLabel();
labelValue.setFont(FontManager.getRunescapeSmallFont());
labelValue.setVerticalAlignment(SwingUtilities.TOP);
updateXp(xp);
uiInfo.add(labelName);
uiInfo.add(labelValue);
// Settings Button
JLabel settingsButton = new JLabel();
settingsButton.setBorder(new EmptyBorder(0, 5, 0, 5));
settingsButton.setIcon(new ImageIcon(ICON_SETTINGS));
settingsButton.setOpaque(true);
settingsButton.setBackground(BACKGROUND_COLOR);
settingsButton.addMouseListener(new MouseAdapter()
{
@Override
public void mouseEntered(MouseEvent e)
{
settingsButton.setBackground(BUTTON_HOVER_COLOR);
}
@Override
public void mouseExited(MouseEvent e)
{
settingsButton.setBackground(BACKGROUND_COLOR);
}
@Override
public void mouseClicked(MouseEvent e)
{
toggleInfo();
}
});
// Create and append elements to container panel
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.setBackground(BACKGROUND_COLOR);
panel.add(image, BorderLayout.LINE_START);
panel.add(uiInfo, BorderLayout.CENTER);
// Only add button if has activity selection options or linked items
List<Activity> activities = Activity.getByCriticalItem(item);
// If linked map has 1 item and it isn't this item still show breakdown (cleaned herbs into unfinished)
if ((linkedMap.size() > 1 || (linkedMap.size() == 1 && linkedMap.get(item) == null))
|| activities.size() > 1)
{
panel.add(settingsButton, BorderLayout.LINE_END);
}
panel.setToolTipText("<html>" + item.getDefinition().getName()
+ "<br/>xp: " + xp
+ "<br/>Total: " + StackFormatter.quantityToStackSize((long) total) + "</html");
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.BOTH;
c.weightx = 1;
c.gridx = 0;
c.gridy = 0;
c.ipady = 20;
this.add(panel, c);
c.gridy++;
this.add(infoContainer, c);
}
private void toggleInfo()
{
infoVisibility = !infoVisibility;
if (infoVisibility)
{
createInfoPanel();
}
else
{
infoContainer.removeAll();
infoContainer.setVisible(false);
infoContainer.revalidate();
infoContainer.repaint();
}
}
private void createInfoPanel()
{
infoContainer.removeAll();
infoContainer.setVisible(true);
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.BOTH;
c.weightx = 1;
c.gridx = 0;
c.gridy = 0;
c.ipady = 0;
JPanel p = createActivitiesPanel();
if (p != null)
{
infoContainer.add(p, c);
c.gridy++;
}
// Show linked item breakdown, including own items
if (linkedMap.size() > 1 || (linkedMap.size() == 1 && linkedMap.get(item) == null))
{
JLabel l = new JLabel("Item Breakdown");
l.setBorder(new EmptyBorder(3, 0, 3, 0));
l.setHorizontalAlignment(JLabel.CENTER);
infoContainer.add(l, c);
c.gridy++;
JPanel con = new JPanel();
con.setLayout(new GridBagLayout());
con.setBackground(BACKGROUND_COLOR);
for (Map.Entry<CriticalItem, Integer> e : linkedMap.entrySet())
{
// Icon
AsyncBufferedImage icon = itemManager.getImage(e.getKey().getItemID(), e.getValue(), e.getKey().getDefinition().isStackable() || e.getValue() > 1);
JLabel image = new JLabel();
image.setMinimumSize(ICON_SIZE);
image.setMaximumSize(ICON_SIZE);
image.setPreferredSize(ICON_SIZE);
image.setHorizontalAlignment(SwingConstants.CENTER);
image.setBorder(new EmptyBorder(0, 8, 0, 0));
Runnable resize = () ->
image.setIcon(new ImageIcon(icon.getScaledInstance((int) ICON_SIZE.getWidth(), (int) ICON_SIZE.getHeight(), Image.SCALE_SMOOTH)));
icon.onChanged(resize);
resize.run();
image.setToolTipText(e.getKey().getDefinition().getName());
con.add(image, c);
c.gridx++;
}
c.gridx = 0;
infoContainer.add(con, c);
}
}
private JPanel createActivitiesPanel()
{
List<Activity> activities = Activity.getByCriticalItem(item);
if (activities == null || activities.size() == 1)
{
return null;
}
JPanel p = new JPanel();
p.setBackground(BACKGROUND_COLOR);
p.setLayout(new BorderLayout());
JLabel label = new JLabel("Possible training methods");
MaterialTabGroup group = new MaterialTabGroup();
group.setLayout(new GridLayout(0, 6, 0, 2));
group.setBorder(new MatteBorder(1, 1, 1, 1, Color.BLACK));
Activity selected = this.bankedCalculator.getSelectedActivity(this.item);
boolean s = false;
for (Activity option : activities)
{
AsyncBufferedImage icon = itemManager.getImage(option.getIcon());
MaterialTab matTab = new MaterialTab("", group, null);
matTab.setHorizontalAlignment(SwingUtilities.RIGHT);
matTab.setToolTipText(option.getName());
Runnable resize = () ->
matTab.setIcon(new ImageIcon(icon.getScaledInstance(24, 24, Image.SCALE_SMOOTH)));
icon.onChanged(resize);
resize.run();
group.addTab(matTab);
// Select first option by default
if (!s)
{
s = true;
group.select(matTab);
}
// Select the option if its their selected activity
if (option.equals(selected))
{
group.select(matTab);
}
// Add click event handler now to prevent above code from triggering it.
matTab.setOnSelectEvent(() ->
{
bankedCalculator.activitySelected(item, option);
return true;
});
}
p.add(label, BorderLayout.NORTH);
p.add(group, BorderLayout.SOUTH);
return p;
}
public void updateXp(double newXpRate)
{
xp = newXpRate;
total = xp * amount;
labelValue.setText(FORMAT_COMMA.format(total) + "xp");
}
public void updateAmount(int newAmount, boolean forceVisible)
{
this.setVisible(newAmount > 0 || forceVisible);
this.amount = newAmount;
AsyncBufferedImage icon = itemManager.getImage(item.getItemID(), amount, item.getDefinition().isStackable() || amount > 1);
Runnable resize = () ->
image.setIcon(new ImageIcon(icon.getScaledInstance((int) ICON_SIZE.getWidth(), (int) ICON_SIZE.getHeight(), Image.SCALE_SMOOTH)));
icon.onChanged(resize);
resize.run();
}
public void updateLinkedMap(Map<CriticalItem, Integer> newLinkedMap)
{
this.linkedMap = newLinkedMap;
int sum = 0;
for (Integer v : newLinkedMap.values())
{
sum += v;
}
this.updateAmount(sum, false);
this.updateXp(xp);
// Refresh info panel if visible
if (infoVisibility)
{
createInfoPanel();
}
}
public void recalculate()
{
updateXp(xp);
}
}

View File

@@ -24,10 +24,9 @@
*/
package net.runelite.client.plugins.skillcalculator.beans;
import lombok.AccessLevel;
import lombok.Getter;
@Getter(AccessLevel.PUBLIC)
@Getter
public class SkillData
{
private SkillDataEntry[] actions;

View File

@@ -24,10 +24,9 @@
*/
package net.runelite.client.plugins.skillcalculator.beans;
import lombok.AccessLevel;
import lombok.Getter;
@Getter(AccessLevel.PUBLIC)
@Getter
public class SkillDataBonus
{
private String name;

View File

@@ -24,10 +24,9 @@
*/
package net.runelite.client.plugins.skillcalculator.beans;
import lombok.AccessLevel;
import lombok.Getter;
@Getter(AccessLevel.PUBLIC)
@Getter
public class SkillDataEntry
{
private String name;

View File

@@ -166,6 +166,17 @@ public interface SlayerConfig extends Config
return true;
}
@ConfigItem(
position = 14,
keyName = "pointsCommand",
name = "Points Command",
description = "Configures whether the slayer points command is enabled<br> !points"
)
default boolean pointsCommand()
{
return true;
}
// Stored data
@ConfigItem(
keyName = "taskName",

View File

@@ -139,6 +139,7 @@ public class SlayerPlugin extends Plugin
private static final String TASK_COMMAND_STRING = "!task";
private static final Pattern TASK_STRING_VALIDATION = Pattern.compile("[^a-zA-Z0-9' -]");
private static final int TASK_STRING_MAX_LENGTH = 50;
private static final String POINTS_COMMAND_STRING = "!points";
// Superiors
@VisibleForTesting
@@ -280,6 +281,8 @@ public class SlayerPlugin extends Plugin
private boolean taskCommand;
private String taskName;
private String taskLocation;
@Setter(AccessLevel.PACKAGE)
private boolean pointsCommand;
private int amount;
private int initialAmount;
private int lastCertainAmount;
@@ -316,6 +319,8 @@ public class SlayerPlugin extends Plugin
clientToolbar.addNavigation(navButton);
chatCommandManager.registerCommandAsync(TASK_COMMAND_STRING, this::taskLookup, this::taskSubmit);
chatCommandManager.registerCommandAsync(POINTS_COMMAND_STRING, this::pointsLookup); //here
}
@Override
@@ -329,6 +334,7 @@ public class SlayerPlugin extends Plugin
clearTrackedNPCs();
chatCommandManager.unregisterCommand(TASK_COMMAND_STRING);
chatCommandManager.unregisterCommand(POINTS_COMMAND_STRING);
clientToolbar.removeNavigation(navButton);
}
@@ -1121,6 +1127,44 @@ public class SlayerPlugin extends Plugin
client.refreshChat();
}
void pointsLookup(ChatMessage chatMessage, String message)
{
if (!this.pointsCommand)
{
return;
}
ChatMessageType type = chatMessage.getType();
final String player;
if (type.equals(ChatMessageType.PRIVATECHATOUT))
{
player = client.getLocalPlayer().getName();
}
else
{
player = Text.removeTags(chatMessage.getName())
.replace('\u00A0', ' ');
}
if (Integer.toString(getPoints()) == null)
{
return;
}
String response = new ChatMessageBuilder()
.append(ChatColorType.NORMAL)
.append("Slayer Points: ")
.append(ChatColorType.HIGHLIGHT)
.append(Integer.toString(getPoints()))
.build();
final MessageNode messageNode = chatMessage.getMessageNode();
messageNode.setRuneLiteFormatMessage(response);
chatMessageManager.update(messageNode);
client.refreshChat();
}
/* package access method for changing the pause state of the time tracker for the current task */
void setPaused(boolean paused)
{
@@ -1208,6 +1252,7 @@ public class SlayerPlugin extends Plugin
this.drawMinimapNames = config.drawMinimapNames();
this.weaknessPrompt = config.weaknessPrompt();
this.taskCommand = config.taskCommand();
this.pointsCommand = config.pointsCommand();
this.taskName = config.taskName();
this.amount = config.amount();
this.initialAmount = config.initialAmount();

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2018 Abex
* Copyright (c) 2018, Sean Dewar <https://github.com/seandewar>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -22,29 +23,47 @@
* (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.regenmeter;
package net.runelite.client.plugins.statusorbs;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
import net.runelite.client.config.Stub;
@ConfigGroup("regenmeter")
public interface RegenMeterConfig extends Config
@ConfigGroup("statusorbs")
public interface StatusOrbsConfig extends Config
{
@ConfigItem(
keyName = "showHitpoints",
name = "Show hitpoints regen",
description = "Show a ring around the hitpoints orb")
default boolean showHitpoints()
keyName = "hp",
name = "Hitpoints",
description = "",
position = 0
)
default Stub hp()
{
return new Stub();
}
@ConfigItem(
keyName = "dynamicHpHeart",
name = "Dynamic hitpoints heart",
description = "Changes the HP heart color to match players current affliction",
parent = "hp",
position = 1
)
default boolean dynamicHpHeart()
{
return true;
}
@ConfigItem(
keyName = "showSpecial",
name = "Show Spec. Attack regen",
description = "Show a ring around the Special Attack orb")
default boolean showSpecial()
keyName = "showHitpoints",
name = "Show hitpoints regen",
description = "Show a ring around the hitpoints orb",
parent = "hp",
position = 2
)
default boolean showHitpoints()
{
return true;
}
@@ -52,7 +71,10 @@ public interface RegenMeterConfig extends Config
@ConfigItem(
keyName = "showWhenNoChange",
name = "Show hitpoints regen at full hitpoints",
description = "Always show the hitpoints regen orb, even if there will be no stat change")
description = "Always show the hitpoints regen orb, even if there will be no stat change",
parent = "hp",
position = 3
)
default boolean showWhenNoChange()
{
return false;
@@ -61,10 +83,70 @@ public interface RegenMeterConfig extends Config
@ConfigItem(
keyName = "notifyBeforeHpRegenDuration",
name = "Hitpoint Regen Notification (seconds)",
description = "Notify approximately when your next hitpoint is about to regen. A value of 0 will disable notification."
description = "Notify approximately when your next hitpoint is about to regen. A value of 0 will disable notification.",
parent = "hp",
position = 4
)
default int getNotifyBeforeHpRegenSeconds()
{
return 0;
}
}
@ConfigItem(
keyName = "spec",
name = "Special attack",
description = "",
position = 5
)
default Stub spec()
{
return new Stub();
}
@ConfigItem(
keyName = "showSpecial",
name = "Show Spec. Attack regen",
description = "Show a ring around the Special Attack orb",
parent = "spec",
position = 6
)
default boolean showSpecial()
{
return true;
}
@ConfigItem(
keyName = "run",
name = "Run energy",
description = "",
position = 7
)
default Stub run()
{
return new Stub();
}
@ConfigItem(
keyName = "showRun",
name = "Show run energy regen",
description = "Show a ring around the run regen orb",
position = 8,
parent = "run"
)
default boolean showRun()
{
return true;
}
@ConfigItem(
keyName = "replaceOrbText",
name = "Replace run orb text with run time left",
description = "Show the remaining run time (in seconds) next in the energy orb",
position = 9,
parent = "run"
)
default boolean replaceOrbText()
{
return false;
}
}

View File

@@ -0,0 +1,228 @@
/*
* Copyright (c) 2018 Abex
* Copyright (c) 2018, Sean Dewar <https://github.com/seandewar>
* 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.statusorbs;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.geom.Arc2D;
import javax.inject.Inject;
import net.runelite.api.Client;
import net.runelite.api.InventoryID;
import net.runelite.api.Point;
import net.runelite.api.Skill;
import net.runelite.api.VarPlayer;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer;
import net.runelite.client.ui.overlay.OverlayPosition;
import net.runelite.client.ui.overlay.tooltip.Tooltip;
import net.runelite.client.ui.overlay.tooltip.TooltipManager;
import net.runelite.client.util.Graceful;
import org.apache.commons.lang3.StringUtils;
public class StatusOrbsOverlay extends Overlay
{
private static final Color HITPOINTS_COLOR = brighter(0x9B0703);
private static final Color SPECIAL_COLOR = brighter(0x1E95B0);
private static final Color RUN_COLOR = new Color(255, 215, 0);
private static final Color OVERLAY_COLOR = new Color(255, 255, 255, 60);
private static final double DIAMETER = 26D;
private static final int OFFSET = 27;
private final Client client;
private final StatusOrbsPlugin plugin;
private final TooltipManager tooltipManager;
private long last = System.nanoTime();
private double percentHp;
private double lastHp;
private double percentSpec;
private double lastSpec;
private double percentRun;
private double lastRun;
private static Color brighter(int color)
{
float[] hsv = new float[3];
Color.RGBtoHSB(color >>> 16, (color >> 8) & 0xFF, color & 0xFF, hsv);
return Color.getHSBColor(hsv[0], 1.f, 1.f);
}
@Inject
public StatusOrbsOverlay(Client client, StatusOrbsPlugin plugin, TooltipManager tooltipManager)
{
setPosition(OverlayPosition.DYNAMIC);
setLayer(OverlayLayer.ABOVE_WIDGETS);
this.client = client;
this.plugin = plugin;
this.tooltipManager = tooltipManager;
}
@Override
public Dimension render(Graphics2D g)
{
g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
long current = System.nanoTime();
double ms = (current - last) / (double) 1000000;
if (plugin.isShowHitpoints())
{
if (lastHp == plugin.getHitpointsPercentage() && plugin.getHitpointsPercentage() != 0)
{
percentHp += ms * plugin.getHpPerMs();
}
else
{
percentHp = plugin.getHitpointsPercentage();
lastHp = plugin.getHitpointsPercentage();
}
renderRegen(g, WidgetInfo.MINIMAP_HEALTH_ORB, percentHp, HITPOINTS_COLOR);
}
if (plugin.isShowSpecial())
{
if (client.getVar(VarPlayer.SPECIAL_ATTACK_ENABLED) == 1)
{
final Widget widget = client.getWidget(WidgetInfo.MINIMAP_SPEC_ORB);
if (widget != null && !widget.isHidden())
{
final Rectangle bounds = widget.getBounds();
g.setColor(OVERLAY_COLOR);
g.fillOval(
bounds.x + OFFSET,
bounds.y + (int) (bounds.height / 2 - (DIAMETER) / 2),
(int) DIAMETER, (int) DIAMETER);
}
}
if (lastSpec == plugin.getSpecialPercentage() && plugin.getSpecialPercentage() != 0)
{
percentSpec += ms * plugin.getSpecPerMs();
}
else
{
percentSpec = plugin.getSpecialPercentage();
lastSpec = plugin.getSpecialPercentage();
}
renderRegen(g, WidgetInfo.MINIMAP_SPEC_ORB, percentSpec, SPECIAL_COLOR);
}
if (plugin.isReplaceOrbText())
{
final Widget runOrb = client.getWidget(WidgetInfo.MINIMAP_TOGGLE_RUN_ORB);
if (runOrb == null || runOrb.isHidden())
{
return null;
}
final Rectangle bounds = runOrb.getBounds();
if (bounds.getX() <= 0)
{
return null;
}
final Point mousePosition = client.getMouseCanvasPosition();
if (bounds.contains(mousePosition.getX(), mousePosition.getY()))
{
StringBuilder sb = new StringBuilder();
sb.append("Weight: ").append(client.getWeight()).append(" kg</br>");
if (plugin.isReplaceOrbText())
{
sb.append("Run Energy: ").append(client.getEnergy()).append("%");
}
else
{
sb.append("Run Time Remaining: ").append(plugin.getEstimatedRunTimeRemaining(false));
}
int secondsUntil100 = plugin.getEstimatedRecoverTimeRemaining();
if (secondsUntil100 > 0)
{
final int minutes = (int) Math.floor(secondsUntil100 / 60.0);
final int seconds = (int) Math.floor(secondsUntil100 - (minutes * 60.0));
sb.append("</br>").append("100% Energy In: ").append(minutes).append(':').append(StringUtils.leftPad(Integer.toString(seconds), 2, "0"));
}
tooltipManager.add(new Tooltip(sb.toString()));
}
}
if (plugin.isShowRun())
{
if (lastRun == plugin.getRunPercentage() && plugin.getRunPercentage() != 0)
{
double recoverRate = (48 + client.getBoostedSkillLevel(Skill.AGILITY)) / 360000.0;
if (Graceful.hasFullSet(client.getItemContainer(InventoryID.EQUIPMENT)))
{
recoverRate *= 1.3; // 30% recover rate increase from Graceful set effect
}
percentRun += ms * recoverRate;
}
else
{
percentRun = plugin.getRunPercentage();
lastRun = plugin.getRunPercentage();
}
renderRegen(g, WidgetInfo.MINIMAP_RUN_ORB, percentRun, RUN_COLOR);
}
last = current;
return null;
}
private void renderRegen(Graphics2D g, WidgetInfo widgetInfo, double percent, Color color)
{
Widget widget = client.getWidget(widgetInfo);
if (widget == null || widget.isHidden())
{
return;
}
Rectangle bounds = widget.getBounds();
Arc2D.Double arc = new Arc2D.Double(bounds.x + OFFSET, bounds.y + (bounds.height / 2 - DIAMETER / 2), DIAMETER, DIAMETER, 90.d, -360.d * percent, Arc2D.OPEN);
final Stroke STROKE = new BasicStroke(2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER);
g.setStroke(STROKE);
g.setColor(color);
g.draw(arc);
}
}

View File

@@ -0,0 +1,490 @@
/*
* Copyright (c) 2019, Owain van Brakel <https://github.com/Owain94>
* Copyright (c) 2018, TheStonedTurtle <https://github.com/TheStonedTurtle>
* Copyright (c) 2018 Abex
* Copyright (c) 2018, Zimaya <https://github.com/Zimaya>
* Copyright (c) 2017, Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.statusorbs;
import com.google.inject.Provides;
import java.awt.image.BufferedImage;
import javax.inject.Inject;
import lombok.AccessLevel;
import lombok.Getter;
import net.runelite.api.Client;
import net.runelite.api.Constants;
import net.runelite.api.GameState;
import net.runelite.api.InventoryID;
import net.runelite.api.Prayer;
import net.runelite.api.Skill;
import net.runelite.api.SpriteID;
import net.runelite.api.VarPlayer;
import net.runelite.api.Varbits;
import net.runelite.api.coords.WorldPoint;
import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.GameTick;
import net.runelite.api.events.VarbitChanged;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.Notifier;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.overlay.OverlayManager;
import net.runelite.client.util.Graceful;
import net.runelite.client.util.ImageUtil;
import org.apache.commons.lang3.StringUtils;
@PluginDescriptor(
name = "Status Orbs",
description = "Configure settings for the Minimap orbs",
tags = {"minimap", "orb", "regen", "energy", "special"}
)
public class StatusOrbsPlugin extends Plugin
{
private static final BufferedImage HEART_DISEASE;
private static final BufferedImage HEART_POISON;
private static final BufferedImage HEART_VENOM;
static
{
HEART_DISEASE = ImageUtil.resizeCanvas(ImageUtil.getResourceStreamFromClass(StatusOrbsPlugin.class, "1067-DISEASE.png"), 26, 26);
HEART_POISON = ImageUtil.resizeCanvas(ImageUtil.getResourceStreamFromClass(StatusOrbsPlugin.class, "1067-POISON.png"), 26, 26);
HEART_VENOM = ImageUtil.resizeCanvas(ImageUtil.getResourceStreamFromClass(StatusOrbsPlugin.class, "1067-VENOM.png"), 26, 26);
}
private static final int SPEC_REGEN_TICKS = 50;
private static final int NORMAL_HP_REGEN_TICKS = 100;
@Inject
private Client client;
@Inject
private ClientThread clientThread;
@Inject
private ConfigManager configManager;
@Inject
private StatusOrbsConfig config;
@Inject
private StatusOrbsOverlay overlay;
@Inject
private OverlayManager overlayManager;
@Inject
private Notifier notifier;
@Getter
private double hitpointsPercentage;
@Getter
private double specialPercentage;
@Getter
private double runPercentage;
@Getter
private double hpPerMs;
@Getter
private double specPerMs = (double) 1 / (SPEC_REGEN_TICKS * 600);
// RegenMeter
private int ticksSinceSpecRegen;
private int ticksSinceHPRegen;
private boolean wasRapidHeal;
private double ticksSinceRunRegen;
// Run Energy
private int lastEnergy = 0;
private boolean localPlayerRunningToDestination;
private WorldPoint currPoint;
private WorldPoint prevLocalPlayerLocation;
private BufferedImage heart;
private boolean dynamicHpHeart;
@Getter(AccessLevel.PACKAGE)
private boolean showHitpoints;
private boolean showWhenNoChange;
private int getNotifyBeforeHpRegenSeconds;
@Getter(AccessLevel.PACKAGE)
private boolean showSpecial;
@Getter(AccessLevel.PACKAGE)
private boolean showRun;
@Getter(AccessLevel.PACKAGE)
private boolean replaceOrbText;
@Provides
StatusOrbsConfig provideConfig(ConfigManager configManager)
{
return configManager.getConfig(StatusOrbsConfig.class);
}
@Override
protected void startUp() throws Exception
{
migrateConfigs();
updateConfig();
overlayManager.add(overlay);
if (this.dynamicHpHeart && client.getGameState().equals(GameState.LOGGED_IN))
{
clientThread.invoke(this::checkHealthIcon);
}
}
@Override
protected void shutDown() throws Exception
{
overlayManager.remove(overlay);
localPlayerRunningToDestination = false;
prevLocalPlayerLocation = null;
resetRunOrbText();
if (this.dynamicHpHeart)
{
clientThread.invoke(this::resetHealthIcon);
}
}
@Subscribe
public void onConfigChanged(ConfigChanged event)
{
if (event.getGroup().equals("statusorbs"))
{
updateConfig();
switch (event.getKey())
{
case "replaceOrbText":
if (!this.replaceOrbText)
{
resetRunOrbText();
}
break;
case "dynamicHpHeart":
if (this.dynamicHpHeart)
{
checkHealthIcon();
}
else
{
resetHealthIcon();
}
break;
}
}
}
@Subscribe
private void onVarbitChanged(VarbitChanged e)
{
if (this.dynamicHpHeart)
{
checkHealthIcon();
}
boolean isRapidHeal = client.isPrayerActive(Prayer.RAPID_HEAL);
if (wasRapidHeal != isRapidHeal)
{
ticksSinceHPRegen = 0;
}
wasRapidHeal = isRapidHeal;
}
@Subscribe
private void onGameStateChanged(GameStateChanged ev)
{
if (ev.getGameState() == GameState.HOPPING || ev.getGameState() == GameState.LOGIN_SCREEN)
{
ticksSinceHPRegen = -2; // For some reason this makes this accurate
ticksSinceSpecRegen = 0;
ticksSinceRunRegen = -1;
}
}
@Subscribe
public void onGameTick(GameTick event)
{
if (client.getVar(VarPlayer.SPECIAL_ATTACK_PERCENT) == 1000)
{
// The recharge doesn't tick when at 100%
ticksSinceSpecRegen = 0;
}
else
{
ticksSinceSpecRegen = (ticksSinceSpecRegen + 1) % SPEC_REGEN_TICKS;
}
specialPercentage = ticksSinceSpecRegen / (double) SPEC_REGEN_TICKS;
int ticksPerHPRegen = NORMAL_HP_REGEN_TICKS;
hpPerMs = ticksPerHPRegen / (double) 6000000;
if (client.isPrayerActive(Prayer.RAPID_HEAL))
{
ticksPerHPRegen /= 2;
hpPerMs *= 2;
}
ticksSinceHPRegen = (ticksSinceHPRegen + 1) % ticksPerHPRegen;
hitpointsPercentage = ticksSinceHPRegen / (double) ticksPerHPRegen;
int currentHP = client.getBoostedSkillLevel(Skill.HITPOINTS);
int maxHP = client.getRealSkillLevel(Skill.HITPOINTS);
if (currentHP == maxHP && !this.showWhenNoChange)
{
hitpointsPercentage = 0;
}
else if (currentHP > maxHP)
{
// Show it going down
hitpointsPercentage = 1 - hitpointsPercentage;
}
// Run Energy
localPlayerRunningToDestination =
prevLocalPlayerLocation != null &&
client.getLocalDestinationLocation() != null &&
prevLocalPlayerLocation.distanceTo(client.getLocalPlayer().getWorldLocation()) > 1;
if (this.getNotifyBeforeHpRegenSeconds > 0 && currentHP < maxHP && shouldNotifyHpRegenThisTick(ticksPerHPRegen))
{
notifier.notify("[" + client.getLocalPlayer().getName() + "] regenerates their next hitpoint soon!");
}
localPlayerRunningToDestination =
prevLocalPlayerLocation != null &&
client.getLocalDestinationLocation() != null &&
prevLocalPlayerLocation.distanceTo(client.getLocalPlayer().getWorldLocation()) > 1;
prevLocalPlayerLocation = client.getLocalPlayer().getWorldLocation();
if (this.replaceOrbText)
{
setRunOrbText(getEstimatedRunTimeRemaining(true));
}
int currEnergy = client.getEnergy();
currPoint = client.getLocalPlayer().getWorldLocation();
if (currEnergy == 100 || (prevLocalPlayerLocation != null && currPoint.distanceTo(prevLocalPlayerLocation) > 1) || currEnergy < lastEnergy)
{
ticksSinceRunRegen = 0;
}
else if (currEnergy > lastEnergy)
{
if (runPercentage < 1)
{
ticksSinceRunRegen = (1 - runPercentage) / runRegenPerTick();
ticksSinceRunRegen = ticksSinceRunRegen > 1 ? 1 : ticksSinceRunRegen;
}
else
{
ticksSinceRunRegen = (runPercentage - 1) / runRegenPerTick();
}
}
else
{
ticksSinceRunRegen += 1;
}
runPercentage = ticksSinceRunRegen * runRegenPerTick();
prevLocalPlayerLocation = currPoint;
lastEnergy = currEnergy;
}
private boolean shouldNotifyHpRegenThisTick(int ticksPerHPRegen)
{
// if the configured duration lies between two ticks, choose the earlier tick
final int ticksBeforeHPRegen = ticksPerHPRegen - ticksSinceHPRegen;
final int notifyTick = (int) Math.ceil(this.getNotifyBeforeHpRegenSeconds * 1000d / Constants.GAME_TICK_LENGTH);
return ticksBeforeHPRegen == notifyTick;
}
private void setRunOrbText(String text)
{
Widget runOrbText = client.getWidget(WidgetInfo.MINIMAP_RUN_ORB_TEXT);
if (runOrbText != null)
{
runOrbText.setText(text);
}
}
private void resetRunOrbText()
{
setRunOrbText(Integer.toString(client.getEnergy()));
}
String getEstimatedRunTimeRemaining(boolean inSeconds)
{
// Calculate the amount of energy lost every 2 ticks (0.6 seconds).
// Negative weight has the same depletion effect as 0 kg.
final int effectiveWeight = Math.max(client.getWeight(), 0);
double lossRate = (Math.min(effectiveWeight, 64) / 100.0) + 0.64;
if (client.getVar(Varbits.RUN_SLOWED_DEPLETION_ACTIVE) != 0)
{
lossRate *= 0.3; // Stamina effect reduces energy depletion to 30%
}
// Calculate the number of seconds left
final double secondsLeft = (client.getEnergy() * 0.6) / lossRate;
// Return the text
if (inSeconds)
{
return (int) Math.floor(secondsLeft) + "s";
}
else
{
final int minutes = (int) Math.floor(secondsLeft / 60.0);
final int seconds = (int) Math.floor(secondsLeft - (minutes * 60.0));
return minutes + ":" + StringUtils.leftPad(Integer.toString(seconds), 2, "0");
}
}
int getEstimatedRecoverTimeRemaining()
{
if (localPlayerRunningToDestination)
{
return -1;
}
// Calculate the amount of energy recovered every second
double recoverRate = (48 + client.getBoostedSkillLevel(Skill.AGILITY)) / 360.0;
if (Graceful.hasFullSet(client.getItemContainer(InventoryID.EQUIPMENT)))
{
recoverRate *= 1.3; // 30% recover rate increase from Graceful set effect
}
// Calculate the number of seconds left
final double secondsLeft = (100 - client.getEnergy()) / recoverRate;
return (int) secondsLeft;
}
/**
* Check player afflictions to determine health icon
*/
private void checkHealthIcon()
{
BufferedImage newHeart;
int poison = client.getVar(VarPlayer.IS_POISONED);
if (poison >= 1000000)
{
newHeart = HEART_VENOM;
}
else if (poison > 0)
{
newHeart = HEART_POISON;
}
else if (client.getVar(VarPlayer.DISEASE_VALUE) > 0)
{
newHeart = HEART_DISEASE;
}
else
{
heart = null;
resetHealthIcon();
return;
}
// Only update sprites when the heart icon actually changes
if (newHeart != heart)
{
heart = newHeart;
client.getWidgetSpriteCache().reset();
client.getSpriteOverrides().put(SpriteID.MINIMAP_ORB_HITPOINTS_ICON, ImageUtil.getImageSprite(heart, client));
}
}
private double runRegenPerTick()
{
double recoverRate = (client.getBoostedSkillLevel(Skill.AGILITY) / 6d + 8) / 100;
if (Graceful.hasFullSet(client.getItemContainer(InventoryID.EQUIPMENT)))
{
return recoverRate * 1.3;
}
return recoverRate;
}
/**
* Ensure the HP Heart is the default Sprite
*/
private void resetHealthIcon()
{
client.getWidgetSpriteCache().reset();
client.getSpriteOverrides().remove(SpriteID.MINIMAP_ORB_HITPOINTS_ICON);
}
/**
* Migrates configs from runenergy and regenmeter to this plugin and deletes the old config values.
* This method should be removed after a reasonable amount of time.
*/
@Deprecated
private void migrateConfigs()
{
migrateConfig("regenmeter", "showHitpoints");
migrateConfig("regenmeter", "showSpecial");
migrateConfig("regenmeter", "showWhenNoChange");
migrateConfig("regenmeter", "notifyBeforeHpRegenDuration");
migrateConfig("runenergy", "replaceOrbText");
}
/**
* Wrapper for migrating individual config options
* This method should be removed after a reasonable amount of time.
*
* @param group old group name
* @param key key name to migrate
*/
@Deprecated
private void migrateConfig(String group, String key)
{
String value = configManager.getConfiguration(group, key);
if (value != null)
{
configManager.setConfiguration("statusorbs", key, value);
configManager.unsetConfiguration(group, key);
}
}
private void updateConfig()
{
this.dynamicHpHeart = config.dynamicHpHeart();
this.showHitpoints = config.showHitpoints();
this.showWhenNoChange = config.showWhenNoChange();
this.getNotifyBeforeHpRegenSeconds = config.getNotifyBeforeHpRegenSeconds();
this.showSpecial = config.showSpecial();
this.showRun = config.showRun();
this.replaceOrbText = config.replaceOrbText();
}
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) 2019, TheStonedTurtle <http://www.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.ui.components;
import javax.annotation.Nullable;
import javax.swing.Icon;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* Used with ComboBoxListRenderer to render an icon next to the text of the list entry.
* Also supports adding a data object to be used for more complex selection logic
*/
@AllArgsConstructor
@Getter
public class ComboBoxIconEntry
{
private Icon icon;
private String text;
@Nullable
private Object data;
}

View File

@@ -30,6 +30,7 @@ import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.ListCellRenderer;
import javax.swing.border.EmptyBorder;
import lombok.Setter;
import net.runelite.client.ui.ColorScheme;
import net.runelite.client.util.Text;
@@ -41,6 +42,8 @@ import net.runelite.client.util.Text;
*/
public final class ComboBoxListRenderer extends JLabel implements ListCellRenderer
{
@Setter
private String defaultText = "Select an option...";
@Override
public Component getListCellRendererComponent(JList list, Object o, int index, boolean isSelected, boolean cellHasFocus)
@@ -57,12 +60,24 @@ public final class ComboBoxListRenderer extends JLabel implements ListCellRender
}
setBorder(new EmptyBorder(5, 5, 5, 0));
setIcon(null);
String text;
if (o instanceof Enum)
// If using setSelectedItem(null) or setSelectedIndex(-1) show default text until a selection is made
if (index == -1 && o == null)
{
text = defaultText;
}
else if (o instanceof Enum)
{
text = Text.titleCase((Enum) o);
}
else if (o instanceof ComboBoxIconEntry)
{
ComboBoxIconEntry e = (ComboBoxIconEntry) o;
text = e.getText();
setIcon(e.getIcon());
}
else
{
text = o.toString();

View File

@@ -118,7 +118,7 @@ public class GameEventManager
if (itemContainer != null)
{
eventBus.post(new ItemContainerChanged(itemContainer));
eventBus.post(new ItemContainerChanged(inventory.getId(), itemContainer));
}
}

View File

@@ -0,0 +1,102 @@
/*
* Copyright (c) 2018 raiyni <https://github.com/raiyni>
* 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.util;
import com.google.common.collect.ImmutableSet;
import net.runelite.api.EquipmentInventorySlot;
import net.runelite.api.Item;
import net.runelite.api.ItemContainer;
import static net.runelite.api.ItemID.*;
public enum Graceful
{
// TODO: It would be nice if we have the IDs for just the equipped variants of the Graceful set items.
HOOD(
GRACEFUL_HOOD_11851, GRACEFUL_HOOD_13579, GRACEFUL_HOOD_13580, GRACEFUL_HOOD_13591, GRACEFUL_HOOD_13592,
GRACEFUL_HOOD_13603, GRACEFUL_HOOD_13604, GRACEFUL_HOOD_13615, GRACEFUL_HOOD_13616, GRACEFUL_HOOD_13627,
GRACEFUL_HOOD_13628, GRACEFUL_HOOD_13667, GRACEFUL_HOOD_13668, GRACEFUL_HOOD_21061, GRACEFUL_HOOD_21063
),
TOP(
GRACEFUL_TOP_11855, GRACEFUL_TOP_13583, GRACEFUL_TOP_13584, GRACEFUL_TOP_13595, GRACEFUL_TOP_13596,
GRACEFUL_TOP_13607, GRACEFUL_TOP_13608, GRACEFUL_TOP_13619, GRACEFUL_TOP_13620, GRACEFUL_TOP_13631,
GRACEFUL_TOP_13632, GRACEFUL_TOP_13671, GRACEFUL_TOP_13672, GRACEFUL_TOP_21067, GRACEFUL_TOP_21069
),
LEGS(
GRACEFUL_LEGS_11857, GRACEFUL_LEGS_13585, GRACEFUL_LEGS_13586, GRACEFUL_LEGS_13597, GRACEFUL_LEGS_13598,
GRACEFUL_LEGS_13609, GRACEFUL_LEGS_13610, GRACEFUL_LEGS_13621, GRACEFUL_LEGS_13622, GRACEFUL_LEGS_13633,
GRACEFUL_LEGS_13634, GRACEFUL_LEGS_13673, GRACEFUL_LEGS_13674, GRACEFUL_LEGS_21070, GRACEFUL_LEGS_21072
),
GLOVES(
GRACEFUL_GLOVES_11859, GRACEFUL_GLOVES_13587, GRACEFUL_GLOVES_13588, GRACEFUL_GLOVES_13599, GRACEFUL_GLOVES_13600,
GRACEFUL_GLOVES_13611, GRACEFUL_GLOVES_13612, GRACEFUL_GLOVES_13623, GRACEFUL_GLOVES_13624, GRACEFUL_GLOVES_13635,
GRACEFUL_GLOVES_13636, GRACEFUL_GLOVES_13675, GRACEFUL_GLOVES_13676, GRACEFUL_GLOVES_21073, GRACEFUL_GLOVES_21075
),
BOOTS(
GRACEFUL_BOOTS_11861, GRACEFUL_BOOTS_13589, GRACEFUL_BOOTS_13590, GRACEFUL_BOOTS_13601, GRACEFUL_BOOTS_13602,
GRACEFUL_BOOTS_13613, GRACEFUL_BOOTS_13614, GRACEFUL_BOOTS_13625, GRACEFUL_BOOTS_13626, GRACEFUL_BOOTS_13637,
GRACEFUL_BOOTS_13638, GRACEFUL_BOOTS_13677, GRACEFUL_BOOTS_13678, GRACEFUL_BOOTS_21076, GRACEFUL_BOOTS_21078
),
// Agility skill capes and the non-cosmetic Max capes also count for the Graceful set effect
CAPE(
GRACEFUL_CAPE_11853, GRACEFUL_CAPE_13581, GRACEFUL_CAPE_13582, GRACEFUL_CAPE_13593, GRACEFUL_CAPE_13594,
GRACEFUL_CAPE_13605, GRACEFUL_CAPE_13606, GRACEFUL_CAPE_13617, GRACEFUL_CAPE_13618, GRACEFUL_CAPE_13629,
GRACEFUL_CAPE_13630, GRACEFUL_CAPE_13669, GRACEFUL_CAPE_13670, GRACEFUL_CAPE_21064, GRACEFUL_CAPE_21066,
AGILITY_CAPE, AGILITY_CAPET, MAX_CAPE
);
private final ImmutableSet<Integer> ids;
Graceful(Integer... ids)
{
this.ids = ImmutableSet.copyOf(ids);
}
public static boolean hasFullSet(final ItemContainer equipment)
{
if (equipment == null)
{
return false;
}
final Item[] items = equipment.getItems();
if (equipment == null || items.length <= EquipmentInventorySlot.BOOTS.getSlotIdx())
{
return false;
}
return HOOD.ids.contains(items[EquipmentInventorySlot.HEAD.getSlotIdx()].getId())
&& TOP.ids.contains(items[EquipmentInventorySlot.BODY.getSlotIdx()].getId())
&& LEGS.ids.contains(items[EquipmentInventorySlot.LEGS.getSlotIdx()].getId())
&& GLOVES.ids.contains(items[EquipmentInventorySlot.GLOVES.getSlotIdx()].getId())
&& BOOTS.ids.contains(items[EquipmentInventorySlot.BOOTS.getSlotIdx()].getId())
&& CAPE.ids.contains(items[EquipmentInventorySlot.CAPE.getSlotIdx()].getId());
}
}

View File

@@ -30,7 +30,7 @@ import com.sun.jna.platform.win32.WinDef;
import java.util.Arrays;
import java.util.List;
class IcmpEchoReply extends Structure
public class IcmpEchoReply extends Structure
{
private static final int IP_OPTION_INFO_SIZE = 1 + 1 + 1 + 1 + (Pointer.SIZE == 8 ? 12 : 4); // on 64bit vms add 4 byte padding
public static final int SIZE = 4 + 4 + 4 + 2 + 2 + Pointer.SIZE + IP_OPTION_INFO_SIZE;

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@@ -0,0 +1,616 @@
/*
* Copyright (c) 2019, TheStonedTurtle <https://github.com/TheStonedTurtle>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.itemskeptondeath;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.testing.fieldbinder.Bind;
import com.google.inject.testing.fieldbinder.BoundFieldModule;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import net.runelite.api.Client;
import net.runelite.api.Item;
import net.runelite.api.ItemDefinition;
import net.runelite.api.ItemID;
import net.runelite.client.game.ItemManager;
import static net.runelite.client.plugins.itemskeptondeath.ItemsKeptOnDeathPlugin.DeathItems;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.mockito.runners.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class ItemsKeptOnDeathPluginTest
{
@Mock
@Bind
private Client client;
@Mock
@Bind
private ItemManager itemManager;
@Inject
private ItemsKeptOnDeathPlugin plugin;
@Before
public void before()
{
Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this);
resetBuffs();
}
private void resetBuffs()
{
plugin.isSkulled = false;
plugin.protectingItem = false;
plugin.wildyLevel = -1;
}
// Mocks an item and the necessary itemManager functions for it
private Item mItem(final int id, final int qty, final String name, final boolean tradeable, final int price)
{
// Mock Item Composition and necessary ItemManager methods for this item
ItemDefinition c = mock(ItemDefinition.class);
when(c.getId())
.thenReturn(id);
when(c.getName())
.thenReturn(name);
when(c.isTradeable())
.thenReturn(tradeable);
when(c.getPrice())
.thenReturn(price);
if (!tradeable)
{
when(c.getNote()).thenReturn(-1);
when(c.getLinkedNoteId()).thenReturn(-1);
}
when(itemManager.getItemDefinition(id)).thenReturn(c);
when(itemManager.canonicalize(id)).thenReturn(id);
when(itemManager.getItemPrice(id, true)).thenReturn(price);
return mockItem(id, qty);
}
// Creates a mocked item
private Item mockItem(final int id, final int qty)
{
Item item = mock(Item.class);
when(item.getId()).thenReturn(id);
when(item.getQuantity()).thenReturn(qty);
return item;
}
@Test
public void deathPriceTestRegularItems()
{
final Item acs = mItem(ItemID.ARMADYL_CHAINSKIRT, 1, "Armadyl chainskirt", true, 27837495);
assertEquals(27837495, plugin.getDeathPrice(acs));
final Item karambwan = mItem(ItemID.COOKED_KARAMBWAN, 1, "Cooked karambwan", true, 608);
assertEquals(608, plugin.getDeathPrice(karambwan));
final Item defender = mItem(ItemID.RUNE_DEFENDER, 1, "Rune defender", false, 35000);
assertEquals(35000, plugin.getDeathPrice(defender));
}
@Test
public void deathPriceTestItemMapping()
{
mItem(ItemID.OCCULT_NECKLACE, 1, "Occult necklace", true, 1000000);
mItem(ItemID.OCCULT_ORNAMENT_KIT, 1, "Occult ornament kit", true, 3000000);
final Item occult = mItem(ItemID.OCCULT_NECKLACE_OR, 1, "Occult necklace (or)", false, 0);
assertEquals(4000000, plugin.getDeathPrice(occult));
mItem(ItemID.BLACK_MASK, 1, "Black mask", true, 1000000);
final Item blackMask8 = mItem(ItemID.BLACK_MASK_8, 1, "Black mask (8)", false, 0);
assertEquals(1000000, plugin.getDeathPrice(blackMask8));
final Item slayerHelm = mItem(ItemID.SLAYER_HELMET, 1, "Slayer helmet", false, 0);
assertEquals(1000000, plugin.getDeathPrice(slayerHelm));
}
@Test
public void deathPriceTestFixedPriceItems()
{
mItem(ItemID.KARILS_COIF_0, 1, "Karil's coif 0", true, 35000);
final Item coif = mItem(ItemID.KARILS_COIF_100, 1, "Karil's coif 100", false, 0);
final int coifOffset = FixedPriceItem.KARILS_COIF_100.getOffset();
assertEquals(35000 + coifOffset, plugin.getDeathPrice(coif));
mItem(ItemID.AHRIMS_ROBETOP_0, 1, "Ahrim's robetop 0", true, 2500000);
final Item robetop = mItem(ItemID.AHRIMS_ROBETOP_25, 1, "Ahrim's robetop 100", false, 0);
final int robetopOffset = FixedPriceItem.AHRIMS_ROBETOP_25.getOffset();
assertEquals(2500000 + robetopOffset, plugin.getDeathPrice(robetop));
mItem(ItemID.AMULET_OF_GLORY, 1, "Amulet of glory", true, 13000);
final Item glory = mItem(ItemID.AMULET_OF_GLORY3, 1, "Amulet of glory(3)", true, 0);
final int gloryOffset = FixedPriceItem.AMULET_OF_GLORY3.getOffset();
assertEquals(13000 + gloryOffset, plugin.getDeathPrice(glory));
mItem(ItemID.COMBAT_BRACELET, 1, "Combat bracelet", true, 13500);
final Item brace = mItem(ItemID.COMBAT_BRACELET1, 1, "Combat bracelet(1)", true, 0);
final int braceletOffset = FixedPriceItem.COMBAT_BRACELET1.getOffset();
assertEquals(13500 + braceletOffset, plugin.getDeathPrice(brace));
}
@Test
public void deathPriceTestDynamicPriceItems()
{
final Item rod8 = mItem(ItemID.RING_OF_DUELING8, 1, "Ring of dueling(8)", true, 725);
final Item rod3 = mItem(ItemID.RING_OF_DUELING3, 1, "Ring of dueling(3)", true, 0);
final Item rod1 = mItem(ItemID.RING_OF_DUELING1, 1, "Ring of dueling(1)", true, 0);
// Dynamic price items
final int rodPrice = 725 / 8;
assertEquals(rodPrice, plugin.getDeathPrice(rod1));
assertEquals(725, plugin.getDeathPrice(rod8));
assertEquals(rodPrice * 3, plugin.getDeathPrice(rod3));
final Item nop5 = mItem(ItemID.NECKLACE_OF_PASSAGE5, 1, "Necklace of passage(5)", true, 1250);
final Item nop4 = mItem(ItemID.NECKLACE_OF_PASSAGE4, 1, "Necklace of passage(4)", true, 0);
final Item nop2 = mItem(ItemID.NECKLACE_OF_PASSAGE2, 1, "Necklace of passage(2)", true, 0);
final int nopPrice = 1250 / 5;
assertEquals(nopPrice * 2, plugin.getDeathPrice(nop2));
assertEquals(nopPrice * 4, plugin.getDeathPrice(nop4));
assertEquals(1250, plugin.getDeathPrice(nop5));
}
private Item[] getFourExpensiveItems()
{
return new Item[]
{
mItem(ItemID.TWISTED_BOW, 1, "Twister bow", true, Integer.MAX_VALUE),
mItem(ItemID.SCYTHE_OF_VITUR, 1, "Scythe of vitur", true, Integer.MAX_VALUE),
mItem(ItemID.ELYSIAN_SPIRIT_SHIELD, 1, "Elysian spirit shield", true, 800000000),
mItem(ItemID.ARCANE_SPIRIT_SHIELD, 1, "Arcane spirit shield", true, 250000000)
};
}
@Test
public void alwaysLostTestRunePouch()
{
final Item[] inv = getFourExpensiveItems();
final Item[] equip = new Item[]
{
mItem(ItemID.RUNE_POUCH, 1, "Rune pouch", false, 1)
};
final DeathItems deathItems = plugin.calculateKeptLostItems(inv, equip);
assertFalse(deathItems.isHasAlwaysLost());
}
@Test
public void alwaysLostTestRunePouchWildy()
{
final Item[] inv = getFourExpensiveItems();
final Item[] equip = new Item[]
{
mItem(ItemID.RUNE_POUCH, 1, "Rune pouch", false, 1)
};
plugin.wildyLevel = 1;
final DeathItems deathItems = plugin.calculateKeptLostItems(inv, equip);
assertTrue(deathItems.isHasAlwaysLost());
}
@Test
public void alwaysLostTestLootBag()
{
final Item[] inv = getFourExpensiveItems();
final Item[] equip = new Item[]
{
mItem(ItemID.LOOTING_BAG, 1, "Looting bag", false, 1)
};
final DeathItems deathItems = plugin.calculateKeptLostItems(inv, equip);
assertTrue(deathItems.isHasAlwaysLost());
}
@Test
public void alwaysLostTestLootBagWildy()
{
final Item[] inv = getFourExpensiveItems();
final Item[] equip = new Item[]
{
mItem(ItemID.LOOTING_BAG, 1, "Looting bag", false, 1)
};
plugin.wildyLevel = 1;
final DeathItems deathItems = plugin.calculateKeptLostItems(inv, equip);
assertTrue(deathItems.isHasAlwaysLost());
}
private Item[] getClueBoxTestInventory()
{
return new Item[]
{
mItem(ItemID.BLACK_DHIDE_BODY, 1, "Black d'hide body", true, 7552),
mItem(ItemID.ARMADYL_CHAINSKIRT, 1, "Armadyl chainskirt", true, 27837495),
mItem(ItemID.PEGASIAN_BOOTS, 1, "Pegasian boots", true, 30542187),
mItem(ItemID.DRAGON_SCIMITAR, 1, "Dragon scimitar", true, 63123),
mItem(ItemID.HELM_OF_NEITIZNOT, 1, "Helm of neitiznot", true, 45519),
mItem(ItemID.RUNE_DEFENDER, 1, "Rune defender", false, 35000),
mItem(ItemID.SPADE, 1, "Spade", true, 104),
mItem(ItemID.CLUE_SCROLL_EASY, 1, "Clue scroll (easy)", false, 50),
mItem(ItemID.CLUE_BOX, 1, "Clue box", false, 50),
mItem(ItemID.COOKED_KARAMBWAN, 1, "Cooked karambwan", true, 608),
mItem(ItemID.COOKED_KARAMBWAN, 1, "Cooked karambwan", true, 608),
mItem(ItemID.COOKED_KARAMBWAN, 1, "Cooked karambwan", true, 608),
mItem(ItemID.COOKED_KARAMBWAN, 1, "Cooked karambwan", true, 608),
mItem(ItemID.COOKED_KARAMBWAN, 1, "Cooked karambwan", true, 608),
mItem(ItemID.LAW_RUNE, 200, "Law rune", true, 212),
mItem(ItemID.DUST_RUNE, 200, "Dust rune", true, 3),
mItem(ItemID.CLUE_SCROLL_MASTER, 1, "Clue scroll (master)", false, 50),
mItem(ItemID.CLUELESS_SCROLL, 1, "Clueless scroll", false, 50),
};
}
@Test
public void isClueBoxableTest()
{
getClueBoxTestInventory();
mItem(ItemID.REWARD_CASKET_EASY, 1, "Reward casket (easy)", false, 50);
assertTrue(plugin.isClueBoxable(ItemID.CLUE_SCROLL_EASY));
assertTrue(plugin.isClueBoxable(ItemID.CLUE_SCROLL_MASTER));
assertTrue(plugin.isClueBoxable(ItemID.REWARD_CASKET_EASY));
assertFalse(plugin.isClueBoxable(ItemID.CLUELESS_SCROLL));
assertFalse(plugin.isClueBoxable(ItemID.LAW_RUNE));
assertFalse(plugin.isClueBoxable(ItemID.SPADE));
}
@Test
public void clueBoxTestDefault()
{
final Item[] inv = getClueBoxTestInventory();
final Item[] equip = new Item[0];
final DeathItems deathItems = plugin.calculateKeptLostItems(inv, equip);
final List<ItemStack> kept = deathItems.getKeptItems();
final List<ItemStack> expectedKept = Arrays.asList(
new ItemStack(ItemID.PEGASIAN_BOOTS, 1),
new ItemStack(ItemID.ARMADYL_CHAINSKIRT, 1),
new ItemStack(ItemID.DRAGON_SCIMITAR, 1),
new ItemStack(ItemID.RUNE_DEFENDER, 1),
new ItemStack(ItemID.CLUE_SCROLL_EASY, 1),
new ItemStack(ItemID.CLUE_SCROLL_MASTER, 1),
new ItemStack(ItemID.CLUELESS_SCROLL, 1)
);
assertEquals(expectedKept, kept);
final List<ItemStack> lost = deathItems.getLostItems();
assertEquals((inv.length + equip.length) - expectedKept.size(), lost.size());
}
@Test
public void clueBoxTestDeepWildy()
{
final Item[] inv = getClueBoxTestInventory();
final Item[] equip = new Item[0];
plugin.wildyLevel = 21;
final DeathItems deathItems = plugin.calculateKeptLostItems(inv, equip);
final List<ItemStack> kept = deathItems.getKeptItems();
final List<ItemStack> expectedKept = Arrays.asList(
new ItemStack(ItemID.PEGASIAN_BOOTS, 1),
new ItemStack(ItemID.ARMADYL_CHAINSKIRT, 1),
new ItemStack(ItemID.DRAGON_SCIMITAR, 1),
new ItemStack(ItemID.CLUE_SCROLL_MASTER, 1)
);
assertEquals(expectedKept, kept);
final List<ItemStack> lost = deathItems.getLostItems();
final int keptOffset = expectedKept.size();
assertEquals((inv.length + equip.length) - keptOffset, lost.size());
}
@Test
public void clueBoxTestDeepWildyProtectItem()
{
final Item[] inv = getClueBoxTestInventory();
final Item[] equip = new Item[0];
plugin.wildyLevel = 21;
plugin.protectingItem = true;
final DeathItems deathItems = plugin.calculateKeptLostItems(inv, equip);
final List<ItemStack> kept = deathItems.getKeptItems();
final List<ItemStack> expectedKept = Arrays.asList(
new ItemStack(ItemID.PEGASIAN_BOOTS, 1),
new ItemStack(ItemID.ARMADYL_CHAINSKIRT, 1),
new ItemStack(ItemID.DRAGON_SCIMITAR, 1),
new ItemStack(ItemID.HELM_OF_NEITIZNOT, 1),
new ItemStack(ItemID.CLUE_SCROLL_MASTER, 1) // Clue box
);
assertEquals(expectedKept, kept);
final List<ItemStack> lost = deathItems.getLostItems();
final int keptOffset = expectedKept.size();
assertEquals((inv.length + equip.length) - keptOffset, lost.size());
}
@Test
public void clueBoxTestDeepWildySkulled()
{
final Item[] inv = getClueBoxTestInventory();
final Item[] equip = new Item[0];
plugin.wildyLevel = 21;
plugin.isSkulled = true;
final DeathItems deathItems = plugin.calculateKeptLostItems(inv, equip);
final List<ItemStack> kept = deathItems.getKeptItems();
final List<ItemStack> expectedKept = Collections.singletonList(
new ItemStack(ItemID.CLUE_SCROLL_MASTER, 1)
);
assertEquals(expectedKept, kept);
final List<ItemStack> lost = deathItems.getLostItems();
final int keptOffset = expectedKept.size();
assertEquals(lost.size(), (inv.length + equip.length) - keptOffset);
}
@Test
public void clueBoxTestLowWildy()
{
final Item[] inv = getClueBoxTestInventory();
final Item[] equip = new Item[0];
plugin.wildyLevel = 1;
final DeathItems deathItems = plugin.calculateKeptLostItems(inv, equip);
final List<ItemStack> kept = deathItems.getKeptItems();
final List<ItemStack> expectedKept = Arrays.asList(
new ItemStack(ItemID.PEGASIAN_BOOTS, 1),
new ItemStack(ItemID.ARMADYL_CHAINSKIRT, 1),
new ItemStack(ItemID.DRAGON_SCIMITAR, 1),
new ItemStack(ItemID.RUNE_DEFENDER, 1), // Rune defender protected because of broken variant
new ItemStack(ItemID.CLUE_SCROLL_MASTER, 1)
);
assertEquals(expectedKept, kept);
final List<ItemStack> lost = deathItems.getLostItems();
final int keptOffset = expectedKept.size();
assertEquals(lost.size(), (inv.length + equip.length) - keptOffset);
}
@Test
public void clueBoxTestLowWildyProtectItem()
{
final Item[] inv = getClueBoxTestInventory();
final Item[] equip = new Item[0];
plugin.wildyLevel = 1;
plugin.protectingItem = true;
final DeathItems deathItems = plugin.calculateKeptLostItems(inv, equip);
final List<ItemStack> kept = deathItems.getKeptItems();
final List<ItemStack> expectedKept = Arrays.asList(
new ItemStack(ItemID.PEGASIAN_BOOTS, 1),
new ItemStack(ItemID.ARMADYL_CHAINSKIRT, 1),
new ItemStack(ItemID.DRAGON_SCIMITAR, 1),
new ItemStack(ItemID.HELM_OF_NEITIZNOT, 1),
new ItemStack(ItemID.RUNE_DEFENDER, 1), // Rune defender protected because of broken variant
new ItemStack(ItemID.CLUE_SCROLL_MASTER, 1)
);
assertEquals(expectedKept, kept);
final List<ItemStack> lost = deathItems.getLostItems();
final int keptOffset = expectedKept.size();
assertEquals((inv.length + equip.length) - keptOffset, lost.size());
}
@Test
public void clueBoxTestLowWildySkulled()
{
final Item[] inv = getClueBoxTestInventory();
final Item[] equip = new Item[0];
plugin.wildyLevel = 1;
plugin.isSkulled = true;
final DeathItems deathItems = plugin.calculateKeptLostItems(inv, equip);
final List<ItemStack> kept = deathItems.getKeptItems();
final List<ItemStack> expectedKept = Arrays.asList(
new ItemStack(ItemID.RUNE_DEFENDER, 1), // Rune defender protected because of broken variant
new ItemStack(ItemID.CLUE_SCROLL_MASTER, 1)
);
assertEquals(expectedKept, kept);
final List<ItemStack> lost = deathItems.getLostItems();
final int keptOffset = expectedKept.size();
assertEquals((inv.length + equip.length) - keptOffset, lost.size());
}
private Item[] getClueBoxCasketTestInventory()
{
// Reward caskets can stack but the clue box should only protect one
return new Item[]
{
mItem(ItemID.BLACK_DHIDE_BODY, 1, "Black d'hide body", true, 7552),
mItem(ItemID.ARMADYL_CHAINSKIRT, 1, "Armadyl chainskirt", true, 27837495),
mItem(ItemID.PEGASIAN_BOOTS, 1, "Pegasian boots", true, 30542187),
mItem(ItemID.DRAGON_SCIMITAR, 1, "Dragon scimitar", true, 63123),
mItem(ItemID.SPADE, 1, "Spade", true, 104),
mItem(ItemID.CLUE_SCROLL_EASY, 1, "Clue scroll (easy)", false, 50),
mItem(ItemID.REWARD_CASKET_EASY, 20, "Reward casket (easy)", false, 50),
mItem(ItemID.CLUE_BOX, 1, "Clue box", false, 50),
mItem(ItemID.COOKED_KARAMBWAN, 1, "Cooked karambwan", true, 608),
mItem(ItemID.COOKED_KARAMBWAN, 1, "Cooked karambwan", true, 608),
mItem(ItemID.COOKED_KARAMBWAN, 1, "Cooked karambwan", true, 608),
mItem(ItemID.COOKED_KARAMBWAN, 1, "Cooked karambwan", true, 608),
mItem(ItemID.LAW_RUNE, 200, "Law rune", true, 212),
mItem(ItemID.DUST_RUNE, 200, "Dust rune", true, 3),
};
}
@Test
public void clueBoxTestCasketProtect()
{
final Item[] inv = getClueBoxCasketTestInventory();
final Item[] equip = new Item[0];
plugin.wildyLevel = 1;
final DeathItems deathItems = plugin.calculateKeptLostItems(inv, equip);
final List<ItemStack> kept = deathItems.getKeptItems();
final List<ItemStack> expectedKept = Arrays.asList(
new ItemStack(ItemID.PEGASIAN_BOOTS, 1),
new ItemStack(ItemID.ARMADYL_CHAINSKIRT, 1),
new ItemStack(ItemID.DRAGON_SCIMITAR, 1),
new ItemStack(ItemID.REWARD_CASKET_EASY, 1) // Clue box
);
assertEquals(expectedKept, kept);
final List<ItemStack> lost = deathItems.getLostItems();
final int keptOffset = expectedKept.size() - 1; // We are still losing some reward caskets.
assertEquals((inv.length + equip.length) - keptOffset, lost.size());
}
private Item[] getFullGracefulItems()
{
return new Item[]
{
mItem(ItemID.GRACEFUL_HOOD, 1, "Graceful hood", false, 35),
mItem(ItemID.GRACEFUL_CAPE, 1, "Graceful cape", false, 40),
mItem(ItemID.GRACEFUL_TOP, 1, "Graceful top", false, 55),
mItem(ItemID.GRACEFUL_LEGS, 1, "Graceful legs", false, 60),
mItem(ItemID.GRACEFUL_BOOTS, 1, "Graceful boots", false, 40),
mItem(ItemID.GRACEFUL_GLOVES, 1, "Graceful gloves", false, 30),
};
}
@Test
public void gracefulValueTest()
{
final Item[] inv = getFullGracefulItems();
final Item[] equip = new Item[]
{
mItem(ItemID.AMULET_OF_GLORY6, 1, "Amulet of glory (6)", true, 20000)
};
final DeathItems deathItems = plugin.calculateKeptLostItems(inv, equip);
final List<ItemStack> kept = deathItems.getKeptItems();
final List<ItemStack> expectedKept = Arrays.asList(
new ItemStack(ItemID.AMULET_OF_GLORY6, 1),
new ItemStack(ItemID.GRACEFUL_CAPE, 1),
new ItemStack(ItemID.GRACEFUL_TOP, 1),
new ItemStack(ItemID.GRACEFUL_LEGS, 1),
new ItemStack(ItemID.GRACEFUL_BOOTS, 1),
new ItemStack(ItemID.GRACEFUL_HOOD, 1),
new ItemStack(ItemID.GRACEFUL_GLOVES, 1)
);
assertEquals(expectedKept, kept);
final List<ItemStack> lost = deathItems.getLostItems();
assertEquals((inv.length + equip.length) - expectedKept.size(), lost.size());
}
@Test
public void gracefulValueTestWildy()
{
final Item[] inv = getFullGracefulItems();
final Item[] equip = new Item[]
{
mItem(ItemID.AMULET_OF_GLORY6, 1, "Amulet of glory (6)", true, 20000)
};
plugin.wildyLevel = 1;
final DeathItems deathItems = plugin.calculateKeptLostItems(inv, equip);
final List<ItemStack> kept = deathItems.getKeptItems();
final List<ItemStack> expectedKept = Arrays.asList(
new ItemStack(ItemID.AMULET_OF_GLORY6, 1),
new ItemStack(ItemID.GRACEFUL_CAPE, 1),
new ItemStack(ItemID.GRACEFUL_TOP, 1)
);
assertEquals(expectedKept, kept);
final List<ItemStack> lost = deathItems.getLostItems();
assertEquals((inv.length + equip.length) - expectedKept.size(), lost.size());
}
@Test
public void lostIfNotProtectedTestLost()
{
final Item[] inv = getFourExpensiveItems();
final Item[] equip = new Item[]
{
mItem(ItemID.SHADOW_SWORD, 1, "Shadow sword", false, 1)
};
final DeathItems deathItems = plugin.calculateKeptLostItems(inv, equip);
final List<ItemStack> lost = deathItems.getLostItems();
assertTrue(lost.contains(new ItemStack(ItemID.SHADOW_SWORD, 1)));
}
@Test
public void lostIfNotProtectedTestKept()
{
final Item[] inv = new Item[]
{
mItem(ItemID.SHADOW_SWORD, 1, "Shadow sword", false, 1)
};
final Item[] equip = new Item[0];
final DeathItems deathItems = plugin.calculateKeptLostItems(inv, equip);
final List<ItemStack> kept = deathItems.getKeptItems();
assertTrue(kept.contains(new ItemStack(ItemID.SHADOW_SWORD, 1)));
}
}

View File

@@ -162,7 +162,7 @@ public class MotherlodePluginTest
when(client.getItemContainer(InventoryID.INVENTORY)).thenReturn(inventory);
// Trigger comparison
motherlodePlugin.onItemContainerChanged(new ItemContainerChanged(inventory));
motherlodePlugin.onItemContainerChanged(new ItemContainerChanged(InventoryID.INVENTORY.getId(), inventory));
verify(motherlodeSession).updateOreFound(ItemID.RUNITE_ORE, 1);
verify(motherlodeSession).updateOreFound(ItemID.GOLDEN_NUGGET, 4);