Changes 2 (#43)

* Initial commit for maxhit plugin

* WIP: Magic max hit calculator

* Add chance to obtain a Unique from Chambers of Xeric

Based on the formula from the wiki. Does not handle >80% chance properly (it should go into a second item)

* MaxHit Refactor a lot for magic max hit

* Wip: refactoring

* Pest Control Update

* Pest Control: Add Intermediate portals

* Revert "Remove raids points overlay"

This reverts commit fbd3ea6202.

* Wip: refactoring

* Fixed WidgetInfo merge issue

* Fixed trident

* Implement range

* Refactored according to intellij analyzer

* Run checkstyle from xml and fix code style issues

* Fix copyright

* Replace item names with item id's

* Code cleanup with reformat code

* Fixed checkstyle

* Use game slotitem

* Use game slotitem

* Fixed prayer bonus

* Looked up value for saradomin strike

* Fixed prayer bonus

* Fixed surge spell id's

* Fixed magix max hit tests

* Fixed rounding after obisidian

* Fix dharok custom formula

* Add melee max hit

* Refactored spellbonus items for magic

* Added voidknight

* Use boosted skill levels and add copyright

* Add accurate attack style for ranging

* Add range Tests

* Cleanup code

* Cleanup code

* Rename calculate methods to be more distinguishable

* Add parenthesis to dharok maxhit formula for clarification

* Fix widgetinfo merge

* Remove print in MaxHitPlugin

* Make sure an Item is not null when checking if the player is wearing it.

* Add daily notification for collection of ogre arrows from Rantz.

Add varbit for rantz arrow collection

Fix continuation indent settings


Group ifs to single check.

* Refactor all relevant daily checks to have grouped if check.


Further refactor grouped ifs

* Adds type

* Raids point overlay
This commit is contained in:
James
2019-04-22 01:49:35 -07:00
committed by Tyler Bochard
parent 3a01eb67dc
commit 41c12a858d
60 changed files with 5848 additions and 279 deletions

View File

@@ -372,6 +372,7 @@ public enum Varbits {
DAILY_ESSENCE_COLLECTED(4547),
DAILY_RUNES_COLLECTED(4540),
DAILY_SAND_COLLECTED(4549),
DAILY_ARROWS_STATE(4563),
DAILY_FLAX_STATE(4559),
/**
* This varbit tracks how much bonemeal has been redeemed from Robin
@@ -481,6 +482,14 @@ public enum Varbits {
*/
GE_OFFER_CREATION_TYPE(4397),
/*
* Spells being auto-casted
*
* */
AUTO_CAST_SPELL(276),
/**
* The active tab within the quest interface
*/

View File

@@ -55,6 +55,8 @@ public class WidgetID
public static final int DIARY_GROUP_ID = 259;
public static final int PEST_CONTROL_BOAT_GROUP_ID = 407;
public static final int PEST_CONTROL_GROUP_ID = 408;
public static final int PEST_CONTROL_EXCHANGE_WINDOW_GROUP_ID = 243;
public static final int PEST_CONTROL_DIALOG_GROUP_ID = 229;
public static final int CLAN_CHAT_GROUP_ID = 7;
public static final int MINIMAP_GROUP_ID = 160;
public static final int LOGIN_CLICK_TO_PLAY_GROUP_ID = 378;
@@ -127,6 +129,7 @@ public class WidgetID
public static final int FULLSCREEN_MAP_GROUP_ID = 165;
public static final int QUESTLIST_GROUP_ID = 399;
public static final int SKILLS_GROUP_ID = 320;
public static final int EQUIPMENT_PAGE_GROUP_ID = 84;
public static final int QUESTTAB_GROUP_ID = 629;
public static final int MUSIC_GROUP_ID = 239;
public static final int MUSICTAB_GROUP_ID = 239;
@@ -164,12 +167,32 @@ public class WidgetID
static class PestControlBoat
{
static final int INFO = 3;
static final int NEXT_DEPARTURE = 4;
static final int PLAYERS_READY = 5;
static final int POINTS = 6;
}
static class PestControlExchangeWindow
{
static final int ITEM_LIST = 2;
static final int BOTTOM = 5;
static final int POINTS = 8;
static final int CONFIRM_BUTTON = 6;
}
static class PestControlDialog
{
static final int TEXT = 1;
static final int CONTINUE = 2;
}
static class PestControl
{
static final int INFO = 3;
static final int TIME = 6;
static final int ACTIVITY_BAR = 12;
static final int ACTIVITY_PROGRESS = 14;
@@ -675,6 +698,28 @@ public class WidgetID
static final int DESTROY_ITEM_NO = 3;
}
static class EquipmentWidgetIdentifiers
{
static final int EQUIP_YOUR_CHARACTER = 3;
static final int STAB_ATTACK_BONUS = 23;
static final int SLASH_ATTACK_BONUS = 24;
static final int CRUSH_ATTACK_BONUS = 25;
static final int MAGIC_ATTACK_BONUS = 26;
static final int RANGED_ATTACK_BONUS = 27;
static final int STAB_DEFENCE_BONUS = 29;
static final int SLASH_DEFENCE_BONUS = 30;
static final int CRUSH_DEFENCE_BONUS = 31;
static final int MAGIC_DEFENCE_BONUS = 32;
static final int RANGED_DEFENCE_BONUS = 33;
static final int MELEE_STRENGTH = 35;
static final int RANGED_STRENGTH = 36;
static final int MAGIC_DAMAGE = 37;
static final int PRAYER_BONUS = 38;
static final int UNDEAD_DAMAGE_BONUS = 40;
static final int SLAYER_DAMAGE_BONUS = 41;
static final int WEIGHT = 43;
}
static class VarrockMuseum
{
static final int VARROCK_MUSEUM_QUESTION = 28;

View File

@@ -83,8 +83,14 @@ public enum WidgetInfo
DIARY_QUEST_WIDGET_TITLE(WidgetID.DIARY_QUEST_GROUP_ID, WidgetID.Diary.DIARY_TITLE),
DIARY_QUEST_WIDGET_TEXT(WidgetID.DIARY_QUEST_GROUP_ID, WidgetID.Diary.DIARY_TEXT),
PEST_CONTROL_DIALOG(WidgetID.PEST_CONTROL_DIALOG_GROUP_ID, 0),
PEST_CONTROL_DIALOG_TEXT(WidgetID.PEST_CONTROL_DIALOG_GROUP_ID, WidgetID.PestControlDialog.TEXT),
PEST_CONTROL_EXCHANGE_WINDOW(WidgetID.PEST_CONTROL_EXCHANGE_WINDOW_GROUP_ID, 0),
PEST_CONTROL_EXCHANGE_WINDOW_POINTS(WidgetID.PEST_CONTROL_EXCHANGE_WINDOW_GROUP_ID, WidgetID.PestControlExchangeWindow.POINTS),
PEST_CONTROL_BOAT_INFO(WidgetID.PEST_CONTROL_BOAT_GROUP_ID, WidgetID.PestControlBoat.INFO),
PEST_CONTROL_BOAT_INFO_POINTS(WidgetID.PEST_CONTROL_BOAT_GROUP_ID, WidgetID.PestControlBoat.POINTS),
PEST_CONTROL_INFO(WidgetID.PEST_CONTROL_GROUP_ID, WidgetID.PestControl.INFO),
PEST_CONTROL_INFO_TIME(WidgetID.PEST_CONTROL_GROUP_ID, WidgetID.PestControl.TIME),
PEST_CONTROL_PURPLE_SHIELD(WidgetID.PEST_CONTROL_GROUP_ID, WidgetID.PestControl.PURPLE_SHIELD),
PEST_CONTROL_BLUE_SHIELD(WidgetID.PEST_CONTROL_GROUP_ID, WidgetID.PestControl.BLUE_SHIELD),
PEST_CONTROL_YELLOW_SHIELD(WidgetID.PEST_CONTROL_GROUP_ID, WidgetID.PestControl.YELLOW_SHIELD),
@@ -550,7 +556,12 @@ public enum WidgetInfo
MUSICTAB_LOOP_BUTTON(WidgetID.MUSICTAB_GROUP_ID, 12),
MUSICTAB_UNLOCKED_SONGS(WidgetID.MUSICTAB_GROUP_ID, 13),
QUESTTAB_QUEST_TAB(WidgetID.QUESTTAB_GROUP_ID, WidgetID.QuestTab.QUEST_TAB);
QUESTTAB_QUEST_TAB(WidgetID.QUESTTAB_GROUP_ID, WidgetID.QuestTab.QUEST_TAB),
EQUIPMENT_MELEE_STRENGTH(WidgetID.EQUIPMENT_PAGE_GROUP_ID, WidgetID.EquipmentWidgetIdentifiers.MELEE_STRENGTH),
EQUIPMENT_RANGED_STRENGTH(WidgetID.EQUIPMENT_PAGE_GROUP_ID, WidgetID.EquipmentWidgetIdentifiers.RANGED_STRENGTH),
EQUIPMENT_MAGIC_DAMAGE(WidgetID.EQUIPMENT_PAGE_GROUP_ID, WidgetID.EquipmentWidgetIdentifiers.MAGIC_DAMAGE),
EQUIP_YOUR_CHARACTER(WidgetID.EQUIPMENT_PAGE_GROUP_ID, WidgetID.EquipmentWidgetIdentifiers.EQUIP_YOUR_CHARACTER);
private final int groupId;
private final int childId;

View File

@@ -109,4 +109,15 @@ public interface DailyTasksConfig extends Config
{
return true;
}
@ConfigItem(
position = 8,
keyName = "showArrows",
name = "Show Claimable Ogre Arrows",
description = "Show a message when you can collect ogre arrows from Rantz."
)
default boolean showArrows()
{
return true;
}
}

View File

@@ -63,6 +63,7 @@ public class DailyTasksPlugin extends Plugin
private static final String SAND_MESSAGE = "You have sand waiting to be collected from Bert.";
private static final int SAND_QUEST_COMPLETE = 160;
private static final String FLAX_MESSAGE = "You have bowstrings waiting to be converted from flax from the Flax keeper.";
private static final String ARROWS_MESSAGE = "You have ogre arrows waiting to be collected from Rantz.";
private static final String BONEMEAL_MESSAGE = "You have bonemeal and slime waiting to be collected from Robin.";
private static final int BONEMEAL_PER_DIARY = 13;
private static final String RELOG_MESSAGE = " (May require a relog)";
@@ -153,22 +154,21 @@ public class DailyTasksPlugin extends Plugin
{
checkBonemeal(dailyReset);
}
if (config.showArrows())
{
checkArrows(dailyReset);
}
}
}
private void checkHerbBoxes(boolean dailyReset)
{
if (client.getAccountType() == AccountType.NORMAL
if ((client.getAccountType() == AccountType.NORMAL
&& client.getVar(VarPlayer.NMZ_REWARD_POINTS) >= HERB_BOX_COST)
&& (dailyReset || client.getVar(Varbits.DAILY_HERB_BOXES_COLLECTED) < HERB_BOX_MAX))
{
if (client.getVar(Varbits.DAILY_HERB_BOXES_COLLECTED) < HERB_BOX_MAX)
{
sendChatMessage(HERB_BOX_MESSAGE);
}
else if (dailyReset)
{
sendChatMessage(HERB_BOX_MESSAGE);
}
sendChatMessage(HERB_BOX_MESSAGE);
}
}
@@ -189,61 +189,46 @@ public class DailyTasksPlugin extends Plugin
private void checkEssence(boolean dailyReset)
{
if (client.getVar(Varbits.DIARY_ARDOUGNE_MEDIUM) == 1)
if ((client.getVar(Varbits.DIARY_ARDOUGNE_MEDIUM) == 1)
&& (dailyReset || client.getVar(Varbits.DAILY_ESSENCE_COLLECTED) == 0))
{
if (client.getVar(Varbits.DAILY_ESSENCE_COLLECTED) == 0)
{
sendChatMessage(ESSENCE_MESSAGE);
}
else if (dailyReset)
{
sendChatMessage(ESSENCE_MESSAGE);
}
sendChatMessage(ESSENCE_MESSAGE);
}
}
private void checkRunes(boolean dailyReset)
{
if (client.getVar(Varbits.DIARY_WILDERNESS_EASY) == 1)
if ((client.getVar(Varbits.DIARY_WILDERNESS_EASY) == 1)
&& (dailyReset || client.getVar(Varbits.DAILY_RUNES_COLLECTED) == 0))
{
if (client.getVar(Varbits.DAILY_RUNES_COLLECTED) == 0)
{
sendChatMessage(RUNES_MESSAGE);
}
else if (dailyReset)
{
sendChatMessage(RUNES_MESSAGE);
}
sendChatMessage(RUNES_MESSAGE);
}
}
private void checkSand(boolean dailyReset)
{
if (client.getVar(Varbits.QUEST_THE_HAND_IN_THE_SAND) >= SAND_QUEST_COMPLETE)
if ((client.getVar(Varbits.QUEST_THE_HAND_IN_THE_SAND) >= SAND_QUEST_COMPLETE)
&& (dailyReset || client.getVar(Varbits.DAILY_SAND_COLLECTED) == 0))
{
if (client.getVar(Varbits.DAILY_SAND_COLLECTED) == 0)
{
sendChatMessage(SAND_MESSAGE);
}
else if (dailyReset)
{
sendChatMessage(SAND_MESSAGE);
}
sendChatMessage(SAND_MESSAGE);
}
}
private void checkFlax(boolean dailyReset)
{
if (client.getVar(Varbits.DIARY_KANDARIN_EASY) == 1)
if ((client.getVar(Varbits.DIARY_KANDARIN_EASY) == 1)
&& (dailyReset || client.getVar(Varbits.DAILY_FLAX_STATE) == 0))
{
if (client.getVar(Varbits.DAILY_FLAX_STATE) == 0)
{
sendChatMessage(FLAX_MESSAGE);
}
else if (dailyReset)
{
sendChatMessage(FLAX_MESSAGE);
}
sendChatMessage(FLAX_MESSAGE);
}
}
private void checkArrows(boolean dailyReset)
{
if ((client.getVar(Varbits.DIARY_WESTERN_EASY) == 1)
&& (dailyReset || client.getVar(Varbits.DAILY_ARROWS_STATE) == 0))
{
sendChatMessage(ARROWS_MESSAGE);
}
}
@@ -261,11 +246,7 @@ public class DailyTasksPlugin extends Plugin
max += BONEMEAL_PER_DIARY;
}
}
if (collected < max)
{
sendChatMessage(BONEMEAL_MESSAGE);
}
else if (dailyReset)
if (dailyReset || collected < max)
{
sendChatMessage(BONEMEAL_MESSAGE);
}

View File

@@ -0,0 +1,138 @@
/*
* Copyright (c) 2019, Bartvollebregt <https://github.com/Bartvollebregt>
* 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.maxhit;
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.ItemContainerChanged;
import net.runelite.api.events.VarbitChanged;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.plugins.maxhit.calculators.MagicMaxHitCalculator;
import net.runelite.client.plugins.maxhit.calculators.MeleeMaxHitCalculator;
import net.runelite.client.plugins.maxhit.calculators.RangeMaxHitCalculator;
import javax.inject.Inject;
@PluginDescriptor(
name = "Max Hit",
description = "Max Hit Calculator",
type = "PVM",
enabledByDefault = false
)
public class MaxHitPlugin extends Plugin
{
@Inject
private Client client;
@Subscribe
public void onItemContainerChanged(final ItemContainerChanged event)
{
this.updateMaxHitWidget();
}
@Subscribe
public void onConfigChanged(final ConfigChanged event)
{
this.updateMaxHitWidget();
}
@Subscribe
public void onVarbitChanged(VarbitChanged event)
{
this.updateMaxHitWidget();
}
private void updateMaxHitWidget()
{
Widget equipmentStats = client.getWidget(WidgetInfo.EQUIPMENT_INVENTORY_ITEMS_CONTAINER);
ItemContainer equipmentContainer = client.getItemContainer(InventoryID.EQUIPMENT);
Item[] equipedItems = new Item[14];
if (equipmentStats != null && !equipmentStats.isHidden())
{
if (equipmentContainer != null)
{
equipedItems = equipmentContainer.getItems();
}
MeleeMaxHitCalculator meleeMaxHitCalculator = new MeleeMaxHitCalculator(this.client, equipedItems);
RangeMaxHitCalculator rangeMaxHitCalculator = new RangeMaxHitCalculator(this.client, equipedItems);
MagicMaxHitCalculator magicMaxHitCalculator = new MagicMaxHitCalculator(this.client, equipedItems);
MaxHit maxHit = new MaxHit(meleeMaxHitCalculator.getMaxHit(), rangeMaxHitCalculator.getMaxHit(), magicMaxHitCalculator.getMaxHit());
this.setWidgetMaxHit(maxHit);
}
}
private void setWidgetMaxHit(MaxHit maxhit)
{
Widget equipYourCharacter = client.getWidget(WidgetInfo.EQUIP_YOUR_CHARACTER);
String maxHitText = "Melee Max Hit: " + maxhit.getMaxMeleeHit();
maxHitText += "<br>Range Max Hit: " + maxhit.getMaxRangeHit();
maxHitText += "<br>Magic Max Hit: " + maxhit.getMaxMagicHit();
equipYourCharacter.setText(maxHitText);
}
private class MaxHit
{
private final double maxMeleeHit;
private final double maxRangeHit;
private final double maxMagicHit;
MaxHit(double maxMeleeHit, double maxRangeHit, double maxMagicHit)
{
this.maxMeleeHit = maxMeleeHit;
this.maxRangeHit = maxRangeHit;
this.maxMagicHit = maxMagicHit;
}
double getMaxMeleeHit()
{
return maxMeleeHit;
}
double getMaxRangeHit()
{
return maxRangeHit;
}
double getMaxMagicHit()
{
return maxMagicHit;
}
}
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright (c) 2019, Bartvollebregt <https://github.com/Bartvollebregt>
* 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.maxhit.attackstyle;
public enum AttackStyle
{
ACCURATE(0),
AGGRESSIVE(3),
DEFENSIVE(0),
CONTROLLED(1),
ACCURATERANGING(3),
RANGING(0),
LONGRANGE(0),
CASTING(0),
DEFENSIVE_CASTING(0),
OTHER(0);
private final int maxHitBonus;
AttackStyle(int maxHitBonus)
{
this.maxHitBonus = maxHitBonus;
}
public double getMaxHitBonus()
{
return this.maxHitBonus;
}
}

View File

@@ -0,0 +1,89 @@
/*
* Copyright (c) 2019, Bartvollebregt <https://github.com/Bartvollebregt>
* 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.maxhit.attackstyle;
import java.util.HashMap;
import java.util.Map;
import static net.runelite.client.plugins.maxhit.attackstyle.AttackStyle.*;
public enum WeaponType
{
TYPE_0(ACCURATE, AGGRESSIVE, null, DEFENSIVE),
TYPE_1(ACCURATE, AGGRESSIVE, AGGRESSIVE, DEFENSIVE),
TYPE_2(ACCURATE, AGGRESSIVE, null, DEFENSIVE),
TYPE_3(ACCURATERANGING, RANGING, null, LONGRANGE),
TYPE_4(ACCURATE, AGGRESSIVE, CONTROLLED, DEFENSIVE),
TYPE_5(ACCURATERANGING, RANGING, null, LONGRANGE),
TYPE_6(AGGRESSIVE, RANGING, DEFENSIVE_CASTING, null),
TYPE_7(ACCURATERANGING, RANGING, null, LONGRANGE),
TYPE_8(OTHER, AGGRESSIVE, null, null),
TYPE_9(ACCURATE, AGGRESSIVE, CONTROLLED, DEFENSIVE),
TYPE_10(ACCURATE, AGGRESSIVE, AGGRESSIVE, DEFENSIVE),
TYPE_11(ACCURATE, AGGRESSIVE, AGGRESSIVE, DEFENSIVE),
TYPE_12(CONTROLLED, AGGRESSIVE, null, DEFENSIVE),
TYPE_13(ACCURATE, AGGRESSIVE, null, DEFENSIVE),
TYPE_14(ACCURATE, AGGRESSIVE, AGGRESSIVE, DEFENSIVE),
TYPE_15(CONTROLLED, CONTROLLED, CONTROLLED, DEFENSIVE),
TYPE_16(ACCURATE, AGGRESSIVE, CONTROLLED, DEFENSIVE),
TYPE_17(ACCURATE, AGGRESSIVE, AGGRESSIVE, DEFENSIVE),
TYPE_18(ACCURATE, AGGRESSIVE, null, DEFENSIVE, CASTING, DEFENSIVE_CASTING),
TYPE_19(ACCURATERANGING, RANGING, null, LONGRANGE),
TYPE_20(ACCURATE, CONTROLLED, null, DEFENSIVE),
TYPE_21(ACCURATE, AGGRESSIVE, null, DEFENSIVE, CASTING, DEFENSIVE_CASTING),
TYPE_22(ACCURATE, AGGRESSIVE, AGGRESSIVE, DEFENSIVE),
TYPE_23(CASTING, CASTING, null, DEFENSIVE_CASTING),
TYPE_24(ACCURATE, AGGRESSIVE, CONTROLLED, DEFENSIVE),
TYPE_25(CONTROLLED, AGGRESSIVE, null, DEFENSIVE),
TYPE_26(AGGRESSIVE, AGGRESSIVE, null, AGGRESSIVE),
TYPE_27(ACCURATE, null, null, OTHER);
private static final Map<Integer, WeaponType> weaponTypes = new HashMap<>();
static
{
for (WeaponType weaponType : values())
{
weaponTypes.put(weaponType.ordinal(), weaponType);
}
}
private final AttackStyle[] attackStyles;
WeaponType(AttackStyle... attackStyles)
{
this.attackStyles = attackStyles;
}
public static WeaponType getWeaponType(int id)
{
return weaponTypes.get(id);
}
public AttackStyle[] getAttackStyles()
{
return attackStyles;
}
}

View File

@@ -0,0 +1,113 @@
/*
* Copyright (c) 2019, Bartvollebregt <https://github.com/Bartvollebregt>
* 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.maxhit.calculators;
import net.runelite.api.Client;
import net.runelite.api.Item;
import net.runelite.api.Skill;
import net.runelite.api.Varbits;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.plugins.maxhit.config.EquipmentBonusConfig;
import net.runelite.client.plugins.maxhit.config.SpellBaseDamageConfig;
public class MagicMaxHitCalculator extends MaxHitCalculator
{
public MagicMaxHitCalculator(Client client, Item[] equipedItems)
{
super(client, CombatMethod.MAGIC, equipedItems);
}
@Override
protected String getSkillStrengthText(String equipmentText)
{
return equipmentText.replace("Magic damage: ", "").replace(".", "").replace("%", "");
}
@Override
Widget equipmentSkillPower()
{
return this.client.getWidget(WidgetInfo.EQUIPMENT_MAGIC_DAMAGE);
}
@Override
public double getCurrentSkillPower()
{
return this.client.getBoostedSkillLevel(Skill.MAGIC);
}
/*
* Damage formula based on:
* http://services.runescape.com/m=forum/forums.ws?317,318,712,65587452
* Section 4.
* */
@Override
public double calculate()
{
int spellBaseDamage = this.baseDamage;
if (spellBaseDamage == 0)
{
int autoCastSpellId = client.getVar(Varbits.AUTO_CAST_SPELL);
if (autoCastSpellId == 0)
{
return 0.0;
}
SpellBaseDamageConfig autoCastSpell = SpellBaseDamageConfig.findSpellById(autoCastSpellId);
spellBaseDamage = autoCastSpell.getBaseDamage();
}
// a.Find the base maximum damage a spell can deal.
// See CustomFormulaConfig for spells based on magic lvl
double maxHit = spellBaseDamage;
// b. Increase the base damage (Chaos Gauntlets)
maxHit = this.applyEquipmentBonus(maxHit, EquipmentBonusConfig.BonusType.SPECIAL);
// c. The following bonuses stack by adding up. (List of bonus items)
maxHit = this.applyEquipmentBonus(maxHit, EquipmentBonusConfig.BonusType.EQUIPMENT);
// d. Round down to the nearest integer.
maxHit = Math.floor(maxHit);
// e. On a slayer task, multiply by 1.15 (imbued)
maxHit = this.applyEquipmentBonus(maxHit, EquipmentBonusConfig.BonusType.SLAYER);
// f. Round down to the nearest integer.
maxHit = Math.floor(maxHit);
// g. If a fire spell is used, multiply by 1.5 (Tome of fire)
maxHit = this.applyEquipmentBonus(maxHit, EquipmentBonusConfig.BonusType.MAGIC_SPECIAL);
// h. Round down to the nearest integer.
maxHit = Math.floor(maxHit);
// i, j. Castle Wars will not be included
return maxHit;
}
}

