Banked experience & skill calculator changes (#80)

* Add Activity data structures

* Implement Banked Xp Tab in UI

* Remove Banked Xp functionality from SkillCalculator

* Fix MaterialTabGroup removeAll

* Implement BankedCalculator into SkillCalculatorPlugin

* Add Banked Experience Functionality & Example UI

* Rename ItemPanel to CriticalItemPanel

* Minor porting bug fixes

* Add Xp bonuses to BankedXp

* Minor bug fixes

* Fix limit to secondaries toggle

* Remove spam

* SkillCalc optimization

No longer able to select multiple checkboxes (if there are multiple)
Made xp bonus' naming more consistant (changed some .json files)
Made UICombinedActionSlot text more accurate (double as xp and correct amount of actions)

* Clear search bar when switching between skill calculators

* Update skill calculator fields automatically

* Remove some spammy log lines

* Use ImmutablePair
This commit is contained in:
sdburns1998
2019-04-24 02:36:13 +02:00
committed by Kyleeld
parent bb088dd57f
commit 90e5025acd
13 changed files with 2531 additions and 61 deletions

View File

@@ -0,0 +1,666 @@
/*
* 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.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
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 JLabel totalLabel = new JLabel();
private JPanel detailConfigContainer;
private JPanel detailContainer;
// Banked Experience magic
private Map<Integer, Integer> bankMap = new HashMap<>();
private Map<String, Boolean> categoryMap = new HashMap<>(); // Check if CriticalItem Category is enabled
private Map<CriticalItem, CriticalItemPanel> panelMap = new HashMap<>();
private Map<CriticalItem, Integer> criticalMap = new HashMap<>(); // Quantity of CriticalItem inside bankMap
private Map<CriticalItem, Activity> activityMap = new HashMap<>(); // Selected Activity used for calculating xp
private Map<CriticalItem, Integer> linkedMap = new HashMap<>(); // ItemID of item that links to the CriticalItem
BankedCalculator(
SkillCalculatorPanel parent,
Client client,
UICalculatorInputArea uiInput,
SkillCalculatorConfig config,
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
ArrayList<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)
{
if (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))
{
ArrayList<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 == 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)
{
if (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
if (!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(() -> 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

@@ -1,5 +1,6 @@
/*
* 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
@@ -30,26 +31,40 @@ import net.runelite.api.Skill;
@AllArgsConstructor
@Getter
enum CalculatorType
public enum CalculatorType
{
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");
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);
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,13 +34,17 @@ import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
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;
@@ -51,6 +55,8 @@ import net.runelite.client.ui.DynamicGridLayout;
import net.runelite.client.ui.FontManager;
import net.runelite.client.ui.PluginPanel;
import net.runelite.client.ui.components.IconTextField;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
class SkillCalculator extends JPanel
{
@@ -63,7 +69,9 @@ 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 ArrayList<UIActionSlot> combinedActionSlots = new ArrayList<>();
private final List<JCheckBox> bonusCheckBoxes = new ArrayList<>();
private final IconTextField searchBar = new IconTextField();
@@ -74,6 +82,8 @@ class SkillCalculator extends JPanel
private int targetLevel = currentLevel + 1;
private int targetXP = Experience.getXpForLevel(targetLevel);
private float xpFactor = 1.0f;
private float lastBonus = 0.0f;
private CalculatorType calculatorType;
SkillCalculator(Client client, UICalculatorInputArea uiInput, SpriteManager spriteManager, ItemManager itemManager)
{
@@ -111,6 +121,8 @@ class SkillCalculator extends JPanel
void openCalculator(CalculatorType calculatorType)
{
this.calculatorType = calculatorType;
// Load the skill data.
skillData = cacheSkillData.getSkillData(calculatorType.getDataFile());
@@ -118,10 +130,11 @@ class SkillCalculator extends JPanel
xpFactor = 1.0f;
// Update internal skill/XP values.
currentXP = client.getSkillExperience(calculatorType.getSkill());
currentLevel = Experience.getLevelForXp(currentXP);
targetLevel = enforceSkillBounds(currentLevel + 1);
targetXP = Experience.getXpForLevel(targetLevel);
updateInternalValues();
// BankedCalculator prevents these from being editable so just ensure they are editable.
uiInput.getUiFieldTargetLevel().setEditable(true);
uiInput.getUiFieldTargetXP().setEditable(true);
// Remove all components (action slots) from this panel.
removeAll();
@@ -129,6 +142,9 @@ 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();
@@ -145,6 +161,23 @@ 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();
@@ -195,17 +228,23 @@ class SkillCalculator extends JPanel
{
if (skillData.getBonuses() != null)
{
List<JCheckBox> uiCheckBoxList = new ArrayList<>();
lastBonus = 0.0f;
for (SkillDataBonus bonus : skillData.getBonuses())
{
JPanel checkboxPanel = buildCheckboxPanel(bonus);
Pair<JPanel, List<JCheckBox>> combinedCheckboxPanel = buildCheckboxPanel(bonus, uiCheckBoxList);
JPanel checkboxPanel = combinedCheckboxPanel.getKey();
uiCheckBoxList = combinedCheckboxPanel.getValue();
add(checkboxPanel);
add(Box.createRigidArea(new Dimension(0, 5)));
}
add(Box.createRigidArea(new Dimension(0, 5)));
}
}
private JPanel buildCheckboxPanel(SkillDataBonus bonus)
private Pair<JPanel, List<JCheckBox>> buildCheckboxPanel(SkillDataBonus bonus, List<JCheckBox> uiCheckBoxList)
{
JPanel uiOption = new JPanel(new BorderLayout());
JLabel uiLabel = new JLabel(bonus.getName());
@@ -217,33 +256,41 @@ class SkillCalculator extends JPanel
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 ->
JCheckBox uiCheckBox = new JCheckBox();
uiCheckBox.setBackground(ColorScheme.MEDIUM_GRAY_COLOR);
uiCheckBox.addActionListener(e ->
{
if (otherSelectedCheckbox != target)
if (uiCheckBox.isSelected())
{
otherSelectedCheckbox.setSelected(false);
adjustXPBonus(uiCheckBox.isSelected(), bonus.getValue());
lastBonus = bonus.getValue();
for (JCheckBox checkBox : uiCheckBoxList)
{
if (checkBox != uiCheckBox)
{
checkBox.setSelected(false);
}
}
}
else if (xpFactor > 1.0)
{
xpFactor = 1.0f;
lastBonus = 0.0f;
calculate();
}
updateCombinedAction();
});
if (target.isSelected())
{
adjustXPBonus(bonus.getValue());
}
uiCheckBoxList.add(uiCheckBox);
uiOption.add(uiCheckBox, BorderLayout.EAST);
uiOption.add(uiLabel, BorderLayout.WEST);
bonusCheckBoxes.add(uiCheckbox);
return new ImmutablePair<>(uiOption, uiCheckBoxList);
}
private void renderActionSlots()
@@ -342,9 +389,16 @@ class SkillCalculator extends JPanel
calculate();
}
private void adjustXPBonus(float value)
private void adjustXPBonus(boolean addBonus, float value)
{
xpFactor = 1f + value;
clearLastBonus();
xpFactor += addBonus ? value : -value;
calculate();
}
private void clearLastBonus()
{
xpFactor -= lastBonus;
calculate();
}
@@ -409,4 +463,25 @@ 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

@@ -0,0 +1,55 @@
/*
* 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 net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
@ConfigGroup("skillCalculator")
public interface SkillCalculatorConfig extends Config
{
@ConfigItem(
keyName = "showBankedXp",
name = "Show Banked xp Tab",
description = "Shows the Banked xp tab inside the Calculator Panel",
position = 0
)
default boolean showBankedXp()
{
return true;
}
@ConfigItem(
keyName = "limitedBankedSecondaries",
name = "Limit Banked xp to Secondaries",
description = "Limits the Banked xp shown based on secondaries banked as well",
position = 1
)
default boolean limitedBankedSecondaries()
{
return false;
}
}

View File

@@ -1,6 +1,7 @@
/*
* 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
@@ -29,10 +30,18 @@ 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.Map;
import java.util.Objects;
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;
@@ -41,30 +50,42 @@ import net.runelite.client.ui.PluginPanel;
import net.runelite.client.ui.components.materialtabs.MaterialTab;
import net.runelite.client.ui.components.materialtabs.MaterialTabGroup;
@Slf4j
class SkillCalculatorPanel extends PluginPanel
{
private final SkillCalculator uiCalculator;
private final SkillIconManager iconManager;
private final MaterialTabGroup tabGroup;
private final SkillCalculatorConfig config;
private final BankedCalculator bankedCalculator;
SkillCalculatorPanel(SkillIconManager iconManager, Client client, SpriteManager spriteManager, ItemManager itemManager)
private CalculatorType currentCalc;
private final MaterialTabGroup skillGroup;
private final MaterialTabGroup tabGroup;
private String currentTab;
private ArrayList<String> tabs = new ArrayList<>();
@Getter
private Map<Integer, Integer> bankMap = new HashMap<>();
private GridBagConstraints c;
SkillCalculatorPanel(SkillIconManager iconManager, Client client, SkillCalculatorConfig config, 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());
GridBagConstraints c = new GridBagConstraints();
c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 1;
c.gridx = 0;
c.gridy = 0;
tabGroup = new MaterialTabGroup();
tabGroup.setLayout(new GridLayout(0, 6, 7, 7));
skillGroup = new MaterialTabGroup();
skillGroup.setLayout(new GridLayout(0, 6, 7, 7));
addCalculatorButtons();
@@ -73,14 +94,23 @@ class SkillCalculatorPanel extends PluginPanel
uiInput.setBackground(ColorScheme.DARK_GRAY_COLOR);
uiCalculator = new SkillCalculator(client, uiInput, spriteManager, itemManager);
add(tabGroup, c);
bankedCalculator = new BankedCalculator(this, client, uiInput, config, itemManager);
tabGroup = new MaterialTabGroup();
tabGroup.setBorder(new EmptyBorder(0, 0, 10, 0));
addTabButtons();
add(skillGroup, c);
c.gridy++;
add(uiInput, c);
c.gridy++;
add(uiCalculator, c);
add(tabGroup, c);
c.gridy++;
add(uiCalculator, c);
}
private void addCalculatorButtons()
@@ -88,14 +118,126 @@ class SkillCalculatorPanel extends PluginPanel
for (CalculatorType calculatorType : CalculatorType.values())
{
ImageIcon icon = new ImageIcon(iconManager.getSkillImage(calculatorType.getSkill(), true));
MaterialTab tab = new MaterialTab(icon, tabGroup, null);
MaterialTab tab = new MaterialTab(icon, skillGroup, null);
tab.setOnSelectEvent(() ->
{
uiCalculator.openCalculator(calculatorType);
if (currentCalc == calculatorType)
{
return true;
}
currentCalc = calculatorType;
selectedTab(currentTab, true);
return true;
});
tabGroup.addTab(tab);
skillGroup.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,5 +1,6 @@
/*
* 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,14 +26,31 @@
package net.runelite.client.plugins.skillcalculator;
import com.google.inject.Provides;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;
import javax.inject.Inject;
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.client.callback.ClientThread;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.game.ItemManager;
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.ui.ClientToolbar;
import net.runelite.client.ui.NavigationButton;
import net.runelite.client.util.ImageUtil;
@@ -47,6 +65,9 @@ public class SkillCalculatorPlugin extends Plugin
@Inject
private Client client;
@Inject
private ClientThread clientThread;
@Inject
private SkillIconManager skillIconManager;
@@ -59,13 +80,28 @@ public class SkillCalculatorPlugin extends Plugin
@Inject
private ClientToolbar clientToolbar;
@Inject
private SkillCalculatorConfig skillCalculatorConfig;
private NavigationButton uiNavigationButton;
private SkillCalculatorPanel uiPanel;
@Getter
private Map<Integer, Integer> bankMap = new HashMap<>();
private int bankHash;
@Provides
SkillCalculatorConfig getConfig(ConfigManager configManager)
{
return configManager.getConfig(SkillCalculatorConfig.class);
}
@Override
protected void startUp() throws Exception
{
final BufferedImage icon = ImageUtil.getResourceStreamFromClass(getClass(), "calc.png");
final SkillCalculatorPanel uiPanel = new SkillCalculatorPanel(skillIconManager, client, spriteManager, itemManager);
this.uiPanel = new SkillCalculatorPanel(skillIconManager, client, skillCalculatorConfig, spriteManager, itemManager);
uiNavigationButton = NavigationButton.builder()
.tooltip("Skill Calculator")
@@ -75,11 +111,112 @@ public class SkillCalculatorPlugin extends Plugin
.build();
clientToolbar.addNavigation(uiNavigationButton);
clientThread.invokeLater(() ->
{
switch (client.getGameState())
{
case STARTING:
case UNKNOWN:
return false;
}
CriticalItem.prepareItemCompositions(itemManager);
return true;
});
}
@Override
protected void shutDown() throws Exception
{
clientToolbar.removeNavigation(uiNavigationButton);
bankMap.clear();
bankHash = -1;
}
@Subscribe
public void onConfigChanged(ConfigChanged event)
{
if (event.getGroup().equals("skillCalculator"))
{
if (event.getKey().equals("showBankedXp"))
{
bankMap.clear();
bankHash = -1;
}
SwingUtilities.invokeLater(() -> uiPanel.refreshPanel());
}
}
// Pulled from bankvalue plugin to check if bank is open
@Subscribe
public void onGameTick(GameTick 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"))
{
return;
}
updateBankItems();
}
// 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());
// Couldn't find any items in bank, do nothing.
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<>();
for (Item widgetItem : widgetItems)
{
mapCheck.put(widgetItem.getId(), widgetItem.getQuantity());
}
int curHash = mapCheck.hashCode();
if (curHash != bankHash)
{
bankHash = curHash;
return mapCheck;
}
return new HashMap<>();
}
@Subscribe
public void onExperienceChanged(ExperienceChanged changeEvent)
{
uiPanel.updateSkillCalculator(changeEvent.getSkill());
}
}

View File

@@ -0,0 +1,408 @@
/*
* 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 lombok.Getter;
import net.runelite.api.ItemComposition;
import net.runelite.api.ItemID;
import net.runelite.api.Skill;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
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 ItemComposition composition;
CriticalItem(int itemID, String category, Skill skill, int linkedItem)
{
this.itemID = itemID;
this.category = category;
this.skill = skill;
this.linkedItemId = linkedItem;
this.composition = 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, ArrayList<CriticalItem>> buildSkillItemMap()
{
Map<Skill, ArrayList<CriticalItem>> map = new HashMap<>();
for (CriticalItem item : values())
{
map.computeIfAbsent(item.getSkill(), e -> new ArrayList<>()).add(item);
}
return map;
}
private static final Map<Skill, ArrayList<CriticalItem>> bySkillName = buildSkillItemMap();
public static ArrayList<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, ArrayList<CriticalItem>> buildItemSkillCategoryMap()
{
Map<String, ArrayList<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, ArrayList<CriticalItem>> itemsBySkillCategory = buildItemSkillCategoryMap();
public static ArrayList<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 prepareItemCompositions(ItemManager m)
{
for (CriticalItem i : values())
{
i.composition = m.getItemComposition(i.getItemID());
}
}
@Override
public String toString()
{
return "CriticalItem=(name=" + this.name() + ",id=" + this.itemID + ",category=" + this.category + ")";
}
}

View File

@@ -0,0 +1,408 @@
/*
* 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;
import net.runelite.api.Skill;
import net.runelite.client.plugins.skillcalculator.banked.CriticalItem;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
@Getter
public enum Activity
{
/**
* Herblore Activities
*/
// 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),
ATTACK_POTION(ItemID.ATTACK_POTION4, "Attack Potion", Skill.HERBLORE, 3, 25, CriticalItem.GUAM_LEAF_POTION_UNF, ActivitySecondaries.ATTACK_POTION),
// 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),
ANTIPOISON(ItemID.ANTIPOISON4, "Antipoison", Skill.HERBLORE, 5, 37.5, CriticalItem.MARRENTILL_POTION_UNF, ActivitySecondaries.ANTIPOISON),
// 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),
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),
// 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),
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),
// 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),
// 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),
// 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),
// 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),
// Kwuarm
SUPER_STRENGTH(ItemID.SUPER_STRENGTH4, "Super strength", Skill.HERBLORE, 55, 125, CriticalItem.KWUARM_POTION_UNF, ActivitySecondaries.SUPER_STRENGTH),
// 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),
// Cadantine
SUPER_DEFENCE_POTION(ItemID.SUPER_DEFENCE4, "Super defence", Skill.HERBLORE, 66, 150, CriticalItem.CADANTINE_POTION_UNF, ActivitySecondaries.SUPER_DEFENCE_POTION),
// 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),
// Dwarf Weed
RANGING_POTION(ItemID.RANGING_POTION4, "Ranging potion", Skill.HERBLORE, 72, 162.5, CriticalItem.DWARF_WEED_POTION_UNF, ActivitySecondaries.RANGING_POTION),
// 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),
ZAMORAK_BREW(ItemID.ZAMORAK_BREW4, "Zamorak brew", Skill.HERBLORE, 78, 175, CriticalItem.TORSTOL_POTION_UNF, ActivitySecondaries.ZAMORAK_BREW),
// 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),
/**
* 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),
/**
* 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),
// 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),
// 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),
/*
* 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),
WINE(ItemID.JUG_OF_WINE, "Other", Skill.COOKING, 35, 200, CriticalItem.GRAPES, ActivitySecondaries.JUG_OF_WATER),
/*
* 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),
// 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),
// 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),
// 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),
// 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),
// 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),
// 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),
/*
* 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),
// 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),
/**
* 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),
;
private final int icon;
private final String name;
private final Skill skill;
private final int level;
private final double xp;
private final SecondaryItem[] secondaries;
private final CriticalItem criticalItem;
private final boolean preventLinked;
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;
}
Activity(int Icon, String name, Skill skill, int level, double xp, CriticalItem criticalItem, ActivitySecondaries secondaries)
{
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(int Icon, String name, Skill skill, int level, double xp, CriticalItem criticalItem, ActivitySecondaries secondaries, 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())
{
map.computeIfAbsent(item.getCriticalItem(), e -> new ArrayList<Activity>()).add(item);
}
return map;
}
private static final Map<CriticalItem, ArrayList<Activity>> byCriticalItem = buildItemMap();
public static ArrayList<Activity> getByCriticalItem(CriticalItem item)
{
return byCriticalItem.getOrDefault(item, new ArrayList<>());
}
/**
* 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
*/
public static ArrayList<Activity> getByCriticalItem(CriticalItem item, int limitLevel)
{
ArrayList<Activity> activities = getByCriticalItem(item);
ArrayList<Activity> l = new ArrayList<>();
if (limitLevel <= 0)
{
return l;
}
for (Activity a : activities)
{
if (!(a.getLevel() > limitLevel))
{
l.add(a);
}
}
return l;
}
}

View File

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

View File

@@ -0,0 +1,45 @@
/*
* 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;
@Getter
public class SecondaryItem
{
private final int id;
private final int qty;
public SecondaryItem(int id, int qty)
{
this.id = id;
this.qty = qty;
}
public SecondaryItem(int id)
{
this(id, 1);
}
}

View File

@@ -0,0 +1,401 @@
/*
* 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.ArrayList;
import java.util.List;
import java.util.Map;
import javax.imageio.ImageIO;
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.Getter;
import lombok.extern.slf4j.Slf4j;
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;
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
private int amount;
@Getter
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.getComposition().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.getComposition().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.getComposition().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().getComposition().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().getComposition().getName());
con.add(image, c);
c.gridx++;
}
c.gridx = 0;
infoContainer.add(con, c);
}
}
private JPanel createActivitiesPanel()
{
ArrayList<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.getComposition().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

@@ -127,4 +127,11 @@ public class MaterialTabGroup extends JPanel
return true;
}
@Override
public void removeAll()
{
super.removeAll();
tabs.clear();
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 B