Merge remote-tracking branch 'upstream/master' into runelite

Also pulled out a couple of our merged apis into our own classes. Getting much easier to keep up to date with their data

# Conflicts:
#	.github/FUNDING.yml
#	.github/workflows/CI.yml
#	cache-client/pom.xml
#	cache-updater/pom.xml
#	cache/pom.xml
#	cache/src/main/java/net/runelite/cache/fs/jagex/DiskStorage.java
#	ci/build.sh
#	http-api/pom.xml
#	http-service/pom.xml
#	http-service/src/main/java/net/runelite/http/service/chat/ChatController.java
#	http-service/src/main/java/net/runelite/http/service/config/ConfigController.java
#	http-service/src/main/java/net/runelite/http/service/config/ConfigService.java
#	http-service/src/main/java/net/runelite/http/service/ge/GrandExchangeController.java
#	http-service/src/main/java/net/runelite/http/service/ge/Trade.java
#	http-service/src/test/java/net/runelite/http/service/config/ConfigServiceTest.java
#	http-service/src/test/java/net/runelite/http/service/hiscore/HiscoreServiceTest.java
#	pom.xml
#	runelite-api/pom.xml
#	runelite-api/src/main/java/net/runelite/api/Client.java
#	runelite-api/src/main/java/net/runelite/api/ObjectID.java
#	runelite-api/src/main/java/net/runelite/api/ParamHolder.java
#	runelite-api/src/main/java/net/runelite/api/ParamID.java
#	runelite-api/src/main/java/net/runelite/api/Preferences.java
#	runelite-api/src/main/java/net/runelite/api/ScriptEvent.java
#	runelite-api/src/main/java/net/runelite/api/ScriptID.java
#	runelite-api/src/main/java/net/runelite/api/SettingID.java
#	runelite-api/src/main/java/net/runelite/api/StructComposition.java
#	runelite-api/src/main/java/net/runelite/api/StructID.java
#	runelite-api/src/main/java/net/runelite/api/Varbits.java
#	runelite-api/src/main/java/net/runelite/api/events/PlayerChanged.java
#	runelite-api/src/main/java/net/runelite/api/events/PostStructComposition.java
#	runelite-api/src/main/java/net/runelite/api/events/WidgetClosed.java
#	runelite-api/src/main/java/net/runelite/api/events/WidgetHiddenChanged.java
#	runelite-api/src/main/java/net/runelite/api/events/WidgetPositioned.java
#	runelite-api/src/main/java/net/runelite/api/events/WorldChanged.java
#	runelite-api/src/main/java/net/runelite/api/widgets/Widget.java
#	runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java
#	runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java
#	runelite-api/src/main/java/net/runelite/api/widgets/WidgetModalMode.java
#	runelite-api/src/test/java/net/runelite/api/plugins/combatlevel/CombatLevelOverlayTest.java
#	runelite-client/pom.xml
#	runelite-client/src/main/java/net/runelite/client/RuneLiteModule.java
#	runelite-client/src/main/java/net/runelite/client/callback/Hooks.java
#	runelite-client/src/main/java/net/runelite/client/plugins/config/PluginToggleButton.java
#	runelite-client/src/main/java/net/runelite/client/plugins/customcursor/CustomCursor.java
#	runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperConfig.java
#	runelite-client/src/main/java/net/runelite/client/plugins/mta/alchemy/AlchemyRoomTimer.java
#	runelite-client/src/main/java/net/runelite/client/plugins/tearsofguthix/TearsOfGuthixOverlay.java
#	runelite-client/src/main/java/net/runelite/client/plugins/tearsofguthix/TearsOfGuthixPlugin.java
#	runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldTableHeader.java
#	runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldTableRow.java
#	runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java
#	runelite-client/src/main/resources/net/runelite/client/runelite.properties
#	runelite-client/src/main/scripts/OptionsPanelZoomUpdater.hash
#	runelite-client/src/test/java/net/runelite/client/config/ConfigManagerTest.java
#	runelite-client/src/test/java/net/runelite/client/plugins/chatcommands/ChatCommandsPluginTest.java
#	runelite-client/src/test/java/net/runelite/client/plugins/chatfilter/ChatFilterPluginTest.java
#	runelite-client/src/test/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsPluginTest.java
#	runelite-client/src/test/java/net/runelite/client/plugins/discord/DiscordStateTest.java
#	runelite-client/src/test/java/net/runelite/client/plugins/grandexchange/GrandExchangePluginTest.java
#	runelite-client/src/test/java/net/runelite/client/plugins/screenshot/ScreenshotPluginTest.java
#	runelite-client/src/test/java/net/runelite/client/plugins/specialcounter/SpecialCounterPluginTest.java
#	runelite-client/src/test/java/net/runelite/client/plugins/timers/TimersPluginTest.java
#	runelite-client/src/test/java/net/runelite/client/util/ColorUtilTest.java
#	runelite-script-assembler-plugin/pom.xml
This commit is contained in:
TheRealNull
2021-01-14 14:41:17 -05:00
99 changed files with 7485 additions and 1754 deletions

View File

@@ -29,37 +29,15 @@ package com.openosrs.client.plugins.openosrs;
import ch.qos.logback.classic.Logger;
import com.openosrs.client.plugins.openosrs.externals.ExternalPluginManagerPanel;
import com.openosrs.client.config.OpenOSRSConfig;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import static net.runelite.api.ScriptID.BANK_PIN_OP;
import net.runelite.api.events.ScriptCallbackEvent;
import net.runelite.api.widgets.WidgetID;
import static net.runelite.api.widgets.WidgetInfo.BANK_PIN_1;
import static net.runelite.api.widgets.WidgetInfo.BANK_PIN_10;
import static net.runelite.api.widgets.WidgetInfo.BANK_PIN_2;
import static net.runelite.api.widgets.WidgetInfo.BANK_PIN_3;
import static net.runelite.api.widgets.WidgetInfo.BANK_PIN_4;
import static net.runelite.api.widgets.WidgetInfo.BANK_PIN_5;
import static net.runelite.api.widgets.WidgetInfo.BANK_PIN_6;
import static net.runelite.api.widgets.WidgetInfo.BANK_PIN_7;
import static net.runelite.api.widgets.WidgetInfo.BANK_PIN_8;
import static net.runelite.api.widgets.WidgetInfo.BANK_PIN_9;
import static net.runelite.api.widgets.WidgetInfo.BANK_PIN_EXIT_BUTTON;
import static net.runelite.api.widgets.WidgetInfo.BANK_PIN_FIRST_ENTERED;
import static net.runelite.api.widgets.WidgetInfo.BANK_PIN_FORGOT_BUTTON;
import static net.runelite.api.widgets.WidgetInfo.BANK_PIN_FOURTH_ENTERED;
import static net.runelite.api.widgets.WidgetInfo.BANK_PIN_INSTRUCTION_TEXT;
import static net.runelite.api.widgets.WidgetInfo.BANK_PIN_SECOND_ENTERED;
import static net.runelite.api.widgets.WidgetInfo.BANK_PIN_THIRD_ENTERED;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.config.Keybind;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.events.ConfigChanged;
import net.runelite.client.input.KeyListener;
import net.runelite.client.input.KeyManager;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
@@ -78,8 +56,6 @@ import org.slf4j.LoggerFactory;
@Slf4j
public class OpenOSRSPlugin extends Plugin
{
private final openosrsKeyListener keyListener = new openosrsKeyListener();
@Inject
private OpenOSRSConfig config;
@@ -107,9 +83,6 @@ public class OpenOSRSPlugin extends Plugin
client.setOculusOrbNormalSpeed(detach ? 36 : 12);
}
};
private int entered = -1;
private int enterIdx;
private boolean expectInput;
private boolean detach;
private Keybind keybind;
@@ -128,9 +101,6 @@ public class OpenOSRSPlugin extends Plugin
.build();
clientToolbar.addNavigation(navButton);
entered = -1;
enterIdx = 0;
expectInput = false;
this.keybind = config.detachHotkey();
keyManager.registerKeyListener(hotkeyListener);
}
@@ -139,12 +109,6 @@ public class OpenOSRSPlugin extends Plugin
protected void shutDown()
{
clientToolbar.removeNavigation(navButton);
entered = 0;
enterIdx = 0;
expectInput = false;
keyManager.unregisterKeyListener(keyListener);
keyManager.unregisterKeyListener(hotkeyListener);
}
@Subscribe
@@ -157,14 +121,6 @@ public class OpenOSRSPlugin extends Plugin
this.keybind = config.detachHotkey();
if (!config.keyboardPin())
{
entered = 0;
enterIdx = 0;
expectInput = false;
keyManager.unregisterKeyListener(keyListener);
}
if (event.getKey().equals("shareLogs") && !config.shareLogs())
{
final Logger logger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
@@ -172,118 +128,4 @@ public class OpenOSRSPlugin extends Plugin
}
}
@Subscribe
private void onScriptCallbackEvent(ScriptCallbackEvent e)
{
if (!config.keyboardPin())
{
return;
}
if (e.getEventName().equals("bankpin"))
{
int[] intStack = client.getIntStack();
int intStackSize = client.getIntStackSize();
// This'll be anywhere from -1 to 3
// 0 = first number, 1 second, etc
// Anything other than 0123 means the bankpin interface closes
int enterIdx = intStack[intStackSize - 1];
if (enterIdx < 0 || enterIdx > 3)
{
keyManager.unregisterKeyListener(keyListener);
this.enterIdx = 0;
this.entered = 0;
expectInput = false;
return;
}
else if (enterIdx == 0)
{
keyManager.registerKeyListener(keyListener);
}
this.enterIdx = enterIdx;
expectInput = true;
}
}
private void handleKey(char c)
{
if (client.getWidget(WidgetID.BANK_PIN_GROUP_ID, BANK_PIN_INSTRUCTION_TEXT.getChildId()) == null
|| !client.getWidget(BANK_PIN_INSTRUCTION_TEXT).getText().equals("First click the FIRST digit.")
&& !client.getWidget(BANK_PIN_INSTRUCTION_TEXT).getText().equals("Now click the SECOND digit.")
&& !client.getWidget(BANK_PIN_INSTRUCTION_TEXT).getText().equals("Time for the THIRD digit.")
&& !client.getWidget(BANK_PIN_INSTRUCTION_TEXT).getText().equals("Finally, the FOURTH digit."))
{
entered = 0;
enterIdx = 0;
expectInput = false;
keyManager.unregisterKeyListener(keyListener);
return;
}
if (!expectInput)
{
return;
}
int num = Character.getNumericValue(c);
// We gotta copy this cause enteridx changes while the script is executing
int oldEnterIdx = enterIdx;
// Script 685 will call 653, which in turn will set expectInput to true
expectInput = false;
client.runScript(BANK_PIN_OP, num, enterIdx, entered, BANK_PIN_EXIT_BUTTON.getId(), BANK_PIN_FORGOT_BUTTON.getId(), BANK_PIN_1.getId(), BANK_PIN_2.getId(), BANK_PIN_3.getId(), BANK_PIN_4.getId(), BANK_PIN_5.getId(), BANK_PIN_6.getId(), BANK_PIN_7.getId(), BANK_PIN_8.getId(), BANK_PIN_9.getId(), BANK_PIN_10.getId(), BANK_PIN_FIRST_ENTERED.getId(), BANK_PIN_SECOND_ENTERED.getId(), BANK_PIN_THIRD_ENTERED.getId(), BANK_PIN_FOURTH_ENTERED.getId(), BANK_PIN_INSTRUCTION_TEXT.getId());
if (oldEnterIdx == 0)
{
entered = num * 1000;
}
else if (oldEnterIdx == 1)
{
entered += num * 100;
}
else if (oldEnterIdx == 2)
{
entered += num * 10;
}
}
private class openosrsKeyListener implements KeyListener
{
private int lastKeyCycle;
@Override
public void keyTyped(KeyEvent keyEvent)
{
if (!Character.isDigit(keyEvent.getKeyChar()))
{
return;
}
if (client.getGameCycle() - lastKeyCycle <= 5)
{
keyEvent.consume();
return;
}
lastKeyCycle = client.getGameCycle();
clientThread.invoke(() -> handleKey(keyEvent.getKeyChar()));
keyEvent.consume();
}
@Override
public void keyPressed(KeyEvent keyEvent)
{
}
@Override
public void keyReleased(KeyEvent keyEvent)
{
}
}
}

View File

@@ -32,6 +32,7 @@ import net.runelite.api.Constants;
import net.runelite.client.Notifier;
import net.runelite.client.ui.ContainableFrame;
import net.runelite.client.ui.overlay.components.ComponentConstants;
import net.runelite.client.util.OSType;
@ConfigGroup(RuneLiteConfig.GROUP_NAME)
public interface RuneLiteConfig extends Config
@@ -122,14 +123,14 @@ public interface RuneLiteConfig extends Config
@ConfigItem(
keyName = "uiEnableCustomChrome",
name = "Enable custom window chrome",
description = "Use Runelite's custom window title and borders.",
description = "Use RuneLite's custom window title and borders.",
warning = "Please restart your client after changing this setting",
position = 15,
section = windowSettings
)
default boolean enableCustomChrome()
{
return true;
return OSType.getOSType() == OSType.Windows;
}
@Range(
@@ -150,7 +151,7 @@ public interface RuneLiteConfig extends Config
@ConfigItem(
keyName = "gameAlwaysOnTop",
name = "Enable client always on top",
name = "Always on top",
description = "The game will always be on the top of the screen",
position = 17,
section = windowSettings
@@ -162,8 +163,8 @@ public interface RuneLiteConfig extends Config
@ConfigItem(
keyName = "warningOnExit",
name = "Display warning on exit",
description = "Toggles a warning popup when trying to exit the client",
name = "Exit warning",
description = "Shows a warning popup when trying to exit the client",
position = 18,
section = windowSettings
)
@@ -198,7 +199,7 @@ public interface RuneLiteConfig extends Config
@ConfigItem(
keyName = "notificationRequestFocus",
name = "Request focus on notification",
name = "Request focus",
description = "Configures the window focus request type on notification",
position = 21,
section = notificationSettings
@@ -222,8 +223,8 @@ public interface RuneLiteConfig extends Config
@ConfigItem(
keyName = "notificationGameMessage",
name = "Enable game message notifications",
description = "Puts a notification message in the chatbox",
name = "Game message notifications",
description = "Adds a notification message to the chatbox",
position = 23,
section = notificationSettings
)
@@ -234,7 +235,7 @@ public interface RuneLiteConfig extends Config
@ConfigItem(
keyName = "flashNotification",
name = "Flash notification",
name = "Flash",
description = "Flashes the game frame as a notification",
position = 24,
section = notificationSettings
@@ -259,7 +260,7 @@ public interface RuneLiteConfig extends Config
@Alpha
@ConfigItem(
keyName = "notificationFlashColor",
name = "Notification Flash Color",
name = "Notification Flash",
description = "Sets the color of the notification flashes.",
position = 26,
section = notificationSettings
@@ -295,7 +296,7 @@ public interface RuneLiteConfig extends Config
@ConfigItem(
keyName = "interfaceFontType",
name = "Interface Overlay Font",
name = "Interface Font",
description = "Configures what font type is used for in-game interface overlays such as panels, opponent info, clue scrolls etc.",
position = 32,
section = overlaySettings

View File

@@ -689,6 +689,11 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
log.warn("Unable to get clipboard", ex);
}
return;
case KeyEvent.VK_A:
selectionStart = 0;
selectionEnd = value.length();
cursorAt(0, selectionEnd);
return;
}
return;
}
@@ -753,11 +758,25 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
return;
case KeyEvent.VK_LEFT:
ev.consume();
newPos--;
if (cursorStart != cursorEnd)
{
newPos = cursorStart;
}
else
{
newPos--;
}
break;
case KeyEvent.VK_RIGHT:
ev.consume();
newPos++;
if (cursorStart != cursorEnd)
{
newPos = cursorEnd;
}
else
{
newPos++;
}
break;
case KeyEvent.VK_UP:
ev.consume();

View File

@@ -50,9 +50,9 @@ public class KaramjaDiaryRequirement extends GenericDiaryRequirement
add("Claim a ticket from the Agility Arena in Brimhaven.",
new SkillRequirement(Skill.AGILITY, 30));
add("Discover hidden wall in the dungeon below the volcano.",
new QuestRequirement(Quest.DRAGON_SLAYER, true));
new QuestRequirement(Quest.DRAGON_SLAYER_I, true));
add("Visit the Isle of Crandor via the dungeon below the volcano.",
new QuestRequirement(Quest.DRAGON_SLAYER, true));
new QuestRequirement(Quest.DRAGON_SLAYER_I, true));
add("Use Vigroy and Hajedy's cart service.",
new QuestRequirement(Quest.SHILO_VILLAGE));
add("Earn 100% favour in the village of Tai Bwo Wannai.",

View File

@@ -147,7 +147,7 @@ public interface AgilityConfig extends Config
@Alpha
@ConfigItem(
keyName = "portalsHighlight",
name = "Portals Highlight Color",
name = "Portals Color",
description = "Color of highlighted Prifddinas portals",
position = 9
)

View File

@@ -81,7 +81,7 @@ public interface BoostsConfig extends Config
@ConfigItem(
keyName = "displayNextBuffChange",
name = "Display next buff change",
name = "Next buff change",
description = "Configures whether or not to display when the next buffed stat change will be",
position = 4
)
@@ -92,7 +92,7 @@ public interface BoostsConfig extends Config
@ConfigItem(
keyName = "displayNextDebuffChange",
name = "Display next debuff change",
name = "Next debuff change",
description = "Configures whether or not to display when the next debuffed stat change will be",
position = 5
)
@@ -103,7 +103,7 @@ public interface BoostsConfig extends Config
@ConfigItem(
keyName = "boostThreshold",
name = "Boost amount threshold",
name = "Boost threshold",
description = "The threshold at which boosted levels will be displayed in a different color. A value of 0 will disable the feature.",
position = 6
)

View File

@@ -51,7 +51,7 @@ public interface CannonConfig extends Config
)
@ConfigItem(
keyName = "lowWarningThreshold",
name = "Low Warning Threshold",
name = "Low warning threshold",
description = "Configures the number of cannonballs remaining before a notification is sent. <br>Regardless of this value, a notification will still be sent when your cannon is empty.",
position = 2
)
@@ -62,7 +62,7 @@ public interface CannonConfig extends Config
@ConfigItem(
keyName = "showInfobox",
name = "Show Cannonball infobox",
name = "Show cannonball infobox",
description = "Configures whether to show the cannonballs in an infobox",
position = 3
)
@@ -85,7 +85,7 @@ public interface CannonConfig extends Config
@Alpha
@ConfigItem(
keyName = "highlightDoubleHitColor",
name = "Color of double hit spots",
name = "Double hit spots",
description = "Configures the highlight color of double hit spots",
position = 5
)

View File

@@ -156,7 +156,7 @@ public interface ChatFilterConfig extends Config
@ConfigItem(
keyName = "maxRepeatedPublicChats",
name = "Max repeated public chats",
name = "Repeat filter",
description = "Block player chat message if repeated this many times. 0 is off",
position = 11
)

View File

@@ -105,7 +105,7 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc
new CrypticClue("A crate found in the tower of a church is your next location.", CRATE_357, new WorldPoint(2612, 3304, 1), "Climb the ladder and search the crates on the first floor in the Church in Ardougne."),
new CrypticClue("Covered in shadows, the centre of the circle is where you will find the answer.", new WorldPoint(3488, 3289, 0), "Dig in the centre of Mort'ton, where the roads intersect."),
new CrypticClue("I lie lonely and forgotten in mid wilderness, where the dead rise from their beds. Feel free to quarrel and wind me up, and dig while you shoot their heads.", new WorldPoint(3174, 3663, 0), "Directly under the crossbow respawn in the Graveyard of Shadows in level 18 Wilderness."),
new CrypticClue("In the city where merchants are said to have lived, talk to a man with a splendid cape, but a hat dropped by goblins.", "Head chef", new WorldPoint(3143, 3445, 0), "Talk to the Head chef in Cooks' Guild west of Varrock. You will need a chef hat or cooking cape to enter."),
new CrypticClue("In the city where merchants are said to have lived, talk to a man with a splendid cape, but a hat dropped by goblins.", "Head chef", new WorldPoint(3143, 3445, 0), "Talk to the Head chef in Cooks' Guild west of Varrock. You will need a chef's hat, Varrock armour 3 or 4, or the Cooking cape to enter."),
new CrypticClue("The mother of the reptilian sacrifice.", "Zul-Cheray", new WorldPoint(2204, 3050, 0), "Talk to Zul-Cheray in a house near the sacrificial boat at Zul-Andra."),
new CrypticClue("I watch the sea. I watch you fish. I watch your tree.", "Ellena", new WorldPoint(2860, 3431, 0), "Speak to Ellena at Catherby fruit tree patch."),
new CrypticClue("Dig between some ominous stones in Falador.", new WorldPoint(3040, 3399, 0), "Three standing stones inside a walled area. East of the northern Falador gate."),

View File

@@ -50,7 +50,7 @@ import net.runelite.client.ui.overlay.components.TitleComponent;
public class FaloTheBardClue extends ClueScroll implements TextClueScroll, NpcClueScroll
{
private static final List<FaloTheBardClue> CLUES = ImmutableList.of(
new FaloTheBardClue("A blood red weapon, a strong curved sword, found on the island of primate lords.", item(DRAGON_SCIMITAR)),
new FaloTheBardClue("A blood red weapon, a strong curved sword, found on the island of primate lords.", any("Dragon scimitar", item(DRAGON_SCIMITAR), item(DRAGON_SCIMITAR_OR))),
new FaloTheBardClue("A book that preaches of some great figure, lending strength, might and vigour.", any("Any god book (must be complete)", item(HOLY_BOOK), item(BOOK_OF_BALANCE), item(UNHOLY_BOOK), item(BOOK_OF_LAW), item(BOOK_OF_WAR), item(BOOK_OF_DARKNESS))),
new FaloTheBardClue("A bow of elven craft was made, it shimmers bright, but will soon fade.", any("Crystal Bow", item(CRYSTAL_BOW), item(CRYSTAL_BOW_24123))),
new FaloTheBardClue("A fiery axe of great inferno, when you use it, you'll wonder where the logs go.", item(INFERNAL_AXE)),

View File

@@ -91,7 +91,7 @@ public enum HotColdLocation
FREMENNIK_PROVINCE_FREMMY_ISLES_MINE(new WorldPoint(2374, 3850, 0), FREMENNIK_PROVINCE, "Central Fremennik Isles mine.", ANCIENT_WIZARDS),
FREMENNIK_PROVINCE_WEST_ISLES_MINE(new WorldPoint(2313, 3850, 0), FREMENNIK_PROVINCE, "West Fremennik Isles mine.", ANCIENT_WIZARDS),
FREMENNIK_PROVINCE_WEST_JATIZSO_ENTRANCE(new WorldPoint(2393, 3812, 0), FREMENNIK_PROVINCE, "West of the Jatizso mine entrance.", BRASSICAN_MAGE),
FREMENNIK_PROVINCE_PIRATES_COVE(new WorldPoint(2210, 3814, 0), FREMENNIK_PROVINCE, "Pirates' Cove", ANCIENT_WIZARDS),
FREMENNIK_PROVINCE_PIRATES_COVE(new WorldPoint(2211, 3817, 0), FREMENNIK_PROVINCE, "Pirates' Cove", ANCIENT_WIZARDS),
FREMENNIK_PROVINCE_ASTRAL_ALTER(new WorldPoint(2149, 3865, 0), FREMENNIK_PROVINCE, "Astral altar", ANCIENT_WIZARDS),
FREMENNIK_PROVINCE_LUNAR_VILLAGE(new WorldPoint(2084, 3916, 0), FREMENNIK_PROVINCE, "Lunar Isle, inside the village.", ANCIENT_WIZARDS),
FREMENNIK_PROVINCE_LUNAR_NORTH(new WorldPoint(2106, 3949, 0), FREMENNIK_PROVINCE, "Lunar Isle, north of the village.", ANCIENT_WIZARDS),

View File

@@ -487,15 +487,19 @@ class ConfigPanel extends PluginPanel
if (cid.getType().isEnum())
{
Class<? extends Enum> type = (Class<? extends Enum>) cid.getType();
JComboBox box = new JComboBox(type.getEnumConstants());
JComboBox<Enum<?>> box = new JComboBox<Enum<?>>(type.getEnumConstants()); // NOPMD: UseDiamondOperator
// set renderer prior to calling box.getPreferredSize(), since it will invoke the renderer
// to build components for each combobox element in order to compute the display size of the
// combobox
box.setRenderer(new ComboBoxListRenderer<>());
box.setPreferredSize(new Dimension(box.getPreferredSize().width, 25));
box.setRenderer(new ComboBoxListRenderer());
box.setForeground(Color.WHITE);
box.setFocusable(false);
box.setPrototypeDisplayValue("XXXXXXXX"); //sorry but this is the way to keep the size of the combobox in check.
try
{
Enum selectedItem = Enum.valueOf(type, configManager.getConfiguration(cd.getGroup().value(), cid.getItem().keyName()));
Enum<?> selectedItem = Enum.valueOf(type, configManager.getConfiguration(cd.getGroup().value(), cid.getItem().keyName()));
box.setSelectedItem(selectedItem);
box.setToolTipText(Text.titleCase(selectedItem));
}
@@ -508,7 +512,7 @@ class ConfigPanel extends PluginPanel
if (e.getStateChange() == ItemEvent.SELECTED)
{
changeConfiguration(box, cd, cid);
box.setToolTipText(Text.titleCase((Enum) box.getSelectedItem()));
box.setToolTipText(Text.titleCase((Enum<?>) box.getSelectedItem()));
}
});
item.add(box, BorderLayout.EAST);

View File

@@ -56,4 +56,11 @@ public enum CustomCursor
this.name = name;
this.cursorImage = ImageUtil.loadImageResource(CustomCursorPlugin.class, icon);
}
@Override
public String toString()
{
return name;
}
}