View File

@@ -0,0 +1,178 @@
/*
* Copyright (c) 2019, Bartvollebregt <https://github.com/Bartvollebregt>
* 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.maxhit.calculators;
import net.runelite.api.Client;
import net.runelite.api.Item;
import net.runelite.api.VarPlayer;
import net.runelite.api.Varbits;
import net.runelite.api.widgets.Widget;
import net.runelite.client.plugins.maxhit.attackstyle.AttackStyle;
import net.runelite.client.plugins.maxhit.attackstyle.WeaponType;
import net.runelite.client.plugins.maxhit.config.CustomFormulaConfig;
import net.runelite.client.plugins.maxhit.config.EquipmentBonusConfig;
import net.runelite.client.plugins.maxhit.config.PrayerBonusConfig;
import net.runelite.client.plugins.maxhit.equipment.EquipmentHelper;
import net.runelite.client.plugins.maxhit.equipment.EquipmentItemset;
import java.util.ArrayList;
import java.util.function.BiFunction;
public abstract class MaxHitCalculator
{
final Client client;
private final CombatMethod combatMethod;
private final Item[] equipedItems;
int baseDamage = 0;
MaxHitCalculator(Client client, CombatMethod combatMethod, Item[] equipedItems)
{
this.client = client;
this.combatMethod = combatMethod;
this.equipedItems = equipedItems;
}
protected abstract String getSkillStrengthText(String equipmentText);
abstract Widget equipmentSkillPower();
public abstract double getCurrentSkillPower();
AttackStyle getAttackStyle()
{
int equippedWeaponTypeId = client.getVar(Varbits.EQUIPPED_WEAPON_TYPE);
int attackStyleId = client.getVar(VarPlayer.ATTACK_STYLE);
AttackStyle[] attackStyles = WeaponType.getWeaponType(equippedWeaponTypeId).getAttackStyles();
if (attackStyleId < attackStyles.length)
{
AttackStyle attackStyle = attackStyles[attackStyleId];
if (attackStyle != null)
{
return attackStyle;
}
}
return AttackStyle.OTHER;
}
double getPrayerBonus()
{
double bonus = 1;
for (PrayerBonusConfig prayerBonus : PrayerBonusConfig.values())
{
boolean prayerActive = client.getVar(prayerBonus.getPrayerVarbit()) == 1;
boolean sameCombatMethod = prayerBonus.getCombatMethod() == this.combatMethod;
if (prayerActive && sameCombatMethod)
{
bonus += prayerBonus.getStrengthBonus();
}
}
return bonus;
}
double applyEquipmentBonus(double maxhit, EquipmentBonusConfig.BonusType bonusType)
{
double bonus = 1;
ArrayList<Double> addList = new ArrayList<>();
ArrayList<EquipmentBonusConfig> equipmentBonuses = EquipmentBonusConfig.getBonusByType(bonusType);
for (EquipmentBonusConfig equipmentBonus : equipmentBonuses)
{
EquipmentItemset itemSet = equipmentBonus.getItemset();
boolean wearsSet = EquipmentHelper.wearsItemSet(this.equipedItems, itemSet);
if (wearsSet && equipmentBonus.meetsRequirements(this.client))
{
if (equipmentBonus.getOperation() == EquipmentBonusConfig.Operation.MULTIPLY)
{
bonus += equipmentBonus.getBonus(this.combatMethod);
}
else if (equipmentBonus.getOperation() == EquipmentBonusConfig.Operation.ADD)
{
addList.add(equipmentBonus.getBonus(this.combatMethod));
}
}
}
maxhit *= bonus;
maxhit = maxhit + addList.stream().reduce(0.0, Double::sum);
return maxhit;
}
public double getMaxHit()
{
BiFunction<Client, MaxHitCalculator, Double> customFormula = this.getCustomFormula();
if (customFormula != null)
{
return customFormula.apply(this.client, this);
}
return this.calculate();
}
private BiFunction<Client, MaxHitCalculator, Double> getCustomFormula()
{
for (CustomFormulaConfig customFormula : CustomFormulaConfig.values())
{
if (this.combatMethod != customFormula.getRequiredCombatMethod())
{
continue;
}
boolean meetsRequirements = customFormula.getRequirements().stream().allMatch(requirement -> requirement.meetsRequirements(this.client));
if (meetsRequirements)
{
return customFormula.getCustomFormula();
}
}
return null;
}
public abstract double calculate();
public void setBaseDamage(int baseDamage)
{
this.baseDamage = baseDamage;
}
double getSkillStrength()
{
return Double.parseDouble(this.getSkillStrengthText(this.equipmentSkillPower().getText()));
}
public enum CombatMethod
{
MELEE,
RANGE,
MAGIC
}
}

View File

@@ -0,0 +1,137 @@
/*
* Copyright (c) 2019, Bartvollebregt <https://github.com/Bartvollebregt>
* 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.maxhit.calculators;
import net.runelite.api.Client;
import net.runelite.api.Item;
import net.runelite.api.Skill;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.plugins.maxhit.attackstyle.AttackStyle;
import net.runelite.client.plugins.maxhit.config.EquipmentBonusConfig;
public class MeleeMaxHitCalculator extends MaxHitCalculator
{
public MeleeMaxHitCalculator(Client client, Item[] equipedItems)
{
super(client, CombatMethod.MELEE, equipedItems);
}
MeleeMaxHitCalculator(Client client, CombatMethod combatMethod, Item[] equipedItems)
{
super(client, combatMethod, equipedItems);
}
@Override
protected String getSkillStrengthText(String equipmentText)
{
return equipmentText.replace("Melee strength: ", "");
}
@Override
public Widget equipmentSkillPower()
{
return this.client.getWidget(WidgetInfo.EQUIPMENT_MELEE_STRENGTH);
}
@Override
public double getCurrentSkillPower()
{
return this.client.getBoostedSkillLevel(Skill.STRENGTH);
}
private double getEffectiveLevel()
{
// a. Take the visible strength or ranged level from the skills interface.
double skillPower = this.getCurrentSkillPower();
// b. Multiply the level by the prayer adjustment
double effectiveLevel = skillPower * this.getPrayerBonus();
// c. Round down to the nearest integer.
effectiveLevel = Math.floor(effectiveLevel);
// d. Add the stance bonus from the combat options interface.
// Melee:
// • Aggressive: +3
// • Controlled: +1
// Ranged:
// * Accurate: +3
AttackStyle attackStyle = this.getAttackStyle();
effectiveLevel += attackStyle.getMaxHitBonus();
// e. Add up +8.
effectiveLevel += 8;
// f. Multiply by the void bonus:
// • Void melee: multiply by 1.10. Round down.
// • Void ranged: multiply by 1.10. Round down.
// • Elite void ranged: multiply by 1.125. Round down.
effectiveLevel = this.applyEquipmentBonus(effectiveLevel, EquipmentBonusConfig.BonusType.VOID_KNIGHT);
// g. This is the effective (ranged) strength level. Let this equal 'A' in the formula in
return effectiveLevel;
}
// 3.3 Take the melee or ranged strength bonus from the equipment stats interface and let this equal 'B' in the formula in 3.1.
private double getEquipmentBonus()
{
return this.getSkillStrength();
}
/*
* Damage formula based on:
* http://services.runescape.com/m=forum/forums.ws?317,318,712,65587452
* Section 3.1
* */
@Override
public double calculate()
{
// a. Max hit = 0.5 + A * (B+64) /640 (A is effective level, B is Equipment bonus)
double maxHit = 0.5 + this.getEffectiveLevel() * (this.getEquipmentBonus() + 64) / 640;
// b. Round down the max hit to the nearest integer.
maxHit = Math.floor(maxHit);
// 3.4 Special attacks (not actually taking weapon special attacks into account)
// a. Multiply by the bonus of one of the following items (slayer)
maxHit = this.applyEquipmentBonus(maxHit, EquipmentBonusConfig.BonusType.SLAYER);
// b. Round down the max hit to the nearest integer.
maxHit = Math.floor(maxHit);
// c. Multiply by the bonus of one of the following items
maxHit = this.applyEquipmentBonus(maxHit, EquipmentBonusConfig.BonusType.SPECIAL);
// d. Round down to the nearest integer.
maxHit = Math.floor(maxHit);
return maxHit;
}
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2019, Bartvollebregt <https://github.com/Bartvollebregt>
* 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.maxhit.calculators;
import net.runelite.api.Client;
import net.runelite.api.Item;
import net.runelite.api.Skill;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
public class RangeMaxHitCalculator extends MeleeMaxHitCalculator
{
public RangeMaxHitCalculator(Client client, Item[] equipedItems)
{
super(client, CombatMethod.RANGE, equipedItems);
}
@Override
protected String getSkillStrengthText(String equipmentText)
{
return equipmentText.replace("Ranged strength: ", "").replace(".", "").replace("%", "");
}
@Override
public Widget equipmentSkillPower()
{
return this.client.getWidget(WidgetInfo.EQUIPMENT_RANGED_STRENGTH);
}
@Override
public double getCurrentSkillPower()
{
return this.client.getBoostedSkillLevel(Skill.RANGED);
}
}

View File

@@ -0,0 +1,233 @@
/*
* Copyright (c) 2019, Bartvollebregt <https://github.com/Bartvollebregt>
* 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.maxhit.config;
import net.runelite.api.Client;
import net.runelite.api.EquipmentInventorySlot;
import net.runelite.api.ItemID;
import net.runelite.api.Skill;
import net.runelite.client.plugins.maxhit.calculators.MaxHitCalculator;
import net.runelite.client.plugins.maxhit.equipment.EquipmentItemset;
import net.runelite.client.plugins.maxhit.equipment.EquipmentSlotItem;
import net.runelite.client.plugins.maxhit.requirements.EquipmentItemRequirement;
import net.runelite.client.plugins.maxhit.requirements.EquipmentItemSetRequirement;
import net.runelite.client.plugins.maxhit.requirements.Requirement;
import net.runelite.client.plugins.maxhit.requirements.SpellRequirement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.function.BiFunction;
public enum CustomFormulaConfig
{
MAGIC_DART(
MaxHitCalculator.CombatMethod.MAGIC,
new ArrayList<>(Arrays.asList(
new EquipmentItemRequirement(new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Arrays.asList(
ItemID.SLAYERS_STAFF,
ItemID.SLAYERS_STAFF_E
)))),
new SpellRequirement(SpellBaseDamageConfig.MAGIC_DART)
)),
(client, calculator) ->
{
int magicLevel = client.getBoostedSkillLevel(Skill.MAGIC);
return Math.floor((magicLevel / 10.0) + 10.0);
}
),
TRIDENT_OF_SEAS(
MaxHitCalculator.CombatMethod.MAGIC,
new ArrayList<>(Collections.singletonList(
new EquipmentItemRequirement(new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Arrays.asList(
ItemID.TRIDENT_OF_THE_SEAS_FULL,
ItemID.TRIDENT_OF_THE_SEAS,
ItemID.TRIDENT_OF_THE_SEAS_E
))))
)),
(client, calculator) ->
{
int magicLevel = client.getBoostedSkillLevel(Skill.MAGIC);
int baseDamage = (int) Math.floor(magicLevel / 3.0) - 5;
calculator.setBaseDamage(baseDamage);
return calculator.calculate();
}
),
TRIDENT_OF_SWAMP(
MaxHitCalculator.CombatMethod.MAGIC,
new ArrayList<>(Collections.singletonList(
new EquipmentItemRequirement(new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Arrays.asList(
ItemID.TRIDENT_OF_THE_SWAMP,
ItemID.TRIDENT_OF_THE_SWAMP_E
))))
)),
(client, calculator) ->
{
int magicLevel = client.getBoostedSkillLevel(Skill.MAGIC);
int baseDamage = (int) Math.floor(magicLevel / 3.0) - 2;
calculator.setBaseDamage(baseDamage);
return calculator.calculate();
}
),
SWAMP_LIZARD(
MaxHitCalculator.CombatMethod.MAGIC,
new ArrayList<>(Collections.singletonList(
new EquipmentItemRequirement(new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Collections.singletonList(
ItemID.SWAMP_LIZARD
))))
)),
(client, calculator) ->
{
int magicLevel = client.getBoostedSkillLevel(Skill.MAGIC);
return Math.floor(0.5 + magicLevel * (64.0 + 56.0) / 640.0);
}
),
ORANGE_SALAMANDER(
MaxHitCalculator.CombatMethod.MAGIC,
new ArrayList<>(Collections.singletonList(
new EquipmentItemRequirement(new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Collections.singletonList(
ItemID.ORANGE_SALAMANDER
))))
)),
(client, calculator) ->
{
int magicLevel = client.getBoostedSkillLevel(Skill.MAGIC);
return Math.floor(0.5 + magicLevel * (64.0 + 59.0) / 640.0);
}
),
RED_SALAMANDER(
MaxHitCalculator.CombatMethod.MAGIC,
new ArrayList<>(Collections.singletonList(
new EquipmentItemRequirement(new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Collections.singletonList(
ItemID.RED_SALAMANDER
))))
)),
(client, calculator) ->
{
int magicLevel = client.getBoostedSkillLevel(Skill.MAGIC);
return Math.floor(0.5 + magicLevel * (64.0 + 77.0) / 640.0);
}
),
BLACK_SALAMANDER(
MaxHitCalculator.CombatMethod.MAGIC,
new ArrayList<>(Collections.singletonList(
new EquipmentItemRequirement(new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Collections.singletonList(
ItemID.BLACK_SALAMANDER
))))
)),
(client, calculator) ->
{
int magicLevel = client.getBoostedSkillLevel(Skill.MAGIC);
return Math.floor(0.5 + magicLevel * (64.0 + 92.0) / 640.0);
}
),
DHAROK(
MaxHitCalculator.CombatMethod.MELEE,
new ArrayList<>(Collections.singletonList(new EquipmentItemSetRequirement(new EquipmentItemset(Arrays.asList(
new EquipmentSlotItem(EquipmentInventorySlot.HEAD, new ArrayList<>(Arrays.asList(
ItemID.DHAROKS_HELM,
ItemID.DHAROKS_HELM_100,
ItemID.DHAROKS_HELM_75,
ItemID.DHAROKS_HELM_50,
ItemID.DHAROKS_HELM_25,
ItemID.DHAROKS_HELM_0
))),
new EquipmentSlotItem(EquipmentInventorySlot.BODY, new ArrayList<>(Arrays.asList(
ItemID.DHAROKS_PLATEBODY,
ItemID.DHAROKS_PLATEBODY_100,
ItemID.DHAROKS_PLATEBODY_75,
ItemID.DHAROKS_PLATEBODY_50,
ItemID.DHAROKS_PLATEBODY_25,
ItemID.DHAROKS_PLATEBODY_0
))),
new EquipmentSlotItem(EquipmentInventorySlot.LEGS, new ArrayList<>(Arrays.asList(
ItemID.DHAROKS_PLATELEGS,
ItemID.DHAROKS_PLATELEGS_100,
ItemID.DHAROKS_PLATELEGS_75,
ItemID.DHAROKS_PLATELEGS_50,
ItemID.DHAROKS_PLATELEGS_25,
ItemID.DHAROKS_PLATELEGS_0
))),
new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Arrays.asList(
ItemID.DHAROKS_GREATAXE,
ItemID.DHAROKS_GREATAXE_100,
ItemID.DHAROKS_GREATAXE_75,
ItemID.DHAROKS_GREATAXE_50,
ItemID.DHAROKS_GREATAXE_25,
ItemID.DHAROKS_GREATAXE_0
)))
))))),
(client, calculator) ->
{
int currentHP = client.getBoostedSkillLevel(Skill.HITPOINTS);
int maxHP = client.getRealSkillLevel(Skill.HITPOINTS);
int lostHP = maxHP - currentHP;
double initialMaxHit = calculator.calculate();
double multiplier = (1.0 + ((lostHP / 100.0) * (maxHP / 100.0)));
return Math.floor(initialMaxHit * multiplier);
}
);
private final MaxHitCalculator.CombatMethod requiredCombatMethod;
private final ArrayList<Requirement> requirements;
private final BiFunction<Client, MaxHitCalculator, Double> customFormula;
CustomFormulaConfig(MaxHitCalculator.CombatMethod requiredCombatMethod, ArrayList<Requirement> requirements, BiFunction<Client, MaxHitCalculator, Double> customFormula)
{
this.requiredCombatMethod = requiredCombatMethod;
this.requirements = requirements;
this.customFormula = customFormula;
}
public MaxHitCalculator.CombatMethod getRequiredCombatMethod()
{
return requiredCombatMethod;
}
public BiFunction<Client, MaxHitCalculator, Double> getCustomFormula()
{
return customFormula;
}
public ArrayList<Requirement> getRequirements()
{
return this.requirements;
}
}

View File

@@ -0,0 +1,418 @@
/*
* Copyright (c) 2019, Bartvollebregt <https://github.com/Bartvollebregt>
* 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.maxhit.config;
import net.runelite.api.Client;
import net.runelite.api.EquipmentInventorySlot;
import net.runelite.api.ItemID;
import net.runelite.client.plugins.maxhit.calculators.MaxHitCalculator;
import net.runelite.client.plugins.maxhit.equipment.EquipmentCombatBonus;
import net.runelite.client.plugins.maxhit.equipment.EquipmentItemset;
import net.runelite.client.plugins.maxhit.equipment.EquipmentSlotItem;
import net.runelite.client.plugins.maxhit.requirements.AutocastSpellRequirement;
import net.runelite.client.plugins.maxhit.requirements.Requirement;
import net.runelite.client.plugins.maxhit.requirements.SpellBookRequirement;
import java.util.*;
public enum EquipmentBonusConfig
{
/*
* Slayer bonus items
*/
BLACKMASK(BonusType.SLAYER, new EquipmentItemset(Collections.singletonList(
new EquipmentSlotItem(EquipmentInventorySlot.HEAD, new ArrayList<>(Arrays.asList(
ItemID.BLACK_MASK_10,
ItemID.BLACK_MASK_9,
ItemID.BLACK_MASK_8,
ItemID.BLACK_MASK_7,
ItemID.BLACK_MASK_6,
ItemID.BLACK_MASK_5,
ItemID.BLACK_MASK_4,
ItemID.BLACK_MASK_3,
ItemID.BLACK_MASK_2,
ItemID.BLACK_MASK_1,
ItemID.BLACK_MASK
)))
)), new EquipmentCombatBonus(((7.0 / 6.0) - 1), 0, 0)),
SLAYERHELM(BonusType.SLAYER, new EquipmentItemset(Collections.singletonList(
new EquipmentSlotItem(EquipmentInventorySlot.HEAD, new ArrayList<>(Arrays.asList(
ItemID.SLAYER_HELMET,
ItemID.BLACK_SLAYER_HELMET,
ItemID.GREEN_SLAYER_HELMET,
ItemID.RED_SLAYER_HELMET,
ItemID.PURPLE_SLAYER_HELMET,
ItemID.TURQUOISE_SLAYER_HELMET,
ItemID.HYDRA_SLAYER_HELMET
)))
)), new EquipmentCombatBonus(((7.0 / 6.0) - 1), 0, 0)),
BLACKMASKI(BonusType.SLAYER, new EquipmentItemset(Collections.singletonList(
new EquipmentSlotItem(EquipmentInventorySlot.HEAD, new ArrayList<>(Arrays.asList(
ItemID.BLACK_MASK_10_I,
ItemID.BLACK_MASK_9_I,
ItemID.BLACK_MASK_8_I,
ItemID.BLACK_MASK_7_I,
ItemID.BLACK_MASK_6_I,
ItemID.BLACK_MASK_5_I,
ItemID.BLACK_MASK_4_I,
ItemID.BLACK_MASK_3_I,
ItemID.BLACK_MASK_2_I,
ItemID.BLACK_MASK_1_I,
ItemID.BLACK_MASK_I
)))
)), new EquipmentCombatBonus(((7.0 / 6.0) - 1), 0.15, 0.15)),
SLAYERHELMI(BonusType.SLAYER, new EquipmentItemset(Collections.singletonList(
new EquipmentSlotItem(EquipmentInventorySlot.HEAD, new ArrayList<>(Arrays.asList(
ItemID.SLAYER_HELMET_I,
ItemID.BLACK_SLAYER_HELMET_I,
ItemID.GREEN_SLAYER_HELMET_I,
ItemID.RED_SLAYER_HELMET_I,
ItemID.PURPLE_SLAYER_HELMET_I,
ItemID.TURQUOISE_SLAYER_HELMET_I,
ItemID.HYDRA_SLAYER_HELMET_I
)))
)), new EquipmentCombatBonus(((7.0 / 6.0) - 1), 0.15, 0.15)),
/*
* Void bonus items
* */
MELEEVOID(BonusType.VOID_KNIGHT, new EquipmentItemset(Arrays.asList(
new EquipmentSlotItem(EquipmentInventorySlot.HEAD, new ArrayList<>(Arrays.asList(
ItemID.VOID_MELEE_HELM,
ItemID.VOID_MELEE_HELM_11676
))),
new EquipmentSlotItem(EquipmentInventorySlot.BODY, new ArrayList<>(Arrays.asList(
ItemID.VOID_KNIGHT_TOP,
ItemID.VOID_KNIGHT_TOP_10611
))),
new EquipmentSlotItem(EquipmentInventorySlot.LEGS, new ArrayList<>(Collections.singletonList(
ItemID.VOID_KNIGHT_ROBE
))),
new EquipmentSlotItem(EquipmentInventorySlot.GLOVES, new ArrayList<>(Collections.singletonList(
ItemID.VOID_KNIGHT_GLOVES
)))
)), new EquipmentCombatBonus(0.1, 0, 0)),
RANGERVOID(BonusType.VOID_KNIGHT, new EquipmentItemset(Arrays.asList(
new EquipmentSlotItem(EquipmentInventorySlot.HEAD, new ArrayList<>(Arrays.asList(
ItemID.VOID_RANGER_HELM,
ItemID.VOID_RANGER_HELM_11675
))),
new EquipmentSlotItem(EquipmentInventorySlot.BODY, new ArrayList<>(Arrays.asList(
ItemID.VOID_KNIGHT_TOP,
ItemID.VOID_KNIGHT_TOP_10611
))),
new EquipmentSlotItem(EquipmentInventorySlot.LEGS, new ArrayList<>(Collections.singletonList(
ItemID.VOID_KNIGHT_ROBE
))),
new EquipmentSlotItem(EquipmentInventorySlot.GLOVES, new ArrayList<>(Collections.singletonList(
ItemID.VOID_KNIGHT_GLOVES
)))
)), new EquipmentCombatBonus(0, 0.1, 0)),
ELITEMELEERVOID(BonusType.VOID_KNIGHT, new EquipmentItemset(Arrays.asList(
new EquipmentSlotItem(EquipmentInventorySlot.HEAD, new ArrayList<>(Arrays.asList(
ItemID.VOID_MELEE_HELM,
ItemID.VOID_MELEE_HELM_11676
))),
new EquipmentSlotItem(EquipmentInventorySlot.BODY, new ArrayList<>(Collections.singletonList(
ItemID.ELITE_VOID_TOP
))),
new EquipmentSlotItem(EquipmentInventorySlot.LEGS, new ArrayList<>(Collections.singletonList(
ItemID.ELITE_VOID_ROBE
))),
new EquipmentSlotItem(EquipmentInventorySlot.GLOVES, new ArrayList<>(Collections.singletonList(
ItemID.VOID_KNIGHT_GLOVES
)))
)), new EquipmentCombatBonus(0.125, 0, 0)),
ELITERANGERVOID(BonusType.VOID_KNIGHT, new EquipmentItemset(Arrays.asList(
new EquipmentSlotItem(EquipmentInventorySlot.HEAD, new ArrayList<>(Arrays.asList(
ItemID.VOID_RANGER_HELM,
ItemID.VOID_RANGER_HELM_11675
))),
new EquipmentSlotItem(EquipmentInventorySlot.BODY, new ArrayList<>(Collections.singletonList(
ItemID.ELITE_VOID_TOP
))),
new EquipmentSlotItem(EquipmentInventorySlot.LEGS, new ArrayList<>(Collections.singletonList(
ItemID.ELITE_VOID_ROBE
))),
new EquipmentSlotItem(EquipmentInventorySlot.GLOVES, new ArrayList<>(Collections.singletonList(
ItemID.VOID_KNIGHT_GLOVES
)))
)), new EquipmentCombatBonus(0, 0.125, 0)),
ELITEMAGICVOID(BonusType.EQUIPMENT, new EquipmentItemset(Arrays.asList(
new EquipmentSlotItem(EquipmentInventorySlot.HEAD, new ArrayList<>(Arrays.asList(
ItemID.VOID_MAGE_HELM,
ItemID.VOID_MAGE_HELM_11674
))),
new EquipmentSlotItem(EquipmentInventorySlot.BODY, new ArrayList<>(Collections.singletonList(
ItemID.ELITE_VOID_TOP
))),
new EquipmentSlotItem(EquipmentInventorySlot.LEGS, new ArrayList<>(Collections.singletonList(
ItemID.ELITE_VOID_ROBE
))),
new EquipmentSlotItem(EquipmentInventorySlot.GLOVES, new ArrayList<>(Collections.singletonList(
ItemID.VOID_KNIGHT_GLOVES
)))
)), new EquipmentCombatBonus(0, 0, 0.025)),
/*
* Special Melee Equipment
* */
OBISIDIAN(BonusType.SPECIAL, new EquipmentItemset(Arrays.asList(
new EquipmentSlotItem(EquipmentInventorySlot.HEAD, new ArrayList<>(Collections.singletonList(
ItemID.OBSIDIAN_HELMET
))),
new EquipmentSlotItem(EquipmentInventorySlot.BODY, new ArrayList<>(Collections.singletonList(
ItemID.OBSIDIAN_PLATEBODY
))),
new EquipmentSlotItem(EquipmentInventorySlot.LEGS, new ArrayList<>(Collections.singletonList(
ItemID.OBSIDIAN_PLATELEGS
))),
new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Arrays.asList(
ItemID.TOKTZXILAK,
ItemID.TOKTZXILEK,
ItemID.TZHAARKETEM,
ItemID.TZHAARKETOM,
ItemID.TOKTZXILAK_20554
)))
)), new EquipmentCombatBonus(0.1, 0, 0)),
BERSERKERNECKLACE(BonusType.SPECIAL, new EquipmentItemset(Arrays.asList(
new EquipmentSlotItem(EquipmentInventorySlot.AMULET, new ArrayList<>(Collections.singletonList(ItemID.BERSERKER_NECKLACE))),
new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Arrays.asList(
ItemID.TOKTZXILAK,
ItemID.TOKTZXILEK,
ItemID.TZHAARKETEM,
ItemID.TZHAARKETOM,
ItemID.TOKTZXILAK_20554
)))
)), new EquipmentCombatBonus(0.2, 0, 0)),
/*
* Magic Equipment
*/
ANCESTRAL_HAT(BonusType.EQUIPMENT, new EquipmentItemset(Collections.singletonList(
new EquipmentSlotItem(EquipmentInventorySlot.HEAD, new ArrayList<>(Collections.singletonList(
ItemID.ANCESTRAL_HAT
)))
)), new EquipmentCombatBonus(0, 0, 0.02)),
ANCESTRAL_ROBE_TOP(BonusType.EQUIPMENT, new EquipmentItemset(Collections.singletonList(
new EquipmentSlotItem(EquipmentInventorySlot.BODY, new ArrayList<>(Collections.singletonList(
ItemID.ANCESTRAL_ROBE_TOP
)))
)), new EquipmentCombatBonus(0, 0, 0.02)),
ANCESTRAL_ROBE_BOTTOM(BonusType.EQUIPMENT, new EquipmentItemset(Collections.singletonList(
new EquipmentSlotItem(EquipmentInventorySlot.LEGS, new ArrayList<>(Collections.singletonList(
ItemID.ANCESTRAL_ROBE_BOTTOM
)))
)), new EquipmentCombatBonus(0, 0, 0.02)),
IMBUED_GOD_CAPE(BonusType.EQUIPMENT, new EquipmentItemset(Collections.singletonList(
new EquipmentSlotItem(EquipmentInventorySlot.CAPE, new ArrayList<>(Arrays.asList(
ItemID.IMBUED_SARADOMIN_MAX_CAPE,
ItemID.IMBUED_SARADOMIN_CAPE,
ItemID.IMBUED_ZAMORAK_MAX_CAPE,
ItemID.IMBUED_ZAMORAK_CAPE,
ItemID.IMBUED_GUTHIX_MAX_CAPE,
ItemID.IMBUED_GUTHIX_CAPE
)))
)), new EquipmentCombatBonus(0, 0, 0.02)),
KODAI_WAND(BonusType.EQUIPMENT, new EquipmentItemset(Collections.singletonList(
new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Collections.singletonList(
ItemID.KODAI_WAND
)))
)), new EquipmentCombatBonus(0, 0, 0.15)),
OCCULT_NECKLACE(BonusType.EQUIPMENT, new EquipmentItemset(Collections.singletonList(
new EquipmentSlotItem(EquipmentInventorySlot.AMULET, new ArrayList<>(Arrays.asList(
ItemID.OCCULT_NECKLACE,
ItemID.OCCULT_NECKLACE_OR
)))
)), new EquipmentCombatBonus(0, 0, 0.10)),
STAFF_OF_THE_DEAD(BonusType.EQUIPMENT, new EquipmentItemset(Collections.singletonList(
new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Arrays.asList(
ItemID.STAFF_OF_THE_DEAD,
ItemID.TOXIC_STAFF_OF_THE_DEAD,
ItemID.STAFF_OF_LIGHT
)))
)), new EquipmentCombatBonus(0, 0, 0.15)),
TORMENTED_BRACELET(BonusType.EQUIPMENT, new EquipmentItemset(Collections.singletonList(
new EquipmentSlotItem(EquipmentInventorySlot.GLOVES, new ArrayList<>(Collections.singletonList(
ItemID.TORMENTED_BRACELET
)))
)), new EquipmentCombatBonus(0, 0, 0.05)),
SMOKE_STAFF(BonusType.EQUIPMENT, new EquipmentItemset(Collections.singletonList(
new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Arrays.asList(
ItemID.SMOKE_BATTLESTAFF,
ItemID.MYSTIC_SMOKE_STAFF
)))
)), new EquipmentCombatBonus(0, 0, 0.10), Collections.singletonList(new SpellBookRequirement(SpellBaseDamageConfig.SpellBook.NORMAL))),
/*
* Special magic bonusses
* */
CHAOS_GAUNTLETS(BonusType.SPECIAL, new EquipmentItemset(Collections.singletonList(
new EquipmentSlotItem(EquipmentInventorySlot.GLOVES, new ArrayList<>(Collections.singletonList(
ItemID.CHAOS_GAUNTLETS
))))),
new EquipmentCombatBonus(0, 0, 3),
Collections.singletonList(
new AutocastSpellRequirement(new ArrayList<>(Arrays.asList(
SpellBaseDamageConfig.AIR_BOLT,
SpellBaseDamageConfig.WATER_BOLT,
SpellBaseDamageConfig.EARTH_BOLT,
SpellBaseDamageConfig.FIRE_BOLT
)))
),
Operation.ADD
),
TOME_OF_FIRE(BonusType.MAGIC_SPECIAL, new EquipmentItemset(Collections.singletonList(
new EquipmentSlotItem(EquipmentInventorySlot.SHIELD, new ArrayList<>(Collections.singletonList(
ItemID.TOME_OF_FIRE
))))),
new EquipmentCombatBonus(0, 0, 0.5),
Collections.singletonList(
new AutocastSpellRequirement(new ArrayList<>(Arrays.asList(
SpellBaseDamageConfig.FIRE_BLAST,
SpellBaseDamageConfig.FIRE_BOLT,
SpellBaseDamageConfig.FIRE_STRIKE,
SpellBaseDamageConfig.FIRE_SURGE,
SpellBaseDamageConfig.FIRE_WAVE
)))
)
);
private static final Map<BonusType, ArrayList<EquipmentBonusConfig>> bonusTypes = new HashMap<>();
static
{
for (EquipmentBonusConfig equipmentBonus : values())
{
BonusType bonusType = equipmentBonus.bonusType;
if (!bonusTypes.containsKey(bonusType))
{
bonusTypes.put(bonusType, new ArrayList<>());
}
ArrayList<EquipmentBonusConfig> list = bonusTypes.get(bonusType);
list.add(equipmentBonus);
bonusTypes.put(bonusType, list);
}
}
private final EquipmentItemset itemset;
private BonusType bonusType;
private EquipmentCombatBonus equipmentCombatBonus;
private List<Requirement> requirements = new ArrayList<>();
private Operation operation = Operation.MULTIPLY;
EquipmentBonusConfig(BonusType bonusType, EquipmentItemset itemset, EquipmentCombatBonus equipmentCombatBonus)
{
this.bonusType = bonusType;
this.itemset = itemset;
this.equipmentCombatBonus = equipmentCombatBonus;
}
EquipmentBonusConfig(BonusType bonusType, EquipmentItemset itemset, EquipmentCombatBonus equipmentCombatBonus, List<Requirement> requirements)
{
this.bonusType = bonusType;
this.itemset = itemset;
this.equipmentCombatBonus = equipmentCombatBonus;
this.requirements = requirements;
}
EquipmentBonusConfig(BonusType bonusType, EquipmentItemset itemset, EquipmentCombatBonus equipmentCombatBonus, List<Requirement> requirements, Operation operation)
{
this.bonusType = bonusType;
this.itemset = itemset;
this.equipmentCombatBonus = equipmentCombatBonus;
this.requirements = requirements;
this.operation = operation;
}
public static ArrayList<EquipmentBonusConfig> getBonusByType(BonusType bonusType)
{
if (!bonusTypes.containsKey(bonusType))
{
return new ArrayList<>();
}
return bonusTypes.get(bonusType);
}
public EquipmentItemset getItemset()
{
return itemset;
}
public Operation getOperation()
{
return operation;
}
public double getBonus(MaxHitCalculator.CombatMethod combatMethod)
{
return this.equipmentCombatBonus.getCombatBonus(combatMethod);
}
public boolean meetsRequirements(Client client)
{
return requirements.stream().allMatch(requirement -> requirement.meetsRequirements(client));
}
public enum BonusType
{
EQUIPMENT,
SLAYER,
VOID_KNIGHT,
SPECIAL,
MAGIC_SPECIAL
}
public enum Operation
{
ADD,
MULTIPLY
}
}

View File