View File

@@ -99,7 +99,7 @@ public interface DriftNetConfig extends Config
@ConfigItem(
keyName = "tagAnnette",
name = "Tag Annette when no nets in inventory",
name = "Tag Annette",
description = "Tag Annette when no nets in inventory",
position = 6
)

View File

@@ -93,7 +93,7 @@ public interface FishingConfig extends Config
@Alpha
@ConfigItem(
keyName = "minnowsOverlayColor",
name = "Minnows Overlay Color",
name = "Minnows Overlay",
description = "Color of overlays for Minnows",
position = 5
)
@@ -105,7 +105,7 @@ public interface FishingConfig extends Config
@Alpha
@ConfigItem(
keyName = "aerialOverlayColor",
name = "Aerial Overlay Color",
name = "Aerial Overlay",
description = "Color of overlays when 1-tick aerial fishing",
position = 6
)

View File

@@ -156,7 +156,7 @@ public interface GroundItemsConfig extends Config
@ConfigItem(
keyName = "notifyTier",
name = "Notify >= Tier",
name = "Notify tier",
description = "Configures which price tiers will trigger a notification on drop",
position = 8
)
@@ -211,7 +211,7 @@ public interface GroundItemsConfig extends Config
@ConfigItem(
keyName = "hideUnderValue",
name = "Hide < Value",
name = "Hide under value",
description = "Configures hidden ground items under both GE and HA value",
position = 13
)
@@ -223,7 +223,7 @@ public interface GroundItemsConfig extends Config
@Alpha
@ConfigItem(
keyName = "defaultColor",
name = "Default items color",
name = "Default items",
description = "Configures the color for default, non-highlighted items",
position = 14
)
@@ -235,7 +235,7 @@ public interface GroundItemsConfig extends Config
@Alpha
@ConfigItem(
keyName = "highlightedColor",
name = "Highlighted items color",
name = "Highlighted items",
description = "Configures the color for highlighted items",
position = 15
)
@@ -247,7 +247,7 @@ public interface GroundItemsConfig extends Config
@Alpha
@ConfigItem(
keyName = "hiddenColor",
name = "Hidden items color",
name = "Hidden items",
description = "Configures the color for hidden items in right-click menu and when holding ALT",
position = 16
)
@@ -259,7 +259,7 @@ public interface GroundItemsConfig extends Config
@Alpha
@ConfigItem(
keyName = "lowValueColor",
name = "Low value items color",
name = "Low value items",
description = "Configures the color for low value items",
position = 17
)
@@ -282,7 +282,7 @@ public interface GroundItemsConfig extends Config
@Alpha
@ConfigItem(
keyName = "mediumValueColor",
name = "Medium value items color",
name = "Medium value items",
description = "Configures the color for medium value items",
position = 19
)
@@ -305,7 +305,7 @@ public interface GroundItemsConfig extends Config
@Alpha
@ConfigItem(
keyName = "highValueColor",
name = "High value items color",
name = "High value items",
description = "Configures the color for high value items",
position = 21
)
@@ -328,7 +328,7 @@ public interface GroundItemsConfig extends Config
@Alpha
@ConfigItem(
keyName = "insaneValueColor",
name = "Insane value items color",
name = "Insane value items",
description = "Configures the color for insane value items",
position = 23
)
@@ -361,8 +361,8 @@ public interface GroundItemsConfig extends Config
@ConfigItem(
keyName = "doubleTapDelay",
name = "Delay for double-tap ALT to hide",
description = "Decrease this number if you accidentally hide ground items often. (0 = Disabled)",
name = "Double-tap delay",
description = "Delay for the double-tap ALT to hide ground items. 0 to disable.",
position = 26
)
@Units(Units.MILLISECONDS)
@@ -373,7 +373,7 @@ public interface GroundItemsConfig extends Config
@ConfigItem(
keyName = "collapseEntries",
name = "Collapse ground item menu entries",
name = "Collapse ground item menu",
description = "Collapses ground item menu entries together and appends count",
position = 27
)

View File

@@ -90,7 +90,7 @@ public interface IdleNotifierConfig extends Config
@ConfigItem(
keyName = "hitpoints",
name = "Hitpoints Notification Threshold",
name = "Hitpoints Threshold",
description = "The amount of hitpoints to send a notification at. A value of 0 will disable notification.",
position = 6
)
@@ -101,7 +101,7 @@ public interface IdleNotifierConfig extends Config
@ConfigItem(
keyName = "prayer",
name = "Prayer Notification Threshold",
name = "Prayer Threshold",
description = "The amount of prayer points to send a notification at. A value of 0 will disable notification.",
position = 7
)
@@ -112,7 +112,7 @@ public interface IdleNotifierConfig extends Config
@ConfigItem(
keyName = "oxygen",
name = "Oxygen Notification Threshold",
name = "Oxygen Threshold",
position = 8,
description = "The amount of remaining oxygen to send a notification at. A value of 0 will disable notification."
)
@@ -124,9 +124,9 @@ public interface IdleNotifierConfig extends Config
@ConfigItem(
keyName = "spec",
name = "Special Attack Energy Notification Threshold",
name = "Spec Threshold",
position = 9,
description = "The amount of spec energy reached to send a notification at. A value of 0 will disable notification."
description = "The amount of special attack energy reached to send a notification at. A value of 0 will disable notification."
)
@Units(Units.PERCENT)
default int getSpecEnergyThreshold()

View File

@@ -55,7 +55,7 @@ public interface ImplingsConfig extends Config
@ConfigItem(
position = 1,
keyName = "showbaby",
name = "Show Baby implings",
name = "Baby implings",
description = "Configures whether or not Baby impling tags are displayed",
section = implingSection
)
@@ -80,7 +80,7 @@ public interface ImplingsConfig extends Config
@ConfigItem(
position = 3,
keyName = "showyoung",
name = "Show Young implings",
name = "Young implings",
description = "Configures whether or not Young impling tags are displayed",
section = implingSection
)
@@ -105,7 +105,7 @@ public interface ImplingsConfig extends Config
@ConfigItem(
position = 5,
keyName = "showgourmet",
name = "Show Gourmet implings",
name = "Gourmet implings",
description = "Configures whether or not Gourmet impling tags are displayed",
section = implingSection
)
@@ -130,7 +130,7 @@ public interface ImplingsConfig extends Config
@ConfigItem(
position = 7,
keyName = "showearth",
name = "Show Earth implings",
name = "Earth implings",
description = "Configures whether or not Earth impling tags are displayed",
section = implingSection
)
@@ -155,7 +155,7 @@ public interface ImplingsConfig extends Config
@ConfigItem(
position = 9,
keyName = "showessence",
name = "Show Essence implings",
name = "Essence implings",
description = "Configures whether or not Essence impling tags are displayed",
section = implingSection
)
@@ -180,7 +180,7 @@ public interface ImplingsConfig extends Config
@ConfigItem(
position = 11,
keyName = "showeclectic",
name = "Show Eclectic implings",
name = "Eclectic implings",
description = "Configures whether or not Eclectic impling tags are displayed",
section = implingSection
)
@@ -205,7 +205,7 @@ public interface ImplingsConfig extends Config
@ConfigItem(
position = 13,
keyName = "shownature",
name = "Show Nature implings",
name = "Nature implings",
description = "Configures whether or not Nature impling tags are displayed",
section = implingSection
)
@@ -230,7 +230,7 @@ public interface ImplingsConfig extends Config
@ConfigItem(
position = 15,
keyName = "showmagpie",
name = "Show Magpie implings",
name = "Magpie implings",
description = "Configures whether or not Magpie impling tags are displayed",
section = implingSection
)
@@ -255,7 +255,7 @@ public interface ImplingsConfig extends Config
@ConfigItem(
position = 17,
keyName = "showninja",
name = "Show Ninja implings",
name = "Ninja implings",
description = "Configures whether or not Ninja impling tags are displayed",
section = implingSection
)
@@ -280,7 +280,7 @@ public interface ImplingsConfig extends Config
@ConfigItem(
position = 19,
keyName = "showCrystal",
name = "Show Crystal implings",
name = "Crystal implings",
description = "Configures whether or not Crystal implings are displayed",
section = implingSection
)
@@ -305,7 +305,7 @@ public interface ImplingsConfig extends Config
@ConfigItem(
position = 21,
keyName = "showdragon",
name = "Show Dragon implings",
name = "Dragon implings",
description = "Configures whether or not Dragon impling tags are displayed",
section = implingSection
)
@@ -330,7 +330,7 @@ public interface ImplingsConfig extends Config
@ConfigItem(
position = 23,
keyName = "showlucky",
name = "Show Lucky implings",
name = "Lucky implings",
description = "Configures whether or not Lucky impling tags are displayed",
section = implingSection
)

View File

@@ -51,7 +51,7 @@ public interface ItemChargeConfig extends Config
@ConfigItem(
keyName = "veryLowWarningColor",
name = "Very Low Warning Color",
name = "Very Low Warning",
description = "The color of the overlay when charges are very low",
position = 1
)
@@ -62,7 +62,7 @@ public interface ItemChargeConfig extends Config
@ConfigItem(
keyName = "lowWarningColor",
name = "Low Warning Color",
name = "Low Warning",
description = "The color of the overlay when charges are low",
position = 2
)
@@ -95,7 +95,7 @@ public interface ItemChargeConfig extends Config
@ConfigItem(
keyName = "showTeleportCharges",
name = "Show Teleport Charges",
name = "Teleport Charges",
description = "Show teleport item charge counts",
position = 5,
section = chargesSection
@@ -149,7 +149,7 @@ public interface ItemChargeConfig extends Config
@ConfigItem(
keyName = "showImpCharges",
name = "Show Imp-in-a-box charges",
name = "Imp-in-a-box charges",
description = "Show Imp-in-a-box item charges",
position = 8,
section = chargesSection
@@ -161,7 +161,7 @@ public interface ItemChargeConfig extends Config
@ConfigItem(
keyName = "showFungicideCharges",
name = "Show Fungicide Charges",
name = "Fungicide Charges",
description = "Show Fungicide item charges",
position = 9,
section = chargesSection
@@ -173,7 +173,7 @@ public interface ItemChargeConfig extends Config
@ConfigItem(
keyName = "showWateringCanCharges",
name = "Show Watering Can Charges",
name = "Watering Can Charges",
description = "Show Watering can item charges",
position = 10,
section = chargesSection
@@ -185,7 +185,7 @@ public interface ItemChargeConfig extends Config
@ConfigItem(
keyName = "showWaterskinCharges",
name = "Show Waterskin Charges",
name = "Waterskin Charges",
description = "Show Waterskin dose counts",
position = 11,
section = chargesSection
@@ -197,7 +197,7 @@ public interface ItemChargeConfig extends Config
@ConfigItem(
keyName = "showBellowCharges",
name = "Show Bellows Charges",
name = "Bellows Charges",
description = "Show Ogre bellows item charges",
position = 12,
section = chargesSection
@@ -209,7 +209,7 @@ public interface ItemChargeConfig extends Config
@ConfigItem(
keyName = "showBasketCharges",
name = "Show Basket Charges",
name = "Basket Charges",
description = "Show Fruit basket item counts",
position = 13,
section = chargesSection
@@ -221,7 +221,7 @@ public interface ItemChargeConfig extends Config
@ConfigItem(
keyName = "showSackCharges",
name = "Show Sack Charges",
name = "Sack Charges",
description = "Show Sack item counts",
position = 14,
section = chargesSection
@@ -233,7 +233,7 @@ public interface ItemChargeConfig extends Config
@ConfigItem(
keyName = "showAbyssalBraceletCharges",
name = "Show Abyssal Bracelet Charges",
name = "Abyssal Bracelet Charges",
description = "Show Abyssal bracelet item charges",
position = 15,
section = chargesSection
@@ -245,7 +245,7 @@ public interface ItemChargeConfig extends Config
@ConfigItem(
keyName = "showAmuletOfChemistryCharges",
name = "Show Amulet of Chemistry Charges",
name = "Amulet of Chemistry Charges",
description = "Show Amulet of chemistry item charges",
position = 16,
section = chargesSection
@@ -275,7 +275,7 @@ public interface ItemChargeConfig extends Config
@ConfigItem(
keyName = "showAmuletOfBountyCharges",
name = "Show Amulet of Bounty Charges",
name = "Amulet of Bounty Charges",
description = "Show Amulet of bounty item charges",
position = 17,
section = chargesSection
@@ -317,7 +317,7 @@ public interface ItemChargeConfig extends Config
@ConfigItem(
keyName = "showBindingNecklaceCharges",
name = "Show Binding Necklace Charges",
name = "Binding Necklace Charges",
description = "Show Binding necklace item charges",
position = 19,
section = chargesSection
@@ -359,7 +359,7 @@ public interface ItemChargeConfig extends Config
@ConfigItem(
keyName = "showExplorerRingCharges",
name = "Show Explorer's Ring Alch Charges",
name = "Explorer's Ring Alch Charges",
description = "Show Explorer's ring alchemy charges",
position = 21,
section = chargesSection
@@ -389,7 +389,7 @@ public interface ItemChargeConfig extends Config
@ConfigItem(
keyName = "showRingOfForgingCount",
name = "Show Ring of Forging Charges",
name = "Ring of Forging Charges",
description = "Show Ring of forging item charges",
position = 22,
section = chargesSection
@@ -431,7 +431,7 @@ public interface ItemChargeConfig extends Config
@ConfigItem(
keyName = "showInfoboxes",
name = "Show Infoboxes",
name = "Infoboxes",
description = "Show an infobox with remaining charges for equipped items",
position = 24
)
@@ -442,7 +442,7 @@ public interface ItemChargeConfig extends Config
@ConfigItem(
keyName = "showPotionDoseCount",
name = "Show Potion Doses",
name = "Potion Doses",
description = "Show remaining potion doses",
position = 25,
section = chargesSection

View File

@@ -131,7 +131,7 @@ public class ItemStatChanges
add(boost(DEFENCE, perc(.15, 5)), SUPER_DEFENCE1, SUPER_DEFENCE2, SUPER_DEFENCE3, SUPER_DEFENCE4);
add(boost(MAGIC, 3), MAGIC_ESSENCE1, MAGIC_ESSENCE2, MAGIC_ESSENCE3, MAGIC_ESSENCE4);
add(combo(3, boost(ATTACK, perc(.15, 5)), boost(STRENGTH, perc(.15, 5)), boost(DEFENCE, perc(.15, 5))), SUPER_COMBAT_POTION1, SUPER_COMBAT_POTION2, SUPER_COMBAT_POTION3, SUPER_COMBAT_POTION4);
add(combo(3, boost(ATTACK, perc(.20, 2)), boost(STRENGTH, perc(.12, 2)), heal(PRAYER, perc(.10, 0)), heal(DEFENCE, perc(.10, -2)), new BoostedStatBoost(HITPOINTS, false, perc(-.12, 0))), ZAMORAK_BREW1, ZAMORAK_BREW2, ZAMORAK_BREW3, ZAMORAK_BREW4);
add(combo(3, boost(ATTACK, perc(.20, 2)), boost(STRENGTH, perc(.12, 2)), heal(PRAYER, perc(.10, 0)), new BoostedStatBoost(DEFENCE, false, perc(.10, -2)), new BoostedStatBoost(HITPOINTS, false, perc(-.12, 0))), ZAMORAK_BREW1, ZAMORAK_BREW2, ZAMORAK_BREW3, ZAMORAK_BREW4);
add(new SaradominBrew(0.15, 0.2, 0.1, 2, 2), SARADOMIN_BREW1, SARADOMIN_BREW2, SARADOMIN_BREW3, SARADOMIN_BREW4);
add(boost(RANGED, perc(.15, 5)), SUPER_RANGING_1, SUPER_RANGING_2, SUPER_RANGING_3, SUPER_RANGING_4);
add(boost(MAGIC, perc(.15, 5)), SUPER_MAGIC_POTION_1, SUPER_MAGIC_POTION_2, SUPER_MAGIC_POTION_3, SUPER_MAGIC_POTION_4);
@@ -214,6 +214,10 @@ public class ItemStatChanges
add(heal(HITPOINTS, 20), PADDLEFISH);
add(new GauntletPotion(), EGNIOL_POTION_1, EGNIOL_POTION_2, EGNIOL_POTION_3, EGNIOL_POTION_4);
// Soul Wars
add(combo(2, heal(HITPOINTS, perc(.20, 2)), heal(RUN_ENERGY, 100)), BANDAGES_25202);
add(combo(6, boost(ATTACK, perc(.15, 5)), boost(STRENGTH, perc(.15, 5)), boost(DEFENCE, perc(.15, 5)), boost(RANGED, perc(.15, 5)), boost(MAGIC, perc(.15, 5)), heal(PRAYER, perc(.25, 8))), POTION_OF_POWER1, POTION_OF_POWER2, POTION_OF_POWER3, POTION_OF_POWER4);
log.debug("{} items; {} behaviours loaded", effects.size(), new HashSet<>(effects.values()).size());
}

View File

@@ -227,6 +227,10 @@ public class LootTrackerPlugin extends Plugin
private static final String CASKET_EVENT = "Casket";
// Soul Wars
private static final String SPOILS_OF_WAR_EVENT = "Spoils of war";
private static final Set<Integer> SOUL_WARS_REGIONS = ImmutableSet.of(8493, 8749, 9005);
private static final Set<Character> VOWELS = ImmutableSet.of('a', 'e', 'i', 'o', 'u');
@Inject
@@ -487,8 +491,8 @@ public class LootTrackerPlugin extends Plugin
@Subscribe
public void onPlayerLootReceived(final PlayerLootReceived playerLootReceived)
{
// Ignore Last Man Standing player loots
if (isPlayerWithinMapRegion(LAST_MAN_STANDING_REGIONS))
// Ignore Last Man Standing and Soul Wars player loots
if (isPlayerWithinMapRegion(LAST_MAN_STANDING_REGIONS) || isPlayerWithinMapRegion(SOUL_WARS_REGIONS))
{
return;
}
@@ -763,6 +767,7 @@ public class LootTrackerPlugin extends Plugin
|| SEEDPACK_EVENT.equals(eventType)
|| CASKET_EVENT.equals(eventType)
|| BIRDNEST_EVENT.equals(eventType)
|| SPOILS_OF_WAR_EVENT.equals(eventType)
|| eventType.endsWith("Bird House")
|| eventType.startsWith("H.A.M. chest")
|| lootRecordType == LootRecordType.PICKPOCKET)
@@ -808,6 +813,12 @@ public class LootTrackerPlugin extends Plugin
setEvent(LootRecordType.EVENT, CASKET_EVENT);
takeInventorySnapshot();
}
if (event.getMenuOption().equals("Open") && event.getId() == ItemID.SPOILS_OF_WAR)
{
setEvent(LootRecordType.EVENT, SPOILS_OF_WAR_EVENT);
takeInventorySnapshot();
}
}
@Schedule(

View File

@@ -606,4 +606,15 @@ public interface MenuEntrySwapperConfig extends Config
{
return false;
}
@ConfigItem(
keyName = "swapRockCake",
name = "Dwarven rock cake",
description = "Swap Eat with Guzzle on the Dwarven rock cake",
section = itemSection
)
default boolean swapRockCake()
{
return false;
}
}

View File

@@ -355,6 +355,8 @@ public class MenuEntrySwapperPlugin extends Plugin
swapTeleport("camelot teleport", "seers'");
swapTeleport("watchtower teleport", "yanille");
swapTeleport("teleport to house", "outside");
swap("eat", "guzzle", config::swapRockCake);
}
private void swap(String option, String swappedOption, Supplier<Boolean> enabled)

View File

@@ -44,7 +44,7 @@ public interface OpponentInfoConfig extends Config
@ConfigItem(
keyName = "hitpointsDisplayStyle",
name = "Hitpoints display style",
name = "Display style",
description = "Show opponent's hitpoints as a value (if known), percentage, or both",
position = 1
)

View File

@@ -55,7 +55,7 @@ public interface PlayerIndicatorsConfig extends Config
@ConfigItem(
position = 1,
keyName = "ownNameColor",
name = "Own player color",
name = "Own player",
description = "Color of your own player",
section = highlightSection
)
@@ -79,7 +79,7 @@ public interface PlayerIndicatorsConfig extends Config
@ConfigItem(
position = 3,
keyName = "friendNameColor",
name = "Friend color",
name = "Friend",
description = "Color of friend names",
section = highlightSection
)
@@ -103,7 +103,7 @@ public interface PlayerIndicatorsConfig extends Config
@ConfigItem(
position = 5,
keyName = "clanMemberColor",
name = "Friends chat member color",
name = "Friends chat",
description = "Color of friends chat members",
section = highlightSection
)
@@ -127,7 +127,7 @@ public interface PlayerIndicatorsConfig extends Config
@ConfigItem(
position = 7,
keyName = "teamMemberColor",
name = "Team member color",
name = "Team member",
description = "Color of team members",
section = highlightSection
)
@@ -151,7 +151,7 @@ public interface PlayerIndicatorsConfig extends Config
@ConfigItem(
position = 9,
keyName = "nonClanMemberColor",
name = "Others color",
name = "Others",
description = "Color of other players names",
section = highlightSection
)

View File

@@ -133,7 +133,7 @@ public interface PrayerConfig extends Config
@ConfigItem(
position = 9,
keyName = "replaceOrbText",
name = "Replace orb text with prayer time left",
name = "Show time left",
description = "Show time remaining of current prayers in the prayer orb."
)
default boolean replaceOrbText()

View File

@@ -69,7 +69,7 @@ public interface PyramidPlunderConfig extends Config
@ConfigItem(
position = 3,
keyName = "highlightDoorsColor",
name = "Highlight doors color",
name = "Highlight doors",
description = "Selects the color for highlighting tomb doors"
)
default Color highlightDoorsColor()
@@ -92,7 +92,7 @@ public interface PyramidPlunderConfig extends Config
@ConfigItem(
position = 5,
keyName = "highlightSpeartrapColor",
name = "Highlight speartrap color",
name = "Highlight speartrap",
description = "Selects the color for highlighting speartraps"
)
default Color highlightSpeartrapsColor()
@@ -115,7 +115,7 @@ public interface PyramidPlunderConfig extends Config
@ConfigItem(
position = 7,
keyName = "highlightContainersColor",
name = "Highlight containers color",
name = "Highlight containers",
description = "Selects the color for highlighting urns, chests and sarcophagus"
)
default Color highlightContainersColor()

View File

@@ -47,7 +47,7 @@ public interface RaidsConfig extends Config
@ConfigItem(
position = 1,
keyName = "pointsMessage",
name = "Display points in chatbox after raid",
name = "Display points in chatbox",
description = "Display a message with total points, individual points and percentage at the end of a raid"
)
default boolean pointsMessage()
@@ -69,8 +69,8 @@ public interface RaidsConfig extends Config
@ConfigItem(
position = 3,
keyName = "scoutOverlayAtBank",
name = "Show scout overlay outside lobby",
description = "Keep the overlay active while at the raids area"
name = "Show scout overlay outside",
description = "Keep the overlay active outside of the raid starting room"
)
default boolean scoutOverlayAtBank()
{
@@ -168,8 +168,8 @@ public interface RaidsConfig extends Config
@ConfigItem(
position = 12,
keyName = "layoutMessage",
name = "Send raid layout message when entering raid",
description = "Sends game message with raid layout on entering new raid"
name = "Raid layout message",
description = "Sends a game message with the raid layout on entering a raid"
)
default boolean layoutMessage()
{
@@ -179,7 +179,7 @@ public interface RaidsConfig extends Config
@ConfigItem(
position = 13,
keyName = "screenshotHotkey",
name = "Scouter screenshot hotkey",
name = "Screenshot hotkey",
description = "Hotkey used to screenshot the scouting overlay"
)
default Keybind screenshotHotkey()
@@ -190,7 +190,7 @@ public interface RaidsConfig extends Config
@ConfigItem(
position = 14,
keyName = "uploadScreenshot",
name = "Upload scouting screenshot",
name = "Upload screenshot",
description = "Uploads the scouting screenshot to Imgur or the clipboard"
)
default ImageUploadStyle uploadScreenshot()

View File

@@ -52,7 +52,7 @@ public interface RegenMeterConfig extends Config
@ConfigItem(
keyName = "showWhenNoChange",
name = "Show hitpoints regen at full hitpoints",
name = "Show at full hitpoints",
description = "Always show the hitpoints regen orb, even if there will be no stat change")
default boolean showWhenNoChange()
{
@@ -61,7 +61,7 @@ public interface RegenMeterConfig extends Config
@ConfigItem(
keyName = "notifyBeforeHpRegenDuration",
name = "Hitpoint Regen Notification",
name = "Hitpoint Notification",
description = "Notify approximately when your next hitpoint is about to regen. A value of 0 will disable notification."
)
@Units(Units.SECONDS)

View File

@@ -64,7 +64,7 @@ public interface StatusBarsConfig extends Config
@ConfigItem(
keyName = "leftBarMode",
name = "Left Status Bar",
name = "Left Bar",
description = "Configures the left status bar"
)
default BarMode leftBarMode()
@@ -74,7 +74,7 @@ public interface StatusBarsConfig extends Config
@ConfigItem(
keyName = "rightBarMode",
name = "Right Status Bar",
name = "Right Bar",
description = "Configures the right status bar"
)
default BarMode rightBarMode()

View File

@@ -36,8 +36,9 @@ public interface TileIndicatorsConfig extends Config
@Alpha
@ConfigItem(
keyName = "highlightDestinationColor",
name = "Color of current destination highlighting",
description = "Configures the highlight color of current destination"
name = "Destination tile",
description = "Configures the highlight color of current destination",
position = 1
)
default Color highlightDestinationColor()
{
@@ -47,7 +48,8 @@ public interface TileIndicatorsConfig extends Config
@ConfigItem(
keyName = "highlightDestinationTile",
name = "Highlight destination tile",
description = "Highlights tile player is walking to"
description = "Highlights tile player is walking to",
position = 2
)
default boolean highlightDestinationTile()
{
@@ -57,8 +59,9 @@ public interface TileIndicatorsConfig extends Config
@Alpha
@ConfigItem(
keyName = "highlightHoveredColor",
name = "Color of current hovered highlighting",
description = "Configures the highlight color of hovered tile"
name = "Hovered tile",
description = "Configures the highlight color of hovered tile",
position = 3
)
default Color highlightHoveredColor()
{
@@ -68,7 +71,8 @@ public interface TileIndicatorsConfig extends Config
@ConfigItem(
keyName = "highlightHoveredTile",
name = "Highlight hovered tile",
description = "Highlights tile player is hovering with mouse"
description = "Highlights tile player is hovering with mouse",
position = 4
)
default boolean highlightHoveredTile()
{
@@ -78,8 +82,9 @@ public interface TileIndicatorsConfig extends Config
@Alpha
@ConfigItem(
keyName = "highlightCurrentColor",
name = "Color of current true tile highlighting",
description = "Configures the highlight color of current true tile"
name = "True tile",
description = "Configures the highlight color of current true tile",
position = 5
)
default Color highlightCurrentColor()
{
@@ -88,8 +93,9 @@ public interface TileIndicatorsConfig extends Config
@ConfigItem(
keyName = "highlightCurrentTile",
name = "Highlight current true tile",
description = "Highlights true tile player is on as seen by server"
name = "Highlight true tile",
description = "Highlights true tile player is on as seen by server",
position = 6
)
default boolean highlightCurrentTile()
{

View File

@@ -110,7 +110,7 @@ public interface TimeTrackingConfig extends Config
@ConfigItem(
keyName = "timerWarningThreshold",
name = "Timer Warning Threshold",
name = "Warning Threshold",
description = "The time at which to change the timer color to the warning color",
position = 6
)

View File

@@ -51,7 +51,7 @@ public interface WintertodtConfig extends Config
@ConfigItem(
position = 1,
keyName = "damageNotificationColor",
name = "Damage Notification Color",
name = "Damage Notification",
description = "Color of damage notification text in chat"
)
default Color damageNotificationColor()
@@ -62,7 +62,7 @@ public interface WintertodtConfig extends Config
@ConfigItem(
position = 2,
keyName = "roundNotification",
name = "Wintertodt round notification",
name = "Round notification",
description = "Notifies you before the round starts (in seconds)"
)
@Range(

View File

@@ -71,7 +71,13 @@ enum MinigameLocation
CATAPULT_ROOM("Catapult Room", new WorldPoint(2842, 3545, 0)),
SHOT_PUT_ROOM("Shot Put Room", new WorldPoint(2863, 3550, 0)),
HALLOWED_SEPULCHRE("Hallowed Sepulchre", new WorldPoint(3653, 3386, 1)),
THE_GAUNTLET("The Gauntlet", new WorldPoint(3223, 12505, 1));
THE_GAUNTLET("The Gauntlet", new WorldPoint(3223, 12505, 1)),
MAHOGANY_HOMES_ARDOUGNE("Mahogany Homes", new WorldPoint(2634, 3295, 0)),
MAHOGANY_HOMES_FALADOR("Mahogany Homes", new WorldPoint(2989, 3363, 0)),
MAHOGANY_HOMES_HOSIDIUS("Mahogany Homes", new WorldPoint(1780, 3623, 0)),
MAHOGANY_HOMES_VARROCK("Mahogany Homes", new WorldPoint(3240, 3471, 0)),
SOUL_WARS("Soul Wars", new WorldPoint(2209, 2855, 0)),
SOUL_WARS_EDGEVILLE_PORTAL("Soul Wars", new WorldPoint(3082, 3474, 0));
private final String tooltip;
private final WorldPoint location;

View File

@@ -38,7 +38,7 @@ enum QuestStartLocation
THE_CORSAIR_CURSE(Quest.THE_CORSAIR_CURSE, new WorldPoint(3029, 3273, 0)),
DEMON_SLAYER(Quest.DEMON_SLAYER, new WorldPoint(3204, 3424, 0)),
DORICS_QUEST(Quest.DORICS_QUEST, new WorldPoint(2952, 3450, 0)),
DRAGON_SLAYER(Quest.DRAGON_SLAYER, new WorldPoint(3190, 3362, 0)),
DRAGON_SLAYER_I(Quest.DRAGON_SLAYER_I, new WorldPoint(3190, 3362, 0)),
ERNEST_THE_CHICKEN(Quest.ERNEST_THE_CHICKEN, new WorldPoint(3109, 3330, 0)),
GOBLIN_DIPLOMACY(Quest.GOBLIN_DIPLOMACY, new WorldPoint(2957, 3509, 0)),
IMP_CATCHER(Quest.IMP_CATCHER, new WorldPoint(3108, 3160, 0)),
@@ -136,7 +136,7 @@ enum QuestStartLocation
A_PORCINE_OF_INTEREST(Quest.A_PORCINE_OF_INTEREST, new WorldPoint(3085, 3251, 0)),
PRIEST_IN_PERIL(Quest.PRIEST_IN_PERIL, new WorldPoint(3219, 3473, 0)),
THE_QUEEN_OF_THIEVES(Quest.THE_QUEEN_OF_THIEVES, new WorldPoint(1795, 3782, 0)),
RAG_AND_BONE_MAN(new Quest[]{Quest.RAG_AND_BONE_MAN, Quest.RAG_AND_BONE_MAN_II}, new WorldPoint(3359, 3504, 0)),
RAG_AND_BONE_MAN_I(new Quest[]{Quest.RAG_AND_BONE_MAN_I, Quest.RAG_AND_BONE_MAN_II}, new WorldPoint(3359, 3504, 0)),
RECRUITMENT_DRIVE_BLACK_KNIGHTS_FORTRESS(new Quest[]{Quest.BLACK_KNIGHTS_FORTRESS, Quest.RECRUITMENT_DRIVE}, new WorldPoint(2959, 3336, 0)),
ROVING_ELVES(Quest.ROVING_ELVES, new WorldPoint(2288, 3146, 0)),
RUM_DEAL(Quest.RUM_DEAL, new WorldPoint(3679, 3535, 0)),

View File

@@ -192,6 +192,7 @@ enum TransportationPointLocation
MUSHTREE_TAR_SWAMP("Mushtree", new WorldPoint(3676, 3755, 0)),
MUSHTREE_VERDANT_VALLEY("Mushtree", new WorldPoint(3757, 3756, 0)),
MYTHS_GUILD_PORTAL("Portal to Guilds", new WorldPoint(2456, 2856, 0)),
SOUL_WARS_PORTAL("Portal to Edgeville/Ferox Enclave", new WorldPoint(2204, 2858, 0)),
TRAIN_KELDAGRIM("Railway Station", new WorldPoint(2941, 10179, 0)),
WILDERNESS_LEVER_ARDOUGNE("Wilderness Lever to Deserted Keep", new WorldPoint(2559, 3309, 0), new WorldPoint(3154, 3924, 0)),
WILDERNESS_LEVER_EDGEVILLE("Wilderness Lever to Deserted Keep", new WorldPoint(3088, 3474, 0), new WorldPoint(3154, 3924, 0)),

View File

@@ -34,7 +34,7 @@ public interface WorldMapConfig extends Config
{
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_FAIRY_RING_TOOLTIPS,
name = "Show fairy ring codes in tooltip",
name = "Fairy ring code tooltip",
description = "Display the code for fairy rings in the icon tooltip",
position = 1
)
@@ -45,7 +45,7 @@ public interface WorldMapConfig extends Config
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_FAIRY_RING_ICON,
name = "Show fairy ring travel icon",
name = "Fairy ring travel icon",
description = "Override the travel icon for fairy rings",
position = 2
)
@@ -56,7 +56,7 @@ public interface WorldMapConfig extends Config
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_AGILITY_SHORTCUT_TOOLTIPS,
name = "Show agility level requirement",
name = "Agility level requirement",
description = "Display the required Agility level in the icon tooltip",
position = 3
)
@@ -78,7 +78,7 @@ public interface WorldMapConfig extends Config
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_AGILITY_COURSE_TOOLTIPS,
name = "Show agility course in tooltip",
name = "Agility course tooltip",
description = "Displays the name of the agility course in the tooltip",
position = 5
)
@@ -100,7 +100,7 @@ public interface WorldMapConfig extends Config
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_NORMAL_TELEPORT_ICON,
name = "Show Standard Spellbook destinations",
name = "Standard Spellbook destinations",
description = "Show icons at the destinations for teleports in the Standard Spellbook",
position = 7
)
@@ -111,7 +111,7 @@ public interface WorldMapConfig extends Config
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_MINIGAME_TOOLTIP,
name = "Show minigame name in tooltip",
name = "Minigame names",
description = "Display the name of the minigame in the icon tooltip",
position = 8
)
@@ -122,7 +122,7 @@ public interface WorldMapConfig extends Config
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_ANCIENT_TELEPORT_ICON,
name = "Show Ancient Magicks destinations",
name = "Ancient Magicks destinations",
description = "Show icons at the destinations for teleports in the Ancient Spellbook",
position = 9
)
@@ -133,7 +133,7 @@ public interface WorldMapConfig extends Config
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_LUNAR_TELEPORT_ICON,
name = "Show Lunar Spellbook destinations",
name = "Lunar Spellbook destinations",
description = "Show icons at the destinations for teleports in the Lunar Spellbook",
position = 10
)
@@ -144,7 +144,7 @@ public interface WorldMapConfig extends Config
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_ARCEUUS_TELEPORT_ICON,
name = "Show Arceuus Spellbook destinations",
name = "Arceuus Spellbook destinations",
description = "Show icons at the destinations for teleports in the Arceuus Spellbook",
position = 11
)
@@ -155,7 +155,7 @@ public interface WorldMapConfig extends Config
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_JEWELLERY_TELEPORT_ICON,
name = "Show jewellery teleport locations",
name = "Jewellery teleport destinations",
description = "Show icons at the destinations for teleports from jewellery",
position = 12
)
@@ -166,7 +166,7 @@ public interface WorldMapConfig extends Config
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_SCROLL_TELEPORT_ICON,
name = "Show teleport scroll locations",
name = "Teleport scroll destinations",
description = "Show icons at the destinations for teleports from scrolls",
position = 13
)
@@ -177,7 +177,7 @@ public interface WorldMapConfig extends Config
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_MISC_TELEPORT_ICON,
name = "Show misc teleport locations",
name = "Misc teleport destinations",
description = "Show icons at the destinations for miscellaneous teleport items",
position = 14
)
@@ -188,7 +188,7 @@ public interface WorldMapConfig extends Config
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_QUEST_START_TOOLTIPS,
name = "Show quest names and status",
name = "Quest names and status",
description = "Indicates the names of quests and shows completion status",
position = 15
)
@@ -199,7 +199,7 @@ public interface WorldMapConfig extends Config
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_FARMING_PATCH_TOOLTIPS,
name = "Show farming patch type",
name = "Farming patch type",
description = "Display the type of farming patches in the icon tooltip",
position = 16
)
@@ -210,7 +210,7 @@ public interface WorldMapConfig extends Config
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_RARE_TREE_TOOLTIPS,
name = "Show rare tree type",
name = "Rare tree type",
description = "Display the type of rare tree in the icon tooltip",
position = 17
)
@@ -232,7 +232,7 @@ public interface WorldMapConfig extends Config
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_TRANSPORTATION_TELEPORT_TOOLTIPS,
name = "Show transportation tooltips",
name = "Transportation tooltips",
description = "Indicates types and destinations of Transportation",
position = 19
)
@@ -243,7 +243,7 @@ public interface WorldMapConfig extends Config
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_RUNECRAFTING_ALTAR_ICON,
name = "Show runecrafting altar locations",
name = "Runecrafting altar locations",
description = "Show the icons of runecrafting altars",
position = 20
)
@@ -254,7 +254,7 @@ public interface WorldMapConfig extends Config
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_MINING_SITE_TOOLTIPS,
name = "Show mining site tooltips",
name = "Mining site tooltips",
description = "Indicates the ore available at mining sites",
position = 21
)
@@ -265,7 +265,7 @@ public interface WorldMapConfig extends Config
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_DUNGEON_TOOLTIPS,
name = "Show dungeon tooltips",
name = "Dungeon tooltips",
description = "Indicates the names of dungeons",
position = 22
)
@@ -276,7 +276,7 @@ public interface WorldMapConfig extends Config
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_HUNTER_AREA_TOOLTIPS,
name = "Show hunter area tooltips",
name = "Hunter area tooltips",
description = "Indicates the creatures inside a hunting area",
position = 23
)
@@ -287,7 +287,7 @@ public interface WorldMapConfig extends Config
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_FISHING_SPOT_TOOLTIPS,
name = "Show fishing spot tooltips",
name = "Fishing spot tooltips",
description = "Indicates the type of fish fishable at the fishing spot",
position = 24
)
@@ -298,7 +298,7 @@ public interface WorldMapConfig extends Config
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_KOUREND_TASK_TOOLTIPS,
name = "Show Kourend task tooltips",
name = "Kourend task tooltips",
description = "Indicates the task or unlock for Kourend Favour locations",
position = 25
)

View File