@@ -0,0 +1,68 @@
/*
* Copyright (c) 2019, Bartvollebregt <https://github.com/Bartvollebregt>
* 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.maxhit.config;
import net.runelite.api.Varbits;
import net.runelite.client.plugins.maxhit.calculators.MaxHitCalculator;
public enum PrayerBonusConfig
{
BURST_OF_STRENGTH(MaxHitCalculator.CombatMethod.MELEE, Varbits.PRAYER_BURST_OF_STRENGTH, 0.05),
SUPERHUMAN_STRENGTH(MaxHitCalculator.CombatMethod.MELEE, Varbits.PRAYER_SUPERHUMAN_STRENGTH, 0.1),
ULTIMATE_STRENGTH(MaxHitCalculator.CombatMethod.MELEE, Varbits.PRAYER_ULTIMATE_STRENGTH, 0.15),
CHIVALRY(MaxHitCalculator.CombatMethod.MELEE, Varbits.PRAYER_CHIVALRY, 0.18),
PIETY(MaxHitCalculator.CombatMethod.MELEE, Varbits.PRAYER_PIETY, 0.23),
SHARP_EYE(MaxHitCalculator.CombatMethod.RANGE, Varbits.PRAYER_SHARP_EYE, 0.05),
HAWK_EYE(MaxHitCalculator.CombatMethod.RANGE, Varbits.PRAYER_HAWK_EYE, 0.1),
EAGLE_EYE(MaxHitCalculator.CombatMethod.RANGE, Varbits.PRAYER_EAGLE_EYE, 0.15),
RIGOUR(MaxHitCalculator.CombatMethod.RANGE, Varbits.PRAYER_RIGOUR, 0.23);
private final MaxHitCalculator.CombatMethod combatMethod;
private final Varbits prayerVarbit;
private final double strengthBonus;
PrayerBonusConfig(MaxHitCalculator.CombatMethod combatMethod, Varbits prayerVarbit, double strengthBonus)
{
this.combatMethod = combatMethod;
this.prayerVarbit = prayerVarbit;
this.strengthBonus = strengthBonus;
}
public MaxHitCalculator.CombatMethod getCombatMethod()
{
return combatMethod;
}
public Varbits getPrayerVarbit()
{
return prayerVarbit;
}
public double getStrengthBonus()
{
return strengthBonus;
}
}

View File

@@ -0,0 +1,134 @@
/*
* Copyright (c) 2019, Bartvollebregt <https://github.com/Bartvollebregt>
* 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.maxhit.config;
import java.util.Arrays;
public enum SpellBaseDamageConfig
{
/*
* Normal Spellbook
* */
AIR_STRIKE(SpellBook.NORMAL, 1, 2),
WATER_STRIKE(SpellBook.NORMAL, 2, 4),
EARTH_STRIKE(SpellBook.NORMAL, 3, 6),
FIRE_STRIKE(SpellBook.NORMAL, 4, 8),
AIR_BOLT(SpellBook.NORMAL, 5, 9),
WATER_BOLT(SpellBook.NORMAL, 6, 10),
EARTH_BOLT(SpellBook.NORMAL, 7, 11),
FIRE_BOLT(SpellBook.NORMAL, 8, 12),
WIND_BLAST(SpellBook.NORMAL, 9, 13),
WATER_BLAST(SpellBook.NORMAL, 10, 14),
EARTH_BLAST(SpellBook.NORMAL, 11, 15),
FIRE_BLAST(SpellBook.NORMAL, 12, 16),
AIR_WAVE(SpellBook.NORMAL, 13, 17),
WATER_WAVE(SpellBook.NORMAL, 14, 18),
EARTH_WAVE(SpellBook.NORMAL, 15, 19),
FIRE_WAVE(SpellBook.NORMAL, 16, 20),
AIR_SURGE(SpellBook.NORMAL, 48, 21),
WATER_SURGE(SpellBook.NORMAL, 49, 22),
EARTH_SURGE(SpellBook.NORMAL, 50, 23),
FIRE_SURGE(SpellBook.NORMAL, 51, 24),
/*
* Ancient Spellbook
* */
SMOKE_RUSH(SpellBook.ANCIENT, 31, 14),
SHADOW_RUSH(SpellBook.ANCIENT, 32, 15),
BLOOD_RUSH(SpellBook.ANCIENT, 33, 16),
ICE_RUSH(SpellBook.ANCIENT, 34, 17),
SMOKE_BURST(SpellBook.ANCIENT, 35, 18),
SHADOW_BURST(SpellBook.ANCIENT, 36, 19),
BLOOD_BURST(SpellBook.ANCIENT, 37, 21),
ICE_BURST(SpellBook.ANCIENT, 38, 22),
SMOKE_BLITZ(SpellBook.ANCIENT, 39, 23),
SHADOW_BLITZ(SpellBook.ANCIENT, 40, 24),
BLOOD_BLITZ(SpellBook.ANCIENT, 41, 25),
ICE_BLITZ(SpellBook.ANCIENT, 42, 26),
SMOKE_BARRAGE(SpellBook.ANCIENT, 43, 27),
SHADOW_BARRAGE(SpellBook.ANCIENT, 44, 28),
BLOOD_BARRAGE(SpellBook.ANCIENT, 55, 29),
ICE_BARRAGE(SpellBook.ANCIENT, 46, 30),
/*
* Other spells
* */
CRUMBLE_UNDEAD(SpellBook.OTHER, 17, 15),
IBAN_BLAST(SpellBook.OTHER, 47, 25),
FLAMES_OF_ZAMAROK(SpellBook.OTHER, 20, 20),
CLAWS_OF_GUTHIX(SpellBook.OTHER, 19, 20),
SARADOMIN_STRIKE(SpellBook.OTHER, 52, 20),
/*
* Custom Formula spells
* */
MAGIC_DART(SpellBook.OTHER, 18, 0);
private final SpellBook spellBook;
private final int spellID;
private final int baseDamage;
SpellBaseDamageConfig(SpellBook spellBook, int spellID, int baseDamage)
{
this.spellBook = spellBook;
this.spellID = spellID;
this.baseDamage = baseDamage;
}
public static SpellBaseDamageConfig findSpellById(int spellID)
{
return Arrays.stream(values()).filter(spell -> spell.getSpellID() == spellID).findFirst().orElse(null);
}
public int getSpellID()
{
return spellID;
}
public int getBaseDamage()
{
return baseDamage;
}
public SpellBook getSpellBook()
{
return spellBook;
}
public enum SpellBook
{
NORMAL,
ANCIENT,
OTHER
}
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright (c) 2019, Bartvollebregt <https://github.com/Bartvollebregt>
* 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.maxhit.equipment;
import net.runelite.client.plugins.maxhit.calculators.MaxHitCalculator;
public class EquipmentCombatBonus
{
private final double meleeBonus;
private final double rangeBonus;
private final double magicBonus;
public EquipmentCombatBonus(double meleeBonus, double rangeBonus, double magicBonus)
{
this.meleeBonus = meleeBonus;
this.rangeBonus = rangeBonus;
this.magicBonus = magicBonus;
}
public double getCombatBonus(MaxHitCalculator.CombatMethod combatMethod)
{
switch (combatMethod)
{
default:
case MELEE:
return this.meleeBonus;
case RANGE:
return this.rangeBonus;
case MAGIC:
return this.magicBonus;
}
}
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright (c) 2019, Bartvollebregt <https://github.com/Bartvollebregt>
* 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.maxhit.equipment;
import net.runelite.api.EquipmentInventorySlot;
import net.runelite.api.Item;
public class EquipmentHelper
{
public static boolean wearsItemSet(Item[] equipedItems, EquipmentItemset itemSet)
{
return itemSet.getItems().stream().allMatch(item -> wearsItem(equipedItems, item));
}
private static boolean wearsItem(Item[] equipedItems, EquipmentInventorySlot slot, int itemId)
{
Item item = equipedItems[slot.getSlotIdx()];
if (item == null)
{
return false;
}
return item.getId() == itemId;
}
public static boolean wearsItem(Item[] equipedItems, EquipmentSlotItem equipmentSlotItem)
{
return equipmentSlotItem.getItems().stream().anyMatch(itemId ->
wearsItem(equipedItems, equipmentSlotItem.getEquipmentSlot(), itemId)
);
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (c) 2019, Bartvollebregt <https://github.com/Bartvollebregt>
* 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.maxhit.equipment;
import java.util.List;
public class EquipmentItemset
{
private final List<EquipmentSlotItem> items;
public EquipmentItemset(List<EquipmentSlotItem> items)
{
this.items = items;
}
public List<EquipmentSlotItem> getItems()
{
return items;
}
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright (c) 2019, Bartvollebregt <https://github.com/Bartvollebregt>
* 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.maxhit.equipment;
import net.runelite.api.EquipmentInventorySlot;
import java.util.ArrayList;
public class EquipmentSlotItem
{
private final EquipmentInventorySlot equipmentSlot;
private final ArrayList<Integer> itemIds;
public EquipmentSlotItem(EquipmentInventorySlot equipmentSlot, ArrayList<Integer> itemIds)
{
this.equipmentSlot = equipmentSlot;
this.itemIds = itemIds;
}
public ArrayList<Integer> getItems()
{
return this.itemIds;
}
public EquipmentInventorySlot getEquipmentSlot()
{
return this.equipmentSlot;
}
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright (c) 2019, Bartvollebregt <https://github.com/Bartvollebregt>
* 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.maxhit.requirements;
import net.runelite.api.Client;
import net.runelite.api.Varbits;
import net.runelite.client.plugins.maxhit.config.SpellBaseDamageConfig;
import java.util.ArrayList;
public class AutocastSpellRequirement implements Requirement
{
private final ArrayList<SpellBaseDamageConfig> autocastSpells;
public AutocastSpellRequirement(ArrayList<SpellBaseDamageConfig> autocastSpells)
{
this.autocastSpells = autocastSpells;
}
@Override
public boolean meetsRequirements(Client client)
{
int autoCastSpellId = client.getVar(Varbits.AUTO_CAST_SPELL);
if (autoCastSpellId == 0)
{
return false;
}
return this.autocastSpells.stream().anyMatch(spell -> spell.getSpellID() == autoCastSpellId);
}
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright (c) 2019, Bartvollebregt <https://github.com/Bartvollebregt>
* 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.maxhit.requirements;
import net.runelite.api.Client;
import net.runelite.api.InventoryID;
import net.runelite.api.Item;
import net.runelite.api.ItemContainer;
import net.runelite.client.plugins.maxhit.equipment.EquipmentHelper;
import net.runelite.client.plugins.maxhit.equipment.EquipmentSlotItem;
public class EquipmentItemRequirement implements Requirement
{
private final EquipmentSlotItem item;
public EquipmentItemRequirement(EquipmentSlotItem item)
{
this.item = item;
}
@Override
public boolean meetsRequirements(Client client)
{
ItemContainer equipmentContainer = client.getItemContainer(InventoryID.EQUIPMENT);
if (equipmentContainer == null)
{
return false;
}
Item[] equipedItems = equipmentContainer.getItems();
return EquipmentHelper.wearsItem(equipedItems, this.item);
}
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright (c) 2019, Bartvollebregt <https://github.com/Bartvollebregt>
* 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.maxhit.requirements;
import net.runelite.api.Client;
import net.runelite.api.InventoryID;
import net.runelite.api.Item;
import net.runelite.api.ItemContainer;
import net.runelite.client.plugins.maxhit.equipment.EquipmentHelper;
import net.runelite.client.plugins.maxhit.equipment.EquipmentItemset;
public class EquipmentItemSetRequirement implements Requirement
{
private final EquipmentItemset itemSet;
public EquipmentItemSetRequirement(EquipmentItemset itemSet)
{
this.itemSet = itemSet;
}
@Override
public boolean meetsRequirements(Client client)
{
ItemContainer equipmentContainer = client.getItemContainer(InventoryID.EQUIPMENT);
if (equipmentContainer == null)
{
return false;
}
Item[] equipedItems = equipmentContainer.getItems();
return EquipmentHelper.wearsItemSet(equipedItems, this.itemSet);
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright (c) 2019, Bartvollebregt <https://github.com/Bartvollebregt>
* 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.maxhit.requirements;
import net.runelite.api.Client;
public interface Requirement
{
boolean meetsRequirements(Client client);
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (c) 2019, Bartvollebregt <https://github.com/Bartvollebregt>
* 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.maxhit.requirements;
import net.runelite.api.Client;
import net.runelite.api.Varbits;
import net.runelite.client.plugins.maxhit.config.SpellBaseDamageConfig;
public class SpellBookRequirement implements Requirement
{
private final SpellBaseDamageConfig.SpellBook spellBook;
public SpellBookRequirement(SpellBaseDamageConfig.SpellBook spellBook)
{
this.spellBook = spellBook;
}
@Override
public boolean meetsRequirements(Client client)
{
int autoCastSpellId = client.getVar(Varbits.AUTO_CAST_SPELL);
if (autoCastSpellId == 0)
{
return false;
}
SpellBaseDamageConfig autoCastSpell = SpellBaseDamageConfig.findSpellById(autoCastSpellId);
return autoCastSpell.getSpellBook() == this.spellBook;
}
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright (c) 2019, Bartvollebregt <https://github.com/Bartvollebregt>
* 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.maxhit.requirements;
import net.runelite.api.Client;
import net.runelite.api.Varbits;
import net.runelite.client.plugins.maxhit.config.SpellBaseDamageConfig;
public class SpellRequirement implements Requirement
{
private final SpellBaseDamageConfig spellBaseDamageConfig;
public SpellRequirement(SpellBaseDamageConfig spellBaseDamageConfig)
{
this.spellBaseDamageConfig = spellBaseDamageConfig;
}
@Override
public boolean meetsRequirements(Client client)
{
int autoCastSpellId = client.getVar(Varbits.AUTO_CAST_SPELL);
if (autoCastSpellId == 0)
{
return false;
}
return autoCastSpellId == this.spellBaseDamageConfig.getSpellID();
}
}

View File

@@ -282,4 +282,14 @@ public interface MenuEntrySwapperConfig extends Config
{
return true;
}
@ConfigItem(
keyName = "swapRogueschests",
name = "Rogueschests",
description = "Swap Rogueschests from open to Search for traps"
)
default boolean swapRogueschests()
{
return true;
}
}

View File

@@ -544,6 +544,10 @@ public class MenuEntrySwapperPlugin extends Plugin
{
swap("pick-lots", option, target, true);
}
else if (config.swapRogueschests() && target.contains("chest"))
{
swap("search for traps", option, target, true);
}
else if (config.shiftClickCustomization() && shiftModifier && !option.equals("use"))
{
Integer customOption = getSwapConfig(eventId);

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2017, Adam <Adam@sigterm.info>
* Copyright (c) 2019, Yani <yani@xenokore.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -24,97 +25,220 @@
*/
package net.runelite.client.plugins.pestcontrol;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import static net.runelite.client.plugins.pestcontrol.Portal.BLUE;
import static net.runelite.client.plugins.pestcontrol.Portal.PURPLE;
import static net.runelite.client.plugins.pestcontrol.Portal.RED;
import static net.runelite.client.plugins.pestcontrol.Portal.YELLOW;
import net.runelite.api.Client;
import net.runelite.api.NPC;
import net.runelite.api.coords.WorldPoint;
import net.runelite.api.events.GameTick;
@Slf4j
class Game
public class Game
{
private Client client;
private PestControlPlugin plugin;
@Getter
private Portal bluePortal = new Portal(PortalColor.BLUE, WidgetPortal.BLUE);
@Getter
private Portal purplePortal = new Portal(PortalColor.PURPLE, WidgetPortal.PURPLE);
@Getter
private Portal yellowPortal = new Portal(PortalColor.YELLOW, WidgetPortal.YELLOW);
@Getter
private Portal redPortal = new Portal(PortalColor.RED, WidgetPortal.RED);
@Getter
private int shieldsDropped = 0;
// Game starts with all possible rotations
private Rotation[] possibleRotations = Rotation.values();
// Number of shields dropped
private int shieldsDropped;
private PortalRotation[] possibleRotations = PortalRotation.values();
@Getter
private final PortalContext purple = new PortalContext(PURPLE);
@Getter
private final PortalContext blue = new PortalContext(BLUE);
@Getter
private final PortalContext yellow = new PortalContext(YELLOW);
@Getter
private final PortalContext red = new PortalContext(RED);
private boolean portalLocationsSet = false;
void fall(String color)
private Instant startTime = Instant.now();
public Game(Client client, PestControlPlugin plugin)
{
switch (color.toLowerCase())
this.client = client;
this.plugin = plugin;
}
public void onGameTick(GameTick gameTickEvent)
{
if (!portalLocationsSet)
{
loadPortalLocations();
}
WidgetOverlay widgetOverlay = plugin.getWidgetOverlay();
if (!purplePortal.isDead() && widgetOverlay.getPortalHitpoints(PortalColor.PURPLE) == 0)
{
killPortal(purplePortal);
}
if (!yellowPortal.isDead() && widgetOverlay.getPortalHitpoints(PortalColor.YELLOW) == 0)
{
killPortal(yellowPortal);
}
if (!redPortal.isDead() && widgetOverlay.getPortalHitpoints(PortalColor.RED) == 0)
{
killPortal(redPortal);
}
if (!bluePortal.isDead() && widgetOverlay.getPortalHitpoints(PortalColor.BLUE) == 0)
{
killPortal(bluePortal);
}
}
public void lowerPortalShield(String portalColor)
{
switch (portalColor.toLowerCase())
{
case "purple":
fall(purple);
lowerPortalShield(purplePortal);
break;
case "red":
fall(red);
lowerPortalShield(redPortal);
break;
case "yellow":
fall(yellow);
lowerPortalShield(yellowPortal);
break;
case "blue":
fall(blue);
lowerPortalShield(bluePortal);
break;
}
}
private void fall(PortalContext portal)
private void lowerPortalShield(Portal portal)
{
if (!portal.isShielded())
{
return;
}
log.debug("Shield dropped for {}", portal.getPortal());
log.debug("Shield dropped for {}", portal.getColor());
portal.setPortalState(PortalState.ACTIVE);
portal.setShielded(false);
int shieldDrop = shieldsDropped++;
// Remove impossible rotations
List<Rotation> rotations = new ArrayList<>();
List<PortalRotation> rotations = new ArrayList<>();
for (Rotation rotation : possibleRotations)
for (PortalRotation rotation : possibleRotations)
{
if (rotation.getPortal(shieldDrop) == portal.getPortal())
if (rotation.getPortal(this, shieldDrop) == portal)
{
rotations.add(rotation);
}
}
possibleRotations = rotations.toArray(new Rotation[rotations.size()]);
possibleRotations = rotations.toArray(new PortalRotation[rotations.size()]);
}
void die(PortalContext portal)
public void killPortal(Portal portal)
{
if (portal.isDead())
{
return;
}
log.debug("Portal {} died", portal.getPortal());
log.debug("Portal {} died", portal.getColor());
portal.setDead(true);
portal.setPortalState(PortalState.DEAD);
}
Collection<Portal> getNextPortals()
private boolean loadPortalLocations()
{
NPC squire = null;
for (NPC npc : client.getNpcs())
{
if (PestControlNpc.isIngameSquireId(npc.getId()))
{
squire = npc;
break;
}
}
if (squire != null)
{
log.debug("In-game Squire found: {}", squire);
setPortalLocations(squire.getWorldLocation());
return true;
}
return false;
}
public void setPortalLocations(WorldPoint squireLocation)
{
int x = squireLocation.getX();
int y = squireLocation.getY();
purplePortal.setLocation(new WorldPoint(x - 26, y - 15, 0));
bluePortal.setLocation(new WorldPoint(x + 26, y - 18, 0));
yellowPortal.setLocation(new WorldPoint(x + 15, y - 36, 0));
redPortal.setLocation(new WorldPoint(x - 9, y - 37, 0));
portalLocationsSet = true;
}
public List<Portal> getPortals()
{
List<Portal> portalList = new ArrayList<Portal>();
portalList.add(getPurplePortal());
portalList.add(getBluePortal());
portalList.add(getYellowPortal());
portalList.add(getRedPortal());
return portalList;
}
public Portal getPortal(PortalColor portalColor)
{
if (bluePortal.getColor() == portalColor)
{
return bluePortal;
}
if (redPortal.getColor() == portalColor)
{
return redPortal;
}
if (purplePortal.getColor() == portalColor)
{
return purplePortal;
}
if (yellowPortal.getColor() == portalColor)
{
return yellowPortal;
}
return null;
}
public Collection<Portal> getNextPortals()
{
List<Portal> portals = new ArrayList<>();
for (Rotation rotation : possibleRotations)
for (PortalRotation rotation : possibleRotations)
{
Portal portal = rotation.getPortal(shieldsDropped);
Portal portal = rotation.getPortal(this, shieldsDropped);
if (portal != null && !portals.contains(portal))
{
@@ -124,4 +248,40 @@ class Game
return portals;
}
public Collection<Portal> getActivePortals()
{
List<Portal> portals = new ArrayList<>();
for (Portal portal : getPortals())
{
if (portal.isActive())
{
portals.add(portal);
}
}
return portals;
}
public Duration getTimeTillNextPortal()
{
Instant nextShieldDrop;
if (shieldsDropped == 4)
{
return null;
}
if (shieldsDropped == 0)
{
nextShieldDrop = Instant.ofEpochSecond(startTime.getEpochSecond() + 17);
}
else
{
nextShieldDrop = Instant.ofEpochSecond(startTime.getEpochSecond() + 17 + (30 * shieldsDropped));
}
return Duration.between(Instant.now(), nextShieldDrop);
}
}

View File

@@ -0,0 +1,170 @@
/*
* Copyright (c) 2019, Yani <yani@xenokore.com>
* 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.pestcontrol;
import com.google.inject.Inject;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Polygon;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.Player;
import net.runelite.api.Point;
import net.runelite.api.Tile;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer;
import net.runelite.client.ui.overlay.OverlayPosition;
import net.runelite.client.ui.overlay.tooltip.Tooltip;
import net.runelite.client.ui.overlay.tooltip.TooltipManager;
import net.runelite.client.util.ColorUtil;
@Slf4j
public class GangplankOverlay extends Overlay
{
private final Client client;
private final PestControlConfig config;
private final PestControlPlugin plugin;
private final TooltipManager tooltipManager;
@Inject
GangplankOverlay(Client client, PestControlConfig config, PestControlPlugin plugin, TooltipManager toolTipManager)
{
this.config = config;
this.plugin = plugin;
this.client = client;
this.tooltipManager = toolTipManager;
setPosition(OverlayPosition.DYNAMIC);
setLayer(OverlayLayer.ABOVE_SCENE);
}
@Override
public Dimension render(Graphics2D graphics)
{
if (!plugin.isOnPestControlMainIsland())
{
return null;
}
Player localPlayer = client.getLocalPlayer();
if (localPlayer == null)
{
return null;
}
int combatLevel = localPlayer.getCombatLevel();
Color noviceCbColor = (combatLevel >= 40) ? Color.GREEN : Color.RED;
Color intermediateCbColor = (combatLevel >= 70) ? Color.GREEN : Color.RED;
Color veteranCbColor = (combatLevel >= 100) ? Color.GREEN : Color.RED;
Tile noviceGangplankTile = plugin.getNoviceGangplankTile();
Tile intermediateGangplankTile = plugin.getIntermediateGangplankTile();
Tile veteranGangplankTile = plugin.getVeteranGangplankTile();
Point mousePosition = client.getMouseCanvasPosition();
String tooltipString = null;
if (noviceGangplankTile != null)
{
Polygon polygon = noviceGangplankTile.getGameObjects()[0].getConvexHull();
if (polygon != null)
{
graphics.setColor(noviceCbColor);
graphics.setStroke(new BasicStroke(2));
graphics.drawPolygon(polygon);
graphics.setColor(setColorAlpha(noviceCbColor, 45));
graphics.fill(polygon);
if (polygon.contains(mousePosition.getX(), mousePosition.getY()))
{
tooltipString = ColorUtil.wrapWithColorTag("Combat 40+", noviceCbColor) + " (3 points)";
graphics.setColor(setColorAlpha(noviceCbColor, 65));
graphics.fill(polygon);
}
}
}
if (intermediateGangplankTile != null)
{
Polygon polygon = intermediateGangplankTile.getGameObjects()[0].getConvexHull();
if (polygon != null)
{
graphics.setColor(intermediateCbColor);
graphics.setStroke(new BasicStroke(2));
graphics.drawPolygon(polygon);
graphics.setColor(setColorAlpha(intermediateCbColor, 45));
graphics.fill(polygon);
if (polygon.contains(mousePosition.getX(), mousePosition.getY()))
{
tooltipString = ColorUtil.wrapWithColorTag("Combat 70+", intermediateCbColor) + " (4 points)";
graphics.setColor(setColorAlpha(intermediateCbColor, 65));
graphics.fill(polygon);
}
}
}
if (veteranGangplankTile != null)
{
Polygon polygon = veteranGangplankTile.getGameObjects()[0].getConvexHull();
if (polygon != null)
{
graphics.setColor(veteranCbColor);
graphics.setStroke(new BasicStroke(2));
graphics.drawPolygon(polygon);
graphics.setColor(setColorAlpha(veteranCbColor, 45));
graphics.fill(polygon);
if (polygon.contains(mousePosition.getX(), mousePosition.getY()))
{
tooltipString = ColorUtil.wrapWithColorTag("Combat 100+", veteranCbColor) + " (5 points)";
graphics.setColor(setColorAlpha(veteranCbColor, 65));
graphics.fill(polygon);
}
}
}
if (tooltipString != null)
{
tooltipManager.add(new Tooltip(tooltipString));
}
return null;
}
private Color setColorAlpha(Color color, int alpha)
{
return new Color(
color.getRed(),
color.getGreen(),
color.getBlue(),
alpha
);
}
}

View File

@@ -0,0 +1,175 @@
/*
* Copyright (c) 2019, Yani <yani@xenokore.com>
* 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.pestcontrol;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.inject.Inject;
import net.runelite.api.Client;
import net.runelite.api.NPC;
import net.runelite.api.coords.WorldPoint;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer;
import net.runelite.client.ui.overlay.OverlayPosition;
public class HintArrowOverlay extends Overlay
{
private final PestControlConfig config;
private final PestControlPlugin plugin;
private final Client client;
@Inject
HintArrowOverlay(PestControlConfig config, PestControlPlugin plugin, Client client)
{
this.config = config;
this.plugin = plugin;
this.client = client;
setPosition(OverlayPosition.DYNAMIC);
setLayer(OverlayLayer.ABOVE_SCENE);
}
@Override
public Dimension render(Graphics2D graphics)
{
if (plugin.getGame() == null)
{
return null;
}
List<NPC> visibleActivePortals = new ArrayList<>();
List<NPC> visibleShieldedPortals = new ArrayList<>();
for (NPC npc : client.getNpcs())
{
if (PestControlNpc.isActivePortalId(npc.getId()))
{
visibleActivePortals.add(npc);
}
}
if (!visibleActivePortals.isEmpty())
{
NPC closestPortalNpc = getClosestNpc(visibleActivePortals);
if (closestPortalNpc != null)
{
NPC currentHintArrowTarget = client.getHintArrowNpc();
if (currentHintArrowTarget == null || currentHintArrowTarget != closestPortalNpc)
{
client.setHintArrow(closestPortalNpc);
}
}
return null;
}
Portal closestActivePortal = getClosestPortal(PortalState.ACTIVE);
if (closestActivePortal != null)
{
WorldPoint currentHintArrowLocation = client.getHintArrowPoint();
WorldPoint closestActivePortalLocation = closestActivePortal.getLocation();
if (currentHintArrowLocation == null || currentHintArrowLocation != closestActivePortalLocation)
{
client.setHintArrow(closestActivePortalLocation);
}
return null;
}
Collection<Portal> nextPortalList = plugin.getGame().getNextPortals();
if (nextPortalList.size() == 1)
{
client.setHintArrow(nextPortalList.iterator().next().getLocation());
return null;
}
return null;
}
private NPC getClosestNpc(List<NPC> npcList)
{
WorldPoint currentLocation = client.getLocalPlayer().getWorldLocation();
NPC closestNpc = null;
int currentShortestDistance = 1337;
int distanceToNpc;
for (NPC npc : npcList)
{
if (closestNpc != null)
{
distanceToNpc = npc.getWorldLocation().distanceTo(currentLocation);
if (distanceToNpc < currentShortestDistance)
{
closestNpc = npc;
currentShortestDistance = distanceToNpc;
}
}
else
{
closestNpc = npc;
}
}
return closestNpc;
}
private Portal getClosestPortal(PortalState portalState)
{
WorldPoint currentLocation = client.getLocalPlayer().getWorldLocation();
Portal closestPortal = null;
int currentShortestDistance = 1337;
int distanceToWorldPoint;
for (Portal portal : plugin.getGame().getPortals())
{
if (portal.getPortalState() != portalState)
{
continue;
}
distanceToWorldPoint = portal.getLocation().distanceTo(currentLocation);
if (distanceToWorldPoint < currentShortestDistance)
{
closestPortal = portal;
currentShortestDistance = distanceToWorldPoint;
}
}
return closestPortal;
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright (c) 2019, Yani <yani@xenokore.com>
* 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.pestcontrol;
import java.awt.Color;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import net.runelite.client.plugins.pestcontrol.config.NpcHighlightStyle;
@AllArgsConstructor
@Getter
@Setter
public class NpcHighlightContext
{
private NpcHighlightStyle npcRenderStyle;
private Color color;
private boolean showNpcName = false;
}

View File

@@ -0,0 +1,163 @@
/*
* Copyright (c) 2019, Yani <yani@xenokore.com>
* 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.pestcontrol;
import com.google.inject.Inject;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.util.HashMap;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.NPC;
import net.runelite.api.Perspective;
import net.runelite.api.Point;
import net.runelite.client.plugins.pestcontrol.config.NpcHighlightStyle;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer;
import net.runelite.client.ui.overlay.OverlayPosition;
import net.runelite.client.ui.overlay.OverlayUtil;
@Slf4j
public class NpcHighlightOverlay extends Overlay
{
private final PestControlConfig config;
private final PestControlPlugin plugin;
private final Client client;
@Inject
NpcHighlightOverlay(PestControlConfig config, PestControlPlugin plugin, Client client)
{
this.config = config;
this.plugin = plugin;
this.client = client;
setPosition(OverlayPosition.DYNAMIC);
setLayer(OverlayLayer.ABOVE_SCENE);
}
@Override
public Dimension render(Graphics2D graphics)
{
if (plugin.getGame() == null)
{
return null;
}
HashMap highlightedNpcList = plugin.getHighlightedNpcList();
for (NPC npc : client.getNpcs())
{
if (!highlightedNpcList.containsKey(npc.getId()))
{
continue;
}
NpcHighlightContext npcHighlightContext = plugin.getHighlightedNpcList().get(npc.getId());
String name = npcHighlightContext.isShowNpcName() ? npc.getName() : null;
Color color = npcHighlightContext.getColor();
NpcHighlightStyle highlightStyle = npcHighlightContext.getNpcRenderStyle();
switch (highlightStyle)
{
case HULL:
{
renderHullOverlay(graphics, npc, color);
break;
}
case TILE:
{
renderTileOverlay(graphics, npc, color);
break;
}
case BOTH:
{
renderHullOverlay(graphics, npc, color);
renderTileOverlay(graphics, npc, color);
break;
}
}
if (name != null)
{
renderTextOverlay(graphics, npc, name, color);
}
}
return null;
}
private void renderTileOverlay(Graphics2D graphics, NPC npc, Color color)
{
Polygon polygon;
Color fillColor;
// Double the polygon size if it's a Brawler
if (PestControlNpc.isBrawlerId(npc.getId()))
{
polygon = Perspective.getCanvasTileAreaPoly(client, npc.getLocalLocation(), 2);
fillColor = new Color(color.getRed(), color.getGreen(), color.getBlue(), 35);
}
else
{
polygon = npc.getCanvasTilePoly();
fillColor = new Color(0, 0, 0, 50);
}
if (polygon != null)
{
graphics.setColor(color);
graphics.setStroke(new BasicStroke(2));
graphics.drawPolygon(polygon);
graphics.setColor(fillColor);
graphics.fillPolygon(polygon);
}
}
private void renderHullOverlay(Graphics2D graphics, NPC npc, Color color)
{
Polygon objectClickbox = npc.getConvexHull();
if (objectClickbox != null)
{
graphics.setColor(color);
graphics.setStroke(new BasicStroke(2));
graphics.draw(objectClickbox);
graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), 20));
graphics.fill(objectClickbox);
}
}
private void renderTextOverlay(Graphics2D graphics, NPC npc, String text, Color color)
{
Point textLocation = npc.getCanvasTextLocation(graphics, text, npc.getLogicalHeight() + 40);
if (textLocation != null)
{
OverlayUtil.renderTextLocation(graphics, textLocation, text, color);
}
}
}

View File

@@ -0,0 +1,194 @@
/*
* Copyright (c) 2019, Yani <yani@xenokore.com>
* 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.pestcontrol;
import java.awt.Color;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
import net.runelite.client.plugins.pestcontrol.config.HighlightPortalOption;
import net.runelite.client.plugins.pestcontrol.config.NpcHighlightStyle;
@ConfigGroup("pestcontrol")
public interface PestControlConfig extends Config
{
@ConfigItem(
keyName = "showHintArrow",
name = "Show hint arrows",
description = "Show hint arrows to the portals that can be attacked.",
position = 1
)
default boolean showHintArrow()
{
return true;
}
@ConfigItem(
keyName = "showPortalWeakness",
name = "Show portal weakness",
description = "Show the combat style weakness of the portals. For melee the attack styles are shown: Stab/Crush/Slash",
position = 2
)
default boolean showPortalWeakness()
{
return false;
}
@ConfigItem(
keyName = "highlightGangplanks",
name = "Highlight gangplanks",
description = "Highlight the boarding gangplanks and show the required combat level.",
position = 3
)
default boolean highlightGangplanks()
{
return true;
}
@ConfigItem(
keyName = "highlightPortals",
name = "Highlight portals",
description = "Highlight all, active or shielded portals.",
position = 4
)
default HighlightPortalOption portalHighlight()
{
return HighlightPortalOption.ACTIVE;
}
@ConfigItem(
keyName = "activePortalColor",
name = "Active portal color",
description = "Color of the portals that can be attacked.",
position = 5
)
default Color activePortalColor()
{
return Color.GREEN;
}
@ConfigItem(
keyName = "shieldedPortalColor",
name = "Shielded portal color",
description = "Color of the portals that are shielded.",
position = 6
)
default Color shieldedPortalColor()
{
return Color.BLUE;
}
@ConfigItem(
keyName = "highlightSpinners",
name = "Highlight Spinners",
description = "Highlights Spinners. Highlighting them is recommended as Spinners heal the portals.",
position = 7
)
default NpcHighlightStyle highlightSpinners()
{
return NpcHighlightStyle.BOTH;
}
@ConfigItem(
keyName = "spinnerColor",
name = "Spinner color",
description = "Color of highlighted Spinners.",
position = 8
)
default Color spinnerColor()
{
return Color.CYAN;
}
@ConfigItem(
keyName = "highlightBrawlers",
name = "Highlight Brawlers",
description = "Highlights Brawlers.",
position = 9
)
default NpcHighlightStyle highlightBrawlers()
{
return NpcHighlightStyle.TILE;
}
@ConfigItem(
keyName = "brawlerColor",
name = "Brawler color",
description = "Color of highlighted Brawlers.",
position = 10
)
default Color brawlerColor()
{
return Color.ORANGE;
}
@ConfigItem(
keyName = "highlightRepairables",
name = "Highlight repairables",
description = "Highlight repairable barricades and gates.",
position = 11
)
default boolean highlightRepairables()
{
return false;
}
@ConfigItem(
keyName = "repairableColor",
name = "Repairable color",
description = "Color of highlighted repairables.",
position = 12
)
/*default Color repairableColor()
{
return new Color(193, 141, 255);
}*/
default Color repairableColor()
{
return Color.YELLOW;
}
@ConfigItem(
keyName = "showPoints",
name = "Show points indicator",
description = "Always display your points when on the island or in the minigame.",
position = 13
)
default boolean showPoints()
{
return true;
}
@ConfigItem(
keyName = "showTimeTillNextPortal",
name = "Show time till next portal",
description = "Show a timer that counts down till the next portal is attackable.",
position = 14
)
default boolean showTimeTillNextPortal()
{
return true;
}
}

View File

@@ -0,0 +1,259 @@
/*
* Copyright (c) 2019, Yani <yani@xenokore.com>
* 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.pestcontrol;
import com.google.common.collect.ImmutableSet;
import java.util.Set;
import lombok.Getter;
import net.runelite.api.NpcID;
@Getter
public class PestControlNpc
{
@Getter
private static final Set<Integer> splatterIdSet = ImmutableSet.of(
NpcID.SPLATTER,
NpcID.SPLATTER_1690,
NpcID.SPLATTER_1691,
NpcID.SPLATTER_1692,
NpcID.SPLATTER_1693
);
@Getter
public static final Set<Integer> shifterIdSet = ImmutableSet.of(
NpcID.SHIFTER,
NpcID.SHIFTER_1695,
NpcID.SHIFTER_1696,
NpcID.SHIFTER_1697,
NpcID.SHIFTER_1698,
NpcID.SHIFTER_1699,
NpcID.SHIFTER_1700,
NpcID.SHIFTER_1701,
NpcID.SHIFTER_1702,
NpcID.SHIFTER_1703
);
@Getter
private static final Set<Integer> spinnerIdSet = ImmutableSet.of(
NpcID.SPINNER,
NpcID.SPINNER_1710,
NpcID.SPINNER_1711,
NpcID.SPINNER_1712,
NpcID.SPINNER_1713
);
@Getter
private static final Set<Integer> torcherIdSet = ImmutableSet.of(
NpcID.TORCHER,
NpcID.TORCHER_1715,
NpcID.TORCHER_1716,
NpcID.TORCHER_1717,
NpcID.TORCHER_1718,
NpcID.TORCHER_1719,
NpcID.TORCHER_1720,
NpcID.TORCHER_1721,
NpcID.TORCHER_1722,
NpcID.TORCHER_1723
);
@Getter
private static final Set<Integer> defilerIdSet = ImmutableSet.of(
NpcID.DEFILER,
NpcID.DEFILER_1725,
NpcID.DEFILER_1726,
NpcID.DEFILER_1727,
NpcID.DEFILER_1728,
NpcID.DEFILER_1729,
NpcID.DEFILER_1730,
NpcID.DEFILER_1731,
NpcID.DEFILER_1732,
NpcID.DEFILER_1733
);
@Getter
private static final Set<Integer> brawlerIdSet = ImmutableSet.of(
NpcID.BRAWLER,
NpcID.BRAWLER_1735,
NpcID.BRAWLER_1736,
NpcID.BRAWLER_1737,
NpcID.BRAWLER_1738
);
@Getter
private static final Set<Integer> ravagerIdSet = ImmutableSet.of(
NpcID.RAVAGER,
NpcID.RAVAGER_1705,
NpcID.RAVAGER_1706,
NpcID.RAVAGER_1707,
NpcID.RAVAGER_1708
);
@Getter
private static final Set<Integer> activePortalIdSet = ImmutableSet.of(
NpcID.PORTAL_1747, // Novice Purple Active
NpcID.PORTAL_1748, // Novice Blue Active
NpcID.PORTAL_1749, // Novice Yellow Active
NpcID.PORTAL_1750, // Novice Red Active
NpcID.PORTAL, // Intermediate Purple Active
NpcID.PORTAL_1740, // Intermediate Blue Active
NpcID.PORTAL_1741, // Intermediate Yellow Active
NpcID.PORTAL_1742 // Intermediate Red Active
);
@Getter
private static final Set<Integer> shieldedPortalIdSet = ImmutableSet.of(
NpcID.PORTAL_1751, // Novice Purple Shielded
NpcID.PORTAL_1752, // Novice Blue Shielded
NpcID.PORTAL_1753, // Novice Yellow Shielded
NpcID.PORTAL_1754, // Novice Red Shielded
NpcID.PORTAL_1743, // Intermediate Purple Shielded
NpcID.PORTAL_1744, // Intermediate Blue Shielded
NpcID.PORTAL_1745, // Intermediate Yellow Shielded
NpcID.PORTAL_1746 // Intermediate Red Shielded
);
@Getter
private static final Set<Integer> purplePortalIdSet = ImmutableSet.of(
NpcID.PORTAL_1747, // Novice Purple Active
NpcID.PORTAL_1751, // Novice Purple Shielded
NpcID.PORTAL, // Intermediate Purple Active
NpcID.PORTAL_1743 // Intermediate Purple Shielded
);
@Getter
private static final Set<Integer> bluePortalIdSet = ImmutableSet.of(
NpcID.PORTAL_1748, // Novice Blue Active
NpcID.PORTAL_1752, // Novice Blue Shielded
NpcID.PORTAL_1740, // Intermediate Blue Active
NpcID.PORTAL_1744 // Intermediate Blue Shielded
);
@Getter
private static final Set<Integer> yellowPortalIdSet = ImmutableSet.of(
NpcID.PORTAL_1749, // Novice Yellow Active
NpcID.PORTAL_1753, // Novice Yellow Shielded
NpcID.PORTAL_1741, // Intermediate Yellow Active
NpcID.PORTAL_1745 // Intermediate Yellow Shielded
);
@Getter
private static final Set<Integer> redPortalIdSet = ImmutableSet.of(
NpcID.PORTAL_1750, // Novice Red Active
NpcID.PORTAL_1754, // Novice Red Shielded
NpcID.PORTAL_1742, // Intermediate Red Active
NpcID.PORTAL_1746 // Intermediate Red Shielded
);
@Getter
private static final Set<Integer> ingameVoidKnightIdSet = ImmutableSet.of(
NpcID.VOID_KNIGHT_2950,
NpcID.VOID_KNIGHT_2951,
NpcID.VOID_KNIGHT_2952,
NpcID.VOID_KNIGHT_2953
);
@Getter
private static final Integer ingameSquireId = NpcID.SQUIRE_2949;
public static boolean isSplatterId(int npcId)
{
return splatterIdSet.contains(npcId);
}
public static boolean isShifterId(int npcId)
{
return shifterIdSet.contains(npcId);
}
public static boolean isSpinnerId(int npcId)
{
return brawlerIdSet.contains(npcId);
}
public static boolean isTorcherId(int npcId)
{
return torcherIdSet.contains(npcId);
}
public static boolean isDefilerId(int npcId)
{
return defilerIdSet.contains(npcId);
}
public static boolean isBrawlerId(int npcId)
{
return brawlerIdSet.contains(npcId);
}
public static boolean isRavagerId(int npcId)
{
return ravagerIdSet.contains(npcId);
}
public static boolean isIngameVoidKnightId(int npcId)
{
return ingameVoidKnightIdSet.contains(npcId);
}
public static boolean isIngameSquireId(int npcId)
{
return ingameSquireId == npcId;
}
public static boolean isPortalId(int npcId)
{
return (isActivePortalId(npcId) || isShieldedPortalId(npcId));
}
public static boolean isActivePortalId(int npcId)
{
return activePortalIdSet.contains(npcId);
}
public static boolean isShieldedPortalId(int npcId)
{
return shieldedPortalIdSet.contains(npcId);
}
public static boolean isPurplePortalId(int npcId)
{
return purplePortalIdSet.contains(npcId);
}
public static boolean isBluePortalId(int npcId)
{
return bluePortalIdSet.contains(npcId);
}
public static boolean isYellowPortalId(int npcId)
{
return yellowPortalIdSet.contains(npcId);
}
public static boolean isRedPortalId(int npcId)
{
return redPortalIdSet.contains(npcId);
}
}

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2017, Kronos <https://github.com/KronosDesign>
* Copyright (c) 2019, Yani <yani@xenokore.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -24,29 +25,47 @@
*/
package net.runelite.client.plugins.pestcontrol;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Inject;
import com.google.inject.Provides;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.inject.Inject;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.ChatMessageType;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.NPC;
import net.runelite.api.NpcID;
import net.runelite.api.ItemID;
import net.runelite.api.Tile;
import net.runelite.api.TileObject;
import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.GameObjectChanged;
import net.runelite.api.events.GameObjectDespawned;
import net.runelite.api.events.GameObjectSpawned;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.NpcDespawned;
import net.runelite.api.events.NpcSpawned;
import net.runelite.api.events.GameTick;
import net.runelite.api.events.GroundObjectChanged;
import net.runelite.api.events.GroundObjectDespawned;
import net.runelite.api.events.GroundObjectSpawned;
import net.runelite.api.events.WidgetLoaded;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.game.ItemManager;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.plugins.pestcontrol.config.HighlightPortalOption;
import net.runelite.client.plugins.pestcontrol.config.NpcHighlightStyle;
import net.runelite.client.ui.overlay.OverlayManager;
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
import net.runelite.client.util.Text;
@Slf4j
@PluginDescriptor(
name = "Pest Control",
description = "Show helpful information for the Pest Control minigame",
@@ -54,77 +73,598 @@ import net.runelite.client.ui.overlay.OverlayManager;
)
public class PestControlPlugin extends Plugin
{
private static final Set<Integer> SPINNER_IDS = ImmutableSet.of(
NpcID.SPINNER,
NpcID.SPINNER_1710,
NpcID.SPINNER_1711,
NpcID.SPINNER_1712,
NpcID.SPINNER_1713
);
private final int NOVICE_GANGPLANK = 14315; // Combat 40+ (3 points)
private final int INTERMEDIATE_GANGPLANK = 25631; // Combat 70+ (4 points)
private final int VETERAN_GANGPLANK = 25632; // Combat 100+ (5 points)
private final Pattern SHIELD_DROP = Pattern.compile("The ([a-z]+), [^ ]+ portal shield has dropped!", Pattern.CASE_INSENSITIVE);
private final Pattern SHIELD_DROP_PATTERN = Pattern.compile("The ([a-z]+), [^ ]+ portal shield has dropped!");
private final Pattern EXCHANGE_WINDOW_POINTS_PATTERN = Pattern.compile("Points: <col=ffffff>([0-9]+)</col>");
private final Pattern BOAT_POINTS_PATTERN = Pattern.compile("Pest Points: ([0-9]+)");
private final Pattern AWARDED_PATTERN = Pattern.compile("We've awarded you ([0-9]+) Void Knight Commendation points.");
private final Pattern PURCHASE_PATTERN = Pattern.compile("Remaining Void Knight Commendation Points: ([0-9]+)");
@Getter(AccessLevel.PACKAGE)
private List<NPC> spinners = new ArrayList<>();
@Inject
@Getter
private Client client;
@Inject
private OverlayManager overlayManager;
@Inject
private Client client;
private ConfigManager configManager;
@Inject
private PestControlOverlay overlay;
private InfoBoxManager infoBoxManager;
@Inject
@Getter
private ItemManager itemManager;
@Inject
@Getter
private PestControlConfig config;
@Inject
@Getter
private WidgetOverlay widgetOverlay;
@Inject
private HintArrowOverlay hintArrowOverlay;
@Inject
private NpcHighlightOverlay npcHighlightOverlay;
@Inject
private RepairOverlay repairOverlay;
@Inject
private GangplankOverlay gangplankOverlay;
@Inject
private TimerOverlay timerOverlay;
@Inject
private PortalWeaknessOverlay portalWeaknessOverlay;
@Getter
private Game game;
@Getter
private HashMap<Integer, NpcHighlightContext> highlightedNpcList = new HashMap<Integer, NpcHighlightContext>();
@Getter
private List<TileObject> highlightedRepairList = new ArrayList<TileObject>();
@Getter
private Tile noviceGangplankTile;
@Getter
private Tile intermediateGangplankTile;
@Getter
private Tile veteranGangplankTile;
@Getter
private Integer commendationPoints;
private String userConfigKey;
private boolean checkForPointWidgets;
private boolean pointsRewarded = false;
private PointsInfoboxCounter pointsInfoboxCounter;
@Provides
PestControlConfig provideConfig(ConfigManager configManager)
{
return configManager.getConfig(PestControlConfig.class);
}
@Override
protected void startUp() throws Exception
{
overlayManager.add(overlay);
loadPlugin();
}
@Override
protected void shutDown() throws Exception
{
overlayManager.remove(overlay);
spinners.clear();
unloadPlugin();
}
@Subscribe
public void onConfigChanged(ConfigChanged configEvent)
{
if (configEvent.getGroup().equals("pestcontrol"))
{
unloadPlugin();
loadPlugin();
}
}
private boolean loadLocalUserPoints()
{
if (userConfigKey != null)
{
String configKey = "points." + userConfigKey;
String pointString = configManager.getConfiguration("pestcontrol", configKey);
if (pointString != null)
{
commendationPoints = Integer.parseInt(pointString);
return true;
}
}
return false;
}
private void loadPlugin()
{
if (loadLocalUserPoints())
{
handlePointsInfoboxCounter();
}
overlayManager.add(widgetOverlay);
if (config.highlightSpinners() != NpcHighlightStyle.OFF)
{
for (Integer npcId : PestControlNpc.getSpinnerIdSet())
{
highlightedNpcList.put(npcId, new NpcHighlightContext(
config.highlightSpinners(),
config.spinnerColor(),
true
));
}
}
if (config.highlightBrawlers() != NpcHighlightStyle.OFF)
{
for (Integer npcId : PestControlNpc.getBrawlerIdSet())
{
highlightedNpcList.put(npcId, new NpcHighlightContext(
config.highlightBrawlers(),
config.brawlerColor(),
false
));
}
}
if (config.portalHighlight() != HighlightPortalOption.OFF)
{
if (config.portalHighlight() == HighlightPortalOption.ACTIVE ||
config.portalHighlight() == HighlightPortalOption.ALL)
{
for (Integer portalNpcId : PestControlNpc.getActivePortalIdSet())
{
highlightedNpcList.put(portalNpcId, new NpcHighlightContext(
NpcHighlightStyle.HULL,
config.activePortalColor(),
false
));
}
}
if (config.portalHighlight() == HighlightPortalOption.SHIELDED ||
config.portalHighlight() == HighlightPortalOption.ALL)
{
for (Integer portalNpcId : PestControlNpc.getShieldedPortalIdSet())
{
highlightedNpcList.put(portalNpcId, new NpcHighlightContext(
NpcHighlightStyle.HULL,
config.shieldedPortalColor(),
false
));
}
}
}
if (!highlightedNpcList.isEmpty())
{
overlayManager.add(npcHighlightOverlay);
}
if (config.highlightRepairables())
{
overlayManager.add(repairOverlay);
}
if (config.showHintArrow())
{
overlayManager.add(hintArrowOverlay);
if (game != null && client.hasHintArrow())
{
client.clearHintArrow();
}
}
if (config.highlightGangplanks())
{
overlayManager.add(gangplankOverlay);
}
if (config.showTimeTillNextPortal())
{
overlayManager.add(timerOverlay);
}
if (config.showPortalWeakness())
{
overlayManager.add(portalWeaknessOverlay);
}
}
private void unloadPlugin()
{
overlayManager.remove(widgetOverlay);
overlayManager.remove(npcHighlightOverlay);
overlayManager.remove(repairOverlay);
overlayManager.remove(gangplankOverlay);
overlayManager.remove(hintArrowOverlay);
overlayManager.remove(timerOverlay);
overlayManager.remove(portalWeaknessOverlay);
infoBoxManager.removeInfoBox(pointsInfoboxCounter);
pointsInfoboxCounter = null;
highlightedNpcList.clear();
if (game != null && config.showHintArrow() && client.hasHintArrow())
{
client.clearHintArrow();
}
}
@Subscribe
public void onGameStateChanged(GameStateChanged event)
{
GameState gameState = event.getGameState();
if (gameState == GameState.CONNECTION_LOST || gameState == GameState.LOGIN_SCREEN || gameState == GameState.HOPPING)
// LOGGED_IN also triggers when teleporting to the island
if (event.getGameState() == GameState.LOGGED_IN)
{
spinners.clear();
handlePointsInfoboxCounter();
}
}
public void handlePointsInfoboxCounter()
{
if (!config.showPoints())
{
return;
}
if (!isOnPestControlMainIsland() && !isInPestControlInstance())
{
infoBoxManager.removeInfoBox(pointsInfoboxCounter);
pointsInfoboxCounter = null;
return;
}
if (commendationPoints == null)
{
if (pointsInfoboxCounter != null)
{
infoBoxManager.removeInfoBox(pointsInfoboxCounter);
pointsInfoboxCounter = null;
}
return;
}
if (pointsInfoboxCounter != null)
{
pointsInfoboxCounter.setCount(commendationPoints);
}
else
{
BufferedImage image = itemManager.getImage(ItemID.VOID_SEAL1);
pointsInfoboxCounter = new PointsInfoboxCounter(image, this, commendationPoints);
pointsInfoboxCounter.setTooltip("Void Knight Commendation Points");
infoBoxManager.addInfoBox(pointsInfoboxCounter);
}
}
public void getPointsFromWidgets()
{
// Get points from dialog after the game
Widget npcDialog = client.getWidget(WidgetInfo.DIALOG_NPC_TEXT);
if (npcDialog != null)
{
String npcText = Text.sanitizeMultilineText(npcDialog.getText());
Matcher matcher = AWARDED_PATTERN.matcher(npcText);
if (matcher.find())
{
int newPoints = Integer.parseInt(matcher.group(1));
if (commendationPoints != null)
{
newPoints += commendationPoints;
}
setCommendationPoints(newPoints);
log.debug("PEST CONTROL [POINTS REWARDED] UPDATE: {}", commendationPoints);
return;
}
}
// Get points from dialog after purchase
Widget pestControlDialog = client.getWidget(WidgetInfo.PEST_CONTROL_DIALOG_TEXT);
if (pestControlDialog != null)
{
String pestControlDialogText = Text.sanitizeMultilineText(pestControlDialog.getText());
Matcher matcher = PURCHASE_PATTERN.matcher(pestControlDialogText);
if (matcher.find())
{
setCommendationPoints(Integer.parseInt(matcher.group(1)));
log.debug("PEST CONTROL [DIALOG] POINTS UPDATE: {}", commendationPoints);
return;
}
}
// Get points from exchange window
Widget exchangeWindowPointsWidget = client.getWidget(WidgetInfo.PEST_CONTROL_EXCHANGE_WINDOW_POINTS);
if (exchangeWindowPointsWidget != null)
{
String pointsString = exchangeWindowPointsWidget.getText();
Matcher matcher = EXCHANGE_WINDOW_POINTS_PATTERN.matcher(pointsString);
if (matcher.lookingAt())
{
setCommendationPoints(Integer.parseInt(matcher.group(1)));
log.debug("PEST CONTROL [EXCHANGE WINDOW] POINTS UPDATE: {}", commendationPoints);
return;
}
}
// Get points in boat
// NOTE: The boat info widget is still active right after the game
// We should therefor only check for point updates if there are no dialogs
Widget boatPointsWidget = client.getWidget(WidgetInfo.PEST_CONTROL_BOAT_INFO_POINTS);
if (boatPointsWidget != null && npcDialog == null && pestControlDialog == null)
{
String pointsString = boatPointsWidget.getText();
Matcher matcher = BOAT_POINTS_PATTERN.matcher(pointsString);
if (matcher.lookingAt())
{
log.debug(matcher.toString());
log.debug("MATCHER GROUP 1: {}", matcher.group(1));
setCommendationPoints(Integer.parseInt(matcher.group(1)));
log.debug("PEST CONTROL [BOAT] POINTS UPDATE: {}", commendationPoints);
}
}
}
public void setCommendationPoints(int newPoints)
{
if (userConfigKey == null)
{
return;
}
if (commendationPoints == null || commendationPoints != newPoints)
{
commendationPoints = newPoints;
configManager.setConfiguration(
"pestcontrol",
"points." + userConfigKey,
String.valueOf(commendationPoints)
);
}
handlePointsInfoboxCounter();
}
@Subscribe
public void onGameTick(GameTick gameTickEvent)
{
// Check for widgets on main island
if (game == null && isOnPestControlMainIsland())
{
// This must be synchronized for some reason
synchronized (this)
{
if (checkForPointWidgets)
{
checkForPointWidgets = false;
getPointsFromWidgets();
}
}
}
// Load the points of the user
if (userConfigKey == null)
{
String username = client.getUsername();
if (username == null)
{
return;
}
userConfigKey = String.valueOf(username.hashCode());
log.debug("USER CONFIG SCOPE: {}", userConfigKey);
if (loadLocalUserPoints())
{
handlePointsInfoboxCounter();
}
}
// Check if the game has started
if (game == null && isInPestControlInstance())
{
log.debug("Pest control game has started");
game = new Game(client, this);
pointsRewarded = false;
}
// Check if we are in a game
if (game == null)
{
return;
}
// Check if we left the game
if (!isInPestControlInstance())
{
if (game != null)
{
log.debug("Pest control game has ended");
game = null;
}
return;
}
game.onGameTick(gameTickEvent);
}
@Subscribe
public void onChatMessage(ChatMessage chatMessage)
{
if (overlay.getGame() != null && chatMessage.getType() == ChatMessageType.GAMEMESSAGE)
if (game != null && chatMessage.getType() == ChatMessageType.GAMEMESSAGE)
{
Matcher matcher = SHIELD_DROP.matcher(chatMessage.getMessage());
Matcher matcher = SHIELD_DROP_PATTERN.matcher(chatMessage.getMessage());
if (matcher.lookingAt())
{
overlay.getGame().fall(matcher.group(1));
game.lowerPortalShield(matcher.group(1));
}
}
}
@Subscribe
public void onNpcSpawned(NpcSpawned event)
public void onWidgetLoaded(WidgetLoaded event)
{
final NPC npc = event.getNpc();
if (SPINNER_IDS.contains(npc.getId()))
if (game != null)
{
spinners.add(npc);
log.debug(event.toString());
}
if (isOnPestControlMainIsland() && game == null)
{
checkForPointWidgets = true;
}
}
private void unlistTileObject(TileObject tileObject)
{
int tileObjectId = tileObject.getId();
if (PestControlRepairObject.isRepairableBarricadeId(tileObjectId) ||
PestControlRepairObject.isRepairableGateId(tileObjectId))
{
highlightedRepairList.remove(tileObject);
return;
}
switch (tileObjectId)
{
case NOVICE_GANGPLANK:
{
noviceGangplankTile = null;
break;
}
case INTERMEDIATE_GANGPLANK:
{
intermediateGangplankTile = null;
break;
}
case VETERAN_GANGPLANK:
{
veteranGangplankTile = null;
break;
}
}
}
private void handleTileObject(Tile tile, TileObject tileObject)
{
int tileObjectId = tileObject.getId();
if (PestControlRepairObject.isRepairableBarricadeId(tileObjectId) ||
PestControlRepairObject.isRepairableGateId(tileObjectId))
{
highlightedRepairList.add(tileObject);
return;
}
switch (tileObjectId)
{
case NOVICE_GANGPLANK:
{
noviceGangplankTile = tile;
break;
}
case INTERMEDIATE_GANGPLANK:
{
intermediateGangplankTile = tile;
break;
}
case VETERAN_GANGPLANK:
{
veteranGangplankTile = tile;
break;
}
}
}
@Subscribe
public void onNpcDespawned(NpcDespawned event)
public void onGameObjectSpawned(GameObjectSpawned event)
{
spinners.remove(event.getNpc());
handleTileObject(event.getTile(), event.getGameObject());
}
@Subscribe
public void onGameObjectChanged(GameObjectChanged event)
{
unlistTileObject(event.getPrevious());
handleTileObject(event.getTile(), event.getGameObject());
}
@Subscribe
public void onGameObjectDespawned(GameObjectDespawned event)
{
unlistTileObject(event.getGameObject());
}
@Subscribe
public void onGroundObjectSpawned(GroundObjectSpawned event)
{
handleTileObject(event.getTile(), event.getGroundObject());
}
@Subscribe
public void onGroundObjectChanged(GroundObjectChanged event)
{
unlistTileObject(event.getPrevious());
handleTileObject(event.getTile(), event.getGroundObject());
}
@Subscribe
public void onGroundObjectDespawned(GroundObjectDespawned event)
{
unlistTileObject(event.getGroundObject());
}
public boolean isInPestControlInstance()
{
return client.getWidget(WidgetInfo.PEST_CONTROL_BLUE_SHIELD) != null;
}
public boolean isOnPestControlMainIsland()
{
return client.getLocalPlayer().getWorldLocation().getRegionID() == 10537;
}
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright (c) 2019, Yani <yani@xenokore.com>
* 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.pestcontrol;
import com.google.common.collect.ImmutableSet;
import java.util.Set;
import lombok.Getter;
import net.runelite.api.ObjectID;
@Getter
public class PestControlRepairObject
{
@Getter
private static final Set<Integer> repairableBarricades = ImmutableSet.of(
//ObjectID.BARRICADE_14224,
ObjectID.BARRICADE_14227,
ObjectID.BARRICADE_14228,
ObjectID.BARRICADE_14229,
ObjectID.BARRICADE_14230,
ObjectID.BARRICADE_14231,
ObjectID.BARRICADE_14232
);
@Getter
private static final Set<Integer> repairableGates = ImmutableSet.of(
ObjectID.GATE_14238,
ObjectID.GATE_14239,
ObjectID.GATE_14240,
ObjectID.GATE_14241,
ObjectID.GATE_14242,
ObjectID.GATE_14243,
ObjectID.GATE_14244,
ObjectID.GATE_14245,
ObjectID.GATE_14246,
ObjectID.GATE_14247,
ObjectID.GATE_14248
);
public static boolean isRepairableBarricadeId(int objectId)
{
return repairableBarricades.contains(objectId);
}
public static boolean isRepairableGateId(int objectId)
{
return repairableGates.contains(objectId);
}
public static boolean isRepairableId(int objectId)
{
return isRepairableBarricadeId(objectId) || isRepairableGateId(objectId);
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (c) 2019, Yani <yani@xenokore.com>
* 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.pestcontrol;
import java.awt.image.BufferedImage;
import net.runelite.client.ui.overlay.infobox.Counter;
public class PointsInfoboxCounter extends Counter
{
private final PestControlPlugin plugin;
PointsInfoboxCounter(BufferedImage image, PestControlPlugin plugin, int count)
{
super(image, plugin, count);
this.plugin = plugin;
}
}

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2017, Adam <Adam@sigterm.info>
* Copyright (c) 2019, Yani <yani@xenokore.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -23,22 +24,39 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.pestcontrol;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;
import net.runelite.api.widgets.WidgetInfo;
import lombok.Setter;
import net.runelite.api.coords.WorldPoint;
@AllArgsConstructor
@Getter
@ToString
enum Portal
@Setter
class Portal
{
PURPLE(WidgetInfo.PEST_CONTROL_PURPLE_SHIELD, WidgetInfo.PEST_CONTROL_PURPLE_HEALTH, WidgetInfo.PEST_CONTROL_PURPLE_ICON),
BLUE(WidgetInfo.PEST_CONTROL_BLUE_SHIELD, WidgetInfo.PEST_CONTROL_BLUE_HEALTH, WidgetInfo.PEST_CONTROL_BLUE_ICON),
YELLOW(WidgetInfo.PEST_CONTROL_YELLOW_SHIELD, WidgetInfo.PEST_CONTROL_YELLOW_HEALTH, WidgetInfo.PEST_CONTROL_YELLOW_ICON),
RED(WidgetInfo.PEST_CONTROL_RED_SHIELD, WidgetInfo.PEST_CONTROL_RED_HEALTH, WidgetInfo.PEST_CONTROL_RED_ICON);
private PortalColor color;
private WidgetPortal widget;
private WorldPoint location;
private final WidgetInfo shield;
private final WidgetInfo hitpoints;
private final WidgetInfo icon;
private PortalState portalState = PortalState.SHIELDED;
public Portal(PortalColor color, WidgetPortal widget)
{
this.color = color;
this.widget = widget;
}
public boolean isShielded()
{
return portalState == PortalState.SHIELDED;
}
public boolean isDead()
{
return portalState == PortalState.DEAD;
}
public boolean isActive()
{
return (!isShielded() && !isDead());
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Adam <Adam@sigterm.info>
* Copyright (c) 2019, Yani <yani@xenokore.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,15 +25,12 @@
package net.runelite.client.plugins.pestcontrol;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
@RequiredArgsConstructor
@Getter
@Setter
class PortalContext
public enum PortalColor
{
private final Portal portal;
private boolean isShielded = true;
private boolean isDead;
BLUE,
PURPLE,
YELLOW,
RED
}

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2017, Adam <Adam@sigterm.info>
* Copyright (c) 2019, Yani <yani@xenokore.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -24,12 +25,12 @@
*/
package net.runelite.client.plugins.pestcontrol;
import static net.runelite.client.plugins.pestcontrol.Portal.BLUE;
import static net.runelite.client.plugins.pestcontrol.Portal.PURPLE;
import static net.runelite.client.plugins.pestcontrol.Portal.RED;
import static net.runelite.client.plugins.pestcontrol.Portal.YELLOW;
import static net.runelite.client.plugins.pestcontrol.PortalColor.BLUE;
import static net.runelite.client.plugins.pestcontrol.PortalColor.PURPLE;
import static net.runelite.client.plugins.pestcontrol.PortalColor.RED;
import static net.runelite.client.plugins.pestcontrol.PortalColor.YELLOW;
enum Rotation
enum PortalRotation
{
PBYR(PURPLE, BLUE, YELLOW, RED),
PYBR(PURPLE, YELLOW, BLUE, RED),
@@ -38,23 +39,23 @@ enum Rotation
YRPB(YELLOW, RED, PURPLE, BLUE),
YPRB(YELLOW, PURPLE, RED, BLUE);
private final Portal[] portals;
private final PortalColor[] portals;
Rotation(Portal first, Portal second, Portal third, Portal fourth)
PortalRotation(PortalColor first, PortalColor second, PortalColor third, PortalColor fourth)
{
portals = new Portal[]
{
first, second, third, fourth
};
portals = new PortalColor[]
{
first, second, third, fourth
};
}
public Portal getPortal(int index)
public Portal getPortal(Game game, int index)
{
if (index < 0 || index >= portals.length)
{
return null;
}
return portals[index];
return game.getPortal(portals[index]);
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright (c) 2019, Yani <yani@xenokore.com>
* 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.pestcontrol;
public enum PortalState
{
ACTIVE,
SHIELDED,
DEAD
}

View File

@@ -0,0 +1,198 @@
/*
* Copyright (c) 2019, Yani <yani@xenokore.com>
* 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.pestcontrol;
import com.google.inject.Inject;
import java.awt.AlphaComposite;
import java.awt.Composite;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.ItemID;
import net.runelite.api.Perspective;
import net.runelite.api.Point;
import net.runelite.api.Skill;
import net.runelite.api.coords.LocalPoint;
import net.runelite.api.coords.WorldPoint;
import net.runelite.client.game.ItemManager;
import net.runelite.client.game.SkillIconManager;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer;
import net.runelite.client.ui.overlay.OverlayPosition;
import net.runelite.client.ui.overlay.OverlayUtil;
@Slf4j
public class PortalWeaknessOverlay extends Overlay
{
private int zOffset = 100;
private final PestControlConfig config;
private final PestControlPlugin plugin;
private final Client client;
private BufferedImage magicImage;
private BufferedImage rangedImage;
private BufferedImage stabImage;
private BufferedImage slashImage;
private BufferedImage crushImage;
@Inject
PortalWeaknessOverlay(
PestControlConfig config,
PestControlPlugin plugin,
Client client,
ItemManager itemManager,
SkillIconManager skillIconManager
)
{
this.config = config;
this.plugin = plugin;
this.client = client;
this.magicImage = skillIconManager.getSkillImage(Skill.MAGIC);
this.rangedImage = skillIconManager.getSkillImage(Skill.RANGED);
this.stabImage = itemManager.getImage(ItemID.WHITE_DAGGER);
this.slashImage = itemManager.getImage(ItemID.WHITE_SCIMITAR);
this.crushImage = itemManager.getImage(ItemID.WHITE_WARHAMMER);
setPosition(OverlayPosition.DYNAMIC);
setLayer(OverlayLayer.UNDER_WIDGETS);
}
private Point getPortalPoint(Portal portal)
{
WorldPoint portalLocation = portal.getLocation();
LocalPoint localLocation = LocalPoint.fromWorld(client, portalLocation);
if (localLocation == null)
{
return null;
}
// We can use any image here as it's only needed to calculate the position
Point imageLocation = Perspective.getCanvasImageLocation(client, localLocation, magicImage, zOffset);
if (imageLocation != null)
{
return imageLocation;
}
return null;
}
private void renderPortalWeakness(Graphics2D graphics, Portal portal, BufferedImage image)
{
Point portalPoint = getPortalPoint(portal);
if (portalPoint != null)
{
Composite originalComposite = graphics.getComposite();
Composite translucentComposite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f);
graphics.setComposite(translucentComposite);
OverlayUtil.renderImageLocation(graphics, portalPoint, image);
graphics.setComposite(originalComposite);
}
}
private void renderDoublePortalWeakness(
Graphics2D graphics,
Portal portal,
BufferedImage imageLeft,
BufferedImage imageRight
)
{
Point portalPoint = getPortalPoint(portal);
if (portalPoint != null)
{
Point portalLeft = new Point(
portalPoint.getX() - (imageLeft.getWidth() / 2) - 5,
portalPoint.getY()
);
Point portalRight = new Point(
portalPoint.getX() + (imageRight.getWidth() / 2) + 5,
portalPoint.getY()
);
Composite originalComposite = graphics.getComposite();
Composite translucentComposite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.6f);
graphics.setComposite(translucentComposite);
OverlayUtil.renderImageLocation(graphics, portalLeft, imageLeft);
OverlayUtil.renderImageLocation(graphics, portalPoint, imageRight);
graphics.setComposite(originalComposite);
}
}
@Override
public Dimension render(Graphics2D graphics)
{
Game game = plugin.getGame();
if (game == null)
{
return null;
}
for (Portal portal : game.getPortals())
{
if (!portal.isDead())
{
switch (portal.getColor())
{
case BLUE:
{
renderPortalWeakness(graphics, portal, magicImage);
break;
}
case YELLOW:
{
renderDoublePortalWeakness(graphics, portal, stabImage, slashImage);
break;
}
case RED:
{
renderPortalWeakness(graphics, portal, crushImage);
break;
}
case PURPLE:
{
renderPortalWeakness(graphics, portal, rangedImage);
break;
}
}
}
}
return null;
}
}

View File

@@ -0,0 +1,227 @@
/*
* Copyright (c) 2019, Yani <yani@xenokore.com>
* 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.pestcontrol;
import com.google.inject.Inject;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.geom.Area;
import net.runelite.api.Client;
import net.runelite.api.Constants;
import net.runelite.api.GameObject;
import net.runelite.api.GroundObject;
import net.runelite.api.Player;
import net.runelite.api.Point;
import net.runelite.api.Scene;
import net.runelite.api.Tile;
import net.runelite.api.WallObject;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer;
import net.runelite.client.ui.overlay.OverlayPosition;
public class RepairOverlay extends Overlay
{
private final PestControlConfig config;
private final PestControlPlugin plugin;
private final Client client;
private static final int MAX_DISTANCE = 2400;
@Inject
RepairOverlay(PestControlConfig config, PestControlPlugin plugin, Client client)
{
this.config = config;
this.plugin = plugin;
this.client = client;
setPosition(OverlayPosition.DYNAMIC);
setLayer(OverlayLayer.ABOVE_SCENE);
}
@Override
public Dimension render(Graphics2D graphics)
{
if (plugin.getGame() == null)
{
return null;
}
Point mousePosition = client.getMouseCanvasPosition();
Scene scene = client.getScene();
Color color = config.repairableColor();
Tile[][][] tiles = scene.getTiles();
int z = client.getPlane();
for (int x = 0; x < Constants.SCENE_SIZE; ++x)
{
for (int y = 0; y < Constants.SCENE_SIZE; ++y)
{
Tile tile = tiles[z][x][y];
if (tile == null)
{
continue;
}
Player player = client.getLocalPlayer();
if (player == null)
{
continue;
}
// Render GameObjects
GameObject[] gameObjects = tile.getGameObjects();
if (gameObjects != null)
{
for (GameObject gameObject : gameObjects)
{
if (gameObject == null)
{
continue;
}
if (PestControlRepairObject.isRepairableId(gameObject.getId()))
{
if (player.getLocalLocation().distanceTo(gameObject.getLocalLocation()) <= MAX_DISTANCE)
{
renderObjectOverlay(graphics, gameObject.getClickbox(), color, mousePosition);
}
}
}
}
// Render GameObject
GroundObject groundObject = tile.getGroundObject();
if (groundObject != null)
{
if (groundObject == null)
{
continue;
}
if (PestControlRepairObject.isRepairableId(groundObject.getId()))
{
if (player.getLocalLocation().distanceTo(groundObject.getLocalLocation()) <= MAX_DISTANCE)
{
renderObjectOverlay(graphics, groundObject.getClickbox(), color, mousePosition);
}
}
}
// Render WallObject
WallObject wallObject = tile.getWallObject();
if (wallObject != null)
{
if (wallObject == null)
{
continue;
}
if (PestControlRepairObject.isRepairableId(wallObject.getId()))
{
if (player.getLocalLocation().distanceTo(wallObject.getLocalLocation()) <= MAX_DISTANCE)
{
renderObjectOverlay(graphics, wallObject.getClickbox(), color, mousePosition);
}
}
}
}
}
/*if(plugin.getGame() == null)
{
return null;
}
Point mousePosition = client.getMouseCanvasPosition();
List<TileObject> repairList = plugin.getHighlightedRepairList();
for(TileObject tileObject: repairList)
{
//tileObject.getWorldLocation().distanceTo(client.getLocalPlayer().getWorldLocation());
Polygon polygon = tileObject.getCanvasTilePoly();
if(polygon != null)
{
graphics.setColor(color);
graphics.setStroke(new BasicStroke(2));
graphics.drawPolygon(polygon);
graphics.setColor(setColorAlpha(color, 40));
graphics.fill(polygon);
if(polygon.contains(mousePosition.getX(), mousePosition.getY()))
{
graphics.setColor(setColorAlpha(color, 65));
graphics.fill(polygon);
}
}
}
*/
return null;
}
private void renderObjectOverlay(Graphics2D graphics, Area area, Color color, Point mousePosition)
{
if (area == null)
{
return;
}
graphics.setColor(color);
graphics.setStroke(new BasicStroke(2));
graphics.draw(area);
graphics.setColor(setColorAlpha(color, 50));
graphics.fill(area);
if (area.contains(mousePosition.getX(), mousePosition.getY()))
{
graphics.setColor(setColorAlpha(color, 60));
graphics.fill(area);
}
}
private Color setColorAlpha(Color color, int alpha)
{
return new Color(
color.getRed(),
color.getGreen(),
color.getBlue(),
alpha
);
}
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright (c) 2019, Yani <yani@xenokore.com>
* 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.pestcontrol;
import com.google.inject.Inject;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.time.Duration;
import net.runelite.api.Client;
import net.runelite.api.Point;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer;
import net.runelite.client.ui.overlay.OverlayPosition;
import net.runelite.client.ui.overlay.OverlayUtil;
public class TimerOverlay extends Overlay
{
private final PestControlConfig config;
private final PestControlPlugin plugin;
private final Client client;
@Inject
TimerOverlay(PestControlConfig config, PestControlPlugin plugin, Client client)
{
this.config = config;
this.plugin = plugin;
this.client = client;
setPosition(OverlayPosition.DYNAMIC);
setLayer(OverlayLayer.ABOVE_SCENE);
}
@Override
public Dimension render(Graphics2D graphics)
{
if (plugin.getGame() == null)
{
return null;
}
Widget timeWidget = client.getWidget(WidgetInfo.PEST_CONTROL_INFO_TIME);
if (timeWidget == null)
{
return null;
}
int x = timeWidget.getCanvasLocation().getX() + 38;
int y = timeWidget.getCanvasLocation().getY() + 11;
Duration timeTillNextPortal = plugin.getGame().getTimeTillNextPortal();
if (timeTillNextPortal != null)
{
String firstOrNext = (plugin.getGame().getShieldsDropped() == 0) ? "first" : "next";
String string = String.format("- %s portal: %ds", firstOrNext, timeTillNextPortal.getSeconds());
OverlayUtil.renderTextLocation(graphics, new Point(x, y), string, new Color(204, 204, 204));
}
return null;
}
}

View File

@@ -1,6 +1,7 @@
/*
* Copyright (c) 2017, Kronos <https://github.com/KronosDesign>
* Copyright (c) 2017, Adam <Adam@sigterm.info>
* Copyright (c) 2019, Yani <yani@xenokore.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,151 +32,107 @@ import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import javax.inject.Inject;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.NPC;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import static net.runelite.client.plugins.pestcontrol.Portal.BLUE;
import static net.runelite.client.plugins.pestcontrol.Portal.PURPLE;
import static net.runelite.client.plugins.pestcontrol.Portal.RED;
import static net.runelite.client.plugins.pestcontrol.Portal.YELLOW;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer;
import net.runelite.client.ui.overlay.OverlayPosition;
import net.runelite.client.ui.overlay.OverlayUtil;
@Slf4j
public class PestControlOverlay extends Overlay
public class WidgetOverlay extends Overlay
{
private final PestControlPlugin plugin;
private final Client client;
// Pest control game
@Getter(AccessLevel.PACKAGE)
private Game game;
private final PestControlPlugin plugin;
@Inject
public PestControlOverlay(PestControlPlugin plugin, Client client)
public WidgetOverlay(Client client, PestControlPlugin plugin)
{
setPosition(OverlayPosition.DYNAMIC);
this.plugin = plugin;
this.client = client;
setPosition(OverlayPosition.DYNAMIC);
setLayer(OverlayLayer.ABOVE_SCENE);
}
public Integer getPortalHitpoints(PortalColor color)
{
if (plugin.getGame() == null)
{
return null;
}
WidgetInfo healthWidgetInfo = null;
switch (color)
{
case RED:
{
healthWidgetInfo = WidgetPortal.RED.getHitpoints();
break;
}
case BLUE:
{
healthWidgetInfo = WidgetPortal.BLUE.getHitpoints();
break;
}
case PURPLE:
{
healthWidgetInfo = WidgetPortal.PURPLE.getHitpoints();
break;
}
case YELLOW:
{
healthWidgetInfo = WidgetPortal.YELLOW.getHitpoints();
break;
}
}
if (healthWidgetInfo == null)
{
return null;
}
Widget healthWidget = client.getWidget(healthWidgetInfo);
if (healthWidget == null)
{
return null;
}
return Integer.parseInt(healthWidget.getText().trim());
}
@Override
public Dimension render(Graphics2D graphics)
{
// See if we are in a game or not
if (client.getWidget(WidgetInfo.PEST_CONTROL_BLUE_SHIELD) == null)
if (plugin.getGame() == null)
{
if (game != null)
{
log.debug("Pest control game has ended");
game = null;
}
return null;
}
if (game == null)
{
log.debug("Pest control game has started");
game = new Game();
}
renderSpinners(graphics);
renderPortalWidgets(graphics);
return null;
}
private void renderSpinners(Graphics2D graphics)
{
for (NPC npc : plugin.getSpinners())
{
OverlayUtil.renderActorOverlay(graphics, npc, npc.getName(), Color.CYAN);
}
}
private void renderPortalWidgets(Graphics2D graphics)
{
PortalContext purple = game.getPurple();
PortalContext blue = game.getBlue();
PortalContext yellow = game.getYellow();
PortalContext red = game.getRed();
Widget purpleHealth = client.getWidget(PURPLE.getHitpoints());
Widget blueHealth = client.getWidget(BLUE.getHitpoints());
Widget yellowHealth = client.getWidget(YELLOW.getHitpoints());
Widget redHealth = client.getWidget(RED.getHitpoints());
// Check for dead portals
if (isZero(purpleHealth))
{
game.die(purple);
}
if (isZero(blueHealth))
{
game.die(blue);
}
if (isZero(yellowHealth))
{
game.die(yellow);
}
if (isZero(redHealth))
{
game.die(red);
}
// display "ATK" overlay on recorded portals without shields
renderAttack(graphics, purple);
renderAttack(graphics, blue);
renderAttack(graphics, yellow);
renderAttack(graphics, red);
// display "NEXT" overlay on predicted portals
for (Portal portal : game.getNextPortals())
for (Portal portal : plugin.getGame().getNextPortals())
{
renderWidgetOverlay(graphics, portal, "NEXT", Color.ORANGE);
}
renderProgressWidget(graphics);
}
private void renderProgressWidget(Graphics2D graphics)
{
Widget bar = client.getWidget(WidgetInfo.PEST_CONTROL_ACTIVITY_BAR).getChild(0);
Rectangle2D bounds = bar.getBounds().getBounds2D();
Widget prgs = client.getWidget(WidgetInfo.PEST_CONTROL_ACTIVITY_PROGRESS).getChild(0);
int perc = (int) ((prgs.getBounds().getWidth() / bounds.getWidth()) * 100);
Color color = Color.GREEN;
if (perc < 25)
for (Portal portal : plugin.getGame().getActivePortals())
{
color = Color.RED;
renderWidgetOverlay(graphics, portal, "ATT", Color.RED);
}
String text = String.valueOf(perc) + "%";
renderProgressWidget(graphics);
FontMetrics fm = graphics.getFontMetrics();
Rectangle2D textBounds = fm.getStringBounds(text, graphics);
int x = (int) (bounds.getX() - textBounds.getWidth());
int y = (int) (bounds.getY() + fm.getHeight() - 2);
graphics.setColor(Color.BLACK);
graphics.drawString(text, x + 1, y + 1);
graphics.setColor(color);
graphics.drawString(text, x, y);
return null;
}
private void renderWidgetOverlay(Graphics2D graphics, Portal portal, String text, Color color)
{
Widget shield = client.getWidget(portal.getShield());
Widget icon = client.getWidget(portal.getIcon());
Widget hp = client.getWidget(portal.getHitpoints());
Widget shield = client.getWidget(portal.getWidget().getShield());
Widget icon = client.getWidget(portal.getWidget().getIcon());
Widget hp = client.getWidget(portal.getWidget().getHitpoints());
Widget bar = client.getWidget(WidgetInfo.PEST_CONTROL_ACTIVITY_BAR).getChild(0);
@@ -199,6 +156,45 @@ public class PestControlOverlay extends Overlay
graphics.drawString(text, x, y + 4);
}
private void renderProgressWidget(Graphics2D graphics)
{
String text;
int percentage;
Widget bar = client.getWidget(WidgetInfo.PEST_CONTROL_ACTIVITY_BAR).getChild(0);
Rectangle2D bounds = bar.getBounds().getBounds2D();
Widget prgs = client.getWidget(WidgetInfo.PEST_CONTROL_ACTIVITY_PROGRESS).getChild(0);
// At 0% the inner widget changes and your progress will not increase anymore
if ((int) (prgs.getBounds().getX()) - bounds.getX() != 2)
{
percentage = 0;
text = "FAILED";
}
else
{
percentage = (int) ((prgs.getBounds().getWidth() / bounds.getWidth()) * 100);
text = String.valueOf(percentage) + "%";
}
Color color = Color.GREEN;
if (percentage < 25)
{
color = Color.RED;
}
FontMetrics fm = graphics.getFontMetrics();
Rectangle2D textBounds = fm.getStringBounds(text, graphics);
int x = (int) (bounds.getX() - textBounds.getWidth() - 4);
int y = (int) (bounds.getY() + fm.getHeight() - 2);
graphics.setColor(Color.BLACK);
graphics.drawString(text, x + 1, y + 1);
graphics.setColor(color);
graphics.drawString(text, x, y);
}
private static Rectangle2D union(Rectangle2D src1, Rectangle2D src2)
{
double x1 = Math.min(src1.getMinX(), src2.getMinX());
@@ -211,19 +207,4 @@ public class PestControlOverlay extends Overlay
return result;
}
private void renderAttack(Graphics2D graphics, PortalContext portal)
{
if (portal.isShielded() || portal.isDead())
{
return;
}
renderWidgetOverlay(graphics, portal.getPortal(), "ATK", Color.RED);
}
private static boolean isZero(Widget widget)
{
return widget.getText().trim().equals("0");
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (c) 2017, Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.pestcontrol;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;
import net.runelite.api.widgets.WidgetInfo;
@AllArgsConstructor
@Getter
@ToString
enum WidgetPortal
{
PURPLE(WidgetInfo.PEST_CONTROL_PURPLE_SHIELD, WidgetInfo.PEST_CONTROL_PURPLE_HEALTH, WidgetInfo.PEST_CONTROL_PURPLE_ICON),
BLUE(WidgetInfo.PEST_CONTROL_BLUE_SHIELD, WidgetInfo.PEST_CONTROL_BLUE_HEALTH, WidgetInfo.PEST_CONTROL_BLUE_ICON),
YELLOW(WidgetInfo.PEST_CONTROL_YELLOW_SHIELD, WidgetInfo.PEST_CONTROL_YELLOW_HEALTH, WidgetInfo.PEST_CONTROL_YELLOW_ICON),
RED(WidgetInfo.PEST_CONTROL_RED_SHIELD, WidgetInfo.PEST_CONTROL_RED_HEALTH, WidgetInfo.PEST_CONTROL_RED_ICON);
private final WidgetInfo shield;
private final WidgetInfo hitpoints;
private final WidgetInfo icon;
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 2019, Yani <yani@xenokore.com>
* 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.pestcontrol.config;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@Getter
@RequiredArgsConstructor
public enum HighlightPortalOption
{
OFF("Off"),
ACTIVE("Active"),
SHIELDED("Shielded"),
ALL("All");
private final String option;
@Override
public String toString()
{
return option;
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 2019, Yani <yani@xenokore.com>
* 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.pestcontrol.config;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@Getter
@RequiredArgsConstructor
public enum NpcHighlightStyle
{
OFF("Off"),
TILE("Tile"),
HULL("Hull"),
BOTH("Hull + Tile");
private final String style;
@Override
public String toString()
{
return style;
}
}

View File

@@ -59,6 +59,9 @@ import net.runelite.api.Varbits;
import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.VarbitChanged;
import net.runelite.api.events.WidgetHiddenChanged;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.chat.ChatColorType;
import net.runelite.client.chat.ChatMessageBuilder;
@@ -126,6 +129,9 @@ public class RaidsPlugin extends Plugin
@Inject
private RaidsOverlay overlay;
@Inject
private RaidsPointsOverlay pointsOverlay;
@Inject
private LayoutSolver layoutSolver;
@@ -177,6 +183,7 @@ public class RaidsPlugin extends Plugin
protected void startUp() throws Exception
{
overlayManager.add(overlay);
overlayManager.add(pointsOverlay);
updateLists();
clientThread.invokeLater(() -> checkRaidPresence(true));
}
@@ -185,10 +192,17 @@ public class RaidsPlugin extends Plugin
protected void shutDown() throws Exception
{
overlayManager.remove(overlay);
overlayManager.remove(pointsOverlay);
infoBoxManager.removeInfoBox(timer);
inRaidChambers = false;
raid = null;
timer = null;
final Widget widget = client.getWidget(WidgetInfo.RAIDS_POINTS_INFOBOX);
if (widget != null)
{
widget.setHidden(false);
}
}
@Subscribe
@@ -209,6 +223,22 @@ public class RaidsPlugin extends Plugin
clientThread.invokeLater(() -> checkRaidPresence(true));
}
@Subscribe
public void onWidgetHiddenChanged(WidgetHiddenChanged event)
{
if (!inRaidChambers || event.isHidden())
{
return;
}
Widget widget = event.getWidget();
if (widget == client.getWidget(WidgetInfo.RAIDS_POINTS_INFOBOX))
{
widget.setHidden(true);
}
}
@Subscribe
public void onVarbitChanged(VarbitChanged event)
{

View File

@@ -0,0 +1,120 @@
/*
* Copyright (c) 2018, Kamiel
* 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.raids;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.text.NumberFormat;
import java.util.Locale;
import javax.inject.Inject;
import net.runelite.api.Client;
import static net.runelite.api.MenuAction.RUNELITE_OVERLAY_CONFIG;
import net.runelite.api.Varbits;
import static net.runelite.client.plugins.raids.RaidsPlugin.POINTS_FORMAT;
import net.runelite.client.ui.overlay.Overlay;
import static net.runelite.client.ui.overlay.OverlayManager.OPTION_CONFIGURE;
import net.runelite.client.ui.overlay.OverlayMenuEntry;
import net.runelite.client.ui.overlay.OverlayPosition;
import net.runelite.client.ui.overlay.OverlayPriority;
import net.runelite.client.ui.overlay.components.LineComponent;
import net.runelite.client.ui.overlay.components.PanelComponent;
public class RaidsPointsOverlay extends Overlay
{
@Inject
private Client client;
@Inject
private RaidsPlugin plugin;
private final PanelComponent panel = new PanelComponent();
private static final NumberFormat UNIQUE_FORMAT = NumberFormat.getPercentInstance(Locale.ENGLISH);
static
{
UNIQUE_FORMAT.setMaximumFractionDigits(2);
UNIQUE_FORMAT.setMinimumFractionDigits(2);
}
@Inject
private RaidsPointsOverlay(RaidsPlugin plugin)
{
super(plugin);
setPosition(OverlayPosition.TOP_RIGHT);
setPriority(OverlayPriority.HIGH);
getMenuEntries().add(new OverlayMenuEntry(RUNELITE_OVERLAY_CONFIG, OPTION_CONFIGURE, "Raids overlay"));
}
@Override
public Dimension render(Graphics2D graphics)
{
if (!plugin.isInRaidChambers())
{
return null;
}
int totalPoints = client.getVar(Varbits.TOTAL_POINTS);
int personalPoints = client.getVar(Varbits.PERSONAL_POINTS);
int partySize = client.getVar(Varbits.RAID_PARTY_SIZE);
double uniqueChance = totalPoints / 867500f;
panel.getChildren().clear();
panel.getChildren().add(LineComponent.builder()
.left("Total:")
.right(POINTS_FORMAT.format(totalPoints))
.build());
panel.getChildren().add(LineComponent.builder()
.left(client.getLocalPlayer().getName() + ":")
.right(POINTS_FORMAT.format(personalPoints))
.build());
if (partySize > 1)
{
panel.getChildren().add(LineComponent.builder()
.left("Party size:")
.right(String.valueOf(partySize))
.build());
}
panel.getChildren().add(LineComponent.builder()
.left("Unique:")
.right(UNIQUE_FORMAT.format(uniqueChance))
.build());
if (partySize > 1)
{
double personalChance = uniqueChance * (personalPoints / totalPoints);
panel.getChildren().add(LineComponent.builder()
.left("Personal:")
.right(UNIQUE_FORMAT.format(personalChance))
.build());
}
return panel.render(graphics);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -0,0 +1,69 @@
/*
* Copyright (c) 2019, Bartvollebregt <https://github.com/Bartvollebregt>
* 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.maxhit.calculators;
import com.google.inject.Guice;
import com.google.inject.testing.fieldbinder.Bind;
import com.google.inject.testing.fieldbinder.BoundFieldModule;
import net.runelite.api.Client;
import net.runelite.client.plugins.maxhit.calculators.testconfig.MagicMaxHitConfig;
import net.runelite.client.plugins.maxhit.calculators.testconfig.MaxHitConfig;
import net.runelite.client.plugins.maxhit.calculators.testconfig.MeleeMaxHitConfig;
import net.runelite.client.plugins.maxhit.calculators.testconfig.RangeMaxHitConfig;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class MaxHitCalculatorTest
{
@Mock
@Bind
protected Client client;
@Before
public void setUp()
{
Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this);
}
@Test
public void calculate()
{
testMaxHitConfig(MeleeMaxHitConfig.values());
testMaxHitConfig(RangeMaxHitConfig.values());
testMaxHitConfig(MagicMaxHitConfig.values());
}
private void testMaxHitConfig(MaxHitConfig[] maxHitConfigs)
{
for (MaxHitConfig maxHitConfig : maxHitConfigs)
{
maxHitConfig.test(client);
}
}
}

View File

@@ -0,0 +1,243 @@
/*
* Copyright (c) 2019, Bartvollebregt <https://github.com/Bartvollebregt>
* 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.maxhit.calculators.testconfig;
import net.runelite.api.*;
import net.runelite.client.plugins.maxhit.calculators.MagicMaxHitCalculator;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public enum MagicMaxHitConfig implements MaxHitConfig
{
TRIDENT_SLAYER(new int[] {75, 83, 99}, 0, new Item[]
{
mockItem(ItemID.SLAYER_HELMET_I),
mockItem(ItemID.SARADOMIN_CAPE),
mockItem(ItemID.OCCULT_NECKLACE),
mockItem(ItemID.TRIDENT_OF_THE_SEAS),
mockItem(ItemID.MYSTIC_ROBE_TOP),
mockItem(ItemID.BROODOO_SHIELD),
null,
mockItem(ItemID.MYSTIC_ROBE_BOTTOM),
null,
mockItem(ItemID.MYSTIC_GLOVES),
mockItem(ItemID.WIZARD_BOOTS),
mockItem(ItemID.RING_OF_WEALTH)
}, new int[] {25, 27, 34}),
TRIDENT_OF_SEAS(new int[] {75, 83, 99}, 0, new Item[]
{
mockItem(ItemID.MYSTIC_HAT),
mockItem(ItemID.SARADOMIN_CAPE),
mockItem(ItemID.AMULET_OF_GLORY),
mockItem(ItemID.TRIDENT_OF_THE_SEAS),
mockItem(ItemID.MYSTIC_ROBE_TOP),
mockItem(ItemID.BROODOO_SHIELD),
null,
mockItem(ItemID.MYSTIC_ROBE_BOTTOM),
null,
mockItem(ItemID.MYSTIC_GLOVES),
mockItem(ItemID.WIZARD_BOOTS),
mockItem(ItemID.RING_OF_WEALTH)
}, new int[] {20, 22, 28}),
TRIDENT_OF_SWAMP(new int[] {75, 83, 99}, 0, new Item[]
{
mockItem(ItemID.MYSTIC_HAT),
mockItem(ItemID.SARADOMIN_CAPE),
mockItem(ItemID.AMULET_OF_GLORY),
mockItem(ItemID.TRIDENT_OF_THE_SWAMP),
mockItem(ItemID.MYSTIC_ROBE_TOP),
mockItem(ItemID.BROODOO_SHIELD),
null,
mockItem(ItemID.MYSTIC_ROBE_BOTTOM),
null,
mockItem(ItemID.MYSTIC_GLOVES),
mockItem(ItemID.WIZARD_BOOTS),
mockItem(ItemID.RING_OF_WEALTH)
}, new int[] {23, 25, 31}),
MAGIC_DART(new int[] {75, 83, 99}, 18, new Item[]
{
mockItem(ItemID.MYSTIC_HAT),
mockItem(ItemID.SARADOMIN_CAPE),
mockItem(ItemID.AMULET_OF_GLORY),
mockItem(ItemID.SLAYERS_STAFF),
mockItem(ItemID.MYSTIC_ROBE_TOP),
mockItem(ItemID.BROODOO_SHIELD),
null,
mockItem(ItemID.MYSTIC_ROBE_BOTTOM),
null,
mockItem(ItemID.MYSTIC_GLOVES),
mockItem(ItemID.WIZARD_BOOTS),
mockItem(ItemID.RING_OF_WEALTH)
}, new int[] {17, 18, 19}),
FIRE_BOLT(75, 8, new Item[]
{
mockItem(ItemID.SLAYER_HELMET_I),
mockItem(ItemID.IMBUED_SARADOMIN_CAPE),
mockItem(ItemID.OCCULT_NECKLACE),
mockItem(ItemID.STAFF_OF_THE_DEAD),
mockItem(ItemID.MYSTIC_ROBE_TOP),
mockItem(ItemID.TOME_OF_FIRE),
null,
mockItem(ItemID.MYSTIC_ROBE_BOTTOM),
null,
mockItem(ItemID.CHAOS_GAUNTLETS),
mockItem(ItemID.WIZARD_BOOTS),
mockItem(ItemID.RING_OF_WEALTH)
}, 31),
WIND_BLAST(75, 9, new Item[]
{
mockItem(ItemID.MYSTIC_HAT),
mockItem(ItemID.SARADOMIN_CAPE),
mockItem(ItemID.AMULET_OF_GLORY),
mockItem(ItemID.STAFF_OF_AIR),
mockItem(ItemID.MYSTIC_ROBE_TOP),
mockItem(ItemID.BROODOO_SHIELD),
null,
mockItem(ItemID.MYSTIC_ROBE_BOTTOM),
null,
mockItem(ItemID.MYSTIC_GLOVES),
mockItem(ItemID.WIZARD_BOOTS),
mockItem(ItemID.RING_OF_WEALTH)
}, 13),
EARTH_WAVE(75, 15, new Item[]
{
mockItem(ItemID.MYSTIC_HAT),
mockItem(ItemID.SARADOMIN_CAPE),
mockItem(ItemID.OCCULT_NECKLACE),
mockItem(ItemID.STAFF_OF_EARTH),
mockItem(ItemID.MYSTIC_ROBE_TOP),
mockItem(ItemID.TOME_OF_FIRE),
null,
mockItem(ItemID.MYSTIC_ROBE_BOTTOM),
null,
mockItem(ItemID.MYSTIC_GLOVES),
mockItem(ItemID.WIZARD_BOOTS),
mockItem(ItemID.RING_OF_WEALTH)
}, 20),
FLAMES_OF_ZAMORAK(75, 20, new Item[]
{
mockItem(ItemID.MYSTIC_HAT),
mockItem(ItemID.SARADOMIN_CAPE),
mockItem(ItemID.AMULET_OF_GLORY),
mockItem(ItemID.STAFF_OF_THE_DEAD),
mockItem(ItemID.MYSTIC_ROBE_TOP),
mockItem(ItemID.BROODOO_SHIELD),
null,
mockItem(ItemID.MYSTIC_ROBE_BOTTOM),
null,
mockItem(ItemID.MYSTIC_GLOVES),
mockItem(ItemID.WIZARD_BOOTS),
mockItem(ItemID.RING_OF_WEALTH)
}, 23),
SARADOMIN_STRIKE(75, 52, new Item[]
{
mockItem(ItemID.MYSTIC_HAT),
mockItem(ItemID.SARADOMIN_CAPE),
mockItem(ItemID.AMULET_OF_GLORY),
mockItem(ItemID.STAFF_OF_LIGHT),
mockItem(ItemID.MYSTIC_ROBE_TOP),
mockItem(ItemID.BROODOO_SHIELD),
null,
mockItem(ItemID.MYSTIC_ROBE_BOTTOM),
null,
mockItem(ItemID.MYSTIC_GLOVES),
mockItem(ItemID.WIZARD_BOOTS),
mockItem(ItemID.RING_OF_WEALTH)
}, 23),
;
private final int[] magicLevels;
private final int spellId;
private final Item[] equipedItems;
private final int[] expectedMaxHits;
MagicMaxHitConfig(int magicLevel, int spellId, Item[] equipedItems, int expectedMaxHit)
{
this.magicLevels = new int[] {magicLevel};
this.spellId = spellId;
this.equipedItems = equipedItems;
this.expectedMaxHits = new int[] {expectedMaxHit};
}
MagicMaxHitConfig(int[] magicLevels, int spellId, Item[] equipedItems, int[] expectedMaxHits)
{
this.magicLevels = magicLevels;
this.spellId = spellId;
this.equipedItems = equipedItems;
this.expectedMaxHits = expectedMaxHits;
}
private static Item mockItem(int itemId)
{
Item item = mock(Item.class);
when(item.getId()).thenReturn(itemId);
return item;
}
public void test(Client client)
{
int[] magicLevels = this.magicLevels;
for (int i = 0, magicLevelsLength = magicLevels.length; i < magicLevelsLength; i++)
{
int magicLevel = magicLevels[i];
int expectedMaxHit = this.expectedMaxHits[i];
// Mock equipment container
ItemContainer equipmentContainer = mock(ItemContainer.class);
when(equipmentContainer.getItems())
.thenReturn(this.equipedItems);
when(client.getItemContainer(InventoryID.EQUIPMENT)).thenReturn(equipmentContainer);
// Mock Varbits
when(client.getBoostedSkillLevel(Skill.MAGIC)).thenReturn(magicLevel);
when(client.getVar(Varbits.AUTO_CAST_SPELL)).thenReturn(this.spellId);
// Test
MagicMaxHitCalculator maxHitCalculator = new MagicMaxHitCalculator(client, this.equipedItems);
assertEquals(this.toString(), expectedMaxHit, maxHitCalculator.getMaxHit(), 0);
}
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright (c) 2019, Bartvollebregt <https://github.com/Bartvollebregt>
* 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.maxhit.calculators.testconfig;
import net.runelite.api.Client;
public interface MaxHitConfig
{
void test(Client client);
}

View File

@@ -0,0 +1,217 @@
/*
* Copyright (c) 2019, Bartvollebregt <https://github.com/Bartvollebregt>
* 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.maxhit.calculators.testconfig;
import net.runelite.api.*;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.plugins.maxhit.attackstyle.WeaponType;
import net.runelite.client.plugins.maxhit.calculators.MeleeMaxHitCalculator;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public enum MeleeMaxHitConfig implements MaxHitConfig
{
DRAGON_SCIMITAR(new int[] {75, 83, 99}, 66, WeaponType.TYPE_9, 1, new Item[]
{
mockItem(ItemID.IRON_FULL_HELM),
mockItem(ItemID.BLACK_CAPE),
mockItem(ItemID.GOLD_NECKLACE),
mockItem(ItemID.DRAGON_SCIMITAR),
mockItem(ItemID.IRON_PLATEBODY),
mockItem(ItemID.IRON_KITESHIELD),
null,
mockItem(ItemID.IRON_PLATELEGS),
null,
mockItem(ItemID.LEATHER_GLOVES),
mockItem(ItemID.LEATHER_BOOTS),
mockItem(ItemID.GOLD_RING)
}, new int[] {17, 19, 22}),
DRAGON_SCIMITAR_DEFENDER(new int[] {75, 83, 99}, 76, WeaponType.TYPE_9, 1, new Item[]
{
mockItem(ItemID.IRON_FULL_HELM),
mockItem(ItemID.BLACK_CAPE),
mockItem(ItemID.GOLD_NECKLACE),
mockItem(ItemID.DRAGON_SCIMITAR),
mockItem(ItemID.IRON_PLATEBODY),
mockItem(ItemID.DRAGON_DEFENDER),
null,
mockItem(ItemID.IRON_PLATELEGS),
null,
mockItem(ItemID.LEATHER_GLOVES),
mockItem(ItemID.LEATHER_BOOTS),
mockItem(ItemID.GOLD_RING)
}, new int[] {19, 21, 24}),
DRAGON_SCIMITAR_COMPLETE(new int[] {75, 83, 99}, 108, WeaponType.TYPE_9, 1, new Item[]
{
mockItem(ItemID.SLAYER_HELMET),
mockItem(ItemID.FIRE_CAPE),
mockItem(ItemID.AMULET_OF_FURY),
mockItem(ItemID.DRAGON_SCIMITAR),
mockItem(ItemID.FIGHTER_TORSO),
mockItem(ItemID.DRAGON_DEFENDER),
null,
mockItem(ItemID.IRON_PLATELEGS),
null,
mockItem(ItemID.BARROWS_GLOVES),
mockItem(ItemID.DRAGON_BOOTS),
mockItem(ItemID.BERSERKER_RING)
}, new int[] {26, 29, 35}),
OBSIDIAN_SET(new int[] {75, 83, 99}, 61, WeaponType.TYPE_17, 2, new Item[]
{
mockItem(ItemID.OBSIDIAN_HELMET),
mockItem(ItemID.OBSIDIAN_CAPE),
mockItem(ItemID.GOLD_NECKLACE),
mockItem(ItemID.TOKTZXILAK),
mockItem(ItemID.OBSIDIAN_PLATEBODY),
mockItem(ItemID.TOKTZKETXIL),
null,
mockItem(ItemID.OBSIDIAN_PLATELEGS),
null,
mockItem(ItemID.LEATHER_GLOVES),
mockItem(ItemID.LEATHER_BOOTS),
mockItem(ItemID.GOLD_RING)
}, new int[] {18, 19, 23}),
DHAROK_SET(new int[] {75, 75, 75, 83, 83, 83, 99, 99, 99}, 105, WeaponType.TYPE_1, 1,
new int[][] {{99, 99}, {1, 99}, {32, 75}, {99, 99}, {1, 99}, {32, 75}, {99, 99}, {1, 99}, {32, 75}},
new Item[]
{
mockItem(ItemID.DHAROKS_HELM_100),
mockItem(ItemID.BLACK_CAPE),
mockItem(ItemID.GOLD_NECKLACE),
mockItem(ItemID.DHAROKS_GREATAXE_100),
mockItem(ItemID.DHAROKS_PLATEBODY_100),
null,
null,
mockItem(ItemID.DHAROKS_PLATELEGS_100),
null,
mockItem(ItemID.LEATHER_GLOVES),
mockItem(ItemID.LEATHER_BOOTS),
mockItem(ItemID.GOLD_RING)
}, new int[] {23, 45, 30, 25, 49, 33, 29, 57, 38}),
VOID_SET(new int[] {75, 83, 99}, 66, WeaponType.TYPE_9, 1, new Item[]
{
mockItem(ItemID.VOID_MELEE_HELM),
mockItem(ItemID.BLACK_CAPE),
mockItem(ItemID.GOLD_NECKLACE),
mockItem(ItemID.DRAGON_SCIMITAR),
mockItem(ItemID.VOID_KNIGHT_TOP),
mockItem(ItemID.IRON_KITESHIELD),
null,
mockItem(ItemID.VOID_KNIGHT_ROBE),
null,
mockItem(ItemID.VOID_KNIGHT_GLOVES),
mockItem(ItemID.LEATHER_BOOTS),
mockItem(ItemID.GOLD_RING)
}, new int[] {19, 21, 25}),
;
private final int[] strengthLevels;
private final WeaponType weaponType;
private final int attackStyleId;
private final Item[] equipedItems;
private final int[] expectedMaxHits;
private final int[][] hitpoints;
private final int meleeEquipmentStrength;
MeleeMaxHitConfig(int[] strengthLevels, int meleeEquipmentStrength, WeaponType weaponType, int attackStyleId, int[][] hitpoints, Item[] equipedItems, int[] expectedMaxHits)
{
this.strengthLevels = strengthLevels;
this.meleeEquipmentStrength = meleeEquipmentStrength;
this.weaponType = weaponType;
this.attackStyleId = attackStyleId;
this.hitpoints = hitpoints;
this.equipedItems = equipedItems;
this.expectedMaxHits = expectedMaxHits;
}
MeleeMaxHitConfig(int[] strengthLevels, int meleeEquipmentStrength, WeaponType weaponType, int attackStyleId, Item[] equipedItems, int[] expectedMaxHits)
{
this.strengthLevels = strengthLevels;
this.hitpoints = new int[strengthLevels.length][2];
this.meleeEquipmentStrength = meleeEquipmentStrength;
this.weaponType = weaponType;
this.attackStyleId = attackStyleId;
this.equipedItems = equipedItems;
this.expectedMaxHits = expectedMaxHits;
}
private static Item mockItem(int itemId)
{
Item item = mock(Item.class);
when(item.getId()).thenReturn(itemId);
return item;
}
public void test(Client client)
{
int[] strengthLevels = this.strengthLevels;
for (int i = 0, strengthLevelsLength = strengthLevels.length; i < strengthLevelsLength; i++)
{
int strengthLevel = strengthLevels[i];
int[] hitpoints = this.hitpoints[i];
int expectedMaxHit = this.expectedMaxHits[i];
// Mock equipment container
ItemContainer equipmentContainer = mock(ItemContainer.class);
when(equipmentContainer.getItems())
.thenReturn(this.equipedItems);
when(client.getItemContainer(InventoryID.EQUIPMENT)).thenReturn(equipmentContainer);
// Mock equipment strength
Widget equipmentWidget = mock(Widget.class);
when(client.getWidget(WidgetInfo.EQUIPMENT_MELEE_STRENGTH)).thenReturn(equipmentWidget);
when(equipmentWidget.getText()).thenReturn("Melee strength: " + this.meleeEquipmentStrength);
// Mock Varbits
when(client.getVar(Varbits.EQUIPPED_WEAPON_TYPE)).thenReturn(this.weaponType.ordinal());
when(client.getVar(VarPlayer.ATTACK_STYLE)).thenReturn(this.attackStyleId);
// Mock strength
when(client.getBoostedSkillLevel(Skill.STRENGTH)).thenReturn(strengthLevel);
// Mock hitpoints
when(client.getBoostedSkillLevel(Skill.HITPOINTS)).thenReturn(hitpoints[0]);
when(client.getRealSkillLevel(Skill.HITPOINTS)).thenReturn(hitpoints[1]);
// Test
MeleeMaxHitCalculator maxHitCalculator = new MeleeMaxHitCalculator(client, this.equipedItems);
assertEquals(this.toString(), expectedMaxHit, maxHitCalculator.getMaxHit(), 0);
}
}
}

View File

@@ -0,0 +1,167 @@
/*
* Copyright (c) 2019, Bartvollebregt <https://github.com/Bartvollebregt>
* 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.maxhit.calculators.testconfig;
import net.runelite.api.*;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.plugins.maxhit.attackstyle.WeaponType;
import net.runelite.client.plugins.maxhit.calculators.RangeMaxHitCalculator;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public enum RangeMaxHitConfig implements MaxHitConfig
{
MAGIC_SHORTBOW(new int[] {75, 83, 99}, 49, WeaponType.TYPE_3, 1, new Item[]
{
mockItem(ItemID.IRON_FULL_HELM),
mockItem(ItemID.BLACK_CAPE),
mockItem(ItemID.GOLD_NECKLACE),
mockItem(ItemID.MAGIC_SHORTBOW),
mockItem(ItemID.IRON_PLATEBODY),
null,
null,
mockItem(ItemID.IRON_PLATELEGS),
null,
mockItem(ItemID.LEATHER_GLOVES),
mockItem(ItemID.LEATHER_BOOTS),
mockItem(ItemID.GOLD_RING),
mockItem(ItemID.RUNE_ARROW)
}, new int[] {15, 16, 19}),
RUNE_CROSSBOW(new int[] {75, 83, 99}, 115, WeaponType.TYPE_5, 0, new Item[]
{
mockItem(ItemID.IRON_FULL_HELM),
mockItem(ItemID.BLACK_CAPE),
mockItem(ItemID.GOLD_NECKLACE),
mockItem(ItemID.RUNE_CROSSBOW),
mockItem(ItemID.IRON_PLATEBODY),
null,
null,
mockItem(ItemID.IRON_PLATELEGS),
null,
mockItem(ItemID.LEATHER_GLOVES),
mockItem(ItemID.LEATHER_BOOTS),
mockItem(ItemID.GOLD_RING),
mockItem(ItemID.RUNITE_BOLTS)
}, new int[] {24, 26, 31}),
BLOwPIPE(new int[] {75, 83, 99}, 50, WeaponType.TYPE_19, 1, new Item[]
{
mockItem(ItemID.IRON_FULL_HELM),
mockItem(ItemID.BLACK_CAPE),
mockItem(ItemID.GOLD_NECKLACE),
mockItem(ItemID.TOXIC_BLOWPIPE),
mockItem(ItemID.IRON_PLATEBODY),
null,
null,
mockItem(ItemID.IRON_PLATELEGS),
null,
mockItem(ItemID.LEATHER_GLOVES),
mockItem(ItemID.LEATHER_BOOTS),
mockItem(ItemID.GOLD_RING)
}, new int[] {15, 16, 19}),
VOID_SET(new int[] {75, 83, 99}, 115, WeaponType.TYPE_5, 1, new Item[]
{
mockItem(ItemID.VOID_RANGER_HELM),
mockItem(ItemID.BLACK_CAPE),
mockItem(ItemID.GOLD_NECKLACE),
mockItem(ItemID.RUNE_CROSSBOW),
mockItem(ItemID.VOID_KNIGHT_TOP),
mockItem(ItemID.IRON_KITESHIELD),
null,
mockItem(ItemID.VOID_KNIGHT_ROBE),
null,
mockItem(ItemID.VOID_KNIGHT_GLOVES),
mockItem(ItemID.LEATHER_BOOTS),
mockItem(ItemID.GOLD_RING)
}, new int[] {26, 28, 33}),
;
private final int[] rangeLevels;
private final WeaponType weaponType;
private final int attackStyleId;
private final Item[] equipedItems;
private final int[] expectedMaxHits;
private final int ammoEquipmentStrength;
RangeMaxHitConfig(int[] rangeLevels, int ammoEquipmentStrength, WeaponType weaponType, int attackStyleId, Item[] equipedItems, int[] expectedMaxHits)
{
this.rangeLevels = rangeLevels;
this.ammoEquipmentStrength = ammoEquipmentStrength;
this.weaponType = weaponType;
this.attackStyleId = attackStyleId;
this.equipedItems = equipedItems;
this.expectedMaxHits = expectedMaxHits;
}
private static Item mockItem(int itemId)
{
Item item = mock(Item.class);
when(item.getId()).thenReturn(itemId);
return item;
}
public void test(Client client)
{
int[] rangeLevels = this.rangeLevels;
for (int i = 0, rangeLevelsLength = rangeLevels.length; i < rangeLevelsLength; i++)
{
int rangeLevel = rangeLevels[i];
int expectedMaxHit = this.expectedMaxHits[i];
// Mock equipment container
ItemContainer equipmentContainer = mock(ItemContainer.class);
when(equipmentContainer.getItems())
.thenReturn(this.equipedItems);
when(client.getItemContainer(InventoryID.EQUIPMENT)).thenReturn(equipmentContainer);
// Mock equipment strength
Widget equipmentWidget = mock(Widget.class);
when(client.getWidget(WidgetInfo.EQUIPMENT_RANGED_STRENGTH)).thenReturn(equipmentWidget);
when(equipmentWidget.getText()).thenReturn("Ranged strength: " + this.ammoEquipmentStrength);
// Mock Varbits
when(client.getVar(Varbits.EQUIPPED_WEAPON_TYPE)).thenReturn(this.weaponType.ordinal());
when(client.getVar(VarPlayer.ATTACK_STYLE)).thenReturn(this.attackStyleId);
// Mock strength
when(client.getBoostedSkillLevel(Skill.RANGED)).thenReturn(rangeLevel);
// Test
RangeMaxHitCalculator maxHitCalculator = new RangeMaxHitCalculator(client, this.equipedItems);
assertEquals(this.toString(), expectedMaxHit, maxHitCalculator.getMaxHit(), 0);
}
}
}