@@ -69,7 +69,7 @@ public class SplashScreen extends JFrame implements ActionListener
private SplashScreen() throws IOException
{
BufferedImage logo = ImageUtil.getResourceStreamFromClass(SplashScreen.class, "runelite_transparent.png");
BufferedImage logo = ImageUtil.loadImageResource(SplashScreen.class, "runelite_transparent.png");
setTitle("RuneLite Launcher");

View File

@@ -39,11 +39,11 @@ import net.runelite.client.util.Text;
* was very hard to see in the dark gray background, this makes the selected
* item white and adds some padding to the elements for more readable list.
*/
public final class ComboBoxListRenderer extends JLabel implements ListCellRenderer
public final class ComboBoxListRenderer<T> extends JLabel implements ListCellRenderer<T>
{
@Override
public Component getListCellRendererComponent(JList list, Object o, int index, boolean isSelected, boolean cellHasFocus)
public Component getListCellRendererComponent(JList<? extends T> list, T o, int index, boolean isSelected, boolean cellHasFocus)
{
if (isSelected)
{

View File

@@ -0,0 +1 @@
5464D17DCD348F352EFFE6AA6AEEC5A5609ECBA30EAC2CB2B3D479D2C0DDDA9A

View File

@@ -0,0 +1,75 @@
.id 3898
.int_stack_count 6
.string_stack_count 0
.int_var_count 11
.string_var_count 0
get_varbit 4606
iconst 0
if_icmpne LABEL4
jump LABEL5
LABEL4:
return
LABEL5:
iconst 512
istore 6
iconst 512
istore 7
iload 2
iconst 16
sub
istore 8
iconst 0
iload 3
invoke 1045
istore 3
iload 2
iconst 16
sub
iload 3
invoke 1046
istore 3
iconst 896
sconst "innerZoomLimit"
runelite_callback
iconst 128
sconst "outerZoomLimit"
runelite_callback
sub
istore 9
iconst 896
sconst "innerZoomLimit"
runelite_callback
iconst 128
sconst "outerZoomLimit"
runelite_callback
sub
istore 10
iload 3
iload 9
multiply
iload 8
div
iconst 128
sconst "outerZoomLimit"
runelite_callback
add
istore 6
iload 3
iload 10
multiply
iload 8
div
iconst 128
sconst "outerZoomLimit"
runelite_callback
add
istore 7
iload 0
iload 1
iload 7
iload 6
iload 2
iload 4
iload 5
invoke 3899
return

View File

@@ -0,0 +1 @@
AA98471D04D9CB1172253D0B479EFD2D58394BDD2852F3AE8CD2B2D46FA826C3

View File

@@ -0,0 +1,96 @@
.id 3899
.int_stack_count 7
.string_stack_count 0
.int_var_count 11
.string_var_count 0
get_varbit 4606
iconst 0
if_icmpne LABEL4
jump LABEL5
LABEL4:
return
LABEL5:
iconst 896
sconst "innerZoomLimit"
runelite_callback
iload 2
invoke 1046
istore 2
iconst 128
sconst "outerZoomLimit"
runelite_callback
iload 2
invoke 1045
istore 2
iconst 896
sconst "innerZoomLimit"
runelite_callback
iload 3
invoke 1046
istore 3
iconst 128
sconst "outerZoomLimit"
runelite_callback
iload 3
invoke 1045
istore 3
iload 2
iload 3
viewport_setfov
iconst 0
istore 7
iconst 0
istore 8
viewport_geteffectivesize
istore 8
istore 7
iload 8
iconst 334
sub
istore 9
iload 9
iconst 0
if_icmplt LABEL39
jump LABEL42
LABEL39:
iconst 0
istore 9
jump LABEL48
LABEL42:
iload 9
iconst 100
if_icmpgt LABEL46
jump LABEL48
LABEL46:
iconst 100
istore 9
LABEL48:
iload 2
iload 3
iload 2
sub
iload 9
multiply
iconst 100
div
add
istore 10
iconst 25
iconst 25
iload 10
multiply
iconst 256
div
add
cam_setfollowheight
iload 2
iload 3
set_varc_int 74
set_varc_int 73
iload 0
iload 1
iload 4
iload 5
iload 6
invoke 3900
return

View File

@@ -0,0 +1 @@
03D7F1AF9E8405CB4A74779254E8C65563123F865CC0181186238B038A740755

View File

@@ -0,0 +1,78 @@
.id 3900
.int_stack_count 5
.string_stack_count 0
.int_var_count 11
.string_var_count 0
iconst 896
sconst "innerZoomLimit"
runelite_callback
iconst 128
sconst "outerZoomLimit"
runelite_callback
sub
istore 5
iconst 896
sconst "innerZoomLimit"
runelite_callback
iconst 128
sconst "outerZoomLimit"
runelite_callback
sub
istore 6
iload 2
iconst 16
sub
istore 7
iconst 0
istore 8
iconst 0
istore 9
viewport_geteffectivesize
istore 9
istore 8
iconst 0
istore 10
iload 8
iconst 334
if_icmpgt LABEL25
jump LABEL34
LABEL25:
get_varc_int 74
iconst 128
sconst "outerZoomLimit"
runelite_callback
sub
iload 7
multiply
iload 5
div
istore 10
jump LABEL42
LABEL34:
get_varc_int 73
iconst 128
sconst "outerZoomLimit"
runelite_callback
sub
iload 7
multiply
iload 6
div
istore 10
LABEL42:
iload 0
iload 1
cc_find
iconst 1
if_icmpeq LABEL48
jump LABEL55
LABEL48:
iload 4
iload 10
add
iload 3
iconst 0
iconst 0
cc_setposition
LABEL55:
return

View File

@@ -0,0 +1 @@
A1B6D1B291AA3594728DDEA47049E17119F5CCB6F8E757E1524FA89DE92F9A34

View File

@@ -0,0 +1,663 @@
/*
* Copyright (c) 2018, 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.chatcommands;
import com.google.common.collect.Sets;
import com.google.inject.Guice;
import com.google.inject.testing.fieldbinder.Bind;
import com.google.inject.testing.fieldbinder.BoundFieldModule;
import java.io.IOException;
import java.util.concurrent.ScheduledExecutorService;
import javax.inject.Inject;
import net.runelite.api.ChatMessageType;
import static net.runelite.api.ChatMessageType.FRIENDSCHATNOTIFICATION;
import static net.runelite.api.ChatMessageType.GAMEMESSAGE;
import static net.runelite.api.ChatMessageType.TRADE;
import net.runelite.api.Client;
import net.runelite.api.MessageNode;
import net.runelite.api.Player;
import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.GameTick;
import net.runelite.api.events.WidgetLoaded;
import net.runelite.api.widgets.Widget;
import static net.runelite.api.widgets.WidgetID.ADVENTURE_LOG_ID;
import static net.runelite.api.widgets.WidgetID.GENERIC_SCROLL_GROUP_ID;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.chat.ChatCommandManager;
import net.runelite.client.chat.ChatMessageManager;
import net.runelite.client.config.ChatColorConfig;
import net.runelite.client.config.ConfigManager;
import net.runelite.http.api.chat.ChatClient;
import net.runelite.http.api.hiscore.HiscoreClient;
import net.runelite.http.api.hiscore.HiscoreSkill;
import net.runelite.http.api.hiscore.SingleHiscoreSkillResult;
import net.runelite.http.api.hiscore.Skill;
import static org.junit.Assert.assertEquals;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class ChatCommandsPluginTest
{
private static final String PLAYER_NAME = "Adam";
@Mock
@Bind
Client client;
@Mock
@Bind
ConfigManager configManager;
@Mock
@Bind
ScheduledExecutorService scheduledExecutorService;
@Mock
@Bind
ChatColorConfig chatColorConfig;
@Mock
@Bind
ChatCommandManager chatCommandManager;
@Mock
@Bind
HiscoreClient hiscoreClient;
@Mock
@Bind
ChatMessageManager chatMessageManager;
@Mock
@Bind
ChatClient chatClient;
@Mock
@Bind
ChatCommandsConfig chatCommandsConfig;
@Inject
ChatCommandsPlugin chatCommandsPlugin;
@Before
public void before()
{
Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this);
Player player = mock(Player.class);
when(player.getName()).thenReturn(PLAYER_NAME);
when(client.getLocalPlayer()).thenReturn(player);
}
@Test
public void testStartupShutdown()
{
chatCommandsPlugin.startUp();
chatCommandsPlugin.shutDown();
ArgumentCaptor<String> registerCaptor = ArgumentCaptor.forClass(String.class);
verify(chatCommandManager, atLeastOnce()).registerCommand(registerCaptor.capture(), any());
verify(chatCommandManager, atLeastOnce()).registerCommandAsync(registerCaptor.capture(), any());
verify(chatCommandManager, atLeastOnce()).registerCommandAsync(registerCaptor.capture(), any(), any());
ArgumentCaptor<String> unregisterCaptor = ArgumentCaptor.forClass(String.class);
verify(chatCommandManager, atLeastOnce()).unregisterCommand(unregisterCaptor.capture());
assertEquals(Sets.newHashSet(registerCaptor.getAllValues()), Sets.newHashSet(unregisterCaptor.getAllValues()));
}
@Test
public void testCorporealBeastKill()
{
ChatMessage chatMessageEvent = new ChatMessage(null, GAMEMESSAGE, "", "Your Corporeal Beast kill count is: <col=ff0000>4</col>.", null, 0);
chatCommandsPlugin.onChatMessage(chatMessageEvent);
verify(configManager).setRSProfileConfiguration("killcount", "corporeal beast", 4);
}
@Test
public void testTheatreOfBlood()
{
ChatMessage chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Wave 'The Final Challenge' complete! Duration: <col=ff0000>5:04</col><br>Theatre of Blood wave completion time: <col=ff0000>37:04</col> (Personal best!)", null, 0);
chatCommandsPlugin.onChatMessage(chatMessage);
ChatMessage chatMessageEvent = new ChatMessage(null, GAMEMESSAGE, "", "Your completed Theatre of Blood count is: <col=ff0000>73</col>.", null, 0);
chatCommandsPlugin.onChatMessage(chatMessageEvent);
verify(configManager).setRSProfileConfiguration("killcount", "theatre of blood", 73);
verify(configManager).setRSProfileConfiguration("personalbest", "theatre of blood", 37 * 60 + 4);
}
@Test
public void testTheatreOfBloodNoPb()
{
ChatMessage chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Wave 'The Final Challenge' complete! Duration: <col=ff0000>5:04</col><br>Theatre of Blood wave completion time: <col=ff0000>38:17</col><br></col>Personal best: 37:04", null, 0);
chatCommandsPlugin.onChatMessage(chatMessage);
ChatMessage chatMessageEvent = new ChatMessage(null, GAMEMESSAGE, "", "Your completed Theatre of Blood count is: <col=ff0000>73</col>.", null, 0);
chatCommandsPlugin.onChatMessage(chatMessageEvent);
verify(configManager).setRSProfileConfiguration("killcount", "theatre of blood", 73);
verify(configManager).setRSProfileConfiguration("personalbest", "theatre of blood", 37 * 60 + 4);
}
@Test
public void testWintertodt()
{
ChatMessage chatMessageEvent = new ChatMessage(null, GAMEMESSAGE, "", "Your subdued Wintertodt count is: <col=ff0000>4</col>.", null, 0);
chatCommandsPlugin.onChatMessage(chatMessageEvent);
verify(configManager).setRSProfileConfiguration("killcount", "wintertodt", 4);
}
@Test
public void testKreearra()
{
ChatMessage chatMessageEvent = new ChatMessage(null, GAMEMESSAGE, "", "Your Kree'arra kill count is: <col=ff0000>4</col>.", null, 0);
chatCommandsPlugin.onChatMessage(chatMessageEvent);
verify(configManager).setRSProfileConfiguration("killcount", "kree'arra", 4);
}
@Test
public void testBarrows()
{
ChatMessage chatMessageEvent = new ChatMessage(null, GAMEMESSAGE, "", "Your Barrows chest count is: <col=ff0000>277</col>.", null, 0);
chatCommandsPlugin.onChatMessage(chatMessageEvent);
verify(configManager).setRSProfileConfiguration("killcount", "barrows chests", 277);
}
@Test
public void testHerbiboar()
{
ChatMessage chatMessageEvent = new ChatMessage(null, GAMEMESSAGE, "", "Your herbiboar harvest count is: <col=ff0000>4091</col>.", null, 0);
chatCommandsPlugin.onChatMessage(chatMessageEvent);
verify(configManager).setRSProfileConfiguration("killcount", "herbiboar", 4091);
}
@Test
public void testGauntlet()
{
ChatMessage gauntletMessage = new ChatMessage(null, GAMEMESSAGE, "", "Your Gauntlet completion count is: <col=ff0000>123</col>.", null, 0);
chatCommandsPlugin.onChatMessage(gauntletMessage);
verify(configManager).setRSProfileConfiguration("killcount", "gauntlet", 123);
}
@Test
public void testCorruptedGauntlet()
{
ChatMessage corruptedGauntletMessage = new ChatMessage(null, GAMEMESSAGE, "", "Your Corrupted Gauntlet completion count is: <col=ff0000>4729</col>.", null, 0);
chatCommandsPlugin.onChatMessage(corruptedGauntletMessage);
verify(configManager).setRSProfileConfiguration("killcount", "corrupted gauntlet", 4729);
}
@Test
public void testPersonalBest()
{
final String FIGHT_DURATION = "Fight duration: <col=ff0000>2:06</col>. Personal best: 1:19.";
// This sets lastBoss
ChatMessage chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Your Kree'arra kill count is: <col=ff0000>4</col>.", null, 0);
chatCommandsPlugin.onChatMessage(chatMessage);
chatMessage = new ChatMessage(null, GAMEMESSAGE, "", FIGHT_DURATION, null, 0);
chatCommandsPlugin.onChatMessage(chatMessage);
verify(configManager).setRSProfileConfiguration("personalbest", "kree'arra", 79);
}
@Test
public void testPersonalBestNoTrailingPeriod()
{
final String FIGHT_DURATION = "Fight duration: <col=ff0000>0:59</col>. Personal best: 0:55";
// This sets lastBoss
ChatMessage chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Your Zulrah kill count is: <col=ff0000>4</col>.", null, 0);
chatCommandsPlugin.onChatMessage(chatMessage);
chatMessage = new ChatMessage(null, GAMEMESSAGE, "", FIGHT_DURATION, null, 0);
chatCommandsPlugin.onChatMessage(chatMessage);
verify(configManager).setRSProfileConfiguration("personalbest", "zulrah", 55);
}
@Test
public void testNewPersonalBest()
{
final String NEW_PB = "Fight duration: <col=ff0000>3:01</col> (new personal best).";
// This sets lastBoss
ChatMessage chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Your Kree'arra kill count is: <col=ff0000>4</col>.", null, 0);
chatCommandsPlugin.onChatMessage(chatMessage);
chatMessage = new ChatMessage(null, GAMEMESSAGE, "", NEW_PB, null, 0);
chatCommandsPlugin.onChatMessage(chatMessage);
verify(configManager).setRSProfileConfiguration("personalbest", "kree'arra", 181);
}
@Test
public void testDuelArenaWin()
{
ChatMessage chatMessageEvent = new ChatMessage(null, TRADE, "", "You won! You have now won 27 duels.", null, 0);
chatCommandsPlugin.onChatMessage(chatMessageEvent);
verify(configManager).setRSProfileConfiguration("killcount", "duel arena wins", 27);
verify(configManager).setRSProfileConfiguration("killcount", "duel arena win streak", 1);
}
@Test
public void testDuelArenaWin2()
{
ChatMessage chatMessageEvent = new ChatMessage(null, TRADE, "", "You were defeated! You have won 22 duels.", null, 0);
chatCommandsPlugin.onChatMessage(chatMessageEvent);
verify(configManager).setRSProfileConfiguration("killcount", "duel arena wins", 22);
}
@Test
public void testDuelArenaLose()
{
ChatMessage chatMessageEvent = new ChatMessage(null, TRADE, "", "You have now lost 999 duels.", null, 0);
chatCommandsPlugin.onChatMessage(chatMessageEvent);
verify(configManager).setRSProfileConfiguration("killcount", "duel arena losses", 999);
}
@Test
public void testAgilityLap()
{
final String NEW_PB = "Lap duration: <col=ff0000>1:01</col> (new personal best).";
// This sets lastBoss
ChatMessage chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Your Prifddinas Agility Course lap count is: <col=ff0000>2</col>.", null, 0);
chatCommandsPlugin.onChatMessage(chatMessage);
chatMessage = new ChatMessage(null, GAMEMESSAGE, "", NEW_PB, null, 0);
chatCommandsPlugin.onChatMessage(chatMessage);
verify(configManager).setRSProfileConfiguration("personalbest", "prifddinas agility course", 61);
verify(configManager).setRSProfileConfiguration("killcount", "prifddinas agility course", 2);
}
@Test
public void testZukNewPb()
{
ChatMessage chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Your TzKal-Zuk kill count is: <col=ff0000>2</col>.", null, 0);
chatCommandsPlugin.onChatMessage(chatMessage);
chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Duration: <col=ff0000>104:31</col> (new personal best)", null, 0);
chatCommandsPlugin.onChatMessage(chatMessage);
verify(configManager).setRSProfileConfiguration("personalbest", "tzkal-zuk", 104 * 60 + 31);
verify(configManager).setRSProfileConfiguration("killcount", "tzkal-zuk", 2);
}
@Test
public void testZukKill()
{
ChatMessage chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Your TzKal-Zuk kill count is: <col=ff0000>3</col>.", null, 0);
chatCommandsPlugin.onChatMessage(chatMessage);
chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Duration: <col=ff0000>172:18</col>. Personal best: 134:52", null, 0);
chatCommandsPlugin.onChatMessage(chatMessage);
verify(configManager).setRSProfileConfiguration("personalbest", "tzkal-zuk", 134 * 60 + 52);
verify(configManager).setRSProfileConfiguration("killcount", "tzkal-zuk", 3);
}
@Test
public void testGgNewPb()
{
ChatMessage chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Fight duration: <col=ff0000>1:36</col> (new personal best)", null, 0);
chatCommandsPlugin.onChatMessage(chatMessage);
chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Your Grotesque Guardians kill count is: <col=ff0000>179</col>.", null, 0);
chatCommandsPlugin.onChatMessage(chatMessage);
verify(configManager).setRSProfileConfiguration("personalbest", "grotesque guardians", 96);
verify(configManager).setRSProfileConfiguration("killcount", "grotesque guardians", 179);
}
@Test
public void testGgKill()
{
ChatMessage chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Fight duration: <col=ff0000>2:41</col>. Personal best: 2:14", null, 0);
chatCommandsPlugin.onChatMessage(chatMessage);
chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Your Grotesque Guardians kill count is: <col=ff0000>32</col>.", null, 0);
chatCommandsPlugin.onChatMessage(chatMessage);
verify(configManager).setRSProfileConfiguration("personalbest", "grotesque guardians", 2 * 60 + 14);
verify(configManager).setRSProfileConfiguration("killcount", "grotesque guardians", 32);
}
@Test
public void testGuantletPersonalBest()
{
ChatMessage chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Challenge duration: <col=ff0000>10:24</col>. Personal best: 7:59.", null, 0);
chatCommandsPlugin.onChatMessage(chatMessage);
chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Your Gauntlet completion count is: <col=ff0000>124</col>.", null, 0);
chatCommandsPlugin.onChatMessage(chatMessage);
verify(configManager).setRSProfileConfiguration("killcount", "gauntlet", 124);
verify(configManager).setRSProfileConfiguration("personalbest", "gauntlet", 7 * 60 + 59);
}
@Test
public void testGuantletNewPersonalBest()
{
ChatMessage chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Challenge duration: <col=ff0000>10:24</col> (new personal best).", null, 0);
chatCommandsPlugin.onChatMessage(chatMessage);
chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Your Gauntlet completion count is: <col=ff0000>124</col>.", null, 0);
chatCommandsPlugin.onChatMessage(chatMessage);
verify(configManager).setRSProfileConfiguration("personalbest", "gauntlet", 10 * 60 + 24);
verify(configManager).setRSProfileConfiguration("killcount", "gauntlet", 124);
}
@Test
public void testCoXKill()
{
ChatMessage chatMessage = new ChatMessage(null, FRIENDSCHATNOTIFICATION, "", "<col=ef20ff>Congratulations - your raid is complete!</col><br>Team size: <col=ff0000>24+ players</col> Duration:</col> <col=ff0000>37:04</col> (new personal best)</col>>", null, 0);
chatCommandsPlugin.onChatMessage(chatMessage);
chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Your completed Chambers of Xeric count is: <col=ff0000>51</col>.", null, 0);
chatCommandsPlugin.onChatMessage(chatMessage);
verify(configManager).setRSProfileConfiguration("killcount", "chambers of xeric", 51);
verify(configManager).setRSProfileConfiguration("personalbest", "chambers of xeric", 37 * 60 + 4);
}
@Test
public void testCoXKillNoPb()
{
ChatMessage chatMessage = new ChatMessage(null, FRIENDSCHATNOTIFICATION, "", "<col=ef20ff>Congratulations - your raid is complete!</col><br>Team size: <col=ff0000>11-15 players</col> Duration:</col> <col=ff0000>23:25</col> Personal best: </col><col=ff0000>20:19</col>", null, 0);
chatCommandsPlugin.onChatMessage(chatMessage);
chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Your completed Chambers of Xeric count is: <col=ff0000>52</col>.", null, 0);
chatCommandsPlugin.onChatMessage(chatMessage);
verify(configManager).setRSProfileConfiguration("killcount", "chambers of xeric", 52);
verify(configManager).setRSProfileConfiguration("personalbest", "chambers of xeric", 20 * 60 + 19);
}
@Test
public void testAdventureLogCountersPage()
{
Widget advLogWidget = mock(Widget.class);
Widget advLogExploitsTextWidget = mock(Widget.class);
when(advLogWidget.getChild(ChatCommandsPlugin.ADV_LOG_EXPLOITS_TEXT_INDEX)).thenReturn(advLogExploitsTextWidget);
when(advLogExploitsTextWidget.getText()).thenReturn("The Exploits of " + PLAYER_NAME);
when(client.getWidget(WidgetInfo.ADVENTURE_LOG)).thenReturn(advLogWidget);
when(configManager.getRSProfileConfiguration(anyString(), anyString(), any(Class.class))).thenReturn(2224);
WidgetLoaded advLogEvent = new WidgetLoaded();
advLogEvent.setGroupId(ADVENTURE_LOG_ID);
chatCommandsPlugin.onWidgetLoaded(advLogEvent);
chatCommandsPlugin.onGameTick(new GameTick());
String COUNTER_TEXT = "Duel Arena<br>Wins: <col=d0c0b0>4</col><br>Losses: <col=d0c0b0>2</col>" +
"<br><br>Last Man Standing<br>Rank: <col=d0c0b0>0</col>" +
"<br><br>Treasure Trails<br>Beginner: <col=d0c0b0>0</col><br>Easy: <col=d0c0b0>7</col>" +
"<br>Medium: <col=d0c0b0>28</col><br>Hard: <col=d0c0b0>108</col><br>Elite: <col=d0c0b0>15</col>" +
"<br>Master: <col=d0c0b0>27</col><br>Rank: <col=d0c0b0>Novice</col>" +
"<br><br>Chompy Hunting<br>Kills: <col=d0c0b0>1,000</col><br>Rank: <col=d0c0b0>Ogre Expert</col>" +
"<br><br>Order of the White Knights<br>Rank: <col=d0c0b0>Master</col><br>with a kill score of <col=d0c0b0>1,300</col>" +
"<br><br>TzHaar Fight Cave<br>Fastest run: <col=d0c0b0>38:10</col>" +
"<br><br>Inferno<br>Fastest run: <col=d0c0b0>-</col><br><br>Zulrah<br>" +
"Fastest kill: <col=d0c0b0>5:48</col><br><br>Vorkath<br>Fastest kill: <col=d0c0b0>1:21</col>" +
"<br><br>Galvek<br>Fastest kill: <col=d0c0b0>-</col><br><br>Grotesque Guardians<br>" +
"Fastest kill: <col=d0c0b0>2:49</col><br><br>Alchemical Hydra<br>Fastest kill: <col=d0c0b0>-</col>" +
"<br><br>Hespori<br>Fastest kill: <col=d0c0b0>0:57</col><br><br>Nightmare<br>" +
"Fastest kill: <col=d0c0b0>3:30</col><br><br>The Gauntlet<br>Fastest run: <col=d0c0b0>-</col>" +
"<br><br>The Corrupted Gauntlet<br>Fastest run: <col=d0c0b0>-</col><br><br>Fragment of Seren<br>Fastest kill: <col=d0c0b0>-</col>" +
"<br><br>Chambers of Xeric<br>Fastest run - (Team size: 24+ players): <col=d0c0b0>24:17</col>" +
"<br><br>Chambers of Xeric - Challenge mode<br>Fastest run - (Team size: Solo): <col=d0c0b0>22:15</col>" +
"<br><br>Barbarian Assault<br>High-level gambles: <col=d0c0b0>0</col><br><br>Fremennik spirits rested: <col=d0c0b0>0</col>";
Widget countersPage = mock(Widget.class);
when(countersPage.getText()).thenReturn(COUNTER_TEXT);
when(client.getWidget(WidgetInfo.GENERIC_SCROLL_TEXT)).thenReturn(countersPage);
WidgetLoaded countersLogEvent = new WidgetLoaded();
countersLogEvent.setGroupId(GENERIC_SCROLL_GROUP_ID);
chatCommandsPlugin.onWidgetLoaded(countersLogEvent);
chatCommandsPlugin.onGameTick(new GameTick());
verify(configManager).setRSProfileConfiguration("personalbest", "tztok-jad", 38 * 60 + 10);
verify(configManager).setRSProfileConfiguration("personalbest", "zulrah", 5 * 60 + 48);
verify(configManager).setRSProfileConfiguration("personalbest", "vorkath", 1 * 60 + 21);
verify(configManager).setRSProfileConfiguration("personalbest", "grotesque guardians", 2 * 60 + 49);
verify(configManager).setRSProfileConfiguration("personalbest", "hespori", 57);
verify(configManager).setRSProfileConfiguration("personalbest", "nightmare", 3 * 60 + 30);
verify(configManager).setRSProfileConfiguration("personalbest", "chambers of xeric", 24 * 60 + 17);
verify(configManager).setRSProfileConfiguration("personalbest", "chambers of xeric challenge mode", 22 * 60 + 15);
}
@Test
public void testAdventurerLogCountersPage2()
{
Widget advLogWidget = mock(Widget.class);
Widget advLogExploitsTextWidget = mock(Widget.class);
when(advLogWidget.getChild(ChatCommandsPlugin.ADV_LOG_EXPLOITS_TEXT_INDEX)).thenReturn(advLogExploitsTextWidget);
when(advLogExploitsTextWidget.getText()).thenReturn("The Exploits of " + PLAYER_NAME);
when(client.getWidget(WidgetInfo.ADVENTURE_LOG)).thenReturn(advLogWidget);
WidgetLoaded advLogEvent = new WidgetLoaded();
advLogEvent.setGroupId(ADVENTURE_LOG_ID);
chatCommandsPlugin.onWidgetLoaded(advLogEvent);
chatCommandsPlugin.onGameTick(new GameTick());
String COUNTER_TEXT = "Duel Arena<br>Wins: <col=d0c0b0>12</col><br>Losses: <col=d0c0b0>20</col>" +
"<br><br>Last Man Standing<br>Rank: <col=d0c0b0>0</col>" +
"<br><br>Treasure Trails<br>Beginner: <col=d0c0b0>1</col><br>Easy: <col=d0c0b0>4</col>" +
"<br>Medium: <col=d0c0b0>35</col><br>Hard: <col=d0c0b0>66</col><br>Elite: <col=d0c0b0>2</col>" +
"<br>Master: <col=d0c0b0>0</col><br>Rank: <col=d0c0b0>Novice</col>" +
"<br><br>Chompy Hunting<br>Kills: <col=d0c0b0>300</col><br>Rank: <col=d0c0b0>Ogre Forester</col>" +
"<br><br>Order of the White Knights<br>Rank: <col=d0c0b0>Unrated</col><br>with a kill score of <col=d0c0b0>99</col>" +
"<br><br>TzHaar Fight Cave<br>Fastest run: <col=d0c0b0>65:12</col>" +
"<br><br>Inferno<br>Fastest run: <col=d0c0b0>-</col><br><br>Zulrah<br>" +
"Fastest kill: <col=d0c0b0>2:55</col><br><br>Vorkath<br>Fastest kill: <col=d0c0b0>1:37</col>" +
"<br><br>Galvek<br>Fastest kill: <col=d0c0b0>-</col><br><br>Grotesque Guardians<br>" +
"Fastest kill: <col=d0c0b0>-</col><br><br>Alchemical Hydra<br>Fastest kill: <col=d0c0b0>-</col>" +
"<br><br>Hespori<br>Fastest kill: <col=d0c0b0>1:42</col><br><br>Nightmare<br>" +
"Fastest kill: <col=d0c0b0>-</col><br><br>The Gauntlet<br>Fastest run: <col=d0c0b0>-</col>" +
"<br><br>The Corrupted Gauntlet<br>Fastest run: <col=d0c0b0>-</col><br><br>Fragment of Seren<br>Fastest kill: <col=d0c0b0>-</col>" +
"<br><br>Chambers of Xeric<br>Fastest run - (Team size: Solo): <col=d0c0b0>21:23</col><br>Fastest run - (Team size: 3 players): <col=d0c0b0>27:16</col>" +
"<br><br>Chambers of Xeric - Challenge mode<br>Fastest run - (Team size: Solo): <col=d0c0b0>34:30</col><br>Fastest run - (Team size: 4 players): <col=d0c0b0>21:26</col>" +
"<br><br>Barbarian Assault<br>High-level gambles: <col=d0c0b0>0</col><br><br>Fremennik spirits rested: <col=d0c0b0>0</col>";
Widget countersPage = mock(Widget.class);
when(countersPage.getText()).thenReturn(COUNTER_TEXT);
when(client.getWidget(WidgetInfo.GENERIC_SCROLL_TEXT)).thenReturn(countersPage);
WidgetLoaded countersLogEvent = new WidgetLoaded();
countersLogEvent.setGroupId(GENERIC_SCROLL_GROUP_ID);
chatCommandsPlugin.onWidgetLoaded(countersLogEvent);
chatCommandsPlugin.onGameTick(new GameTick());
verify(configManager).setRSProfileConfiguration("personalbest", "tztok-jad", 65 * 60 + 12);
verify(configManager).setRSProfileConfiguration("personalbest", "zulrah", 2 * 60 + 55);
verify(configManager).setRSProfileConfiguration("personalbest", "vorkath", 1 * 60 + 37);
verify(configManager).setRSProfileConfiguration("personalbest", "hespori", 1 * 60 + 42);
verify(configManager).setRSProfileConfiguration("personalbest", "chambers of xeric", 21 * 60 + 23);
verify(configManager).setRSProfileConfiguration("personalbest", "chambers of xeric challenge mode", 21 * 60 + 26);
}
@Test
public void testNotYourAdventureLogCountersPage()
{
Widget advLogWidget = mock(Widget.class);
Widget advLogExploitsTextWidget = mock(Widget.class);
when(advLogWidget.getChild(ChatCommandsPlugin.ADV_LOG_EXPLOITS_TEXT_INDEX)).thenReturn(advLogExploitsTextWidget);
when(advLogExploitsTextWidget.getText()).thenReturn("The Exploits of " + "not the player");
when(client.getWidget(WidgetInfo.ADVENTURE_LOG)).thenReturn(advLogWidget);
WidgetLoaded advLogEvent = new WidgetLoaded();
advLogEvent.setGroupId(ADVENTURE_LOG_ID);
chatCommandsPlugin.onWidgetLoaded(advLogEvent);
chatCommandsPlugin.onGameTick(new GameTick());
WidgetLoaded countersLogEvent = new WidgetLoaded();
countersLogEvent.setGroupId(GENERIC_SCROLL_GROUP_ID);
chatCommandsPlugin.onWidgetLoaded(countersLogEvent);
chatCommandsPlugin.onGameTick(new GameTick());
verifyNoMoreInteractions(configManager);
}
@Test
public void testPlayerSkillLookup() throws IOException
{
when(chatCommandsConfig.lvl()).thenReturn(true);
SingleHiscoreSkillResult skillResult = new SingleHiscoreSkillResult();
skillResult.setPlayer(PLAYER_NAME);
skillResult.setSkill(new Skill(10, 1000, -1));
when(hiscoreClient.lookup(PLAYER_NAME, HiscoreSkill.ZULRAH, null)).thenReturn(skillResult);
MessageNode messageNode = mock(MessageNode.class);
ChatMessage chatMessage = new ChatMessage();
chatMessage.setType(ChatMessageType.PUBLICCHAT);
chatMessage.setName(PLAYER_NAME);
chatMessage.setMessageNode(messageNode);
chatCommandsPlugin.playerSkillLookup(chatMessage, "!lvl zulrah");
verify(messageNode).setRuneLiteFormatMessage("<colNORMAL>Level <colHIGHLIGHT>Zulrah: 1000<colNORMAL> Rank: <colHIGHLIGHT>10");
}
@Test
public void testHsFloorNoPb()
{
ChatMessage chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Floor 1 time: <col=ff0000>1:19</col>. Personal best: 0:28", null, 0);
chatCommandsPlugin.onChatMessage(chatMessage);
verify(configManager).setRSProfileConfiguration("personalbest", "hallowed sepulchre floor 1", 28);
}
@Test
public void testHsFloorPb()
{
ChatMessage chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Floor 2 time: <col=ff0000>0:47</col> (new personal best)", null, 0);
chatCommandsPlugin.onChatMessage(chatMessage);
verify(configManager).setRSProfileConfiguration("personalbest", "hallowed sepulchre floor 2", 47);
}
@Test
public void testHsOverallPb_Pb()
{
ChatMessage chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Floor 5 time: <col=ff0000>4:46</col> (new personal best)<br>Overall time: <col=ff0000>9:53</col> (new personal best)<br>", null, 0);
chatCommandsPlugin.onChatMessage(chatMessage);
verify(configManager).setRSProfileConfiguration("personalbest", "hallowed sepulchre floor 5", 4 * 60 + 46);
verify(configManager).setRSProfileConfiguration("personalbest", "hallowed sepulchre", 9 * 60 + 53);
}
@Test
public void testHsOverallPb_NoPb()
{
ChatMessage chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Floor 5 time: <col=ff0000>3:26</col> (new personal best)<br>Overall time: <col=ff0000>9:17</col>. Personal best: 9:15<br>", null, 0);
chatCommandsPlugin.onChatMessage(chatMessage);
verify(configManager).setRSProfileConfiguration("personalbest", "hallowed sepulchre floor 5", 3 * 60 + 26);
verify(configManager).setRSProfileConfiguration("personalbest", "hallowed sepulchre", 9 * 60 + 15);
}
@Test
public void testHsOverallNoPb_NoPb()
{
ChatMessage chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Floor 5 time: <col=ff0000>3:56</col>. Personal best: 3:05<br>Overall time: <col=ff0000>9:14</col>. Personal best: 7:49<br>", null, 0);
chatCommandsPlugin.onChatMessage(chatMessage);
verify(configManager).setRSProfileConfiguration("personalbest", "hallowed sepulchre floor 5", 3 * 60 + 5);
verify(configManager).setRSProfileConfiguration("personalbest", "hallowed sepulchre", 7 * 60 + 49);
}
@Test
public void testHsOverallNoPb_Pb()
{
ChatMessage chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Floor 5 time: <col=ff0000>3:10</col>. Personal best: 3:04<br>Overall time: <col=ff0000>7:47</col> (new personal best)<br>", null, 0);
chatCommandsPlugin.onChatMessage(chatMessage);
verify(configManager).setRSProfileConfiguration("personalbest", "hallowed sepulchre floor 5", 3 * 60 + 4);
verify(configManager).setRSProfileConfiguration("personalbest", "hallowed sepulchre", 7 * 60 + 47);
}
@Test
public void testHsFloorKc()
{
ChatMessage chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "You have completed Floor 5 of the Hallowed Sepulchre! Total completions: <col=ff0000>81</col>.", null, 0);
chatCommandsPlugin.onChatMessage(chatMessage);
verify(configManager).setRSProfileConfiguration("killcount", "hallowed sepulchre floor 5", 81);
}
@Test
public void testHsGhcKc()
{
ChatMessage chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "You have opened the Grand Hallowed Coffin <col=ff0000>36</col> times!", null, 0);
chatCommandsPlugin.onChatMessage(chatMessage);
verify(configManager).setRSProfileConfiguration("killcount", "hallowed sepulchre", 36);
}
@Test
public void testJadNewPbWithLeagueTask()
{
ChatMessage chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Your TzTok-Jad kill count is: <col=ff0000>2</col>.", null, 0);
chatCommandsPlugin.onChatMessage(chatMessage);
chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Congratulations, you've completed a master task: <col=7f3700>Complete the Fight Caves in 25:00</col>.", null, 0);
chatCommandsPlugin.onChatMessage(chatMessage);
chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Duration: <col=ff0000>21:58</col> (new personal best)", null, 0);
chatCommandsPlugin.onChatMessage(chatMessage);
verify(configManager).setRSProfileConfiguration("personalbest", "tztok-jad", 21 * 60 + 58);
verify(configManager).setRSProfileConfiguration("killcount", "tztok-jad", 2);
}
}

View File

@@ -0,0 +1,424 @@
/*
* Copyright (c) 2019, Adam <Adam@sigterm.info>
* Copyright (c) 2019, osrs-music-map <osrs-music-map@users.noreply.github.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.chatfilter;
import com.google.inject.Guice;
import com.google.inject.testing.fieldbinder.Bind;
import com.google.inject.testing.fieldbinder.BoundFieldModule;
import javax.inject.Inject;
import net.runelite.api.ChatMessageType;
import net.runelite.api.Client;
import net.runelite.api.IterableHashTable;
import net.runelite.api.MessageNode;
import net.runelite.api.Player;
import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.ScriptCallbackEvent;
import net.runelite.client.game.FriendChatManager;
import static net.runelite.client.plugins.chatfilter.ChatFilterPlugin.CENSOR_MESSAGE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class ChatFilterPluginTest
{
@Mock
@Bind
private Client client;
@Mock
@Bind
private ChatFilterConfig chatFilterConfig;
@Mock
@Bind
private FriendChatManager friendChatManager;
@Mock
private Player localPlayer;
@Inject
private ChatFilterPlugin chatFilterPlugin;
@Before
public void before()
{
Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this);
when(chatFilterConfig.filterType()).thenReturn(ChatFilterType.CENSOR_WORDS);
when(chatFilterConfig.filteredWords()).thenReturn("");
when(chatFilterConfig.filteredRegex()).thenReturn("");
when(chatFilterConfig.filteredNames()).thenReturn("");
when(client.getLocalPlayer()).thenReturn(localPlayer);
}
private ScriptCallbackEvent createCallbackEvent(final String sender, final String chatMessage, final ChatMessageType messageType)
{
ScriptCallbackEvent event = new ScriptCallbackEvent();
event.setScript(null);
event.setEventName("chatFilterCheck");
int[] simulatedIntStack =
new int[]{1, messageType.getType(), 1}; // is msg allowed to show, ChatMessageType.PUBLICCHAT, message id
String[] simulatedStringStack = new String[]{chatMessage};
IterableHashTable<MessageNode> messageTable = mock(IterableHashTable.class);
MessageNode mockedMsgNode = mockMessageNode(sender);
when(client.getIntStack()).thenReturn(simulatedIntStack);
when(client.getIntStackSize()).thenReturn(simulatedIntStack.length);
when(client.getStringStack()).thenReturn(simulatedStringStack);
when(client.getStringStackSize()).thenReturn(simulatedStringStack.length);
when(client.getMessages()).thenReturn(messageTable);
when(messageTable.get(1)).thenReturn(mockedMsgNode);
return event;
}
private MessageNode mockMessageNode(String sender)
{
MessageNode node = mock(MessageNode.class);
when(node.getName()).thenReturn(sender);
return node;
}
private MessageNode mockMessageNode(int id)
{
MessageNode node = mock(MessageNode.class);
when(node.getId()).thenReturn(id);
return node;
}
private MessageNode mockMessageNode(int id, String sender, String value)
{
MessageNode node = mock(MessageNode.class);
when(node.getId()).thenReturn(id);
when(node.getName()).thenReturn(sender);
when(node.getValue()).thenReturn(value);
return node;
}
@Test
public void testCensorWords()
{
when(chatFilterConfig.filteredWords()).thenReturn("hat");
chatFilterPlugin.updateFilteredPatterns();
assertEquals("w***s up", chatFilterPlugin.censorMessage("Blue", "whats up"));
}
@Test
public void testCensorRegex()
{
when(chatFilterConfig.filterType()).thenReturn(ChatFilterType.REMOVE_MESSAGE);
when(chatFilterConfig.filteredRegex()).thenReturn("5[0-9]x2\n(");
chatFilterPlugin.updateFilteredPatterns();
assertNull(chatFilterPlugin.censorMessage("Blue", "55X2 Dicing | Trusted Ranks | Huge Pay Outs!"));
}
@Test
public void testBrokenRegex()
{
when(chatFilterConfig.filteredRegex()).thenReturn("Test\n)\n73");
chatFilterPlugin.updateFilteredPatterns();
assertEquals("** isn't funny", chatFilterPlugin.censorMessage("Blue", "73 isn't funny"));
}
@Test
public void testCaseSensitivity()
{
when(chatFilterConfig.filterType()).thenReturn(ChatFilterType.CENSOR_MESSAGE);
when(chatFilterConfig.filteredWords()).thenReturn("ReGeX!!!");
chatFilterPlugin.updateFilteredPatterns();
assertEquals(CENSOR_MESSAGE, chatFilterPlugin.censorMessage("Blue", "I love regex!!!!!!!!"));
}
@Test
public void testNonPrintableCharacters()
{
when(chatFilterConfig.filterType()).thenReturn(ChatFilterType.REMOVE_MESSAGE);
when(chatFilterConfig.filteredWords()).thenReturn("test");
chatFilterPlugin.updateFilteredPatterns();
assertNull(chatFilterPlugin.censorMessage("Blue", "te\u008Cst"));
}
@Test
public void testReplayedMessage()
{
when(chatFilterConfig.filterType()).thenReturn(ChatFilterType.REMOVE_MESSAGE);
when(chatFilterConfig.filteredWords()).thenReturn("hello osrs");
chatFilterPlugin.updateFilteredPatterns();
assertNull(chatFilterPlugin.censorMessage("Blue", "hello\u00A0osrs"));
}
@Test
public void testMessageFromFriendIsFiltered()
{
when(friendChatManager.isMember("Iron Mammal")).thenReturn(false);
when(chatFilterConfig.filterFriends()).thenReturn(true);
assertTrue(chatFilterPlugin.shouldFilterPlayerMessage("Iron Mammal"));
}
@Test
public void testMessageFromFriendIsNotFiltered()
{
when(client.isFriended("Iron Mammal", false)).thenReturn(true);
when(chatFilterConfig.filterFriends()).thenReturn(false);
assertFalse(chatFilterPlugin.shouldFilterPlayerMessage("Iron Mammal"));
}
@Test
public void testMessageFromFriendsChatIsFiltered()
{
when(client.isFriended("B0aty", false)).thenReturn(false);
when(chatFilterConfig.filterFriendsChat()).thenReturn(true);
assertTrue(chatFilterPlugin.shouldFilterPlayerMessage("B0aty"));
}
@Test
public void testMessageFromFriendsChatIsNotFiltered()
{
when(friendChatManager.isMember("B0aty")).thenReturn(true);
when(chatFilterConfig.filterFriendsChat()).thenReturn(false);
assertFalse(chatFilterPlugin.shouldFilterPlayerMessage("B0aty"));
}
@Test
public void testMessageFromSelfIsNotFiltered()
{
when(localPlayer.getName()).thenReturn("Swampletics");
assertFalse(chatFilterPlugin.shouldFilterPlayerMessage("Swampletics"));
}
@Test
public void testMessageFromNonFriendNonFCIsFiltered()
{
when(client.isFriended("Woox", false)).thenReturn(false);
when(friendChatManager.isMember("Woox")).thenReturn(false);
assertTrue(chatFilterPlugin.shouldFilterPlayerMessage("Woox"));
}
@Test
public void testShouldFilterByName()
{
when(chatFilterConfig.filteredNames()).thenReturn("Gamble [0-9]*");
chatFilterPlugin.updateFilteredPatterns();
assertTrue(chatFilterPlugin.shouldFilterByName("Gamble 1234"));
assertFalse(chatFilterPlugin.shouldFilterByName("Adam"));
}
@Test
public void testCensorWordsByName()
{
when(chatFilterConfig.filteredNames()).thenReturn("Blue");
chatFilterPlugin.updateFilteredPatterns();
assertEquals("************", chatFilterPlugin.censorMessage("Blue", "Gamble today"));
}
@Test
public void textCensorMessageByName()
{
when(chatFilterConfig.filteredNames()).thenReturn("Blue");
chatFilterPlugin.updateFilteredPatterns();
when(chatFilterConfig.filterType()).thenReturn(ChatFilterType.CENSOR_MESSAGE);
assertEquals(CENSOR_MESSAGE,
chatFilterPlugin.censorMessage("Blue", "Meet swampletics, my morytania locked ultimate ironman"));
}
@Test
public void testRemoveMessageByName()
{
when(chatFilterConfig.filteredNames()).thenReturn("Blue");
chatFilterPlugin.updateFilteredPatterns();
when(chatFilterConfig.filterType()).thenReturn(ChatFilterType.REMOVE_MESSAGE);
assertNull(
chatFilterPlugin.censorMessage("Blue", "What about now it's time to rock with the biggity buck bumble"));
}
@Test
public void testEventRemoveByName()
{
when(chatFilterConfig.filteredNames()).thenReturn("Gamble [0-9]*");
when(chatFilterConfig.filterType()).thenReturn(ChatFilterType.REMOVE_MESSAGE);
chatFilterPlugin.updateFilteredPatterns();
ScriptCallbackEvent event = createCallbackEvent("Gamble 1234", "filterme", ChatMessageType.PUBLICCHAT);
chatFilterPlugin.onScriptCallbackEvent(event);
assertEquals(0, client.getIntStack()[client.getIntStackSize() - 3]);
}
@Test
public void testEventRemoveByText()
{
when(chatFilterConfig.filteredWords()).thenReturn("filterme");
when(chatFilterConfig.filterType()).thenReturn(ChatFilterType.REMOVE_MESSAGE);
chatFilterPlugin.updateFilteredPatterns();
ScriptCallbackEvent event = createCallbackEvent("Adam", "please filterme plugin", ChatMessageType.PUBLICCHAT);
chatFilterPlugin.onScriptCallbackEvent(event);
assertEquals(0, client.getIntStack()[client.getIntStackSize() - 3]);
}
@Test
public void testEventCensorWordsByName()
{
when(chatFilterConfig.filteredNames()).thenReturn("Gamble [0-9]*");
when(chatFilterConfig.filterType()).thenReturn(ChatFilterType.CENSOR_WORDS);
chatFilterPlugin.updateFilteredPatterns();
ScriptCallbackEvent event = createCallbackEvent("Gamble 1234", "filterme", ChatMessageType.PUBLICCHAT);
chatFilterPlugin.onScriptCallbackEvent(event);
assertEquals("********", client.getStringStack()[client.getStringStackSize() - 1]);
}
@Test
public void testEventCensorWordsByText()
{
when(chatFilterConfig.filteredWords()).thenReturn("filterme");
when(chatFilterConfig.filterType()).thenReturn(ChatFilterType.CENSOR_WORDS);
chatFilterPlugin.updateFilteredPatterns();
ScriptCallbackEvent event = createCallbackEvent("Adam", "please filterme plugin", ChatMessageType.PUBLICCHAT);
chatFilterPlugin.onScriptCallbackEvent(event);
assertEquals("please ******** plugin", client.getStringStack()[client.getStringStackSize() - 1]);
}
@Test
public void testEventCensorMessageByName()
{
when(chatFilterConfig.filteredNames()).thenReturn("Gamble [0-9]*");
when(chatFilterConfig.filterType()).thenReturn(ChatFilterType.CENSOR_MESSAGE);
chatFilterPlugin.updateFilteredPatterns();
ScriptCallbackEvent event = createCallbackEvent("Gamble 1234", "filterme", ChatMessageType.PUBLICCHAT);
chatFilterPlugin.onScriptCallbackEvent(event);
assertEquals(CENSOR_MESSAGE, client.getStringStack()[client.getStringStackSize() - 1]);
}
@Test
public void testEventCensorMessageByText()
{
when(chatFilterConfig.filteredWords()).thenReturn("filterme");
when(chatFilterConfig.filterType()).thenReturn(ChatFilterType.CENSOR_MESSAGE);
chatFilterPlugin.updateFilteredPatterns();
ScriptCallbackEvent event = createCallbackEvent("Adam", "please filterme plugin", ChatMessageType.PUBLICCHAT);
chatFilterPlugin.onScriptCallbackEvent(event);
assertEquals(CENSOR_MESSAGE, client.getStringStack()[client.getStringStackSize() - 1]);
}
@Test
public void testDuplicateChatFiltered()
{
when(chatFilterConfig.collapseGameChat()).thenReturn(true);
chatFilterPlugin.onChatMessage(new ChatMessage(mockMessageNode(0, null, "testMessage"), ChatMessageType.GAMEMESSAGE, null, null, null, 0));
ScriptCallbackEvent event = createCallbackEvent(null, "testMessage", ChatMessageType.GAMEMESSAGE);
chatFilterPlugin.onScriptCallbackEvent(event);
assertEquals(0, client.getIntStack()[client.getIntStackSize() - 3]);
}
@Test
public void testNoDuplicate()
{
when(chatFilterConfig.collapseGameChat()).thenReturn(true);
chatFilterPlugin.onChatMessage(new ChatMessage(mockMessageNode(1), ChatMessageType.GAMEMESSAGE, null, "testMessage", null, 0));
ScriptCallbackEvent event = createCallbackEvent(null, "testMessage", ChatMessageType.GAMEMESSAGE);
chatFilterPlugin.onScriptCallbackEvent(event);
assertEquals(1, client.getIntStack()[client.getIntStackSize() - 3]);
assertEquals("testMessage", client.getStringStack()[client.getStringStackSize() - 1]);
}
@Test
public void testDuplicateChatCount()
{
when(chatFilterConfig.collapseGameChat()).thenReturn(true);
chatFilterPlugin.onChatMessage(new ChatMessage(mockMessageNode(4, null, "testMessage"), ChatMessageType.GAMEMESSAGE, null, null, null, 0));
chatFilterPlugin.onChatMessage(new ChatMessage(mockMessageNode(3, null, "testMessage"), ChatMessageType.GAMEMESSAGE, null, null, null, 0));
chatFilterPlugin.onChatMessage(new ChatMessage(mockMessageNode(2, null, "testMessage"), ChatMessageType.GAMEMESSAGE, null, null, null, 0));
chatFilterPlugin.onChatMessage(new ChatMessage(mockMessageNode(1, null, "testMessage"), ChatMessageType.GAMEMESSAGE, null, null, null, 0));
ScriptCallbackEvent event = createCallbackEvent(null, "testMessage", ChatMessageType.GAMEMESSAGE);
chatFilterPlugin.onScriptCallbackEvent(event);
assertEquals(1, client.getIntStack()[client.getIntStackSize() - 3]);
assertEquals("testMessage (4)", client.getStringStack()[client.getStringStackSize() - 1]);
}
@Test
public void publicChatFilteredOnDuplicate()
{
when(chatFilterConfig.collapsePlayerChat()).thenReturn(true);
when(chatFilterConfig.maxRepeatedPublicChats()).thenReturn(2);
chatFilterPlugin.onChatMessage(new ChatMessage(mockMessageNode(1, "testName", "testMessage"), ChatMessageType.PUBLICCHAT, null, null, null, 0));
chatFilterPlugin.onChatMessage(new ChatMessage(mockMessageNode(1, "testName", "testMessage"), ChatMessageType.PUBLICCHAT, null, null, null, 0));
chatFilterPlugin.onChatMessage(new ChatMessage(mockMessageNode(1, "testName", "testMessage"), ChatMessageType.PUBLICCHAT, null, null, null, 0));
ScriptCallbackEvent event = createCallbackEvent("testName", "testMessage", ChatMessageType.PUBLICCHAT);
chatFilterPlugin.onScriptCallbackEvent(event);
assertEquals(0, client.getIntStack()[client.getIntStackSize() - 3]);
}
@Test
public void testDuplicateChatFilterIgnoresFormatting()
{
when(chatFilterConfig.collapseGameChat()).thenReturn(true);
chatFilterPlugin.onChatMessage(new ChatMessage(mockMessageNode(4, null, "<col=000000>testMessage</col>"), ChatMessageType.GAMEMESSAGE, null, null, null, 0));
chatFilterPlugin.onChatMessage(new ChatMessage(mockMessageNode(3, null, "<col=000000>testMessage</col>"), ChatMessageType.GAMEMESSAGE, null, null, null, 0));
chatFilterPlugin.onChatMessage(new ChatMessage(mockMessageNode(2, null, "<col=000000>testMessage</col>"), ChatMessageType.GAMEMESSAGE, null, null, null, 0));
chatFilterPlugin.onChatMessage(new ChatMessage(mockMessageNode(1, null, "<col=000000>testMessage</col>"), ChatMessageType.GAMEMESSAGE, null, null, null, 0));
ScriptCallbackEvent event = createCallbackEvent(null, "<col=000000>testMessage</col>", ChatMessageType.GAMEMESSAGE);
chatFilterPlugin.onScriptCallbackEvent(event);
assertEquals(1, client.getIntStack()[client.getIntStackSize() - 3]);
assertEquals("<col=000000>testMessage</col> (4)", client.getStringStack()[client.getStringStackSize() - 1]);
}
@Test
public void testChatIcons()
{
when(chatFilterConfig.filteredWords()).thenReturn("test");
// if this test is broken, this stubbing is required to trip the assert
lenient().when(chatFilterConfig.filterType()).thenReturn(ChatFilterType.REMOVE_MESSAGE);
when(friendChatManager.isMember("Lazark")).thenReturn(true);
chatFilterPlugin.updateFilteredPatterns();
ScriptCallbackEvent event = createCallbackEvent("<img=22>Lazark", "test", ChatMessageType.PUBLICCHAT);
chatFilterPlugin.onScriptCallbackEvent(event);
assertEquals(1, client.getIntStack()[client.getIntStackSize() - 3]); // not filtered
}
}

View File

@@ -0,0 +1,289 @@
/*
* Copyright (c) 2018, 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.chatnotifications;
import com.google.inject.Guice;
import com.google.inject.testing.fieldbinder.Bind;
import com.google.inject.testing.fieldbinder.BoundFieldModule;
import java.util.Iterator;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Named;
import net.runelite.api.ChatMessageType;
import net.runelite.api.Client;
import net.runelite.api.MessageNode;
import net.runelite.api.Player;
import net.runelite.api.events.ChatMessage;
import net.runelite.client.Notifier;
import net.runelite.client.chat.ChatMessageManager;
import net.runelite.client.util.Text;
import static org.junit.Assert.assertEquals;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class ChatNotificationsPluginTest
{
@Mock
@Bind
private Client client;
@Mock
@Bind
private ChatNotificationsConfig config;
@Mock
@Bind
private ChatMessageManager chatMessageManager;
@Mock
@Bind
private Notifier notifier;
@Bind
@Named("runelite.title")
private String runeliteTitle = "RuneLite";
@Inject
private ChatNotificationsPlugin chatNotificationsPlugin;
@Before
public void before()
{
Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this);
}
@Test
public void onChatMessage()
{
when(config.highlightWordsString()).thenReturn("Deathbeam, Deathbeam OSRS , test");
MessageNode messageNode = mock(MessageNode.class);
when(messageNode.getValue()).thenReturn("Deathbeam, Deathbeam OSRS");
ChatMessage chatMessage = new ChatMessage();
chatMessage.setType(ChatMessageType.PUBLICCHAT);
chatMessage.setMessageNode(messageNode);
chatNotificationsPlugin.startUp(); // load highlight config
chatNotificationsPlugin.onChatMessage(chatMessage);
verify(messageNode).setValue("<colHIGHLIGHT>Deathbeam<colNORMAL>, <colHIGHLIGHT>Deathbeam<colNORMAL> OSRS");
}
@Test
public void testLtGt()
{
when(config.highlightWordsString()).thenReturn("<test>");
String message = "test <lt>test<gt> test";
MessageNode messageNode = mock(MessageNode.class);
when(messageNode.getValue()).thenReturn(message);
ChatMessage chatMessage = new ChatMessage();
chatMessage.setType(ChatMessageType.PUBLICCHAT);
chatMessage.setMessageNode(messageNode);
chatNotificationsPlugin.startUp(); // load highlight config
chatNotificationsPlugin.onChatMessage(chatMessage);
verify(messageNode).setValue("test <colHIGHLIGHT><lt>test<gt><colNORMAL> test");
}
@Test
public void testMatchEntireMessage()
{
when(config.highlightWordsString()).thenReturn(".Your divine potion effect is about to expire.");
String message = ".Your divine potion effect is about to expire.";
MessageNode messageNode = mock(MessageNode.class);
when(messageNode.getValue()).thenReturn(message);
ChatMessage chatMessage = new ChatMessage();
chatMessage.setType(ChatMessageType.PUBLICCHAT);
chatMessage.setMessageNode(messageNode);
chatNotificationsPlugin.startUp(); // load highlight config
chatNotificationsPlugin.onChatMessage(chatMessage);
verify(messageNode).setValue("<colHIGHLIGHT>.Your divine potion effect is about to expire.<colNORMAL>");
}
@Test
public void testFullStop()
{
when(config.highlightWordsString()).thenReturn("test");
String message = "foo test. bar";
MessageNode messageNode = mock(MessageNode.class);
when(messageNode.getValue()).thenReturn(message);
ChatMessage chatMessage = new ChatMessage();
chatMessage.setType(ChatMessageType.PUBLICCHAT);
chatMessage.setMessageNode(messageNode);
chatNotificationsPlugin.startUp(); // load highlight config
chatNotificationsPlugin.onChatMessage(chatMessage);
verify(messageNode).setValue("foo <colHIGHLIGHT>test<colNORMAL>. bar");
}
@Test
public void testColor()
{
when(config.highlightWordsString()).thenReturn("you. It");
String message = "Your dodgy necklace protects you. <col=ff0000>It has 1 charge left.</col>";
MessageNode messageNode = mock(MessageNode.class);
when(messageNode.getValue()).thenReturn(message);
ChatMessage chatMessage = new ChatMessage();
chatMessage.setType(ChatMessageType.PUBLICCHAT);
chatMessage.setMessageNode(messageNode);
chatNotificationsPlugin.startUp(); // load highlight config
chatNotificationsPlugin.onChatMessage(chatMessage);
verify(messageNode).setValue("Your dodgy necklace protects <colHIGHLIGHT>you. It<col=ff0000> has 1 charge left.</col>");
}
@Test
public void testPreceedingColor()
{
when(config.highlightWordsString()).thenReturn("you. It");
String message = "Your dodgy <col=00ff00>necklace protects you. It has 1 charge left.</col>";
MessageNode messageNode = mock(MessageNode.class);
when(messageNode.getValue()).thenReturn(message);
ChatMessage chatMessage = new ChatMessage();
chatMessage.setType(ChatMessageType.PUBLICCHAT);
chatMessage.setMessageNode(messageNode);
chatNotificationsPlugin.startUp(); // load highlight config
chatNotificationsPlugin.onChatMessage(chatMessage);
verify(messageNode).setValue("Your dodgy <col=00ff00>necklace protects <colHIGHLIGHT>you. It<col=00ff00> has 1 charge left.</col>");
}
@Test
public void testEmoji()
{
when(config.highlightWordsString()).thenReturn("test");
String message = "emoji test <img=29>";
MessageNode messageNode = mock(MessageNode.class);
when(messageNode.getValue()).thenReturn(message);
ChatMessage chatMessage = new ChatMessage();
chatMessage.setType(ChatMessageType.PUBLICCHAT);
chatMessage.setMessageNode(messageNode);
chatNotificationsPlugin.startUp(); // load highlight config
chatNotificationsPlugin.onChatMessage(chatMessage);
verify(messageNode).setValue("emoji <colHIGHLIGHT>test<colNORMAL> <img=29>");
}
@Test
public void testNonMatchedColors()
{
when(config.highlightWordsString()).thenReturn("test");
String message = "<col=ff0000>color</col> test <img=29>";
MessageNode messageNode = mock(MessageNode.class);
when(messageNode.getValue()).thenReturn(message);
ChatMessage chatMessage = new ChatMessage();
chatMessage.setType(ChatMessageType.PUBLICCHAT);
chatMessage.setMessageNode(messageNode);
chatNotificationsPlugin.startUp(); // load highlight config
chatNotificationsPlugin.onChatMessage(chatMessage);
verify(messageNode).setValue("<col=ff0000>color</col> <colHIGHLIGHT>test<colNORMAL> <img=29>");
}
@Test
public void highlightListTest()
{
when(config.highlightWordsString()).thenReturn("this,is, a , test, ");
final List<String> higlights = Text.fromCSV(config.highlightWordsString());
assertEquals(4, higlights.size());
final Iterator<String> iterator = higlights.iterator();
assertEquals("this", iterator.next());
assertEquals("is", iterator.next());
assertEquals("a", iterator.next());
assertEquals("test", iterator.next());
}
@Test
public void testStripColor()
{
assertEquals("you. It", ChatNotificationsPlugin.stripColor("you. <col=ff0000>It"));
}
@Test
public void testHighlightOwnName()
{
Player player = mock(Player.class);
when(player.getName()).thenReturn("Logic Knot");
when(client.getLocalPlayer()).thenReturn(player);
when(config.highlightOwnName()).thenReturn(true);
MessageNode messageNode = mock(MessageNode.class);
when(messageNode.getValue()).thenReturn("<col=005f00>Logic Knot received a drop: Adamant longsword</col>");
ChatMessage chatMessage = new ChatMessage(messageNode, ChatMessageType.GAMEMESSAGE, "", "", "", 0);
chatNotificationsPlugin.onChatMessage(chatMessage);
verify(messageNode).setValue("<col=005f00><colHIGHLIGHT><u>Logic Knot</u><colNORMAL> received a drop: Adamant longsword</col>");
}
@Test
public void testHighlightOwnNameNbsp()
{
Player player = mock(Player.class);
when(player.getName()).thenReturn("Logic Knot");
when(client.getLocalPlayer()).thenReturn(player);
when(config.highlightOwnName()).thenReturn(true);
MessageNode messageNode = mock(MessageNode.class);
when(messageNode.getValue()).thenReturn("<col=005f00>Logic\u00a0Knot received a drop: Adamant longsword</col>");
ChatMessage chatMessage = new ChatMessage(messageNode, ChatMessageType.GAMEMESSAGE, "", "", "", 0);
chatNotificationsPlugin.onChatMessage(chatMessage);
// set value uses our player name, which has nbsp replaced
verify(messageNode).setValue("<col=005f00><colHIGHLIGHT><u>Logic Knot</u><colNORMAL> received a drop: Adamant longsword</col>");
}
}

View File

@@ -0,0 +1,139 @@
/*
* Copyright (c) 2018, 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.discord;
import com.google.inject.Guice;
import com.google.inject.testing.fieldbinder.Bind;
import com.google.inject.testing.fieldbinder.BoundFieldModule;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.UUID;
import javax.inject.Inject;
import javax.inject.Named;
import net.runelite.api.Client;
import net.runelite.client.discord.DiscordPresence;
import net.runelite.client.discord.DiscordService;
import net.runelite.client.ws.PartyService;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import static org.mockito.ArgumentMatchers.any;
import org.mockito.Mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class DiscordStateTest
{
@Inject
DiscordState discordState;
@Mock
@Bind
DiscordConfig discordConfig;
@Mock
@Bind
DiscordService discordService;
@Mock
@Bind
Client client;
@Mock
@Bind
PartyService partyService;
@Bind
@Named("runelite.title")
private String runeliteTitle = "RuneLite";
@Bind
@Named("runelite.version")
private String runeliteVersion = "version";
@Before
public void before()
{
Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this);
when(partyService.getLocalPartyId()).thenReturn(UUID.nameUUIDFromBytes("test".getBytes(StandardCharsets.UTF_8)));
}
@Test
public void testStatusReset()
{
when(discordConfig.actionTimeout()).thenReturn(-1);
when(discordConfig.elapsedTimeType()).thenReturn(DiscordConfig.ElapsedTimeType.ACTIVITY);
discordState.triggerEvent(DiscordGameEventType.IN_MENU);
verify(discordService).updatePresence(any(DiscordPresence.class));
discordState.checkForTimeout();
ArgumentCaptor<DiscordPresence> captor = ArgumentCaptor.forClass(DiscordPresence.class);
verify(discordService, times(2)).updatePresence(captor.capture());
List<DiscordPresence> captured = captor.getAllValues();
assertNull(captured.get(captured.size() - 1).getEndTimestamp());
}
@Test
public void testStatusTimeout()
{
when(discordConfig.actionTimeout()).thenReturn(-1);
when(discordConfig.elapsedTimeType()).thenReturn(DiscordConfig.ElapsedTimeType.ACTIVITY);
discordState.triggerEvent(DiscordGameEventType.TRAINING_AGILITY);
verify(discordService).updatePresence(any(DiscordPresence.class));
discordState.checkForTimeout();
verify(discordService, times(1)).clearPresence();
}
@Test
public void testAreaChange()
{
when(discordConfig.elapsedTimeType()).thenReturn(DiscordConfig.ElapsedTimeType.TOTAL);
// Start with state of IN_GAME
ArgumentCaptor<DiscordPresence> captor = ArgumentCaptor.forClass(DiscordPresence.class);
discordState.triggerEvent(DiscordGameEventType.IN_GAME);
verify(discordService, times(1)).updatePresence(captor.capture());
assertEquals(DiscordGameEventType.IN_GAME.getState(), captor.getValue().getState());
// IN_GAME -> CITY
discordState.triggerEvent(DiscordGameEventType.CITY_VARROCK);
verify(discordService, times(2)).updatePresence(captor.capture());
assertEquals(DiscordGameEventType.CITY_VARROCK.getState(), captor.getValue().getState());
// CITY -> IN_GAME
discordState.triggerEvent(DiscordGameEventType.IN_GAME);
verify(discordService, times(3)).updatePresence(captor.capture());
assertEquals(DiscordGameEventType.IN_GAME.getState(), captor.getValue().getState());
}
}

View File

@@ -0,0 +1,332 @@
/*
* Copyright (c) 2020, 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.grandexchange;
import com.google.inject.Guice;
import com.google.inject.testing.fieldbinder.Bind;
import com.google.inject.testing.fieldbinder.BoundFieldModule;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
import javax.inject.Inject;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.GrandExchangeOffer;
import net.runelite.api.GrandExchangeOfferState;
import net.runelite.api.ItemComposition;
import net.runelite.api.ItemID;
import net.runelite.api.WorldType;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.GrandExchangeOfferChanged;
import net.runelite.client.Notifier;
import net.runelite.client.account.SessionManager;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.config.RuneLiteConfig;
import net.runelite.client.game.ItemManager;
import net.runelite.client.input.KeyManager;
import net.runelite.client.input.MouseManager;
import static net.runelite.client.plugins.grandexchange.GrandExchangePlugin.findFuzzyIndices;
import static net.runelite.http.api.RuneLiteAPI.GSON;
import net.runelite.http.api.ge.GrandExchangeClient;
import net.runelite.http.api.ge.GrandExchangeTrade;
import net.runelite.http.api.osbuddy.OSBGrandExchangeClient;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import org.mockito.Mock;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class GrandExchangePluginTest
{
@Inject
private GrandExchangePlugin grandExchangePlugin;
@Mock
@Bind
private GrandExchangeConfig grandExchangeConfig;
@Mock
@Bind
private Notifier notifier;
@Mock
@Bind
private SessionManager sessionManager;
@Mock
@Bind
private ConfigManager configManager;
@Mock
@Bind
private ItemManager itemManager;
@Mock
@Bind
private KeyManager keyManager;
@Mock
@Bind
private MouseManager mouseManager;
@Mock
@Bind
private ScheduledExecutorService scheduledExecutorService;
@Mock
@Bind
private GrandExchangeClient grandExchangeClient;
@Mock
@Bind
private OSBGrandExchangeClient osbGrandExchangeClient;
@Mock
@Bind
private Client client;
@Mock
@Bind
private RuneLiteConfig runeLiteConfig;
@Before
public void setUp()
{
Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this);
when(client.getWorldType()).thenReturn(EnumSet.noneOf(WorldType.class));
}
@Test
public void testFindFuzzyIndices()
{
List<Integer> fuzzyIndices = findFuzzyIndices("Ancestral robe bottom", "obby");
// r<u>ob</u>e <u>b</u>ottom
assertEquals(Arrays.asList(11, 12, 15), fuzzyIndices);
}
@Test
public void testSubmitTrade()
{
// 1 @ 25
SavedOffer savedOffer = new SavedOffer();
savedOffer.setItemId(ItemID.ABYSSAL_WHIP);
savedOffer.setQuantitySold(1);
savedOffer.setTotalQuantity(10);
savedOffer.setPrice(1000);
savedOffer.setSpent(25);
savedOffer.setState(GrandExchangeOfferState.BUYING);
when(configManager.getRSProfileConfiguration("geoffer", "0")).thenReturn(GSON.toJson(savedOffer));
// buy 2 @ 10/ea
GrandExchangeOffer grandExchangeOffer = mock(GrandExchangeOffer.class);
when(grandExchangeOffer.getQuantitySold()).thenReturn(1 + 2);
when(grandExchangeOffer.getItemId()).thenReturn(ItemID.ABYSSAL_WHIP);
when(grandExchangeOffer.getTotalQuantity()).thenReturn(10);
when(grandExchangeOffer.getPrice()).thenReturn(1000);
when(grandExchangeOffer.getSpent()).thenReturn(25 + 10 * 2);
when(grandExchangeOffer.getState()).thenReturn(GrandExchangeOfferState.BUYING);
grandExchangePlugin.submitTrade(0, grandExchangeOffer);
ArgumentCaptor<GrandExchangeTrade> captor = ArgumentCaptor.forClass(GrandExchangeTrade.class);
verify(grandExchangeClient).submit(captor.capture());
GrandExchangeTrade trade = captor.getValue();
assertTrue(trade.isBuy());
assertEquals(ItemID.ABYSSAL_WHIP, trade.getItemId());
assertEquals(2, trade.getDqty());
assertEquals(10, trade.getTotal());
assertEquals(45, trade.getSpent());
assertEquals(20, trade.getDspent());
}
@Test
public void testDuplicateTrade()
{
SavedOffer savedOffer = new SavedOffer();
savedOffer.setItemId(ItemID.ABYSSAL_WHIP);
savedOffer.setQuantitySold(1);
savedOffer.setTotalQuantity(10);
savedOffer.setPrice(1000);
savedOffer.setSpent(25);
savedOffer.setState(GrandExchangeOfferState.BUYING);
when(configManager.getRSProfileConfiguration("geoffer", "0")).thenReturn(GSON.toJson(savedOffer));
GrandExchangeOffer grandExchangeOffer = mock(GrandExchangeOffer.class);
when(grandExchangeOffer.getQuantitySold()).thenReturn(1);
when(grandExchangeOffer.getItemId()).thenReturn(ItemID.ABYSSAL_WHIP);
when(grandExchangeOffer.getTotalQuantity()).thenReturn(10);
when(grandExchangeOffer.getPrice()).thenReturn(1000);
lenient().when(grandExchangeOffer.getSpent()).thenReturn(25);
when(grandExchangeOffer.getState()).thenReturn(GrandExchangeOfferState.BUYING);
grandExchangePlugin.submitTrade(0, grandExchangeOffer);
verify(grandExchangeClient, never()).submit(any(GrandExchangeTrade.class));
}
@Test
public void testCancelTrade()
{
SavedOffer savedOffer = new SavedOffer();
savedOffer.setItemId(ItemID.ABYSSAL_WHIP);
savedOffer.setQuantitySold(1);
savedOffer.setTotalQuantity(10);
savedOffer.setPrice(1000);
savedOffer.setSpent(25);
savedOffer.setState(GrandExchangeOfferState.BUYING);
when(configManager.getRSProfileConfiguration("geoffer", "0")).thenReturn(GSON.toJson(savedOffer));
GrandExchangeOffer grandExchangeOffer = mock(GrandExchangeOffer.class);
when(grandExchangeOffer.getQuantitySold()).thenReturn(1);
when(grandExchangeOffer.getItemId()).thenReturn(ItemID.ABYSSAL_WHIP);
when(grandExchangeOffer.getTotalQuantity()).thenReturn(10);
when(grandExchangeOffer.getPrice()).thenReturn(1000);
when(grandExchangeOffer.getSpent()).thenReturn(25);
when(grandExchangeOffer.getState()).thenReturn(GrandExchangeOfferState.CANCELLED_BUY);
grandExchangePlugin.submitTrade(0, grandExchangeOffer);
ArgumentCaptor<GrandExchangeTrade> captor = ArgumentCaptor.forClass(GrandExchangeTrade.class);
verify(grandExchangeClient).submit(captor.capture());
GrandExchangeTrade trade = captor.getValue();
assertTrue(trade.isBuy());
assertTrue(trade.isCancel());
assertEquals(ItemID.ABYSSAL_WHIP, trade.getItemId());
assertEquals(1, trade.getQty());
assertEquals(10, trade.getTotal());
assertEquals(25, trade.getSpent());
}
@Test
public void testHop()
{
when(client.getGameState()).thenReturn(GameState.HOPPING);
GrandExchangeOffer grandExchangeOffer = mock(GrandExchangeOffer.class);
when(grandExchangeOffer.getState()).thenReturn(GrandExchangeOfferState.EMPTY);
GrandExchangeOfferChanged grandExchangeOfferChanged = new GrandExchangeOfferChanged();
grandExchangeOfferChanged.setOffer(grandExchangeOffer);
grandExchangePlugin.onGrandExchangeOfferChanged(grandExchangeOfferChanged);
verify(configManager, never()).unsetRSProfileConfiguration(anyString(), anyString());
}
@Test
public void testLogin()
{
GrandExchangePanel panel = mock(GrandExchangePanel.class);
when(panel.getOffersPanel()).thenReturn(mock(GrandExchangeOffersPanel.class));
grandExchangePlugin.setPanel(panel);
when(itemManager.getItemComposition(anyInt())).thenReturn(mock(ItemComposition.class));
// provide config support so getOffer and setOffer work
final Map<String, Object> config = new HashMap<>();
doAnswer(a ->
{
Object[] arguments = a.getArguments();
config.put((String) arguments[1], arguments[2]);
return null;
}).when(configManager).setRSProfileConfiguration(eq("geoffer"), anyString(), anyString());
when(configManager.getRSProfileConfiguration(eq("geoffer"), anyString())).thenAnswer(a ->
{
Object[] arguments = a.getArguments();
return config.get((String) arguments[1]);
});
// set loginBurstGeUpdates
GameStateChanged gameStateChanged = new GameStateChanged();
gameStateChanged.setGameState(GameState.LOGIN_SCREEN);
grandExchangePlugin.onGameStateChanged(gameStateChanged);
// 8x buy 10 whip @ 1k ea, bought 1 sofar.
for (int i = 0; i < GrandExchangePlugin.GE_SLOTS; ++i)
{
GrandExchangeOffer grandExchangeOffer = mock(GrandExchangeOffer.class);
when(grandExchangeOffer.getQuantitySold()).thenReturn(1);
when(grandExchangeOffer.getItemId()).thenReturn(ItemID.ABYSSAL_WHIP);
when(grandExchangeOffer.getTotalQuantity()).thenReturn(10);
when(grandExchangeOffer.getPrice()).thenReturn(1000);
when(grandExchangeOffer.getSpent()).thenReturn(1000);
when(grandExchangeOffer.getState()).thenReturn(GrandExchangeOfferState.SELLING);
GrandExchangeOfferChanged grandExchangeOfferChanged = new GrandExchangeOfferChanged();
grandExchangeOfferChanged.setSlot(i);
grandExchangeOfferChanged.setOffer(grandExchangeOffer);
grandExchangePlugin.onGrandExchangeOfferChanged(grandExchangeOfferChanged);
}
// Now send update for one of the slots
GrandExchangeOffer grandExchangeOffer = mock(GrandExchangeOffer.class);
when(grandExchangeOffer.getQuantitySold()).thenReturn(2);
when(grandExchangeOffer.getItemId()).thenReturn(ItemID.ABYSSAL_WHIP);
when(grandExchangeOffer.getTotalQuantity()).thenReturn(10);
when(grandExchangeOffer.getPrice()).thenReturn(1000);
when(grandExchangeOffer.getSpent()).thenReturn(2000);
when(grandExchangeOffer.getState()).thenReturn(GrandExchangeOfferState.SELLING);
GrandExchangeOfferChanged grandExchangeOfferChanged = new GrandExchangeOfferChanged();
grandExchangeOfferChanged.setSlot(2);
grandExchangeOfferChanged.setOffer(grandExchangeOffer);
grandExchangePlugin.onGrandExchangeOfferChanged(grandExchangeOfferChanged);
// verify trade update
ArgumentCaptor<GrandExchangeTrade> captor = ArgumentCaptor.forClass(GrandExchangeTrade.class);
verify(grandExchangeClient).submit(captor.capture());
GrandExchangeTrade trade = captor.getValue();
assertFalse(trade.isBuy());
assertEquals(ItemID.ABYSSAL_WHIP, trade.getItemId());
assertEquals(2, trade.getQty());
assertEquals(1, trade.getDqty());
assertEquals(10, trade.getTotal());
assertEquals(1000, trade.getDspent());
assertEquals(2000, trade.getSpent());
assertEquals(1000, trade.getOffer());
assertEquals(2, trade.getSlot());
assertTrue(trade.isLogin());
}
}

View File

@@ -0,0 +1,318 @@
/*
* Copyright (c) 2018, 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.screenshot;
import com.google.inject.Guice;
import com.google.inject.testing.fieldbinder.Bind;
import com.google.inject.testing.fieldbinder.BoundFieldModule;
import java.util.concurrent.ScheduledExecutorService;
import java.util.function.Consumer;
import javax.inject.Inject;
import static net.runelite.api.ChatMessageType.GAMEMESSAGE;
import net.runelite.api.Client;
import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.GameTick;
import net.runelite.api.events.WidgetLoaded;
import net.runelite.api.widgets.Widget;
import static net.runelite.api.widgets.WidgetID.DIALOG_SPRITE_GROUP_ID;
import static net.runelite.api.widgets.WidgetID.LEVEL_UP_GROUP_ID;
import static net.runelite.api.widgets.WidgetInfo.DIALOG_SPRITE_TEXT;
import static net.runelite.api.widgets.WidgetInfo.LEVEL_UP_LEVEL;
import net.runelite.client.Notifier;
import net.runelite.client.config.RuneLiteConfig;
import net.runelite.client.ui.ClientUI;
import net.runelite.client.ui.DrawManager;
import net.runelite.client.ui.overlay.OverlayManager;
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
import net.runelite.client.util.ImageCapture;
import static org.junit.Assert.assertEquals;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import org.mockito.Mock;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class ScreenshotPluginTest
{
private static final String CLUE_SCROLL = "<col=3300ff>You have completed 28 medium Treasure Trails</col>";
private static final String BARROWS_CHEST = "Your Barrows chest count is <col=ff0000>310</col>";
private static final String CHAMBERS_OF_XERIC_CHEST = "Your completed Chambers of Xeric count is: <col=ff0000>489</col>.";
private static final String THEATRE_OF_BLOOD_CHEST = "Your completed Theatre of Blood count is: <col=ff0000>73</col>.";
private static final String VALUABLE_DROP = "<col=ef1020>Valuable drop: 6 x Bronze arrow (42 coins)</col>";
private static final String UNTRADEABLE_DROP = "<col=ef1020>Untradeable drop: Rusty sword";
private static final String BA_HIGH_GAMBLE_REWARD = "Raw shark (x 300)!<br>High level gamble count: <col=7f0000>100</col>";
private static final String HUNTER_LEVEL_2_TEXT = "<col=000080>Congratulations, you've just advanced a Hunter level.<col=000000><br><br>Your Hunter level is now 2.";
@Mock
@Bind
private Client client;
@Inject
private ScreenshotPlugin screenshotPlugin;
@Mock
@Bind
private ScreenshotConfig screenshotConfig;
@Mock
@Bind
Notifier notifier;
@Mock
@Bind
ClientUI clientUi;
@Mock
@Bind
DrawManager drawManager;
@Mock
@Bind
RuneLiteConfig config;
@Mock
@Bind
ScheduledExecutorService service;
@Mock
@Bind
private OverlayManager overlayManager;
@Mock
@Bind
private InfoBoxManager infoBoxManager;
@Mock
@Bind
private ImageCapture imageCapture;
@Before
public void before()
{
Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this);
when(screenshotConfig.screenshotLevels()).thenReturn(true);
when(screenshotConfig.screenshotValuableDrop()).thenReturn(true);
when(screenshotConfig.screenshotUntradeableDrop()).thenReturn(true);
}
@Test
public void testClueScroll()
{
ChatMessage chatMessageEvent = new ChatMessage(null, GAMEMESSAGE, "Seth", CLUE_SCROLL, null, 0);
screenshotPlugin.onChatMessage(chatMessageEvent);
assertEquals("medium", screenshotPlugin.getClueType());
assertEquals(28, screenshotPlugin.getClueNumber());
}
@Test
public void testBarrowsChest()
{
ChatMessage chatMessageEvent = new ChatMessage(null, GAMEMESSAGE, "Seth", BARROWS_CHEST, null, 0);
screenshotPlugin.onChatMessage(chatMessageEvent);
assertEquals(310, screenshotPlugin.getBarrowsNumber());
}
@Test
public void testChambersOfXericChest()
{
ChatMessage chatMessageEvent = new ChatMessage(null, GAMEMESSAGE, "Seth", CHAMBERS_OF_XERIC_CHEST, null, 0);
screenshotPlugin.onChatMessage(chatMessageEvent);
assertEquals(489, screenshotPlugin.getChambersOfXericNumber());
}
@Test
public void testTheatreOfBloodChest()
{
ChatMessage chatMessageEvent = new ChatMessage(null, GAMEMESSAGE, "Magic fTail", THEATRE_OF_BLOOD_CHEST, null, 0);
screenshotPlugin.onChatMessage(chatMessageEvent);
assertEquals(73, screenshotPlugin.gettheatreOfBloodNumber());
}
@Test
public void testValuableDrop()
{
ChatMessage chatMessageEvent = new ChatMessage(null, GAMEMESSAGE, "", VALUABLE_DROP, null, 0);
screenshotPlugin.onChatMessage(chatMessageEvent);
verify(drawManager).requestNextFrameListener(any(Consumer.class));
}
@Test
public void testUntradeableDrop()
{
ChatMessage chatMessageEvent = new ChatMessage(null, GAMEMESSAGE, "", UNTRADEABLE_DROP, null, 0);
screenshotPlugin.onChatMessage(chatMessageEvent);
verify(drawManager).requestNextFrameListener(any(Consumer.class));
}
@Test
public void testHitpointsLevel99()
{
Widget levelChild = mock(Widget.class);
when(client.getWidget(eq(LEVEL_UP_LEVEL))).thenReturn(levelChild);
when(levelChild.getText()).thenReturn("Your Hitpoints are now 99.");
assertEquals("Hitpoints(99)", screenshotPlugin.parseLevelUpWidget(LEVEL_UP_LEVEL));
WidgetLoaded event = new WidgetLoaded();
event.setGroupId(LEVEL_UP_GROUP_ID);
screenshotPlugin.onWidgetLoaded(event);
GameTick tick = new GameTick();
screenshotPlugin.onGameTick(tick);
verify(drawManager).requestNextFrameListener(any(Consumer.class));
}
@Test
public void testFiremakingLevel9()
{
Widget levelChild = mock(Widget.class);
when(client.getWidget(eq(LEVEL_UP_LEVEL))).thenReturn(levelChild);
when(levelChild.getText()).thenReturn("Your Firemaking level is now 9.");
assertEquals("Firemaking(9)", screenshotPlugin.parseLevelUpWidget(LEVEL_UP_LEVEL));
WidgetLoaded event = new WidgetLoaded();
event.setGroupId(LEVEL_UP_GROUP_ID);
screenshotPlugin.onWidgetLoaded(event);
GameTick tick = new GameTick();
screenshotPlugin.onGameTick(tick);
verify(drawManager).requestNextFrameListener(any(Consumer.class));
}
@Test
public void testAttackLevel70()
{
Widget levelChild = mock(Widget.class);
when(client.getWidget(eq(LEVEL_UP_LEVEL))).thenReturn(levelChild);
when(levelChild.getText()).thenReturn("Your Attack level is now 70.");
assertEquals("Attack(70)", screenshotPlugin.parseLevelUpWidget(LEVEL_UP_LEVEL));
WidgetLoaded event = new WidgetLoaded();
event.setGroupId(LEVEL_UP_GROUP_ID);
screenshotPlugin.onWidgetLoaded(event);
GameTick tick = new GameTick();
screenshotPlugin.onGameTick(tick);
verify(drawManager).requestNextFrameListener(any(Consumer.class));
}
@Test
public void testHunterLevel2()
{
Widget levelChild = mock(Widget.class);
when(client.getWidget(eq(DIALOG_SPRITE_TEXT))).thenReturn(levelChild);
when(levelChild.getText()).thenReturn(HUNTER_LEVEL_2_TEXT);
assertEquals("Hunter(2)", screenshotPlugin.parseLevelUpWidget(DIALOG_SPRITE_TEXT));
WidgetLoaded event = new WidgetLoaded();
event.setGroupId(DIALOG_SPRITE_GROUP_ID);
screenshotPlugin.onWidgetLoaded(event);
GameTick tick = new GameTick();
screenshotPlugin.onGameTick(tick);
verify(drawManager).requestNextFrameListener(any(Consumer.class));
}
@Test
public void testQuestParsing()
{
assertEquals("Quest(The Corsair Curse)", ScreenshotPlugin.parseQuestCompletedWidget("You have completed The Corsair Curse!"));
assertEquals("Quest(One Small Favour)", ScreenshotPlugin.parseQuestCompletedWidget("'One Small Favour' completed!"));
assertEquals("Quest(Hazeel Cult partial completion)", ScreenshotPlugin.parseQuestCompletedWidget("You have... kind of... completed the Hazeel Cult Quest!"));
assertEquals("Quest(Rag and Bone Man II)", ScreenshotPlugin.parseQuestCompletedWidget("You have completely completed Rag and Bone Man!"));
assertEquals("Quest(Recipe for Disaster - Culinaromancer)", ScreenshotPlugin.parseQuestCompletedWidget("Congratulations! You have defeated the Culinaromancer!"));
assertEquals("Quest(Recipe for Disaster - Another Cook's Quest)", ScreenshotPlugin.parseQuestCompletedWidget("You have completed Another Cook's Quest!"));
assertEquals("Quest(Doric's Quest)", ScreenshotPlugin.parseQuestCompletedWidget("You have completed Doric's Quest!"));
assertEquals("Quest(quest not found)", ScreenshotPlugin.parseQuestCompletedWidget("Sins of the Father forgiven!"));
}
@Test
public void testBAHighGambleRewardParsing()
{
assertEquals("High Gamble(100)", ScreenshotPlugin.parseBAHighGambleWidget(BA_HIGH_GAMBLE_REWARD));
}
@Test
public void testLevelUpScreenshotsDisabled()
{
// Level up dialogs use the same widget interface as BA high gamble results
when(screenshotConfig.screenshotLevels()).thenReturn(false);
when(screenshotConfig.screenshotHighGamble()).thenReturn(true);
Widget dialogChild = mock(Widget.class);
when(dialogChild.getText()).thenReturn(HUNTER_LEVEL_2_TEXT);
when(client.getWidget(DIALOG_SPRITE_TEXT)).thenReturn(dialogChild);
WidgetLoaded event = new WidgetLoaded();
event.setGroupId(DIALOG_SPRITE_GROUP_ID);
screenshotPlugin.onWidgetLoaded(event);
screenshotPlugin.onGameTick(new GameTick());
verify(drawManager, times(0)).requestNextFrameListener(any(Consumer.class));
}
@Test
public void testBAHighGambleScreenshotsDisabled()
{
// BA high gamble results use the same widget interface as level up dialogs
when(screenshotConfig.screenshotLevels()).thenReturn(true);
when(screenshotConfig.screenshotHighGamble()).thenReturn(false);
Widget dialogChild = mock(Widget.class);
when(dialogChild.getText()).thenReturn(BA_HIGH_GAMBLE_REWARD);
when(client.getWidget(DIALOG_SPRITE_TEXT)).thenReturn(dialogChild);
WidgetLoaded event = new WidgetLoaded();
event.setGroupId(DIALOG_SPRITE_GROUP_ID);
screenshotPlugin.onWidgetLoaded(event);
screenshotPlugin.onGameTick(new GameTick());
verify(drawManager, times(0)).requestNextFrameListener(any(Consumer.class));
}
}

View File

@@ -0,0 +1,297 @@
/*
* Copyright (c) 2020, 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.specialcounter;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.testing.fieldbinder.Bind;
import com.google.inject.testing.fieldbinder.BoundFieldModule;
import net.runelite.api.Actor;
import net.runelite.api.Client;
import net.runelite.api.EquipmentInventorySlot;
import net.runelite.api.Hitsplat;
import net.runelite.api.InventoryID;
import net.runelite.api.Item;
import net.runelite.api.ItemContainer;
import net.runelite.api.ItemID;
import net.runelite.api.NPC;
import net.runelite.api.Player;
import net.runelite.api.VarPlayer;
import net.runelite.api.events.HitsplatApplied;
import net.runelite.api.events.InteractingChanged;
import net.runelite.api.events.VarbitChanged;
import net.runelite.client.Notifier;
import net.runelite.client.game.ItemManager;
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
import net.runelite.client.ws.PartyService;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.mockito.ArgumentMatchers.any;
import org.mockito.Mock;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class SpecialCounterPluginTest
{
@Mock
@Bind
private Client client;
@Mock
@Bind
private InfoBoxManager infoBoxManager;
@Mock
@Bind
private PartyService partyService;
@Mock
@Bind
private ItemManager itemManager;
@Mock
@Bind
private Notifier notifier;
@Mock
@Bind
private SpecialCounterConfig specialCounterConfig;
@Inject
private SpecialCounterPlugin specialCounterPlugin;
@Before
public void before()
{
Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this);
// Set up spec weapon
ItemContainer equipment = mock(ItemContainer.class);
when(equipment.getItem(EquipmentInventorySlot.WEAPON.getSlotIdx())).thenReturn(new Item(ItemID.BANDOS_GODSWORD, 1));
when(client.getItemContainer(InventoryID.EQUIPMENT)).thenReturn(equipment);
// Set up special attack energy
when(client.getVar(VarPlayer.SPECIAL_ATTACK_PERCENT)).thenReturn(100);
specialCounterPlugin.onVarbitChanged(new VarbitChanged());
}
private static HitsplatApplied hitsplat(Actor target, Hitsplat.HitsplatType type)
{
Hitsplat hitsplat = new Hitsplat(type, type == Hitsplat.HitsplatType.DAMAGE_ME ? 1 : 0, 42);
HitsplatApplied hitsplatApplied = new HitsplatApplied();
hitsplatApplied.setActor(target);
hitsplatApplied.setHitsplat(hitsplat);
return hitsplatApplied;
}
@Test
public void testSpecDamage()
{
NPC target = mock(NPC.class);
Player player = mock(Player.class);
when(client.getLocalPlayer()).thenReturn(player);
// spec npc
when(client.getVar(VarPlayer.SPECIAL_ATTACK_PERCENT)).thenReturn(50);
specialCounterPlugin.onVarbitChanged(new VarbitChanged());
lenient().when(player.getInteracting()).thenReturn(target);
specialCounterPlugin.onInteractingChanged(new InteractingChanged(player, target));
// hit 1
specialCounterPlugin.onHitsplatApplied(hitsplat(target, Hitsplat.HitsplatType.DAMAGE_ME));
verify(infoBoxManager).addInfoBox(any(SpecialCounter.class));
}
@Test
public void testSpecBlock()
{
NPC target = mock(NPC.class);
Player player = mock(Player.class);
when(client.getLocalPlayer()).thenReturn(player);
// spec npc
when(client.getVar(VarPlayer.SPECIAL_ATTACK_PERCENT)).thenReturn(50);
specialCounterPlugin.onVarbitChanged(new VarbitChanged());
lenient().when(player.getInteracting()).thenReturn(target);
specialCounterPlugin.onInteractingChanged(new InteractingChanged(player, target));
// block 0
specialCounterPlugin.onHitsplatApplied(hitsplat(target, Hitsplat.HitsplatType.BLOCK_ME));
// hit 1
specialCounterPlugin.onHitsplatApplied(hitsplat(target, Hitsplat.HitsplatType.DAMAGE_ME));
verify(infoBoxManager, never()).addInfoBox(any(SpecialCounter.class));
}
@Test
public void testUnaggro()
{
NPC target = mock(NPC.class);
Player player = mock(Player.class);
when(client.getLocalPlayer()).thenReturn(player);
// tick 1: attack npc
when(player.getInteracting()).thenReturn(target);
specialCounterPlugin.onInteractingChanged(new InteractingChanged(player, target));
// tick 2: spec fires and un-interact npc
when(client.getVar(VarPlayer.SPECIAL_ATTACK_PERCENT)).thenReturn(50);
specialCounterPlugin.onVarbitChanged(new VarbitChanged());
lenient().when(player.getInteracting()).thenReturn(null);
specialCounterPlugin.onInteractingChanged(new InteractingChanged(player, null));
// tick 3: hit 1
specialCounterPlugin.onHitsplatApplied(hitsplat(target, Hitsplat.HitsplatType.DAMAGE_ME));
verify(infoBoxManager).addInfoBox(any(SpecialCounter.class));
}
@Test
public void testSameTick()
{
NPC targetA = mock(NPC.class);
NPC targetB = mock(NPC.class);
Player player = mock(Player.class);
when(client.getLocalPlayer()).thenReturn(player);
// tick 1: attack npc A
when(player.getInteracting()).thenReturn(targetA);
specialCounterPlugin.onInteractingChanged(new InteractingChanged(player, targetA));
// tick 2: spec npc B
when(client.getVar(VarPlayer.SPECIAL_ATTACK_PERCENT)).thenReturn(50);
specialCounterPlugin.onVarbitChanged(new VarbitChanged());
lenient().when(player.getInteracting()).thenReturn(targetB);
specialCounterPlugin.onInteractingChanged(new InteractingChanged(player, targetB));
// tick 3: hitsplat A, hitsplat B
specialCounterPlugin.onHitsplatApplied(hitsplat(targetA, Hitsplat.HitsplatType.DAMAGE_ME));
verify(infoBoxManager, never()).addInfoBox(any(SpecialCounter.class));
specialCounterPlugin.onHitsplatApplied(hitsplat(targetB, Hitsplat.HitsplatType.DAMAGE_ME));
verify(infoBoxManager).addInfoBox(any(SpecialCounter.class));
}
@Test
public void testReset()
{
NPC targetA = mock(NPC.class);
NPC targetB = mock(NPC.class);
when(targetB.getId()).thenReturn(1); // a different npc type
Player player = mock(Player.class);
when(client.getLocalPlayer()).thenReturn(player);
// spec npc
when(client.getVar(VarPlayer.SPECIAL_ATTACK_PERCENT)).thenReturn(50);
specialCounterPlugin.onVarbitChanged(new VarbitChanged());
lenient().when(player.getInteracting()).thenReturn(targetA);
specialCounterPlugin.onInteractingChanged(new InteractingChanged(player, targetA));
// hit 1
specialCounterPlugin.onHitsplatApplied(hitsplat(targetA, Hitsplat.HitsplatType.DAMAGE_ME));
verify(infoBoxManager).addInfoBox(any(SpecialCounter.class));
// attack npc 2
specialCounterPlugin.onInteractingChanged(new InteractingChanged(player, targetB));
// hit 1
specialCounterPlugin.onHitsplatApplied(hitsplat(targetB, Hitsplat.HitsplatType.DAMAGE_ME));
verify(infoBoxManager).removeInfoBox(any(SpecialCounter.class));
}
@Test
public void testNotification()
{
// Create an enemy
NPC target = mock(NPC.class);
// Create player
Player player = mock(Player.class);
when(client.getLocalPlayer()).thenReturn(player);
when(specialCounterConfig.bandosGodswordThreshold()).thenReturn(2);
when(specialCounterConfig.thresholdNotification()).thenReturn(true);
// Attack enemy
when(player.getInteracting()).thenReturn(target);
specialCounterPlugin.onInteractingChanged(new InteractingChanged(player, target));
// First special attack
when(client.getVar(VarPlayer.SPECIAL_ATTACK_PERCENT)).thenReturn(50);
specialCounterPlugin.onVarbitChanged(new VarbitChanged());
specialCounterPlugin.onHitsplatApplied(hitsplat(target, Hitsplat.HitsplatType.DAMAGE_ME));
// Second special attack
when(client.getVar(VarPlayer.SPECIAL_ATTACK_PERCENT)).thenReturn(0);
specialCounterPlugin.onVarbitChanged(new VarbitChanged());
specialCounterPlugin.onHitsplatApplied(hitsplat(target, Hitsplat.HitsplatType.DAMAGE_ME));
verify(notifier).notify("Bandos Godsword special attack threshold reached!");
}
@Test
public void testNotificationNotThreshold()
{
// Create an enemy
NPC target = mock(NPC.class);
// Create player
Player player = mock(Player.class);
when(client.getLocalPlayer()).thenReturn(player);
when(specialCounterConfig.bandosGodswordThreshold()).thenReturn(3);
lenient().when(specialCounterConfig.thresholdNotification()).thenReturn(true);
// Attack enemy
when(player.getInteracting()).thenReturn(target);
specialCounterPlugin.onInteractingChanged(new InteractingChanged(player, target));
// First special attack
when(client.getVar(VarPlayer.SPECIAL_ATTACK_PERCENT)).thenReturn(50);
specialCounterPlugin.onVarbitChanged(new VarbitChanged());
specialCounterPlugin.onHitsplatApplied(hitsplat(target, Hitsplat.HitsplatType.DAMAGE_ME));
// Second special attack
when(client.getVar(VarPlayer.SPECIAL_ATTACK_PERCENT)).thenReturn(0);
specialCounterPlugin.onVarbitChanged(new VarbitChanged());
specialCounterPlugin.onHitsplatApplied(hitsplat(target, Hitsplat.HitsplatType.DAMAGE_ME));
verify(notifier, never()).notify(any());
}
}

View File

@@ -0,0 +1,372 @@
/*
* Copyright (c) 2019, 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.timers;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.testing.fieldbinder.Bind;
import com.google.inject.testing.fieldbinder.BoundFieldModule;
import java.time.Duration;
import java.time.Instant;
import net.runelite.api.ChatMessageType;
import net.runelite.api.Client;
import net.runelite.api.InventoryID;
import net.runelite.api.ItemContainer;
import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.ItemContainerChanged;
import net.runelite.client.game.ItemManager;
import net.runelite.client.game.SpriteManager;
import net.runelite.client.ui.overlay.infobox.InfoBox;
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.nullable;
import org.mockito.Mock;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
@RunWith(MockitoJUnitRunner.class)
public class TimersPluginTest
{
@Inject
private TimersPlugin timersPlugin;
@Mock
@Bind
private TimersConfig timersConfig;
@Mock
@Bind
private Client client;
@Mock
@Bind
private ItemManager itemManager;
@Mock
@Bind
private SpriteManager spriteManager;
@Mock
@Bind
private InfoBoxManager infoBoxManager;
@Before
public void before()
{
Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this);
}
@Test
public void testHalfTeleblock()
{
when(timersConfig.showTeleblock()).thenReturn(true);
ChatMessage chatMessage = new ChatMessage(null, ChatMessageType.SPAM, "", "<col=4f006f>A Tele Block spell has been cast on you by Runelite. It will expire in 2 minutes, 30 seconds.</col>", "", 0);
timersPlugin.onChatMessage(chatMessage);
ArgumentCaptor<InfoBox> captor = ArgumentCaptor.forClass(InfoBox.class);
verify(infoBoxManager).addInfoBox(captor.capture());
TimerTimer infoBox = (TimerTimer) captor.getValue();
assertEquals(GameTimer.TELEBLOCK, infoBox.getTimer());
assertEquals(Duration.ofSeconds(2 * 60 + 30), infoBox.getDuration());
}
@Test
public void testFullTeleblock()
{
when(timersConfig.showTeleblock()).thenReturn(true);
ChatMessage chatMessage = new ChatMessage(null, ChatMessageType.SPAM, "", "<col=4f006f>A Tele Block spell has been cast on you by Runelite. It will expire in 5 minutes.</col>", "", 0);
timersPlugin.onChatMessage(chatMessage);
ArgumentCaptor<InfoBox> captor = ArgumentCaptor.forClass(InfoBox.class);
verify(infoBoxManager).addInfoBox(captor.capture());
TimerTimer infoBox = (TimerTimer) captor.getValue();
assertEquals(GameTimer.TELEBLOCK, infoBox.getTimer());
assertEquals(Duration.ofMinutes(5), infoBox.getDuration());
}
@Test
public void testDmmHalfTb()
{
when(timersConfig.showTeleblock()).thenReturn(true);
ChatMessage chatMessage = new ChatMessage(null, ChatMessageType.SPAM, "", "<col=4f006f>A Tele Block spell has been cast on you by Runelite. It will expire in 1 minute, 15 seconds.</col>", "", 0);
timersPlugin.onChatMessage(chatMessage);
ArgumentCaptor<InfoBox> captor = ArgumentCaptor.forClass(InfoBox.class);
verify(infoBoxManager).addInfoBox(captor.capture());
TimerTimer infoBox = (TimerTimer) captor.getValue();
assertEquals(GameTimer.TELEBLOCK, infoBox.getTimer());
assertEquals(Duration.ofSeconds(60 + 15), infoBox.getDuration());
}
@Test
public void testDmmFullTb()
{
when(timersConfig.showTeleblock()).thenReturn(true);
ChatMessage chatMessage = new ChatMessage(null, ChatMessageType.SPAM, "", "<col=4f006f>A Tele Block spell has been cast on you by Runelite. It will expire in 2 minutes, 30 seconds.</col>", "", 0);
timersPlugin.onChatMessage(chatMessage);
ArgumentCaptor<InfoBox> captor = ArgumentCaptor.forClass(InfoBox.class);
verify(infoBoxManager).addInfoBox(captor.capture());
TimerTimer infoBox = (TimerTimer) captor.getValue();
assertEquals(GameTimer.TELEBLOCK, infoBox.getTimer());
assertEquals(Duration.ofSeconds(60 * 2 + 30), infoBox.getDuration());
}
@Test
public void testDivineBastion()
{
when(timersConfig.showDivine()).thenReturn(true);
ChatMessage chatMessage = new ChatMessage(null, ChatMessageType.SPAM, "", "You drink some of your divine bastion potion.", "", 0);
timersPlugin.onChatMessage(chatMessage);
ArgumentCaptor<InfoBox> captor = ArgumentCaptor.forClass(InfoBox.class);
verify(infoBoxManager).addInfoBox(captor.capture());
TimerTimer infoBox = (TimerTimer) captor.getValue();
assertEquals(GameTimer.DIVINE_BASTION, infoBox.getTimer());
}
@Test
public void testDivineBattlemage()
{
when(timersConfig.showDivine()).thenReturn(true);
ChatMessage chatMessage = new ChatMessage(null, ChatMessageType.SPAM, "", "You drink some of your divine battlemage potion.", "", 0);
timersPlugin.onChatMessage(chatMessage);
ArgumentCaptor<InfoBox> captor = ArgumentCaptor.forClass(InfoBox.class);
verify(infoBoxManager).addInfoBox(captor.capture());
TimerTimer infoBox = (TimerTimer) captor.getValue();
assertEquals(GameTimer.DIVINE_BATTLEMAGE, infoBox.getTimer());
}
@Test
public void testTransparentChatboxTb()
{
when(timersConfig.showTeleblock()).thenReturn(true);
ChatMessage chatMessage = new ChatMessage(null, ChatMessageType.SPAM, "", "<col=c356ef>A Tele Block spell has been cast on you by Alexsuperfly. It will expire in 5 minutes.</col>", "", 0);
timersPlugin.onChatMessage(chatMessage);
ArgumentCaptor<InfoBox> captor = ArgumentCaptor.forClass(InfoBox.class);
verify(infoBoxManager).addInfoBox(captor.capture());
TimerTimer infoBox = (TimerTimer) captor.getValue();
assertEquals(GameTimer.TELEBLOCK, infoBox.getTimer());
assertEquals(Duration.ofMinutes(5), infoBox.getDuration());
}
@Test
public void testTransparentChatboxTbRemoved()
{
when(timersConfig.showTeleblock()).thenReturn(true);
ChatMessage chatMessage = new ChatMessage(null, ChatMessageType.SPAM, "", "<col=c356ef>Your Tele Block has been removed because you killed Alexsuperfly.</col>", "", 0);
timersPlugin.onChatMessage(chatMessage);
verify(infoBoxManager, atLeastOnce()).removeIf(any());
}
@Test
public void testMageArena2TbFull()
{
when(timersConfig.showTeleblock()).thenReturn(true);
ChatMessage chatMessage = new ChatMessage(null, ChatMessageType.SPAM, "", "<col=c356ef>A Tele Block spell has been cast on you. It will expire in 2 minutes.</col>", "", 0);
timersPlugin.onChatMessage(chatMessage);
ArgumentCaptor<InfoBox> captor = ArgumentCaptor.forClass(InfoBox.class);
verify(infoBoxManager).addInfoBox(captor.capture());
TimerTimer infoBox = (TimerTimer) captor.getValue();
assertEquals(GameTimer.TELEBLOCK, infoBox.getTimer());
assertEquals(Duration.ofMinutes(2), infoBox.getDuration());
}
@Test
public void testMageArena2TbHalf()
{
when(timersConfig.showTeleblock()).thenReturn(true);
ChatMessage chatMessage = new ChatMessage(null, ChatMessageType.SPAM, "", "<col=c356ef>A Tele Block spell has been cast on you. It will expire in 1 minute.</col>", "", 0);
timersPlugin.onChatMessage(chatMessage);
ArgumentCaptor<InfoBox> captor = ArgumentCaptor.forClass(InfoBox.class);
verify(infoBoxManager).addInfoBox(captor.capture());
TimerTimer infoBox = (TimerTimer) captor.getValue();
assertEquals(GameTimer.TELEBLOCK, infoBox.getTimer());
assertEquals(Duration.ofMinutes(1), infoBox.getDuration());
}
@Test
public void testStamina()
{
when(timersConfig.showStamina()).thenReturn(true);
ChatMessage chatMessage = new ChatMessage(null, ChatMessageType.SPAM, "", "You drink some of your stamina potion.", "", 0);
timersPlugin.onChatMessage(chatMessage);
ArgumentCaptor<InfoBox> captor = ArgumentCaptor.forClass(InfoBox.class);
verify(infoBoxManager).addInfoBox(captor.capture());
TimerTimer infoBox = (TimerTimer) captor.getValue();
assertEquals(GameTimer.STAMINA, infoBox.getTimer());
assertEquals(Duration.ofMinutes(2), infoBox.getDuration());
}
@Test
public void testSireStunTimer()
{
when(timersConfig.showAbyssalSireStun()).thenReturn(true);
ChatMessage chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", "The Sire has been disorientated temporarily.", "", 0);
timersPlugin.onChatMessage(chatMessage);
ArgumentCaptor<InfoBox> captor = ArgumentCaptor.forClass(InfoBox.class);
verify(infoBoxManager).addInfoBox(captor.capture());
TimerTimer infoBox = (TimerTimer) captor.getValue();
assertEquals(GameTimer.ABYSSAL_SIRE_STUN, infoBox.getTimer());
assertEquals(Duration.ofSeconds(30), infoBox.getDuration());
}
@Test
public void testEndurance()
{
when(timersConfig.showStamina()).thenReturn(true);
ChatMessage chatMessage = new ChatMessage(null, ChatMessageType.SPAM, "", "Your Ring of endurance doubles the duration of your stamina potion's effect.", "", 0);
timersPlugin.onChatMessage(chatMessage);
chatMessage = new ChatMessage(null, ChatMessageType.SPAM, "", "You drink some of your stamina potion.", "", 0);
timersPlugin.onChatMessage(chatMessage);
ArgumentCaptor<InfoBox> captor = ArgumentCaptor.forClass(InfoBox.class);
verify(infoBoxManager).addInfoBox(captor.capture());
TimerTimer infoBox = (TimerTimer) captor.getValue();
assertEquals(GameTimer.STAMINA, infoBox.getTimer());
assertEquals(Duration.ofMinutes(4), infoBox.getDuration());
// unwield ring
timersPlugin.onItemContainerChanged(new ItemContainerChanged(InventoryID.EQUIPMENT.getId(), mock(ItemContainer.class)));
// some time has elapsed in the test; this should be just under 2 mins
int mins = (int) infoBox.getDuration().toMinutes();
assertTrue(mins == 1 || mins == 2);
}
@Test
public void testTzhaarTimer()
{
when(timersConfig.showTzhaarTimers()).thenReturn(true);
when(client.getMapRegions()).thenReturn(new int[]{TimersPlugin.FIGHT_CAVES_REGION_ID});
class InstantRef
{
Instant i;
}
InstantRef startTime = new InstantRef();
when(timersConfig.tzhaarStartTime()).then(a -> startTime.i);
doAnswer((Answer<Void>) invocationOnMock ->
{
Object argument = invocationOnMock.getArguments()[0];
startTime.i = (Instant) argument;
return null;
}).when(timersConfig).tzhaarStartTime(nullable(Instant.class));
InstantRef lastTime = new InstantRef();
when(timersConfig.tzhaarLastTime()).then(a -> lastTime.i);
doAnswer((Answer<Void>) invocationOnMock ->
{
Object argument = invocationOnMock.getArguments()[0];
lastTime.i = (Instant) argument;
return null;
}).when(timersConfig).tzhaarLastTime(nullable(Instant.class));
// test timer creation: verify the infobox was added and that it is an ElapsedTimer
ChatMessage chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", "<col=ef1020>Wave: 1</col>", "", 0);
timersPlugin.onChatMessage(chatMessage);
ArgumentCaptor<InfoBox> captor = ArgumentCaptor.forClass(InfoBox.class);
verify(infoBoxManager, times(1)).addInfoBox(captor.capture());
assertTrue(captor.getValue() instanceof ElapsedTimer);
// test timer pause: verify the added ElapsedTimer has a non-null lastTime
chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", "<col=ef1020>The Inferno has been paused. You may now log out.", "", 0);
timersPlugin.onChatMessage(chatMessage);
verify(infoBoxManager, times(1)).removeInfoBox(captor.capture());
verify(infoBoxManager, times(2)).addInfoBox(captor.capture());
assertTrue(captor.getValue() instanceof ElapsedTimer);
ElapsedTimer timer = (ElapsedTimer) captor.getValue();
assertNotEquals(timer.getLastTime(), null);
Instant oldTime = ((ElapsedTimer) captor.getValue()).getStartTime();
// test timer unpause: verify the last time is null after being unpaused
chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", "<col=ef1020>Wave: 2</col>", "", 0);
timersPlugin.onChatMessage(chatMessage);
verify(infoBoxManager, times(2)).removeInfoBox(captor.capture());
verify(infoBoxManager, times(3)).addInfoBox(captor.capture());
assertTrue(captor.getValue() instanceof ElapsedTimer);
timer = (ElapsedTimer) captor.getValue();
assertNull(timer.getLastTime());
// test timer remove: verify the infobox was removed (and no more were added)
chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", "You have been defeated!", "", 0);
timersPlugin.onChatMessage(chatMessage);
verify(infoBoxManager, times(3)).removeInfoBox(captor.capture());
verify(infoBoxManager, times(3)).addInfoBox(captor.capture());
}
@Test
public void testInfernoTimerStartOffset()
{
when(timersConfig.showTzhaarTimers()).thenReturn(true);
when(client.getMapRegions()).thenReturn(new int[]{TimersPlugin.INFERNO_REGION_ID});
class InstantRef
{
Instant i;
}
InstantRef startTime = new InstantRef();
when(timersConfig.tzhaarStartTime()).then(a -> startTime.i);
doAnswer((Answer<Void>) invocationOnMock ->
{
Object argument = invocationOnMock.getArguments()[0];
startTime.i = (Instant) argument;
return null;
}).when(timersConfig).tzhaarStartTime(nullable(Instant.class));
ChatMessage chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", "<col=ef1020>Wave: 1</col>", "", 0);
timersPlugin.onChatMessage(chatMessage);
ArgumentCaptor<InfoBox> captor = ArgumentCaptor.forClass(InfoBox.class);
verify(infoBoxManager, times(1)).addInfoBox(captor.capture());
assertTrue(captor.getValue() instanceof ElapsedTimer);
ElapsedTimer timer = (ElapsedTimer) captor.getValue();
assertEquals("00:06", timer.getText());
}
}

View File

@@ -0,0 +1,129 @@
/*
* Copyright (c) 2018, Jordan Atwood <jordan.atwood423@gmail.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.util;
import com.google.common.collect.ImmutableMap;
import java.awt.Color;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class ColorUtilTest
{
private static final Map<Color, String> COLOR_HEXSTRING_MAP = new ImmutableMap.Builder<Color, String>().
put(Color.BLACK, "000000").
put(new Color(0x1), "000001").
put(new Color(0x100000), "100000").
put(Color.RED, "ff0000").
put(Color.GREEN, "00ff00").
put(Color.BLUE, "0000ff").
put(new Color(0xA1B2C3), "a1b2c3").
put(Color.WHITE, "ffffff").build();
private static final Map<Color, String> COLOR_ALPHA_HEXSTRING_MAP = ImmutableMap.of(
new Color(0x00000000, true), "00000000",
new Color(0xA1B2C3D4, true), "a1b2c3d4"
);
@Test
public void colorTag()
{
COLOR_HEXSTRING_MAP.forEach((color, hex) ->
{
assertEquals("<col=" + hex + ">", ColorUtil.colorTag(color));
});
}
@Test
public void prependColorTag()
{
COLOR_HEXSTRING_MAP.forEach((color, hex) ->
{
assertEquals("<col=" + hex + ">test", ColorUtil.prependColorTag("test", color));
assertEquals("<col=" + hex + ">", ColorUtil.prependColorTag("", color));
});
assertEquals("<col=ff0000>94<col=ffffff>/99", ColorUtil.prependColorTag("94" + ColorUtil.prependColorTag("/99", Color.WHITE), Color.RED));
}
@Test
public void wrapWithColorTag()
{
COLOR_HEXSTRING_MAP.forEach((color, hex) ->
{
assertEquals("<col=" + hex + ">test</col>", ColorUtil.wrapWithColorTag("test", color));
assertEquals("<col=" + hex + "></col>", ColorUtil.wrapWithColorTag("", color));
});
}
@Test
public void toHexColor()
{
COLOR_HEXSTRING_MAP.forEach((color, hex) ->
{
assertEquals("#" + hex, ColorUtil.toHexColor(color));
});
}
@Test
public void colorWithAlpha()
{
int[] alpha = {73};
COLOR_HEXSTRING_MAP.forEach((color, hex) ->
{
assertEquals(new Color(color.getRed(), color.getGreen(), color.getBlue(), alpha[0]),
ColorUtil.colorWithAlpha(color, alpha[0]));
alpha[0] += 73;
alpha[0] %= 255;
});
COLOR_ALPHA_HEXSTRING_MAP.forEach((color, hex) ->
{
assertEquals(new Color(color.getRed(), color.getGreen(), color.getBlue(), alpha[0]),
ColorUtil.colorWithAlpha(color, alpha[0]));
alpha[0] += 73;
alpha[0] %= 255;
});
}
@Test
public void colorLerp()
{
assertEquals(Color.WHITE, ColorUtil.colorLerp(Color.WHITE, Color.WHITE, 0.9));
assertEquals(new Color(128, 128, 128), ColorUtil.colorLerp(Color.BLACK, Color.WHITE, 0.5));
assertEquals(Color.BLACK, ColorUtil.colorLerp(Color.BLACK, Color.CYAN, 0));
assertEquals(Color.CYAN, ColorUtil.colorLerp(Color.BLACK, Color.CYAN, 1));
}
@Test
public void colorToHexCode()
{
COLOR_HEXSTRING_MAP.forEach((color, hex) ->
{
assertEquals(hex, ColorUtil.colorToHexCode(color));
});
}
}