additional plugins
This commit is contained in:
@@ -16,6 +16,7 @@ import net.runelite.client.plugins.PluginDescriptor;
|
||||
name = "fKeyRemapping",
|
||||
description = "Used for interface hotkeys",
|
||||
tags = {"hotkey", "remapping"},
|
||||
type = "utility",
|
||||
enabledByDefault = true
|
||||
)
|
||||
public class fKeyRemappingPlugin extends Plugin
|
||||
|
||||
@@ -17,6 +17,7 @@ import java.util.LinkedHashMap;
|
||||
name = "!Group Item List",
|
||||
description = "Group the right click menu of a pile of items.",
|
||||
tags = {"ground", "compress", "pile", "group"},
|
||||
type = "utility",
|
||||
enabledByDefault = false
|
||||
)
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package net.runelite.client.plugins.inventorysetups;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class InventorySetup
|
||||
{
|
||||
@Getter
|
||||
private ArrayList<InventorySetupItem> inventory;
|
||||
@Getter
|
||||
private ArrayList<InventorySetupItem> equipment;
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package net.runelite.client.plugins.inventorysetups;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.Point;
|
||||
import net.runelite.api.Query;
|
||||
import net.runelite.api.SpritePixels;
|
||||
import net.runelite.api.queries.BankItemQuery;
|
||||
import net.runelite.api.widgets.Widget;
|
||||
import net.runelite.api.widgets.WidgetInfo;
|
||||
import net.runelite.api.widgets.WidgetItem;
|
||||
import net.runelite.client.ui.FontManager;
|
||||
import net.runelite.client.ui.overlay.Overlay;
|
||||
import net.runelite.client.ui.overlay.OverlayLayer;
|
||||
import net.runelite.client.ui.overlay.OverlayPosition;
|
||||
import net.runelite.client.ui.overlay.OverlayPriority;
|
||||
import net.runelite.client.util.QueryRunner;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
@Slf4j
|
||||
public class InventorySetupBankOverlay extends Overlay
|
||||
{
|
||||
private final Client client;
|
||||
private final QueryRunner queryRunner;
|
||||
private final InventorySetupPlugin plugin;
|
||||
private final InventorySetupConfig config;
|
||||
|
||||
@Inject
|
||||
public InventorySetupBankOverlay(Client client, QueryRunner queryRunner, InventorySetupPlugin plugin, InventorySetupConfig config)
|
||||
{
|
||||
setPosition(OverlayPosition.DYNAMIC);
|
||||
setPriority(OverlayPriority.LOW);
|
||||
setLayer(OverlayLayer.ABOVE_WIDGETS);
|
||||
this.client = client;
|
||||
this.queryRunner = queryRunner;
|
||||
this.plugin = plugin;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension render(Graphics2D graphics)
|
||||
{
|
||||
if (config.getBankHighlight())
|
||||
{
|
||||
int[] ids = plugin.getCurrentInventorySetupIds();
|
||||
if (ids == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
ids = Arrays.stream(ids)
|
||||
.filter(Objects::nonNull)
|
||||
.filter(id -> id != -1)
|
||||
.toArray();
|
||||
final Query query = new BankItemQuery().idEquals(ids);
|
||||
final WidgetItem[] widgetItems = queryRunner.runQuery(query);
|
||||
final Widget bankContainer = client.getWidget(WidgetInfo.BANK_CONTAINER);
|
||||
for (final WidgetItem item : widgetItems)
|
||||
{
|
||||
Point canvasLocation = item.getCanvasLocation();
|
||||
Rectangle canvasBounds = item.getCanvasBounds();
|
||||
Point windowLocation = bankContainer.getCanvasLocation();
|
||||
|
||||
if (canvasLocation == null || windowLocation == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!(canvasLocation.getY() + 60 >= windowLocation.getY() + bankContainer.getHeight()) && !(canvasLocation.getY() + canvasBounds.getHeight() <= windowLocation.getY() + 90))
|
||||
{
|
||||
final Color color = config.getBankHighlightColor();
|
||||
|
||||
if (color != null)
|
||||
{
|
||||
final BufferedImage outline = loadItemOutline(item.getId(), item.getQuantity(), color);
|
||||
graphics.drawImage(outline, item.getCanvasLocation().getX() + 1, item.getCanvasLocation().getY() + 1, null);
|
||||
if (item.getQuantity() > 1)
|
||||
{
|
||||
drawQuantity(graphics, item, Color.YELLOW);
|
||||
}
|
||||
else if (item.getQuantity() == 0)
|
||||
{
|
||||
drawQuantity(graphics, item, Color.YELLOW.darker());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void drawQuantity(Graphics2D graphics, WidgetItem item, Color darker)
|
||||
{
|
||||
graphics.setColor(Color.BLACK);
|
||||
graphics.drawString(String.valueOf(item.getQuantity()), item.getCanvasLocation().getX() + 2, item.getCanvasLocation().getY() + 11);
|
||||
graphics.setColor(darker);
|
||||
graphics.setFont(FontManager.getRunescapeSmallFont());
|
||||
graphics.drawString(String.valueOf(item.getQuantity()), item.getCanvasLocation().getX() + 1, item.getCanvasLocation().getY() + 10);
|
||||
}
|
||||
|
||||
private BufferedImage loadItemOutline(final int itemId, final int itemQuantity, final Color outlineColor)
|
||||
{
|
||||
final SpritePixels itemSprite = client.createItemSprite(itemId, itemQuantity, 2, 0, 0, true, 710);
|
||||
return itemSprite.toBufferedOutline(outlineColor);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package net.runelite.client.plugins.inventorysetups;
|
||||
|
||||
import net.runelite.client.config.Config;
|
||||
import net.runelite.client.config.ConfigGroup;
|
||||
import net.runelite.client.config.ConfigItem;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
@ConfigGroup("inventorysetups")
|
||||
public interface InventorySetupConfig extends Config
|
||||
{
|
||||
@ConfigItem(
|
||||
keyName = "highlightDifferences",
|
||||
name = "Highlight Differences",
|
||||
description = "Highlight slots that don't match the selected setup",
|
||||
position = 0
|
||||
)
|
||||
|
||||
default boolean getHighlightDifferences()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "highlightDifferenceColor",
|
||||
name = "Highlight Color",
|
||||
description = "The color used to highlight differences between setups",
|
||||
position = 1
|
||||
)
|
||||
|
||||
default Color getHighlightColor()
|
||||
{
|
||||
return Color.RED;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "stackDifference",
|
||||
name = "Stack Difference",
|
||||
description = "Differences between setups will be highlighted if the stack size is different",
|
||||
position = 2
|
||||
)
|
||||
|
||||
default boolean getStackDifference()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "variationDifference",
|
||||
name = "Variation Difference",
|
||||
description = "Variations of items (E.g., charged jewellery) will be counted as different",
|
||||
position = 2
|
||||
)
|
||||
|
||||
default boolean getVariationDifference()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "bankHighlight",
|
||||
name = "Bank Highlight",
|
||||
description = "Highlight setup items in bank",
|
||||
position = 4
|
||||
)
|
||||
|
||||
default boolean getBankHighlight()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "bankHighlightColor",
|
||||
name = "Bank Highlight Color",
|
||||
description = "The color used to highlight setup items in bank",
|
||||
position = 5
|
||||
)
|
||||
|
||||
default Color getBankHighlightColor()
|
||||
{
|
||||
return Color.RED;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package net.runelite.client.plugins.inventorysetups;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class InventorySetupItem
|
||||
{
|
||||
@Getter
|
||||
private final int id;
|
||||
@Getter
|
||||
private final String name;
|
||||
@Getter
|
||||
private final int quantity;
|
||||
}
|
||||
@@ -0,0 +1,403 @@
|
||||
package net.runelite.client.plugins.inventorysetups;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.google.inject.Provides;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.GameState;
|
||||
import net.runelite.api.InventoryID;
|
||||
import net.runelite.api.Item;
|
||||
import net.runelite.api.ItemComposition;
|
||||
import net.runelite.api.ItemContainer;
|
||||
import net.runelite.api.events.ConfigChanged;
|
||||
import net.runelite.api.events.GameStateChanged;
|
||||
import net.runelite.api.events.ItemContainerChanged;
|
||||
import net.runelite.client.callback.ClientThread;
|
||||
import net.runelite.client.config.ConfigManager;
|
||||
import net.runelite.client.eventbus.Subscribe;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.game.ItemVariationMapping;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
import net.runelite.client.plugins.PluginDescriptor;
|
||||
import net.runelite.client.plugins.inventorysetups.ui.InventorySetupPluginPanel;
|
||||
import net.runelite.client.ui.ClientToolbar;
|
||||
import net.runelite.client.ui.NavigationButton;
|
||||
import net.runelite.client.ui.overlay.OverlayManager;
|
||||
import net.runelite.client.util.ImageUtil;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
@PluginDescriptor(
|
||||
name = "Inventory Setups",
|
||||
description = "Save inventory setups",
|
||||
tags = { "items", "inventory", "setups"},
|
||||
type = "utility",
|
||||
enabledByDefault = false
|
||||
)
|
||||
|
||||
@Slf4j
|
||||
public class InventorySetupPlugin extends Plugin
|
||||
{
|
||||
|
||||
private static final String CONFIG_GROUP = "inventorysetups";
|
||||
private static final String CONFIG_KEY = "setups";
|
||||
private static final int NUM_INVENTORY_ITEMS = 28;
|
||||
private static final int NUM_EQUIPMENT_ITEMS = 14;
|
||||
|
||||
@Inject
|
||||
private Client client;
|
||||
|
||||
@Inject
|
||||
private ItemManager itemManager;
|
||||
|
||||
@Inject
|
||||
private InventorySetupBankOverlay overlay;
|
||||
|
||||
@Inject
|
||||
private ClientToolbar clientToolbar;
|
||||
|
||||
@Inject
|
||||
private InventorySetupConfig config;
|
||||
|
||||
@Inject
|
||||
private OverlayManager overlayManager;
|
||||
|
||||
@Inject
|
||||
private ClientThread clientThread;
|
||||
|
||||
@Inject
|
||||
private ConfigManager configManager;
|
||||
|
||||
private InventorySetupPluginPanel panel;
|
||||
|
||||
private HashMap<String, InventorySetup> inventorySetups;
|
||||
|
||||
private NavigationButton navButton;
|
||||
|
||||
private boolean highlightDifference;
|
||||
|
||||
@Override
|
||||
public void startUp()
|
||||
{
|
||||
overlayManager.add(overlay);
|
||||
|
||||
panel = new InventorySetupPluginPanel(this, itemManager);
|
||||
|
||||
final BufferedImage icon = ImageUtil.getResourceStreamFromClass(getClass(), "inventorysetups_icon.png");
|
||||
|
||||
navButton = NavigationButton.builder()
|
||||
.tooltip("Inventory Setups")
|
||||
.icon(icon)
|
||||
.priority(9)
|
||||
.panel(panel)
|
||||
.build();
|
||||
|
||||
clientToolbar.addNavigation(navButton);
|
||||
|
||||
// load all the inventory setups from the config file
|
||||
clientThread.invokeLater(() ->
|
||||
{
|
||||
if (client.getGameState() != GameState.LOGIN_SCREEN)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
loadConfig();
|
||||
panel.showNoSetupsPanel();
|
||||
return true;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public void addInventorySetup()
|
||||
{
|
||||
final String name = JOptionPane.showInputDialog(panel,
|
||||
"Enter the name of this setup.",
|
||||
"Add New Setup",
|
||||
JOptionPane.PLAIN_MESSAGE);
|
||||
|
||||
// cancel button was clicked
|
||||
if (name == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (name.isEmpty())
|
||||
{
|
||||
JOptionPane.showMessageDialog(panel,
|
||||
"Invalid Setup Name",
|
||||
"Names must not be empty.",
|
||||
JOptionPane.PLAIN_MESSAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (inventorySetups.containsKey(name))
|
||||
{
|
||||
String builder = "The setup " + name + " already exists. " +
|
||||
"Would you like to replace it with the current setup?";
|
||||
int confirm = JOptionPane.showConfirmDialog(panel,
|
||||
builder,
|
||||
"Warning",
|
||||
JOptionPane.OK_CANCEL_OPTION,
|
||||
JOptionPane.PLAIN_MESSAGE);
|
||||
|
||||
if (confirm == JOptionPane.CANCEL_OPTION)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// delete the old setup, no need to ask for confirmation
|
||||
// because the user confirmed above
|
||||
removeInventorySetup(name, false);
|
||||
}
|
||||
|
||||
clientThread.invoke(() ->
|
||||
{
|
||||
ArrayList<InventorySetupItem> inv = getNormalizedContainer(InventoryID.INVENTORY);
|
||||
ArrayList<InventorySetupItem> eqp = getNormalizedContainer(InventoryID.EQUIPMENT);
|
||||
|
||||
final InventorySetup invSetup = new InventorySetup(inv, eqp);
|
||||
SwingUtilities.invokeLater(() ->
|
||||
{
|
||||
inventorySetups.put(name, invSetup);
|
||||
panel.addInventorySetup(name);
|
||||
panel.setCurrentInventorySetup(name);
|
||||
|
||||
updateConfig();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public void removeInventorySetup(final String name, boolean askForConfirmation)
|
||||
{
|
||||
if (inventorySetups.containsKey(name))
|
||||
{
|
||||
int confirm = JOptionPane.YES_OPTION;
|
||||
|
||||
if (askForConfirmation)
|
||||
{
|
||||
confirm = JOptionPane.showConfirmDialog(panel,
|
||||
"Are you sure you want to remove this setup?",
|
||||
"Warning",
|
||||
JOptionPane.YES_NO_OPTION,
|
||||
JOptionPane.PLAIN_MESSAGE);
|
||||
}
|
||||
|
||||
if (confirm == JOptionPane.YES_OPTION)
|
||||
{
|
||||
inventorySetups.remove(name);
|
||||
panel.removeInventorySetup(name);
|
||||
}
|
||||
|
||||
updateConfig();
|
||||
}
|
||||
}
|
||||
|
||||
public final InventorySetup getInventorySetup(final String name)
|
||||
{
|
||||
return inventorySetups.get(name);
|
||||
}
|
||||
|
||||
@Provides
|
||||
InventorySetupConfig provideConfig(ConfigManager configManager)
|
||||
{
|
||||
return configManager.getConfig(InventorySetupConfig.class);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onConfigChanged(ConfigChanged event)
|
||||
{
|
||||
if (event.getGroup().equals(CONFIG_GROUP))
|
||||
{
|
||||
// only allow highlighting if the config is enabled and the player is logged in
|
||||
highlightDifference = config.getHighlightDifferences() && client.getGameState() == GameState.LOGGED_IN;
|
||||
final String setupName = panel.getSelectedInventorySetup();
|
||||
if (highlightDifference && !setupName.isEmpty())
|
||||
{
|
||||
panel.setCurrentInventorySetup(setupName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateConfig()
|
||||
{
|
||||
if (inventorySetups.isEmpty())
|
||||
{
|
||||
configManager.unsetConfiguration(CONFIG_GROUP, CONFIG_KEY);
|
||||
return;
|
||||
}
|
||||
|
||||
final Gson gson = new Gson();
|
||||
final String json = gson.toJson(inventorySetups);
|
||||
configManager.setConfiguration(CONFIG_GROUP, CONFIG_KEY, json);
|
||||
}
|
||||
|
||||
private void loadConfig()
|
||||
{
|
||||
// serialize the internal data structure from the json in the configuration
|
||||
final String json = configManager.getConfiguration(CONFIG_GROUP, CONFIG_KEY);
|
||||
if (json == null || json.isEmpty())
|
||||
{
|
||||
inventorySetups = new HashMap<>();
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO add last resort?, serialize exception just make empty map
|
||||
final Gson gson = new Gson();
|
||||
Type type = new TypeToken<HashMap<String, InventorySetup>>()
|
||||
{
|
||||
|
||||
}.getType();
|
||||
inventorySetups = gson.fromJson(json, type);
|
||||
}
|
||||
|
||||
for (final String key : inventorySetups.keySet())
|
||||
{
|
||||
panel.addInventorySetup(key);
|
||||
}
|
||||
|
||||
highlightDifference = false;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onItemContainerChanged(ItemContainerChanged event)
|
||||
{
|
||||
|
||||
if (!highlightDifference || client.getGameState() != GameState.LOGGED_IN)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// empty entry, no need to compare anything
|
||||
final String selectedInventorySetup = panel.getSelectedInventorySetup();
|
||||
if (selectedInventorySetup.isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// check to see that the container is the equipment or inventory
|
||||
ItemContainer container = event.getItemContainer();
|
||||
|
||||
if (container == client.getItemContainer(InventoryID.INVENTORY))
|
||||
{
|
||||
ArrayList<InventorySetupItem> normContainer = getNormalizedContainer(InventoryID.INVENTORY);
|
||||
final InventorySetup setup = inventorySetups.get(selectedInventorySetup);
|
||||
panel.highlightDifferences(normContainer, setup, InventoryID.INVENTORY);
|
||||
}
|
||||
else if (container == client.getItemContainer(InventoryID.EQUIPMENT))
|
||||
{
|
||||
ArrayList<InventorySetupItem> normContainer = getNormalizedContainer(InventoryID.EQUIPMENT);
|
||||
final InventorySetup setup = inventorySetups.get(selectedInventorySetup);
|
||||
panel.highlightDifferences(normContainer, setup, InventoryID.EQUIPMENT);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onGameStateChanged(GameStateChanged event)
|
||||
{
|
||||
switch (event.getGameState())
|
||||
{
|
||||
// set the highlighting off if login screen shows up
|
||||
case LOGIN_SCREEN:
|
||||
highlightDifference = false;
|
||||
final String setupName = panel.getSelectedInventorySetup();
|
||||
if (!setupName.isEmpty())
|
||||
{
|
||||
panel.setCurrentInventorySetup(setupName);
|
||||
}
|
||||
break;
|
||||
|
||||
// set highlighting
|
||||
case LOGGED_IN:
|
||||
highlightDifference = config.getHighlightDifferences();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public ArrayList<InventorySetupItem> getNormalizedContainer(final InventoryID id)
|
||||
{
|
||||
assert id == InventoryID.INVENTORY || id == InventoryID.EQUIPMENT : "invalid inventory ID";
|
||||
|
||||
final ItemContainer container = client.getItemContainer(id);
|
||||
|
||||
ArrayList<InventorySetupItem> newContainer = new ArrayList<>();
|
||||
|
||||
Item[] items = null;
|
||||
if (container != null)
|
||||
{
|
||||
items = container.getItems();
|
||||
}
|
||||
|
||||
int size = id == InventoryID.INVENTORY ? NUM_INVENTORY_ITEMS : NUM_EQUIPMENT_ITEMS;
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
if (items == null || i >= items.length)
|
||||
{
|
||||
newContainer.add(new InventorySetupItem(-1, "", 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
final Item item = items[i];
|
||||
String itemName = "";
|
||||
if (client.isClientThread())
|
||||
{
|
||||
itemName = itemManager.getItemComposition(item.getId()).getName();
|
||||
}
|
||||
newContainer.add(new InventorySetupItem(item.getId(), itemName, item.getQuantity()));
|
||||
}
|
||||
}
|
||||
|
||||
return newContainer;
|
||||
}
|
||||
|
||||
public final InventorySetupConfig getConfig()
|
||||
{
|
||||
return config;
|
||||
}
|
||||
|
||||
public boolean getHighlightDifference()
|
||||
{
|
||||
return highlightDifference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutDown()
|
||||
{
|
||||
overlayManager.remove(overlay);
|
||||
clientToolbar.removeNavigation(navButton);
|
||||
}
|
||||
|
||||
final int[] getCurrentInventorySetupIds()
|
||||
{
|
||||
InventorySetup setup = inventorySetups.get(panel.getSelectedInventorySetup());
|
||||
if (setup == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
ArrayList<InventorySetupItem> items = new ArrayList<>();
|
||||
items.addAll(setup.getEquipment());
|
||||
items.addAll(setup.getInventory());
|
||||
ArrayList<Integer> itemIds = new ArrayList<>();
|
||||
for (InventorySetupItem item : items)
|
||||
{
|
||||
int id = item.getId();
|
||||
ItemComposition itemComposition = itemManager.getItemComposition(id);
|
||||
if (id > 0)
|
||||
{
|
||||
itemIds.add(ItemVariationMapping.map(id));
|
||||
itemIds.add(itemComposition.getPlaceholderId());
|
||||
}
|
||||
|
||||
}
|
||||
return itemIds.stream().mapToInt(i -> i).toArray();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package net.runelite.client.plugins.inventorysetups.ui;
|
||||
|
||||
import net.runelite.client.game.AsyncBufferedImage;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.game.ItemVariationMapping;
|
||||
import net.runelite.client.plugins.inventorysetups.InventorySetupConfig;
|
||||
import net.runelite.client.plugins.inventorysetups.InventorySetupItem;
|
||||
import net.runelite.client.plugins.inventorysetups.InventorySetupPlugin;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public abstract class InventorySetupContainerPanel extends JPanel
|
||||
{
|
||||
|
||||
protected ItemManager itemManager;
|
||||
|
||||
private final InventorySetupPlugin plugin;
|
||||
|
||||
InventorySetupContainerPanel(final ItemManager itemManager, final InventorySetupPlugin plugin, String captionText)
|
||||
{
|
||||
this.itemManager = itemManager;
|
||||
this.plugin = plugin;
|
||||
JPanel containerPanel = new JPanel();
|
||||
|
||||
final JPanel containerSlotsPanel = new JPanel();
|
||||
|
||||
setupContainerPanel(containerSlotsPanel);
|
||||
|
||||
// caption
|
||||
final JLabel caption = new JLabel(captionText);
|
||||
caption.setHorizontalAlignment(JLabel.CENTER);
|
||||
caption.setVerticalAlignment(JLabel.CENTER);
|
||||
|
||||
// panel that holds the caption and any other graphics
|
||||
final JPanel captionPanel = new JPanel();
|
||||
captionPanel.add(caption);
|
||||
|
||||
containerPanel.setLayout(new BorderLayout());
|
||||
containerPanel.add(captionPanel, BorderLayout.NORTH);
|
||||
containerPanel.add(containerSlotsPanel, BorderLayout.CENTER);
|
||||
|
||||
add(containerPanel);
|
||||
}
|
||||
|
||||
void setContainerSlot(int index,
|
||||
final InventorySetupSlot containerSlot,
|
||||
final ArrayList<InventorySetupItem> items)
|
||||
{
|
||||
if (index >= items.size() || items.get(index).getId() == -1)
|
||||
{
|
||||
containerSlot.setImageLabel(null, null);
|
||||
return;
|
||||
}
|
||||
|
||||
int itemId = items.get(index).getId();
|
||||
int quantity = items.get(index).getQuantity();
|
||||
final String itemName = items.get(index).getName();
|
||||
AsyncBufferedImage itemImg = itemManager.getImage(itemId, quantity, quantity > 1);
|
||||
String toolTip = itemName;
|
||||
if (quantity > 1)
|
||||
{
|
||||
toolTip += " (" + quantity + ")";
|
||||
}
|
||||
containerSlot.setImageLabel(toolTip, itemImg);
|
||||
}
|
||||
|
||||
void highlightDifferentSlotColor(InventorySetupItem savedItem,
|
||||
InventorySetupItem currItem,
|
||||
final InventorySetupSlot containerSlot)
|
||||
{
|
||||
// important note: do not use item names for comparisons
|
||||
// they are all empty to avoid clientThread usage when highlighting
|
||||
|
||||
final InventorySetupConfig config = plugin.getConfig();
|
||||
final Color highlightColor = config.getHighlightColor();
|
||||
|
||||
if (config.getStackDifference() && currItem.getQuantity() != savedItem.getQuantity())
|
||||
{
|
||||
containerSlot.setBackground(highlightColor);
|
||||
return;
|
||||
}
|
||||
|
||||
int currId = currItem.getId();
|
||||
int checkId = savedItem.getId();
|
||||
|
||||
if (!config.getVariationDifference())
|
||||
{
|
||||
currId = ItemVariationMapping.map(currId);
|
||||
checkId = ItemVariationMapping.map(checkId);
|
||||
}
|
||||
|
||||
if (currId != checkId)
|
||||
{
|
||||
containerSlot.setBackground(highlightColor);
|
||||
return;
|
||||
}
|
||||
|
||||
// set the color back to the original, because they match
|
||||
containerSlot.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
}
|
||||
|
||||
abstract public void setupContainerPanel(final JPanel containerSlotsPanel);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package net.runelite.client.plugins.inventorysetups.ui;
|
||||
|
||||
import net.runelite.api.EquipmentInventorySlot;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.plugins.inventorysetups.InventorySetup;
|
||||
import net.runelite.client.plugins.inventorysetups.InventorySetupItem;
|
||||
import net.runelite.client.plugins.inventorysetups.InventorySetupPlugin;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import java.awt.GridLayout;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class InventorySetupEquipmentPanel extends InventorySetupContainerPanel
|
||||
{
|
||||
private HashMap<EquipmentInventorySlot, InventorySetupSlot> equipmentSlots;
|
||||
|
||||
InventorySetupEquipmentPanel(final ItemManager itemManager, final InventorySetupPlugin plugin)
|
||||
{
|
||||
super(itemManager, plugin, "Equipment");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupContainerPanel(final JPanel containerSlotsPanel)
|
||||
{
|
||||
this.equipmentSlots = new HashMap<>();
|
||||
for (EquipmentInventorySlot slot : EquipmentInventorySlot.values())
|
||||
{
|
||||
equipmentSlots.put(slot, new InventorySetupSlot(ColorScheme.DARKER_GRAY_COLOR));
|
||||
}
|
||||
|
||||
final GridLayout gridLayout = new GridLayout(5, 3, 1, 1);
|
||||
containerSlotsPanel.setLayout(gridLayout);
|
||||
|
||||
// add the grid layouts, including invisible ones
|
||||
containerSlotsPanel.add(new InventorySetupSlot(ColorScheme.DARK_GRAY_COLOR));
|
||||
containerSlotsPanel.add(equipmentSlots.get(EquipmentInventorySlot.HEAD));
|
||||
containerSlotsPanel.add(new InventorySetupSlot(ColorScheme.DARK_GRAY_COLOR));
|
||||
containerSlotsPanel.add(equipmentSlots.get(EquipmentInventorySlot.CAPE));
|
||||
containerSlotsPanel.add(equipmentSlots.get(EquipmentInventorySlot.AMULET));
|
||||
containerSlotsPanel.add(equipmentSlots.get(EquipmentInventorySlot.AMMO));
|
||||
containerSlotsPanel.add(equipmentSlots.get(EquipmentInventorySlot.WEAPON));
|
||||
containerSlotsPanel.add(equipmentSlots.get(EquipmentInventorySlot.BODY));
|
||||
containerSlotsPanel.add(equipmentSlots.get(EquipmentInventorySlot.SHIELD));
|
||||
containerSlotsPanel.add(new InventorySetupSlot(ColorScheme.DARK_GRAY_COLOR));
|
||||
containerSlotsPanel.add(equipmentSlots.get(EquipmentInventorySlot.LEGS));
|
||||
containerSlotsPanel.add(new InventorySetupSlot(ColorScheme.DARK_GRAY_COLOR));
|
||||
containerSlotsPanel.add(equipmentSlots.get(EquipmentInventorySlot.GLOVES));
|
||||
containerSlotsPanel.add(equipmentSlots.get(EquipmentInventorySlot.BOOTS));
|
||||
containerSlotsPanel.add(equipmentSlots.get(EquipmentInventorySlot.RING));
|
||||
|
||||
}
|
||||
|
||||
void setEquipmentSetupSlots(final InventorySetup setup)
|
||||
{
|
||||
final ArrayList<InventorySetupItem> equipment = setup.getEquipment();
|
||||
|
||||
for (final EquipmentInventorySlot slot : EquipmentInventorySlot.values())
|
||||
{
|
||||
int i = slot.getSlotIdx();
|
||||
super.setContainerSlot(i, equipmentSlots.get(slot), equipment);
|
||||
}
|
||||
|
||||
validate();
|
||||
repaint();
|
||||
|
||||
}
|
||||
|
||||
void highlightDifferences(final ArrayList<InventorySetupItem> currEquipment, final InventorySetup inventorySetup)
|
||||
{
|
||||
final ArrayList<InventorySetupItem> equipToCheck = inventorySetup.getEquipment();
|
||||
|
||||
assert currEquipment.size() == equipToCheck.size() : "size mismatch";
|
||||
|
||||
for (final EquipmentInventorySlot slot : EquipmentInventorySlot.values())
|
||||
{
|
||||
|
||||
int slotIdx = slot.getSlotIdx();
|
||||
super.highlightDifferentSlotColor(equipToCheck.get(slotIdx), currEquipment.get(slotIdx), equipmentSlots.get(slot));
|
||||
}
|
||||
}
|
||||
|
||||
void resetEquipmentSlotsColor()
|
||||
{
|
||||
for (final EquipmentInventorySlot slot : EquipmentInventorySlot.values())
|
||||
{
|
||||
equipmentSlots.get(slot).setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package net.runelite.client.plugins.inventorysetups.ui;
|
||||
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.plugins.inventorysetups.InventorySetup;
|
||||
import net.runelite.client.plugins.inventorysetups.InventorySetupItem;
|
||||
import net.runelite.client.plugins.inventorysetups.InventorySetupPlugin;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import java.awt.GridLayout;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class InventorySetupInventoryPanel extends InventorySetupContainerPanel
|
||||
{
|
||||
|
||||
private static final int ITEMS_PER_ROW = 4;
|
||||
private static final int NUM_INVENTORY_ITEMS = 28;
|
||||
|
||||
private ArrayList<InventorySetupSlot> inventorySlots;
|
||||
|
||||
InventorySetupInventoryPanel(final ItemManager itemManager, final InventorySetupPlugin plugin)
|
||||
{
|
||||
super(itemManager, plugin, "Inventory");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setupContainerPanel(final JPanel containerSlotsPanel)
|
||||
{
|
||||
this.inventorySlots = new ArrayList<>();
|
||||
for (int i = 0; i < NUM_INVENTORY_ITEMS; i++)
|
||||
{
|
||||
inventorySlots.add(new InventorySetupSlot(ColorScheme.DARKER_GRAY_COLOR));
|
||||
}
|
||||
|
||||
int numRows = (NUM_INVENTORY_ITEMS + ITEMS_PER_ROW - 1) / ITEMS_PER_ROW;
|
||||
containerSlotsPanel.setLayout(new GridLayout(numRows, ITEMS_PER_ROW, 1, 1));
|
||||
for (int i = 0; i < NUM_INVENTORY_ITEMS; i++)
|
||||
{
|
||||
containerSlotsPanel.add(inventorySlots.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
void setInventorySetupSlots(final InventorySetup setup)
|
||||
{
|
||||
ArrayList<InventorySetupItem> inventory = setup.getInventory();
|
||||
|
||||
for (int i = 0; i < NUM_INVENTORY_ITEMS; i++)
|
||||
{
|
||||
super.setContainerSlot(i, inventorySlots.get(i), inventory);
|
||||
}
|
||||
|
||||
validate();
|
||||
repaint();
|
||||
|
||||
}
|
||||
|
||||
void highlightDifferentSlots(final ArrayList<InventorySetupItem> currInventory, final InventorySetup inventorySetup)
|
||||
{
|
||||
|
||||
final ArrayList<InventorySetupItem> inventoryToCheck = inventorySetup.getInventory();
|
||||
|
||||
assert currInventory.size() == inventoryToCheck.size() : "size mismatch";
|
||||
|
||||
for (int i = 0; i < NUM_INVENTORY_ITEMS; i++)
|
||||
{
|
||||
super.highlightDifferentSlotColor(inventoryToCheck.get(i), currInventory.get(i), inventorySlots.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
void resetInventorySlotsColor()
|
||||
{
|
||||
for (InventorySetupSlot inventorySlot : inventorySlots)
|
||||
{
|
||||
inventorySlot.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,287 @@
|
||||
package net.runelite.client.plugins.inventorysetups.ui;
|
||||
|
||||
import net.runelite.api.InventoryID;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.plugins.inventorysetups.InventorySetup;
|
||||
import net.runelite.client.plugins.inventorysetups.InventorySetupItem;
|
||||
import net.runelite.client.plugins.inventorysetups.InventorySetupPlugin;
|
||||
import net.runelite.client.ui.PluginPanel;
|
||||
import net.runelite.client.ui.components.PluginErrorPanel;
|
||||
import net.runelite.client.util.ImageUtil;
|
||||
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.FlowLayout;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class InventorySetupPluginPanel extends PluginPanel
|
||||
{
|
||||
|
||||
private static ImageIcon ADD_ICON;
|
||||
private static ImageIcon ADD_HOVER_ICON;
|
||||
private static ImageIcon REMOVE_ICON;
|
||||
private static ImageIcon REMOVE_HOVER_ICON;
|
||||
|
||||
private final JPanel noSetupsPanel;
|
||||
private final JPanel invEqPanel;
|
||||
|
||||
private final InventorySetupInventoryPanel invPanel;
|
||||
private final InventorySetupEquipmentPanel eqpPanel;
|
||||
|
||||
private final JComboBox<String> setupComboBox;
|
||||
|
||||
private final JLabel removeMarker;
|
||||
|
||||
private final InventorySetupPlugin plugin;
|
||||
|
||||
static
|
||||
{
|
||||
final BufferedImage addIcon = ImageUtil.getResourceStreamFromClass(InventorySetupPlugin.class, "add_icon.png");
|
||||
ADD_ICON = new ImageIcon(addIcon);
|
||||
ADD_HOVER_ICON = new ImageIcon(ImageUtil.alphaOffset(addIcon, 0.53f));
|
||||
|
||||
final BufferedImage removeIcon = ImageUtil.getResourceStreamFromClass(InventorySetupPlugin.class, "remove_icon.png");
|
||||
REMOVE_ICON = new ImageIcon(removeIcon);
|
||||
REMOVE_HOVER_ICON = new ImageIcon(ImageUtil.alphaOffset(removeIcon, 0.53f));
|
||||
}
|
||||
|
||||
public InventorySetupPluginPanel(final InventorySetupPlugin plugin, final ItemManager itemManager)
|
||||
{
|
||||
super(false);
|
||||
this.plugin = plugin;
|
||||
this.removeMarker = new JLabel(REMOVE_ICON);
|
||||
this.invPanel = new InventorySetupInventoryPanel(itemManager, plugin);
|
||||
this.eqpPanel = new InventorySetupEquipmentPanel(itemManager, plugin);
|
||||
this.noSetupsPanel = new JPanel();
|
||||
this.invEqPanel = new JPanel();
|
||||
this.setupComboBox = new JComboBox<>();
|
||||
|
||||
// setup the title
|
||||
final JLabel addMarker = new JLabel(ADD_ICON);
|
||||
final JLabel title = new JLabel();
|
||||
title.setText("Inventory Setups");
|
||||
title.setForeground(Color.WHITE);
|
||||
|
||||
// setup the add marker (+ sign in the top right)
|
||||
addMarker.setToolTipText("Add a new inventory setup");
|
||||
addMarker.addMouseListener(new MouseAdapter()
|
||||
{
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e)
|
||||
{
|
||||
plugin.addInventorySetup();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent e)
|
||||
{
|
||||
addMarker.setIcon(ADD_HOVER_ICON);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(MouseEvent e)
|
||||
{
|
||||
addMarker.setIcon(ADD_ICON);
|
||||
}
|
||||
});
|
||||
|
||||
// setup the remove marker (X sign in the top right)
|
||||
removeMarker.setToolTipText("Remove the current inventory setup");
|
||||
removeMarker.addMouseListener(new MouseAdapter()
|
||||
{
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e)
|
||||
{
|
||||
final String name = (String)setupComboBox.getSelectedItem();
|
||||
plugin.removeInventorySetup(name, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent e)
|
||||
{
|
||||
if (removeMarker.isEnabled())
|
||||
{
|
||||
removeMarker.setIcon(REMOVE_HOVER_ICON);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(MouseEvent e)
|
||||
{
|
||||
removeMarker.setIcon(REMOVE_ICON);
|
||||
}
|
||||
});
|
||||
|
||||
// setup the combo box for selection switching
|
||||
// add empty to indicate the empty position
|
||||
setupComboBox.addItem("");
|
||||
setupComboBox.setSelectedIndex(0);
|
||||
setupComboBox.addItemListener(e ->
|
||||
{
|
||||
if (e.getStateChange() == ItemEvent.SELECTED)
|
||||
{
|
||||
String selection = (String)e.getItem();
|
||||
setCurrentInventorySetup(selection);
|
||||
}
|
||||
});
|
||||
|
||||
// the panel on the top right that holds the add and delete buttons
|
||||
final JPanel markersPanel = new JPanel();
|
||||
markersPanel.setLayout(new FlowLayout(FlowLayout.RIGHT, 10, 0));
|
||||
markersPanel.add(removeMarker);
|
||||
markersPanel.add(addMarker);
|
||||
|
||||
// the top panel that has the title and the buttons
|
||||
final JPanel titleAndMarkersPanel = new JPanel();
|
||||
titleAndMarkersPanel.setLayout(new BorderLayout());
|
||||
titleAndMarkersPanel.add(title, BorderLayout.WEST);
|
||||
titleAndMarkersPanel.add(markersPanel, BorderLayout.EAST);
|
||||
|
||||
// the panel that stays at the top and doesn't scroll
|
||||
// contains the title, buttons, and the combo box
|
||||
final JPanel northAnchoredPanel = new JPanel();
|
||||
northAnchoredPanel.setLayout(new BoxLayout(northAnchoredPanel, BoxLayout.Y_AXIS));
|
||||
northAnchoredPanel.setBorder(new EmptyBorder(0, 0, 10, 0));
|
||||
northAnchoredPanel.add(titleAndMarkersPanel);
|
||||
northAnchoredPanel.add(Box.createRigidArea(new Dimension(0, 10)));
|
||||
northAnchoredPanel.add(setupComboBox);
|
||||
|
||||
// the panel that holds the inventory and equipment panels
|
||||
final BoxLayout invEqLayout = new BoxLayout(invEqPanel, BoxLayout.Y_AXIS);
|
||||
invEqPanel.setLayout(invEqLayout);
|
||||
invEqPanel.add(invPanel);
|
||||
invEqPanel.add(Box.createRigidArea(new Dimension(0, 10)));
|
||||
invEqPanel.add(eqpPanel);
|
||||
|
||||
// setup the error panel. It's wrapped around a normal panel
|
||||
// so it doesn't stretch to fill the parent panel
|
||||
final PluginErrorPanel errorPanel = new PluginErrorPanel();
|
||||
errorPanel.setContent("Inventory Setups", "Select or create an inventory setup.");
|
||||
noSetupsPanel.add(errorPanel);
|
||||
|
||||
// the panel that holds the inventory panels, and the error panel
|
||||
final JPanel contentPanel = new JPanel();
|
||||
final BoxLayout contentLayout = new BoxLayout(contentPanel, BoxLayout.Y_AXIS);
|
||||
contentPanel.setLayout(contentLayout);
|
||||
contentPanel.add(invEqPanel);
|
||||
contentPanel.add(noSetupsPanel);
|
||||
|
||||
// wrapper for the main content panel to keep it from stretching
|
||||
final JPanel contentWrapper = new JPanel(new BorderLayout());
|
||||
contentWrapper.add(Box.createGlue(), BorderLayout.CENTER);
|
||||
contentWrapper.add(contentPanel, BorderLayout.NORTH);
|
||||
final JScrollPane contentWrapperPane = new JScrollPane(contentWrapper);
|
||||
contentWrapperPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
|
||||
setLayout(new BorderLayout());
|
||||
setBorder(new EmptyBorder(10, 10, 10, 10));
|
||||
add(northAnchoredPanel, BorderLayout.NORTH);
|
||||
add(contentWrapperPane, BorderLayout.CENTER);
|
||||
|
||||
// show the no setups panel on startup
|
||||
showNoSetupsPanel();
|
||||
|
||||
}
|
||||
|
||||
public void showNoSetupsPanel()
|
||||
{
|
||||
setupComboBox.setSelectedIndex(0);
|
||||
removeMarker.setEnabled(false);
|
||||
noSetupsPanel.setVisible(true);
|
||||
invEqPanel.setVisible(false);
|
||||
}
|
||||
|
||||
private void showHasSetupPanel(final String name)
|
||||
{
|
||||
setupComboBox.setSelectedItem(name);
|
||||
removeMarker.setEnabled(true);
|
||||
noSetupsPanel.setVisible(false);
|
||||
invEqPanel.setVisible(true);
|
||||
}
|
||||
|
||||
public void setCurrentInventorySetup(final String name)
|
||||
{
|
||||
if (name.isEmpty())
|
||||
{
|
||||
showNoSetupsPanel();
|
||||
return;
|
||||
}
|
||||
|
||||
showHasSetupPanel(name);
|
||||
|
||||
final InventorySetup inventorySetup = plugin.getInventorySetup(name);
|
||||
|
||||
invPanel.setInventorySetupSlots(inventorySetup);
|
||||
eqpPanel.setEquipmentSetupSlots(inventorySetup);
|
||||
|
||||
if (plugin.getHighlightDifference())
|
||||
{
|
||||
final ArrayList<InventorySetupItem> normInv = plugin.getNormalizedContainer(InventoryID.INVENTORY);
|
||||
final ArrayList<InventorySetupItem> normEqp = plugin.getNormalizedContainer(InventoryID.EQUIPMENT);
|
||||
|
||||
highlightDifferences(normInv, inventorySetup, InventoryID.INVENTORY);
|
||||
highlightDifferences(normEqp, inventorySetup, InventoryID.EQUIPMENT);
|
||||
}
|
||||
else
|
||||
{
|
||||
invPanel.resetInventorySlotsColor();
|
||||
eqpPanel.resetEquipmentSlotsColor();
|
||||
}
|
||||
|
||||
validate();
|
||||
repaint();
|
||||
}
|
||||
|
||||
public void addInventorySetup(final String name)
|
||||
{
|
||||
setupComboBox.addItem(name);
|
||||
}
|
||||
|
||||
public void removeInventorySetup(final String name)
|
||||
{
|
||||
setupComboBox.removeItem(name);
|
||||
showNoSetupsPanel();
|
||||
|
||||
invPanel.resetInventorySlotsColor();
|
||||
eqpPanel.resetEquipmentSlotsColor();
|
||||
|
||||
validate();
|
||||
repaint();
|
||||
}
|
||||
|
||||
public void highlightDifferences(final ArrayList<InventorySetupItem> container,
|
||||
final InventorySetup setupToCheck,
|
||||
final InventoryID type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case INVENTORY:
|
||||
invPanel.highlightDifferentSlots(container, setupToCheck);
|
||||
break;
|
||||
|
||||
case EQUIPMENT:
|
||||
eqpPanel.highlightDifferences(container, setupToCheck);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public final String getSelectedInventorySetup()
|
||||
{
|
||||
return (String)setupComboBox.getSelectedItem();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package net.runelite.client.plugins.inventorysetups.ui;
|
||||
|
||||
import net.runelite.client.game.AsyncBufferedImage;
|
||||
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.SwingConstants;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
|
||||
public class InventorySetupSlot extends JPanel
|
||||
{
|
||||
|
||||
private final JLabel imageLabel;
|
||||
|
||||
public InventorySetupSlot(Color color)
|
||||
{
|
||||
imageLabel = new JLabel();
|
||||
imageLabel.setVerticalAlignment(SwingConstants.CENTER);
|
||||
setPreferredSize(new Dimension(46, 42));
|
||||
setBackground(color);
|
||||
add(imageLabel);
|
||||
|
||||
}
|
||||
|
||||
public void setImageLabel(String toolTip, AsyncBufferedImage itemImage)
|
||||
{
|
||||
if (itemImage == null || toolTip == null)
|
||||
{
|
||||
imageLabel.setToolTipText("");
|
||||
imageLabel.setIcon(null);
|
||||
imageLabel.revalidate();
|
||||
return;
|
||||
}
|
||||
|
||||
imageLabel.setToolTipText(toolTip);
|
||||
itemImage.addTo(imageLabel);
|
||||
|
||||
validate();
|
||||
repaint();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (c) 2018 AWPH-I
|
||||
* 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.lootingbagviewer;
|
||||
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.InventoryID;
|
||||
import net.runelite.api.Item;
|
||||
import net.runelite.api.ItemContainer;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.ui.overlay.Overlay;
|
||||
import net.runelite.client.ui.overlay.OverlayPosition;
|
||||
import net.runelite.client.ui.overlay.components.ImageComponent;
|
||||
import net.runelite.client.ui.overlay.components.PanelComponent;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
class LootingBagViewerOverlay extends Overlay
|
||||
{
|
||||
private static final int INVENTORY_SIZE = 28;
|
||||
private static final int PLACEHOLDER_WIDTH = 36;
|
||||
private static final int PLACEHOLDER_HEIGHT = 32;
|
||||
private static final ImageComponent PLACEHOLDER_IMAGE = new ImageComponent(new BufferedImage(PLACEHOLDER_WIDTH, PLACEHOLDER_HEIGHT, BufferedImage.TYPE_4BYTE_ABGR));
|
||||
|
||||
private final Client client;
|
||||
private final ItemManager itemManager;
|
||||
|
||||
private final PanelComponent panelComponent = new PanelComponent();
|
||||
|
||||
private ItemContainer itemContainer;
|
||||
private Item[] items;
|
||||
|
||||
@Inject
|
||||
private LootingBagViewerOverlay(Client client, ItemManager itemManager)
|
||||
{
|
||||
setPosition(OverlayPosition.BOTTOM_RIGHT);
|
||||
panelComponent.setWrapping(4);
|
||||
panelComponent.setGap(new Point(6, 4));
|
||||
panelComponent.setOrientation(PanelComponent.Orientation.HORIZONTAL);
|
||||
this.itemManager = itemManager;
|
||||
this.client = client;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension render(Graphics2D graphics)
|
||||
{
|
||||
if (itemContainer == null)
|
||||
{
|
||||
if(client.getItemContainer(InventoryID.LOOTING_BAG) != null) {
|
||||
itemContainer = client.getItemContainer(InventoryID.LOOTING_BAG);
|
||||
items = itemContainer.getItems();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
else if(itemContainer != null && client.getItemContainer(InventoryID.LOOTING_BAG) != null)
|
||||
{
|
||||
itemContainer = client.getItemContainer(InventoryID.LOOTING_BAG);
|
||||
Item[] tempItems = itemContainer.getItems();
|
||||
|
||||
for(int i = 0; i < items.length; i++)
|
||||
{
|
||||
if(!items[i].equals(tempItems[i]))
|
||||
{
|
||||
items = tempItems;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
panelComponent.getChildren().clear();
|
||||
|
||||
for (int i = 0; i < INVENTORY_SIZE; i++)
|
||||
{
|
||||
if (i < items.length)
|
||||
{
|
||||
final Item item = items[i];
|
||||
if (item.getQuantity() > 0)
|
||||
{
|
||||
final BufferedImage image = getImage(item);
|
||||
if (image != null)
|
||||
{
|
||||
panelComponent.getChildren().add(new ImageComponent(image));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// put a placeholder image so each item is aligned properly and the panel is not resized
|
||||
panelComponent.getChildren().add(PLACEHOLDER_IMAGE);
|
||||
}
|
||||
|
||||
return panelComponent.render(graphics);
|
||||
}
|
||||
|
||||
private BufferedImage getImage(Item item)
|
||||
{
|
||||
return itemManager.getImage(item.getId(), item.getQuantity(), item.getQuantity() > 1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2018 AWPH-I
|
||||
* 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.lootingbagviewer;
|
||||
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
import net.runelite.client.plugins.PluginDescriptor;
|
||||
import net.runelite.client.ui.overlay.OverlayManager;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@PluginDescriptor(
|
||||
name = "PvP Looting Bag Viewer",
|
||||
description = "Add an overlay showing the contents of your looting bag",
|
||||
tags = {"alternate", "items", "overlay", "second"},
|
||||
type = "utility",
|
||||
enabledByDefault = false
|
||||
)
|
||||
public class LootingBagViewerPlugin extends Plugin
|
||||
{
|
||||
@Inject
|
||||
private net.runelite.client.plugins.lootingbagviewer.LootingBagViewerOverlay overlay;
|
||||
|
||||
@Inject
|
||||
private OverlayManager overlayManager;
|
||||
|
||||
@Override
|
||||
public void startUp()
|
||||
{
|
||||
overlayManager.add(overlay);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutDown()
|
||||
{
|
||||
overlayManager.remove(overlay);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Tim Lehner <Timothy.Lehner.2011@live.rhul.ac.uk>
|
||||
* 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.raidsthieving.BatSolver;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.HashSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.TreeSet;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import static net.runelite.client.plugins.raidsthieving.BatSolver.SolutionSet.SOLUTION_SETS;
|
||||
|
||||
public class BatSolver
|
||||
{
|
||||
private Map<Integer, Integer> numberOfSolutionsWithPoison;
|
||||
private final SolutionSet solution;
|
||||
|
||||
private final HashSet<Integer> grubsChests;
|
||||
|
||||
public BatSolver(ThievingRoomType roomType)
|
||||
{
|
||||
solution = new SolutionSet(roomType);
|
||||
grubsChests = new HashSet<>();
|
||||
}
|
||||
|
||||
public void addEmptyChest(int chestId)
|
||||
{
|
||||
// When a new empty chest is found, add it to the current solution set
|
||||
solution.addEmptyChest(chestId);
|
||||
calculateChanceOfPoison();
|
||||
}
|
||||
|
||||
public void addGrubsChest(int chestId)
|
||||
{
|
||||
// When a chest with grubs is found, keep track of it to invalidate solutions
|
||||
grubsChests.add(chestId);
|
||||
calculateChanceOfPoison();
|
||||
}
|
||||
|
||||
public TreeSet<Integer> matchSolutions()
|
||||
{
|
||||
TreeSet<Integer> possibleEmptyChests = new TreeSet<>();
|
||||
for (SolutionSet knownSolution : SolutionSet.SOLUTION_SETS)
|
||||
{
|
||||
if (knownSolution.getType() == solution.getType() && matchSolution(knownSolution))
|
||||
{
|
||||
possibleEmptyChests.addAll(knownSolution.getEmptyChests());
|
||||
}
|
||||
}
|
||||
|
||||
return possibleEmptyChests;
|
||||
}
|
||||
|
||||
private boolean matchSolution(SolutionSet testSolution)
|
||||
{
|
||||
for (Integer grubsChest : grubsChests)
|
||||
{
|
||||
if (testSolution.containsChest(grubsChest))
|
||||
{
|
||||
// If one of the chests is known to have grubs, it cannot be a solution
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
boolean matchesAll = true;
|
||||
boolean everMatched = false;
|
||||
for (int i : solution.getEmptyChests())
|
||||
{
|
||||
if (!testSolution.containsChest(i))
|
||||
{
|
||||
matchesAll = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
everMatched = true;
|
||||
}
|
||||
}
|
||||
return matchesAll && everMatched;
|
||||
}
|
||||
|
||||
public ThievingRoomType getType()
|
||||
{
|
||||
return solution.getType();
|
||||
}
|
||||
|
||||
|
||||
public void calculateChanceOfPoison()
|
||||
{
|
||||
if (getType() == null)
|
||||
{
|
||||
numberOfSolutionsWithPoison = null;
|
||||
return;
|
||||
}
|
||||
|
||||
numberOfSolutionsWithPoison = new HashMap<>();
|
||||
for (SolutionSet sol : getPosssibleSolutions())
|
||||
{
|
||||
if (getType() == sol.getType() && (solution.getEmptyChests().size() == 0 || matchSolution(sol)))
|
||||
{
|
||||
for (Integer i : sol.getEmptyChests())
|
||||
{
|
||||
if (numberOfSolutionsWithPoison.containsKey(i))
|
||||
{
|
||||
numberOfSolutionsWithPoison.put(i, numberOfSolutionsWithPoison.get(i) + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
numberOfSolutionsWithPoison.put(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<SolutionSet> getPosssibleSolutions()
|
||||
{
|
||||
List<SolutionSet> possibleSolutions = new ArrayList<>();
|
||||
for (SolutionSet soln : SOLUTION_SETS)
|
||||
{
|
||||
// Check if we've found grubs in one of the chests, invalidating it as an solution
|
||||
boolean foundMatch = false;
|
||||
for (int i : grubsChests)
|
||||
{
|
||||
if (soln.containsChest(i))
|
||||
{
|
||||
foundMatch = true;
|
||||
}
|
||||
}
|
||||
if (!foundMatch)
|
||||
{
|
||||
possibleSolutions.add(soln);
|
||||
}
|
||||
}
|
||||
return possibleSolutions;
|
||||
}
|
||||
|
||||
public double relativeLikelihoodPoison(int chestId)
|
||||
{
|
||||
// Returns a double between 0 and 1 of how likely the chest has poison based on the number of possible solutions
|
||||
// Uses a Sigmoid like function to give good contrast in drawn opacity,
|
||||
// perhaps could be changed to something more accurate quantitavely.
|
||||
if (numberOfSolutionsWithPoison == null)
|
||||
{
|
||||
calculateChanceOfPoison();
|
||||
}
|
||||
if (numberOfSolutionsWithPoison == null)
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
int mostFrequentPoison = 0;
|
||||
for (Map.Entry<Integer, Integer> entry : numberOfSolutionsWithPoison.entrySet())
|
||||
{
|
||||
if (entry.getValue() > mostFrequentPoison)
|
||||
{
|
||||
mostFrequentPoison = entry.getValue();
|
||||
}
|
||||
}
|
||||
int timesFound = 0;
|
||||
if (numberOfSolutionsWithPoison.containsKey(chestId))
|
||||
{
|
||||
timesFound = numberOfSolutionsWithPoison.get(chestId);
|
||||
}
|
||||
double chestChance = (double) (timesFound) / (double) (mostFrequentPoison);
|
||||
return 1. / (1 + Math.exp(5 - 10 * chestChance));
|
||||
}
|
||||
|
||||
public int getNumberOfEmptyChests()
|
||||
{
|
||||
return solution.getEmptyChests().size();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Tim Lehner <Timothy.Lehner.2011@live.rhul.ac.uk>
|
||||
* 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.raidsthieving.BatSolver;
|
||||
|
||||
import net.runelite.client.plugins.raidsthieving.InstancePoint;
|
||||
import net.runelite.client.plugins.raidsthieving.ThievingChest;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class ChestIdentifier
|
||||
{
|
||||
public ChestIdentifier(ThievingRoomType roomType)
|
||||
{
|
||||
chestIds = new HashMap<>();
|
||||
switch (roomType)
|
||||
{
|
||||
case LEFT_TURN:
|
||||
chestIds.put(new InstancePoint(3283, 5379), 1);
|
||||
chestIds.put(new InstancePoint(3285, 5380), 2);
|
||||
chestIds.put(new InstancePoint(3279, 5381), 3);
|
||||
chestIds.put(new InstancePoint(3287, 5382), 4);
|
||||
chestIds.put(new InstancePoint(3281, 5382), 5);
|
||||
chestIds.put(new InstancePoint(3284, 5383), 6);
|
||||
chestIds.put(new InstancePoint(3283, 5384), 7);
|
||||
chestIds.put(new InstancePoint(3286, 5384), 8);
|
||||
chestIds.put(new InstancePoint(3288, 5384), 9);
|
||||
chestIds.put(new InstancePoint(3277, 5385), 10);
|
||||
chestIds.put(new InstancePoint(3280, 5385), 11);
|
||||
chestIds.put(new InstancePoint(3285, 5386), 12);
|
||||
chestIds.put(new InstancePoint(3290, 5386), 13);
|
||||
chestIds.put(new InstancePoint(3275, 5387), 14);
|
||||
chestIds.put(new InstancePoint(3287, 5387), 15);
|
||||
chestIds.put(new InstancePoint(3288, 5387), 16);
|
||||
chestIds.put(new InstancePoint(3281, 5388), 17);
|
||||
chestIds.put(new InstancePoint(3291, 5388), 18);
|
||||
chestIds.put(new InstancePoint(3280, 5389), 19);
|
||||
chestIds.put(new InstancePoint(3285, 5389), 20);
|
||||
chestIds.put(new InstancePoint(3289, 5389), 21);
|
||||
chestIds.put(new InstancePoint(3283, 5390), 22);
|
||||
chestIds.put(new InstancePoint(3285, 5390), 23);
|
||||
chestIds.put(new InstancePoint(3288, 5390), 24);
|
||||
chestIds.put(new InstancePoint(3290, 5390), 25);
|
||||
chestIds.put(new InstancePoint(3282, 5391), 26);
|
||||
chestIds.put(new InstancePoint(3289, 5391), 27);
|
||||
chestIds.put(new InstancePoint(3292, 5391), 28);
|
||||
chestIds.put(new InstancePoint(3279, 5392), 29);
|
||||
chestIds.put(new InstancePoint(3276, 5393), 30);
|
||||
chestIds.put(new InstancePoint(3279, 5393), 31);
|
||||
chestIds.put(new InstancePoint(3284, 5393), 32);
|
||||
chestIds.put(new InstancePoint(3285, 5393), 33);
|
||||
chestIds.put(new InstancePoint(3291, 5393), 34);
|
||||
chestIds.put(new InstancePoint(3275, 5394), 35);
|
||||
chestIds.put(new InstancePoint(3277, 5394), 36);
|
||||
chestIds.put(new InstancePoint(3288, 5394), 37);
|
||||
chestIds.put(new InstancePoint(3276, 5395), 38);
|
||||
chestIds.put(new InstancePoint(3281, 5395), 39);
|
||||
chestIds.put(new InstancePoint(3285, 5395), 40);
|
||||
chestIds.put(new InstancePoint(3287, 5395), 41);
|
||||
chestIds.put(new InstancePoint(3289, 5395), 42);
|
||||
chestIds.put(new InstancePoint(3274, 5396), 43);
|
||||
chestIds.put(new InstancePoint(3283, 5396), 44);
|
||||
chestIds.put(new InstancePoint(3285, 5396), 45);
|
||||
chestIds.put(new InstancePoint(3288, 5396), 46);
|
||||
chestIds.put(new InstancePoint(3272, 5397), 47);
|
||||
chestIds.put(new InstancePoint(3280, 5397), 48);
|
||||
chestIds.put(new InstancePoint(3277, 5398), 49);
|
||||
chestIds.put(new InstancePoint(3281, 5398), 50);
|
||||
chestIds.put(new InstancePoint(3284, 5398), 51);
|
||||
chestIds.put(new InstancePoint(3276, 5399), 52);
|
||||
chestIds.put(new InstancePoint(3278, 5399), 53);
|
||||
chestIds.put(new InstancePoint(3283, 5399), 54);
|
||||
chestIds.put(new InstancePoint(3285, 5399), 55);
|
||||
chestIds.put(new InstancePoint(3277, 5400), 56);
|
||||
chestIds.put(new InstancePoint(3284, 5400), 57);
|
||||
chestIds.put(new InstancePoint(3288, 5400), 58);
|
||||
chestIds.put(new InstancePoint(3281, 5401), 59);
|
||||
chestIds.put(new InstancePoint(3286, 5401), 60);
|
||||
chestIds.put(new InstancePoint(3279, 5402), 61);
|
||||
chestIds.put(new InstancePoint(3285, 5402), 62);
|
||||
chestIds.put(new InstancePoint(3280, 5403), 63);
|
||||
chestIds.put(new InstancePoint(3283, 5403), 64);
|
||||
break;
|
||||
case RIGHT_TURN:
|
||||
chestIds.put(new InstancePoint(3338, 5405), 1);
|
||||
chestIds.put(new InstancePoint(3334, 5405), 2);
|
||||
chestIds.put(new InstancePoint(3342, 5404), 3);
|
||||
chestIds.put(new InstancePoint(3340, 5404), 4);
|
||||
chestIds.put(new InstancePoint(3345, 5403), 5);
|
||||
chestIds.put(new InstancePoint(3334, 5403), 6);
|
||||
chestIds.put(new InstancePoint(3330, 5403), 7);
|
||||
chestIds.put(new InstancePoint(3343, 5402), 8);
|
||||
chestIds.put(new InstancePoint(3342, 5402), 9);
|
||||
chestIds.put(new InstancePoint(3339, 5402), 10);
|
||||
chestIds.put(new InstancePoint(3338, 5402), 11);
|
||||
chestIds.put(new InstancePoint(3336, 5402), 12);
|
||||
chestIds.put(new InstancePoint(3347, 5401), 13);
|
||||
chestIds.put(new InstancePoint(3330, 5401), 14);
|
||||
chestIds.put(new InstancePoint(3345, 5400), 15);
|
||||
chestIds.put(new InstancePoint(3341, 5400), 16);
|
||||
chestIds.put(new InstancePoint(3337, 5400), 17);
|
||||
chestIds.put(new InstancePoint(3334, 5400), 18);
|
||||
chestIds.put(new InstancePoint(3345, 5399), 19);
|
||||
chestIds.put(new InstancePoint(3343, 5399), 20);
|
||||
chestIds.put(new InstancePoint(3340, 5399), 21);
|
||||
chestIds.put(new InstancePoint(3335, 5399), 22);
|
||||
chestIds.put(new InstancePoint(3331, 5399), 23);
|
||||
chestIds.put(new InstancePoint(3338, 5398), 24);
|
||||
chestIds.put(new InstancePoint(3337, 5398), 25);
|
||||
chestIds.put(new InstancePoint(3345, 5397), 26);
|
||||
chestIds.put(new InstancePoint(3341, 5397), 27);
|
||||
chestIds.put(new InstancePoint(3334, 5397), 28);
|
||||
chestIds.put(new InstancePoint(3331, 5397), 29);
|
||||
chestIds.put(new InstancePoint(3346, 5396), 30);
|
||||
chestIds.put(new InstancePoint(3343, 5396), 31);
|
||||
chestIds.put(new InstancePoint(3339, 5396), 32);
|
||||
chestIds.put(new InstancePoint(3335, 5396), 33);
|
||||
chestIds.put(new InstancePoint(3333, 5396), 34);
|
||||
chestIds.put(new InstancePoint(3340, 5395), 35);
|
||||
chestIds.put(new InstancePoint(3337, 5395), 36);
|
||||
chestIds.put(new InstancePoint(3334, 5395), 37);
|
||||
chestIds.put(new InstancePoint(3345, 5394), 38);
|
||||
chestIds.put(new InstancePoint(3342, 5394), 39);
|
||||
chestIds.put(new InstancePoint(3332, 5394), 40);
|
||||
chestIds.put(new InstancePoint(3343, 5393), 41);
|
||||
chestIds.put(new InstancePoint(3341, 5393), 42);
|
||||
chestIds.put(new InstancePoint(3338, 5393), 43);
|
||||
chestIds.put(new InstancePoint(3335, 5393), 44);
|
||||
chestIds.put(new InstancePoint(3334, 5393), 45);
|
||||
chestIds.put(new InstancePoint(3346, 5392), 46);
|
||||
chestIds.put(new InstancePoint(3342, 5392), 47);
|
||||
chestIds.put(new InstancePoint(3332, 5392), 48);
|
||||
chestIds.put(new InstancePoint(3350, 5391), 49);
|
||||
chestIds.put(new InstancePoint(3346, 5391), 50);
|
||||
chestIds.put(new InstancePoint(3340, 5391), 51);
|
||||
chestIds.put(new InstancePoint(3339, 5391), 52);
|
||||
chestIds.put(new InstancePoint(3336, 5391), 53);
|
||||
chestIds.put(new InstancePoint(3333, 5391), 54);
|
||||
chestIds.put(new InstancePoint(3349, 5390), 55);
|
||||
chestIds.put(new InstancePoint(3343, 5390), 56);
|
||||
chestIds.put(new InstancePoint(3337, 5390), 57);
|
||||
chestIds.put(new InstancePoint(3335, 5390), 58);
|
||||
chestIds.put(new InstancePoint(3344, 5389), 59);
|
||||
chestIds.put(new InstancePoint(3340, 5389), 60);
|
||||
chestIds.put(new InstancePoint(3336, 5389), 61);
|
||||
chestIds.put(new InstancePoint(3333, 5389), 62);
|
||||
chestIds.put(new InstancePoint(3346, 5388), 63);
|
||||
chestIds.put(new InstancePoint(3340, 5387), 64);
|
||||
chestIds.put(new InstancePoint(3337, 5386), 65);
|
||||
chestIds.put(new InstancePoint(3333, 5386), 66);
|
||||
chestIds.put(new InstancePoint(3338, 5385), 67);
|
||||
chestIds.put(new InstancePoint(3336, 5385), 68);
|
||||
chestIds.put(new InstancePoint(3337, 5384), 69);
|
||||
chestIds.put(new InstancePoint(3340, 5382), 70);
|
||||
chestIds.put(new InstancePoint(3334, 5383), 71);
|
||||
chestIds.put(new InstancePoint(3340, 5379), 72);
|
||||
chestIds.put(new InstancePoint(3338, 5380), 73);
|
||||
chestIds.put(new InstancePoint(3336, 5381), 74);
|
||||
break;
|
||||
case STRAIGHT:
|
||||
chestIds.put(new InstancePoint(3308, 5378), 1);
|
||||
chestIds.put(new InstancePoint(3305, 5379), 2);
|
||||
chestIds.put(new InstancePoint(3307, 5379), 3);
|
||||
chestIds.put(new InstancePoint(3304, 5381), 4);
|
||||
chestIds.put(new InstancePoint(3310, 5381), 5);
|
||||
chestIds.put(new InstancePoint(3302, 5382), 6);
|
||||
chestIds.put(new InstancePoint(3307, 5382), 7);
|
||||
chestIds.put(new InstancePoint(3312, 5382), 8);
|
||||
chestIds.put(new InstancePoint(3317, 5382), 9);
|
||||
chestIds.put(new InstancePoint(3319, 5382), 10);
|
||||
chestIds.put(new InstancePoint(3304, 5383), 11);
|
||||
chestIds.put(new InstancePoint(3305, 5383), 12);
|
||||
chestIds.put(new InstancePoint(3307, 5383), 13);
|
||||
chestIds.put(new InstancePoint(3310, 5383), 14);
|
||||
chestIds.put(new InstancePoint(3315, 5383), 15);
|
||||
chestIds.put(new InstancePoint(3320, 5383), 16);
|
||||
chestIds.put(new InstancePoint(3300, 5384), 17);
|
||||
chestIds.put(new InstancePoint(3309, 5384), 18);
|
||||
chestIds.put(new InstancePoint(3311, 5384), 19);
|
||||
chestIds.put(new InstancePoint(3313, 5384), 20);
|
||||
chestIds.put(new InstancePoint(3317, 5384), 21);
|
||||
chestIds.put(new InstancePoint(3318, 5384), 22);
|
||||
chestIds.put(new InstancePoint(3302, 5385), 23);
|
||||
chestIds.put(new InstancePoint(3306, 5385), 24);
|
||||
chestIds.put(new InstancePoint(3310, 5385), 25);
|
||||
chestIds.put(new InstancePoint(3313, 5385), 26);
|
||||
chestIds.put(new InstancePoint(3320, 5385), 27);
|
||||
chestIds.put(new InstancePoint(3302, 5386), 28);
|
||||
chestIds.put(new InstancePoint(3305, 5386), 29);
|
||||
chestIds.put(new InstancePoint(3316, 5386), 30);
|
||||
chestIds.put(new InstancePoint(3321, 5386), 31);
|
||||
chestIds.put(new InstancePoint(3300, 5387), 32);
|
||||
chestIds.put(new InstancePoint(3308, 5387), 33);
|
||||
chestIds.put(new InstancePoint(3314, 5387), 34);
|
||||
chestIds.put(new InstancePoint(3317, 5387), 35);
|
||||
chestIds.put(new InstancePoint(3301, 5388), 36);
|
||||
chestIds.put(new InstancePoint(3306, 5388), 37);
|
||||
chestIds.put(new InstancePoint(3312, 5388), 38);
|
||||
chestIds.put(new InstancePoint(3322, 5388), 39);
|
||||
chestIds.put(new InstancePoint(3309, 5389), 40);
|
||||
chestIds.put(new InstancePoint(3311, 5389), 41);
|
||||
chestIds.put(new InstancePoint(3313, 5389), 42);
|
||||
chestIds.put(new InstancePoint(3316, 5389), 43);
|
||||
chestIds.put(new InstancePoint(3320, 5389), 44);
|
||||
chestIds.put(new InstancePoint(3300, 5390), 45);
|
||||
chestIds.put(new InstancePoint(3303, 5390), 46);
|
||||
chestIds.put(new InstancePoint(3304, 5390), 47);
|
||||
chestIds.put(new InstancePoint(3312, 5390), 48);
|
||||
chestIds.put(new InstancePoint(3320, 5390), 49);
|
||||
chestIds.put(new InstancePoint(3307, 5391), 50);
|
||||
chestIds.put(new InstancePoint(3310, 5391), 51);
|
||||
chestIds.put(new InstancePoint(3317, 5391), 52);
|
||||
chestIds.put(new InstancePoint(3318, 5391), 53);
|
||||
chestIds.put(new InstancePoint(3323, 5391), 54);
|
||||
chestIds.put(new InstancePoint(3301, 5392), 55);
|
||||
chestIds.put(new InstancePoint(3303, 5392), 56);
|
||||
chestIds.put(new InstancePoint(3309, 5392), 57);
|
||||
chestIds.put(new InstancePoint(3314, 5392), 58);
|
||||
chestIds.put(new InstancePoint(3322, 5392), 59);
|
||||
chestIds.put(new InstancePoint(3305, 5393), 60);
|
||||
chestIds.put(new InstancePoint(3307, 5393), 61);
|
||||
chestIds.put(new InstancePoint(3316, 5393), 62);
|
||||
chestIds.put(new InstancePoint(3309, 5394), 63);
|
||||
chestIds.put(new InstancePoint(3312, 5394), 64);
|
||||
chestIds.put(new InstancePoint(3322, 5394), 65);
|
||||
chestIds.put(new InstancePoint(3310, 5379), 66);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public int indentifyChest(ThievingChest chest)
|
||||
{
|
||||
int id = chestIds.get(chest.getInstancePoint());
|
||||
chest.setChestId(id);
|
||||
return id;
|
||||
}
|
||||
|
||||
private Map<InstancePoint, Integer> chestIds;
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Tim Lehner <Timothy.Lehner.2011@live.rhul.ac.uk>
|
||||
* 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.raidsthieving.BatSolver;
|
||||
|
||||
import lombok.Getter;
|
||||
import java.util.HashSet;
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
|
||||
// Each Thieving room has 4 empty chests
|
||||
// User-reported data shows these 4 come in groups,
|
||||
//
|
||||
// e.g. if there is an empty chest in L room chest 1, the other empty chests could be 16, 17, 38, 54, 55
|
||||
// See https://dikkenoob.github.io/ for more information
|
||||
|
||||
public class SolutionSet
|
||||
{
|
||||
public static final SolutionSet[] SOLUTION_SETS =
|
||||
{
|
||||
new SolutionSet(ThievingRoomType.LEFT_TURN, 1, 16, 17, 55),
|
||||
new SolutionSet(ThievingRoomType.LEFT_TURN, 1, 17, 38, 54),
|
||||
new SolutionSet(ThievingRoomType.LEFT_TURN, 2, 7, 21, 37),
|
||||
new SolutionSet(ThievingRoomType.LEFT_TURN, 3, 5, 19, 30),
|
||||
new SolutionSet(ThievingRoomType.LEFT_TURN, 3, 11, 15, 40),
|
||||
new SolutionSet(ThievingRoomType.LEFT_TURN, 4, 22, 27, 46),
|
||||
new SolutionSet(ThievingRoomType.LEFT_TURN, 5, 9, 19, 45),
|
||||
new SolutionSet(ThievingRoomType.LEFT_TURN, 6, 24, 26, 41),
|
||||
new SolutionSet(ThievingRoomType.LEFT_TURN, 6, 26, 32, 52),
|
||||
new SolutionSet(ThievingRoomType.LEFT_TURN, 7, 13, 44, 59),
|
||||
new SolutionSet(ThievingRoomType.LEFT_TURN, 8, 14, 41, 43),
|
||||
new SolutionSet(ThievingRoomType.LEFT_TURN, 8, 10, 28, 33),
|
||||
new SolutionSet(ThievingRoomType.LEFT_TURN, 8, 31, 47, 50),
|
||||
new SolutionSet(ThievingRoomType.LEFT_TURN, 10, 35, 54, 63),
|
||||
new SolutionSet(ThievingRoomType.LEFT_TURN, 10, 30, 32, 59),
|
||||
new SolutionSet(ThievingRoomType.LEFT_TURN, 12, 40, 53, 56),
|
||||
new SolutionSet(ThievingRoomType.LEFT_TURN, 12, 13, 42, 54),
|
||||
new SolutionSet(ThievingRoomType.LEFT_TURN, 13, 22, 27, 46),
|
||||
new SolutionSet(ThievingRoomType.LEFT_TURN, 14, 18, 23, 51),
|
||||
new SolutionSet(ThievingRoomType.LEFT_TURN, 15, 43, 44, 58),
|
||||
new SolutionSet(ThievingRoomType.LEFT_TURN, 15, 16, 42, 45),
|
||||
new SolutionSet(ThievingRoomType.LEFT_TURN, 20, 29, 45, 51),
|
||||
new SolutionSet(ThievingRoomType.LEFT_TURN, 20, 25, 32, 34),
|
||||
new SolutionSet(ThievingRoomType.LEFT_TURN, 20, 28, 51, 62),
|
||||
new SolutionSet(ThievingRoomType.LEFT_TURN, 21, 39, 41, 58),
|
||||
new SolutionSet(ThievingRoomType.LEFT_TURN, 22, 25, 54, 64),
|
||||
new SolutionSet(ThievingRoomType.LEFT_TURN, 23, 31, 47, 55),
|
||||
new SolutionSet(ThievingRoomType.LEFT_TURN, 23, 33, 37, 60),
|
||||
new SolutionSet(ThievingRoomType.LEFT_TURN, 24, 34, 55),
|
||||
new SolutionSet(ThievingRoomType.LEFT_TURN, 26, 50, 63, 27),
|
||||
new SolutionSet(ThievingRoomType.LEFT_TURN, 29, 39, 41, 61),
|
||||
new SolutionSet(ThievingRoomType.LEFT_TURN, 33, 46, 52, 57),
|
||||
new SolutionSet(ThievingRoomType.LEFT_TURN, 34, 45, 49, 60),
|
||||
new SolutionSet(ThievingRoomType.LEFT_TURN, 36, 40, 42, 62),
|
||||
new SolutionSet(ThievingRoomType.LEFT_TURN, 37, 38, 51, 64),
|
||||
new SolutionSet(ThievingRoomType.LEFT_TURN, 48, 53, 55, 56),
|
||||
new SolutionSet(ThievingRoomType.RIGHT_TURN, 1, 6, 28, 41),
|
||||
new SolutionSet(ThievingRoomType.RIGHT_TURN, 1, 42, 55, 60),
|
||||
new SolutionSet(ThievingRoomType.RIGHT_TURN, 2, 10, 31, 44),
|
||||
new SolutionSet(ThievingRoomType.RIGHT_TURN, 2, 33, 51, 68),
|
||||
new SolutionSet(ThievingRoomType.RIGHT_TURN, 3, 31, 43, 46),
|
||||
new SolutionSet(ThievingRoomType.RIGHT_TURN, 3, 5, 21, 48),
|
||||
new SolutionSet(ThievingRoomType.RIGHT_TURN, 4, 20, 24, 33),
|
||||
new SolutionSet(ThievingRoomType.RIGHT_TURN, 4, 38, 47),
|
||||
new SolutionSet(ThievingRoomType.RIGHT_TURN, 5, 21, 48),
|
||||
new SolutionSet(ThievingRoomType.RIGHT_TURN, 5, 17, 35, 63),
|
||||
new SolutionSet(ThievingRoomType.RIGHT_TURN, 7, 17, 45, 47),
|
||||
new SolutionSet(ThievingRoomType.RIGHT_TURN, 7, 37, 41, 52),
|
||||
new SolutionSet(ThievingRoomType.RIGHT_TURN, 8, 13, 40, 42),
|
||||
new SolutionSet(ThievingRoomType.RIGHT_TURN, 8, 20, 24, 30),
|
||||
new SolutionSet(ThievingRoomType.RIGHT_TURN, 9, 15, 23, 35),
|
||||
new SolutionSet(ThievingRoomType.RIGHT_TURN, 11, 13, 21, 50),
|
||||
new SolutionSet(ThievingRoomType.RIGHT_TURN, 11, 18, 37, 39),
|
||||
new SolutionSet(ThievingRoomType.RIGHT_TURN, 12, 14, 27, 34),
|
||||
new SolutionSet(ThievingRoomType.RIGHT_TURN, 14, 45, 67, 71),
|
||||
new SolutionSet(ThievingRoomType.RIGHT_TURN, 16, 22, 29, 32),
|
||||
new SolutionSet(ThievingRoomType.RIGHT_TURN, 18, 28, 31, 64),
|
||||
new SolutionSet(ThievingRoomType.RIGHT_TURN, 19, 21, 63, 69),
|
||||
new SolutionSet(ThievingRoomType.RIGHT_TURN, 20, 51, 68, 72),
|
||||
new SolutionSet(ThievingRoomType.RIGHT_TURN, 22, 29, 56, 61),
|
||||
new SolutionSet(ThievingRoomType.RIGHT_TURN, 23, 53, 66, 74),
|
||||
new SolutionSet(ThievingRoomType.RIGHT_TURN, 26, 35, 53, 59),
|
||||
new SolutionSet(ThievingRoomType.RIGHT_TURN, 27, 30, 55, 57),
|
||||
new SolutionSet(ThievingRoomType.RIGHT_TURN, 31, 58, 60, 73),
|
||||
new SolutionSet(ThievingRoomType.RIGHT_TURN, 34, 57, 58, 70),
|
||||
new SolutionSet(ThievingRoomType.RIGHT_TURN, 38, 56, 61, 70),
|
||||
new SolutionSet(ThievingRoomType.RIGHT_TURN, 40, 54, 65, 72),
|
||||
new SolutionSet(ThievingRoomType.RIGHT_TURN, 42, 46, 65),
|
||||
new SolutionSet(ThievingRoomType.RIGHT_TURN, 47, 49, 66, 67),
|
||||
new SolutionSet(ThievingRoomType.RIGHT_TURN, 48, 62, 69),
|
||||
new SolutionSet(ThievingRoomType.RIGHT_TURN, 9, 19, 32, 41),
|
||||
new SolutionSet(ThievingRoomType.RIGHT_TURN, 16, 26, 36, 39),
|
||||
new SolutionSet(ThievingRoomType.STRAIGHT, 1, 39, 43, 51),
|
||||
new SolutionSet(ThievingRoomType.STRAIGHT, 2, 15, 20, 53),
|
||||
new SolutionSet(ThievingRoomType.STRAIGHT, 3, 10, 42, 44),
|
||||
new SolutionSet(ThievingRoomType.STRAIGHT, 4, 14, 38, 52),
|
||||
new SolutionSet(ThievingRoomType.STRAIGHT, 5, 6, 35, 41),
|
||||
new SolutionSet(ThievingRoomType.STRAIGHT, 7, 16, 34, 49),
|
||||
new SolutionSet(ThievingRoomType.STRAIGHT, 9, 12, 26, 27),
|
||||
new SolutionSet(ThievingRoomType.STRAIGHT, 13, 25, 30, 31),
|
||||
new SolutionSet(ThievingRoomType.STRAIGHT, 15, 20, 53),
|
||||
new SolutionSet(ThievingRoomType.STRAIGHT, 17, 24, 34, 58),
|
||||
new SolutionSet(ThievingRoomType.STRAIGHT, 18, 23, 35, 57),
|
||||
new SolutionSet(ThievingRoomType.STRAIGHT, 19, 26, 47, 65),
|
||||
new SolutionSet(ThievingRoomType.STRAIGHT, 21, 33, 36, 61),
|
||||
new SolutionSet(ThievingRoomType.STRAIGHT, 21, 54, 66),
|
||||
new SolutionSet(ThievingRoomType.STRAIGHT, 22, 25, 46, 55),
|
||||
new SolutionSet(ThievingRoomType.STRAIGHT, 24, 34, 58),
|
||||
new SolutionSet(ThievingRoomType.STRAIGHT, 28, 40, 52, 62),
|
||||
new SolutionSet(ThievingRoomType.STRAIGHT, 29, 41, 42, 63),
|
||||
new SolutionSet(ThievingRoomType.STRAIGHT, 30, 32, 37, 64),
|
||||
new SolutionSet(ThievingRoomType.STRAIGHT, 39, 43, 51),
|
||||
new SolutionSet(ThievingRoomType.STRAIGHT, 43, 45, 50, 60),
|
||||
new SolutionSet(ThievingRoomType.STRAIGHT, 51, 53, 56, 59)
|
||||
};
|
||||
|
||||
SolutionSet(ThievingRoomType type)
|
||||
{
|
||||
this.type = type;
|
||||
emptyChests = new HashSet<>();
|
||||
}
|
||||
|
||||
private SolutionSet(ThievingRoomType type, Integer... emptyChests)
|
||||
{
|
||||
this.type = type;
|
||||
this.emptyChests = new HashSet<>(Arrays.asList(emptyChests));
|
||||
}
|
||||
|
||||
public void addEmptyChest(int chestId)
|
||||
{
|
||||
emptyChests.add(chestId);
|
||||
}
|
||||
|
||||
public boolean containsChest(int chestId)
|
||||
{
|
||||
return emptyChests.contains(chestId);
|
||||
}
|
||||
|
||||
@Getter
|
||||
private ThievingRoomType type;
|
||||
|
||||
@Getter
|
||||
private Set<Integer> emptyChests;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Tim Lehner <Timothy.Lehner.2011@live.rhul.ac.uk>
|
||||
* 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.raidsthieving.BatSolver;
|
||||
|
||||
// There are three distinct Thieving rooms, distinguished by the position of the entrance relative to the exit
|
||||
// e.g. If you enter the room and must turn left to get to the exit and trough, this is a LEFT_TURN
|
||||
|
||||
import net.runelite.client.plugins.raidsthieving.InstancePoint;
|
||||
|
||||
public enum ThievingRoomType
|
||||
{
|
||||
LEFT_TURN(3271, 5389),
|
||||
RIGHT_TURN(3350, 5399),
|
||||
STRAIGHT(3317, 5397);
|
||||
|
||||
private final int x;
|
||||
private final int y;
|
||||
|
||||
ThievingRoomType(int x, int y)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public static ThievingRoomType IdentifyByInstancePoint(InstancePoint point)
|
||||
{
|
||||
for (ThievingRoomType type : ThievingRoomType.values())
|
||||
{
|
||||
if (Math.abs(type.x - point.getX()) <= 1 &&
|
||||
Math.abs(type.y - point.getY()) <= 1)
|
||||
{
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Tim Lehner <Timothy.Lehner.2011@live.rhul.ac.uk>
|
||||
* 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.raidsthieving;
|
||||
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.Perspective;
|
||||
import net.runelite.api.Point;
|
||||
import net.runelite.api.coords.LocalPoint;
|
||||
import net.runelite.api.coords.WorldPoint;
|
||||
import net.runelite.client.plugins.raidsthieving.BatSolver.BatSolver;
|
||||
import net.runelite.client.ui.overlay.Overlay;
|
||||
import net.runelite.client.ui.overlay.OverlayLayer;
|
||||
import net.runelite.client.ui.overlay.OverlayPosition;
|
||||
import net.runelite.client.ui.overlay.components.ProgressPieComponent;
|
||||
import javax.inject.Inject;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics2D;
|
||||
import java.util.Map;
|
||||
import java.util.TreeSet;
|
||||
|
||||
/**
|
||||
* Represents the overlay that shows timers on traps that are placed by the
|
||||
* player.
|
||||
*/
|
||||
public class ChestOverlay extends Overlay
|
||||
{
|
||||
|
||||
private final Client client;
|
||||
private final RaidsThievingPlugin plugin;
|
||||
private final RaidsThievingConfig config;
|
||||
|
||||
@Inject
|
||||
ChestOverlay(Client client, RaidsThievingPlugin plugin, RaidsThievingConfig config)
|
||||
{
|
||||
setPosition(OverlayPosition.DYNAMIC);
|
||||
setLayer(OverlayLayer.ABOVE_SCENE);
|
||||
this.plugin = plugin;
|
||||
this.config = config;
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension render(Graphics2D graphics)
|
||||
{
|
||||
drawChests(graphics);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the timer colors.
|
||||
*/
|
||||
public void updateConfig()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over all the traps that were placed by the local player, and
|
||||
* draws a circle or a timer on the trap, depending on the trap state.
|
||||
*
|
||||
* @param graphics
|
||||
*/
|
||||
private void drawChests(Graphics2D graphics)
|
||||
{
|
||||
|
||||
for (Map.Entry<WorldPoint, ThievingChest> entry : plugin.getChests().entrySet())
|
||||
{
|
||||
ThievingChest chest = entry.getValue();
|
||||
WorldPoint pos = entry.getKey();
|
||||
|
||||
|
||||
if (chest != null)
|
||||
{
|
||||
if (!plugin.isBatsFound() && !chest.isEverOpened())
|
||||
{
|
||||
if (shouldDrawChest(pos))
|
||||
{
|
||||
Color drawColor = new Color(config.getPotentialBatColor().getRed(),
|
||||
config.getPotentialBatColor().getGreen(),
|
||||
config.getPotentialBatColor().getBlue(),
|
||||
getChestOpacity(pos));
|
||||
drawCircleOnTrap(graphics, chest, drawColor);
|
||||
}
|
||||
}
|
||||
if (chest.isPoison())
|
||||
{
|
||||
drawCircleOnTrap(graphics, chest, config.getPoisonTrapColor());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldDrawChest(WorldPoint chestPos)
|
||||
{
|
||||
if (plugin.numberOfEmptyChestsFound() == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
int chestId = plugin.getChestId(chestPos);
|
||||
BatSolver solver = plugin.getSolver();
|
||||
if (solver != null && chestId != -1)
|
||||
{
|
||||
TreeSet<Integer> matches = solver.matchSolutions();
|
||||
return matches.contains(chestId) || matches.size() == 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a timer on a given trap.
|
||||
*
|
||||
* @param graphics
|
||||
* @param chest The chest on which the circle needs to be drawn
|
||||
* @param fill The fill color of the timer
|
||||
*/
|
||||
private void drawCircleOnTrap(Graphics2D graphics, ThievingChest chest, Color fill)
|
||||
{
|
||||
if (chest.getLocalPoint().getPlane() != client.getPlane())
|
||||
{
|
||||
return;
|
||||
}
|
||||
LocalPoint localLoc = LocalPoint.fromWorld(client, chest.getLocalPoint());
|
||||
if (localLoc == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Point loc = Perspective.localToCanvas(client, localLoc, chest.getLocalPoint().getPlane());
|
||||
|
||||
ProgressPieComponent pie = new ProgressPieComponent();
|
||||
pie.setFill(fill);
|
||||
pie.setBorderColor(Color.BLACK);
|
||||
pie.setPosition(loc);
|
||||
pie.setProgress(1);
|
||||
if (graphics != null && loc != null)
|
||||
{
|
||||
pie.render(graphics);
|
||||
}
|
||||
}
|
||||
|
||||
private int getChestOpacity(WorldPoint chestPos)
|
||||
{
|
||||
int chestId = plugin.getChestId(chestPos);
|
||||
BatSolver solver = plugin.getSolver();
|
||||
if (solver != null && chestId != -1)
|
||||
{
|
||||
return (int) (255 * solver.relativeLikelihoodPoison(chestId));
|
||||
}
|
||||
return 255;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package net.runelite.client.plugins.raidsthieving;
|
||||
|
||||
import lombok.Getter;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.Point;
|
||||
import net.runelite.api.coords.WorldPoint;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Represents a point in the instance chunk, invariant of rotation.
|
||||
*/
|
||||
@Getter
|
||||
public class InstancePoint
|
||||
{
|
||||
private static final int CHUNK_SIZE = 8;
|
||||
private static final double CHUNK_OFFSET = 3.5;
|
||||
|
||||
public InstancePoint(int x, int y, int rot)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.rot = rot;
|
||||
}
|
||||
|
||||
public InstancePoint(int x, int y)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.rot = 0;
|
||||
}
|
||||
|
||||
public static InstancePoint buildFromPoint(WorldPoint worldPoint, Client client)
|
||||
{
|
||||
Point point = new Point(worldPoint.getX(), worldPoint.getY());
|
||||
Point base = new Point(client.getBaseX(), client.getBaseY());
|
||||
int plane = worldPoint.getPlane();
|
||||
|
||||
int deltaX = point.getX() - base.getX();
|
||||
int deltaY = point.getY() - base.getY();
|
||||
int chunkIndexX = deltaX / CHUNK_SIZE;
|
||||
int chunkIndexY = deltaY / CHUNK_SIZE;
|
||||
|
||||
int chunkData = client.getInstanceTemplateChunks()[plane][chunkIndexX][chunkIndexY];
|
||||
int rotation = chunkData >> 1 & 0x3;
|
||||
int y = (chunkData >> 3 & 0x7FF) * 8;
|
||||
int x = (chunkData >> 14 & 0x3FF) * 8;
|
||||
|
||||
return buildFromTile(base, point, rotation, new Point(x, y));
|
||||
}
|
||||
|
||||
public static InstancePoint buildFromTile(Point base, Point tile, int rot, Point chunkOrigin)
|
||||
{
|
||||
int deltaX = tile.getX() - base.getX();
|
||||
int deltaY = tile.getY() - base.getY();
|
||||
|
||||
double chunkOffsetX = (deltaX % CHUNK_SIZE) - CHUNK_OFFSET;
|
||||
double chunkOffsetY = (deltaY % CHUNK_SIZE) - CHUNK_OFFSET;
|
||||
|
||||
for (int i = 0; i < rot; i++)
|
||||
{
|
||||
double temp = chunkOffsetX;
|
||||
chunkOffsetX = -chunkOffsetY;
|
||||
chunkOffsetY = temp;
|
||||
}
|
||||
|
||||
chunkOffsetX += CHUNK_OFFSET;
|
||||
chunkOffsetY += CHUNK_OFFSET;
|
||||
|
||||
int invariantChunkOffsetX = (int) chunkOffsetX;
|
||||
int invariantChunkOffsetY = (int) chunkOffsetY;
|
||||
|
||||
return new InstancePoint(
|
||||
chunkOrigin.getX() + invariantChunkOffsetX,
|
||||
chunkOrigin.getY() + invariantChunkOffsetY,
|
||||
rot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
InstancePoint that = (InstancePoint) o;
|
||||
return x == that.x &&
|
||||
y == that.y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(x, y);
|
||||
}
|
||||
|
||||
private int x;
|
||||
private int y;
|
||||
private int rot;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Tim Lehner <Timothy.Lehner.2011@live.rhul.ac.uk>
|
||||
* 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.raidsthieving;
|
||||
|
||||
import net.runelite.client.config.Config;
|
||||
import net.runelite.client.config.ConfigGroup;
|
||||
import net.runelite.client.config.ConfigItem;
|
||||
import java.awt.Color;
|
||||
|
||||
@ConfigGroup("raidsthievingplugin")
|
||||
public interface RaidsThievingConfig extends Config
|
||||
{
|
||||
@ConfigItem(
|
||||
position = 1,
|
||||
keyName = "hexColorPotentialBat",
|
||||
name = "Potential Bat",
|
||||
description = "Color of marker for chests which could have bat"
|
||||
)
|
||||
default Color getPotentialBatColor()
|
||||
{
|
||||
return Color.YELLOW;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
position = 2,
|
||||
keyName = "hexColorPoison",
|
||||
name = "Poison trap",
|
||||
description = "Color of chest with poison"
|
||||
)
|
||||
default Color getPoisonTrapColor()
|
||||
{
|
||||
return Color.GREEN;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
position = 5,
|
||||
keyName = "batNotify",
|
||||
name = "Notify when found",
|
||||
description = "Send notification if you see bats being found."
|
||||
)
|
||||
default boolean batFoundNotify()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Tim Lehner <Timothy.Lehner.2011@live.rhul.ac.uk>
|
||||
* 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.raidsthieving;
|
||||
|
||||
public class RaidsThievingConstants
|
||||
{
|
||||
public static final int CLOSED_CHEST_ID = 29742;
|
||||
public static final int OPEN_EMPTY_CHEST = 29743;
|
||||
public static final int OPEN_FULL_CHEST_1 = 29744;
|
||||
public static final int OPEN_FULL_CHEST_2 = 29745;
|
||||
public static final int EMPTY_TROUGH = 29746;
|
||||
public static final int[] STORAGE = {29769, 29770, 29771, 29772};
|
||||
}
|
||||
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Tim Lehner <Timothy.Lehner.2011@live.rhul.ac.uk>
|
||||
* 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.raidsthieving;
|
||||
|
||||
import com.google.inject.Provides;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.GameObject;
|
||||
import net.runelite.api.GraphicsObject;
|
||||
import net.runelite.api.Varbits;
|
||||
import net.runelite.api.coords.WorldPoint;
|
||||
import net.runelite.api.events.ConfigChanged;
|
||||
import net.runelite.api.events.GameObjectSpawned;
|
||||
import net.runelite.api.events.GraphicsObjectCreated;
|
||||
import net.runelite.api.events.VarbitChanged;
|
||||
import net.runelite.client.Notifier;
|
||||
import net.runelite.client.config.ConfigManager;
|
||||
import net.runelite.client.eventbus.Subscribe;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
import net.runelite.client.plugins.PluginDescriptor;
|
||||
import net.runelite.client.plugins.raidsthieving.BatSolver.BatSolver;
|
||||
import net.runelite.client.plugins.raidsthieving.BatSolver.ChestIdentifier;
|
||||
import net.runelite.client.plugins.raidsthieving.BatSolver.ThievingRoomType;
|
||||
import net.runelite.client.ui.overlay.OverlayManager;
|
||||
import javax.inject.Inject;
|
||||
import java.text.MessageFormat;
|
||||
import java.time.Instant;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
@PluginDescriptor(
|
||||
name = "<font color=\"#4863A0\">!Raids Bat Finder</font>",
|
||||
description = "Tracks which chests need to be searched for bats and which poison",
|
||||
tags = {"overlay", "skilling", "raid"}
|
||||
)
|
||||
public class RaidsThievingPlugin extends Plugin
|
||||
{
|
||||
@Inject
|
||||
private Client client;
|
||||
|
||||
@Inject
|
||||
private OverlayManager overlayManager;
|
||||
|
||||
@Inject
|
||||
private ChestOverlay overlay;
|
||||
|
||||
@Inject
|
||||
private Notifier notifier;
|
||||
|
||||
@Inject
|
||||
private RaidsThievingConfig config;
|
||||
|
||||
@Getter
|
||||
private final Map<WorldPoint, ThievingChest> chests = new HashMap<>();
|
||||
|
||||
@Getter
|
||||
private Instant lastActionTime = Instant.ofEpochMilli(0);
|
||||
|
||||
private boolean inRaidChambers;
|
||||
|
||||
@Getter
|
||||
private boolean batsFound;
|
||||
|
||||
@Getter
|
||||
private BatSolver solver;
|
||||
|
||||
@Getter
|
||||
private ChestIdentifier mapper;
|
||||
|
||||
|
||||
@Provides
|
||||
RaidsThievingConfig provideConfig(ConfigManager configManager)
|
||||
{
|
||||
return configManager.getConfig(RaidsThievingConfig.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startUp()
|
||||
{
|
||||
overlayManager.add(overlay);
|
||||
overlay.updateConfig();
|
||||
reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void shutDown() throws Exception
|
||||
{
|
||||
overlayManager.remove(overlay);
|
||||
lastActionTime = Instant.ofEpochMilli(0);
|
||||
chests.clear();
|
||||
}
|
||||
|
||||
|
||||
@Subscribe
|
||||
public void onGameObjectSpawned(GameObjectSpawned event)
|
||||
{
|
||||
GameObject obj = event.getGameObject();
|
||||
WorldPoint loc = obj.getWorldLocation();
|
||||
InstancePoint absLoc = InstancePoint.buildFromPoint(loc, client);
|
||||
|
||||
if (obj.getId() == RaidsThievingConstants.EMPTY_TROUGH)
|
||||
{
|
||||
ThievingRoomType type = ThievingRoomType.IdentifyByInstancePoint(absLoc);
|
||||
|
||||
if (type != null)
|
||||
{
|
||||
solver = new BatSolver(type);
|
||||
mapper = new ChestIdentifier(type);
|
||||
for (ThievingChest chest : chests.values())
|
||||
{
|
||||
mapper.indentifyChest(chest);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log.error(MessageFormat.format("Unable to identify room type with: {0} {1} {2} {3} {4}.",
|
||||
loc.getX(), loc.getY(), absLoc.getX(), absLoc.getY(), absLoc.getRot()));
|
||||
log.error("Please report this @https://github.com/runelite/runelite/pull/4914!");
|
||||
}
|
||||
}
|
||||
if (obj.getId() == RaidsThievingConstants.CLOSED_CHEST_ID)
|
||||
{
|
||||
if (!chests.containsKey(loc))
|
||||
{
|
||||
ThievingChest chest = new ThievingChest(obj, absLoc);
|
||||
|
||||
if (mapper != null)
|
||||
{
|
||||
mapper.indentifyChest(chest);
|
||||
}
|
||||
|
||||
chests.put(loc, chest);
|
||||
}
|
||||
else
|
||||
{
|
||||
checkForBats();
|
||||
}
|
||||
}
|
||||
|
||||
if (obj.getId() == RaidsThievingConstants.OPEN_FULL_CHEST_1 ||
|
||||
obj.getId() == RaidsThievingConstants.OPEN_FULL_CHEST_2)
|
||||
{
|
||||
ThievingChest chest = chests.get(obj.getWorldLocation());
|
||||
// We found a chest that has grubs
|
||||
log.info(MessageFormat.format("Found grubs at {0}, {1} chestId: {2}", loc.getX(), loc.getY(), chest.getChestId()));
|
||||
if (solver != null && chest.getChestId() != -1)
|
||||
{
|
||||
chest.setEverOpened(true);
|
||||
solver.addGrubsChest(chest.getChestId());
|
||||
}
|
||||
checkForBats();
|
||||
}
|
||||
|
||||
if (obj.getId() == RaidsThievingConstants.OPEN_EMPTY_CHEST)
|
||||
{
|
||||
ThievingChest chest = chests.get(obj.getWorldLocation());
|
||||
// We found a chest that could have poison
|
||||
if (solver != null && chest.getChestId() != -1)
|
||||
{
|
||||
chest.setEmpty(true);
|
||||
chest.setEverOpened(true);
|
||||
solver.addEmptyChest(chest.getChestId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Subscribe
|
||||
public void onGraphicsObjectCreated(GraphicsObjectCreated event)
|
||||
{
|
||||
GraphicsObject obj = event.getGraphicsObject();
|
||||
if (obj.getId() == 184)
|
||||
{
|
||||
log.debug("Found poison splat");
|
||||
WorldPoint loc = WorldPoint.fromLocal(client, obj.getLocation());
|
||||
chests.get(loc).setPoison(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onVarbitChanged(VarbitChanged event)
|
||||
{
|
||||
boolean setting = client.getVar(Varbits.IN_RAID) == 1;
|
||||
|
||||
if (inRaidChambers != setting)
|
||||
{
|
||||
inRaidChambers = setting;
|
||||
reset();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onConfigChanged(ConfigChanged event)
|
||||
{
|
||||
if (event.getGroup().equals("raidsthievingplugin"))
|
||||
{
|
||||
overlay.updateConfig();
|
||||
}
|
||||
}
|
||||
|
||||
private void reset()
|
||||
{
|
||||
chests.clear();
|
||||
batsFound = false;
|
||||
solver = null;
|
||||
mapper = null;
|
||||
}
|
||||
|
||||
public int numberOfEmptyChestsFound()
|
||||
{
|
||||
int total = 0;
|
||||
for (ThievingChest chest : chests.values())
|
||||
{
|
||||
if (chest.isEmpty())
|
||||
{
|
||||
total++;
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
|
||||
private boolean checkForBats()
|
||||
{
|
||||
for (ThievingChest chest : chests.values())
|
||||
{
|
||||
if (chest.isEmpty() && !chest.isPoison())
|
||||
{
|
||||
batsFound = true;
|
||||
if (config.batFoundNotify())
|
||||
{
|
||||
notifier.notify("Bats have been found!");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getChestId(WorldPoint worldPoint)
|
||||
{
|
||||
return chests.get(worldPoint).getChestId();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Tim Lehner <Timothy.Lehner.2011@live.rhul.ac.uk>
|
||||
* 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.raidsthieving;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.runelite.api.GameObject;
|
||||
import net.runelite.api.coords.WorldPoint;
|
||||
|
||||
/**
|
||||
* Wrapper class for a GameObject that represents a chest in the thieving room of Chambers of Xeric.
|
||||
*/
|
||||
@Getter
|
||||
public class ThievingChest
|
||||
{
|
||||
/**
|
||||
* If the chest has never been opened, it could have bats.
|
||||
*/
|
||||
@Setter
|
||||
private boolean everOpened;
|
||||
|
||||
/**
|
||||
* If the chest is empty, it could have bats.
|
||||
*/
|
||||
@Setter
|
||||
private boolean empty;
|
||||
|
||||
/**
|
||||
* If the chest contains a poison trap instead.
|
||||
*/
|
||||
@Setter
|
||||
private boolean poison;
|
||||
|
||||
|
||||
@Setter
|
||||
private int chestId;
|
||||
|
||||
private final WorldPoint localPoint;
|
||||
private final InstancePoint instancePoint;
|
||||
|
||||
/**
|
||||
* Constructor for a ThievingChest object
|
||||
*
|
||||
* @param gameObject The gameobject thats corresponds with this trap.
|
||||
*/
|
||||
ThievingChest(GameObject gameObject, InstancePoint instancePoint)
|
||||
{
|
||||
this.everOpened = false;
|
||||
this.poison = false;
|
||||
this.empty = false;
|
||||
localPoint = gameObject.getWorldLocation();
|
||||
this.instancePoint = instancePoint;
|
||||
this.chestId = -1;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -45,6 +45,7 @@ import net.runelite.client.plugins.PluginDescriptor;
|
||||
@PluginDescriptor(
|
||||
name = "!Remember Clan",
|
||||
description = "Remember a specific clan!",
|
||||
type = "utility",
|
||||
enabledByDefault = false
|
||||
)
|
||||
public class RememberClanPlugin extends Plugin
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package net.runelite.client.plugins.safespot;
|
||||
|
||||
import java.awt.Color;
|
||||
import net.runelite.client.config.ConfigItem;
|
||||
import net.runelite.client.config.ConfigGroup;
|
||||
import net.runelite.client.config.Config;
|
||||
|
||||
@ConfigGroup("safespot")
|
||||
public interface SafeSpotConfig extends Config
|
||||
{
|
||||
@ConfigItem(position = 1, keyName = "playerSafeSpots", name = "Render for Players", description = "Renders 1 way safe spots vs other players")
|
||||
default boolean playerSafeSpots() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ConfigItem(position = 2, keyName = "npcSafeSpots", name = "Render for NPCs", description = "Renders 1 way safe spots vs NPCs")
|
||||
default boolean npcSafeSpots() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ConfigItem(position = 3, keyName = "tileColor", name = "Tile Color", description = "Color of safe spot tile")
|
||||
default Color tileColor() {
|
||||
return Color.MAGENTA;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package net.runelite.client.plugins.safespot;
|
||||
|
||||
import javax.inject.*;
|
||||
import net.runelite.client.ui.overlay.*;
|
||||
import java.awt.*;
|
||||
import net.runelite.api.*;
|
||||
|
||||
public class SafeSpotOverlay extends Overlay
|
||||
{
|
||||
private final Client client;
|
||||
private final SafeSpotPlugin safeSpotPlugin;
|
||||
private final SafeSpotConfig config;
|
||||
|
||||
@Inject
|
||||
public SafeSpotOverlay( Client client, SafeSpotPlugin safeSpotPlugin, SafeSpotConfig config) {
|
||||
this.client = client;
|
||||
this.safeSpotPlugin = safeSpotPlugin;
|
||||
this.config = config;
|
||||
this.setPosition(OverlayPosition.DYNAMIC);
|
||||
this.setPriority(OverlayPriority.LOW);
|
||||
this.setLayer(OverlayLayer.ABOVE_SCENE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension render(Graphics2D graphics) {
|
||||
if (safeSpotPlugin.isSafeSpotsRenderable() && safeSpotPlugin.getSafeSpotList() != null && safeSpotPlugin.getSafeSpotList().size() > 0) {
|
||||
safeSpotPlugin.getSafeSpotList().forEach(tile -> {
|
||||
Polygon poly;
|
||||
if (tile != null && tile.getLocalLocation() != null) {
|
||||
poly = Perspective.getCanvasTilePoly(client, tile.getLocalLocation());
|
||||
if (poly != null) {
|
||||
OverlayUtil.renderPolygon(graphics, poly, config.tileColor());
|
||||
}
|
||||
}
|
||||
return;
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
package net.runelite.client.plugins.safespot;
|
||||
|
||||
|
||||
import net.runelite.api.coords.LocalPoint;
|
||||
import net.runelite.api.coords.WorldPoint;
|
||||
import java.util.List;
|
||||
import net.runelite.api.Actor;
|
||||
import net.runelite.api.coords.WorldArea;
|
||||
import net.runelite.api.NPC;
|
||||
import net.runelite.api.Player;
|
||||
import net.runelite.api.events.GameTick;
|
||||
import net.runelite.client.eventbus.Subscribe;
|
||||
import net.runelite.api.events.InteractingChanged;
|
||||
import com.google.inject.Provides;
|
||||
import net.runelite.client.config.ConfigManager;
|
||||
import net.runelite.api.Tile;
|
||||
import java.util.ArrayList;
|
||||
import net.runelite.client.ui.overlay.OverlayManager;
|
||||
import javax.inject.Inject;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.client.plugins.PluginDescriptor;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
|
||||
@PluginDescriptor(
|
||||
name = "1 Way Safe Spots",
|
||||
description = "Renders tile overlays for one way safe spots",
|
||||
tags = { "safe spot", "pvp", "safespots", "pklite" },
|
||||
type = "PVP",
|
||||
enabledByDefault = false
|
||||
)
|
||||
|
||||
// TODO : filter tiles you cant stand on
|
||||
|
||||
public class SafeSpotPlugin extends Plugin
|
||||
{
|
||||
@Inject
|
||||
private Client client;
|
||||
@Inject
|
||||
OverlayManager overlayManager;
|
||||
@Inject
|
||||
private SafeSpotConfig config;
|
||||
private ArrayList<Tile> safeSpotList;
|
||||
private boolean safeSpotsRenderable;
|
||||
private SafeSpotOverlay safeSpotOverlay;
|
||||
private int tickCount;
|
||||
|
||||
public SafeSpotPlugin() {
|
||||
this.safeSpotsRenderable = false;
|
||||
this.tickCount = 0;
|
||||
}
|
||||
|
||||
@Provides
|
||||
SafeSpotConfig config(ConfigManager configManager) {
|
||||
return configManager.getConfig(SafeSpotConfig.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startUp() throws Exception {
|
||||
this.safeSpotOverlay = new SafeSpotOverlay(this.client, this, this.config);
|
||||
this.overlayManager.add(safeSpotOverlay);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void shutDown() throws Exception {
|
||||
this.overlayManager.remove(safeSpotOverlay);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
private void onInteractingChanged(InteractingChanged event) {
|
||||
if (event.getSource() != client.getLocalPlayer()) {
|
||||
return;
|
||||
}
|
||||
if (event.getTarget() == null && (config.npcSafeSpots() || config.playerSafeSpots())) {
|
||||
tickCount = 10;
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onGameTick(GameTick event) {
|
||||
if (client.getLocalPlayer().getInteracting() != null) {
|
||||
if (client.getLocalPlayer().getInteracting() instanceof Player && config.playerSafeSpots()) {
|
||||
safeSpotsRenderable = true;
|
||||
updateSafeSpots();
|
||||
}
|
||||
if (client.getLocalPlayer().getInteracting() instanceof NPC && config.npcSafeSpots()) {
|
||||
safeSpotsRenderable = true;
|
||||
updateSafeSpots();
|
||||
}
|
||||
}
|
||||
else {
|
||||
safeSpotsRenderable = false;
|
||||
}
|
||||
if (tickCount > 0) {
|
||||
--tickCount;
|
||||
safeSpotsRenderable = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateSafeSpots()
|
||||
{
|
||||
if (client.getLocalPlayer().getInteracting() != null)
|
||||
{
|
||||
Actor enemy = client.getLocalPlayer().getInteracting();
|
||||
|
||||
WorldArea worldArea = new WorldArea(enemy.getWorldLocation().getX() - 12, enemy.getWorldLocation().getY() - 12, 24, 24, client.getPlane());
|
||||
List<WorldPoint> worldPoints = worldArea.toWorldPointList();
|
||||
safeSpotList = getSafeSpotList(enemy, worldPoints);
|
||||
}
|
||||
}
|
||||
|
||||
private ArrayList<Tile> getSafeSpotList(Actor actor, List<WorldPoint> worldPoints)
|
||||
{
|
||||
ArrayList<Tile> safeSpotList = new ArrayList();
|
||||
Tile[][][] tiles = client.getScene().getTiles();
|
||||
for (WorldPoint w : worldPoints)
|
||||
{
|
||||
LocalPoint toPoint = LocalPoint.fromWorld(client, w);
|
||||
Tile fromTile = tiles[client.getPlane()][actor.getLocalLocation().getSceneX()][actor.getLocalLocation().getSceneY()];
|
||||
Tile toTile = tiles[client.getPlane()][toPoint.getSceneX()][toPoint.getSceneY()];
|
||||
if ((toTile.hasLineOfSightTo(fromTile)) && (!fromTile.hasLineOfSightTo(toTile)))
|
||||
{
|
||||
safeSpotList.add(toTile);
|
||||
}
|
||||
}
|
||||
return safeSpotList;
|
||||
}
|
||||
|
||||
public ArrayList<Tile> getSafeSpotList() {
|
||||
return safeSpotList;
|
||||
}
|
||||
|
||||
public boolean isSafeSpotsRenderable() {
|
||||
return safeSpotsRenderable;
|
||||
}
|
||||
}
|
||||
@@ -43,6 +43,7 @@ import java.awt.Color;
|
||||
name = "!Stronghold",
|
||||
description = "Highlights the correct answer to Stronghold of Security questions",
|
||||
tags = {"stronghold", "security", "overlay", "answer", "highlight"}
|
||||
type = "utility",
|
||||
)
|
||||
@Slf4j
|
||||
public class StrongholdPlugin extends Plugin {
|
||||
|
||||
@@ -57,6 +57,7 @@ import net.runelite.client.ui.overlay.OverlayManager;
|
||||
name = "<font color=\"aqua\">!War</font>",
|
||||
description = "War War War.",
|
||||
tags = {"skill", "total", "max", "PVP"},
|
||||
type = "PVP",
|
||||
enabledByDefault = false
|
||||
)
|
||||
public class WarIndicatorPlugin extends Plugin
|
||||
|
||||
@@ -55,6 +55,7 @@ import net.runelite.client.ui.overlay.OverlayManager;
|
||||
name = "<font color=\"aqua\">!MultiLines</font>",
|
||||
description = "Show borders of multicombat and PvP safezones",
|
||||
tags = {"multicombat", "lines", "pvp", "deadman", "safezones", "bogla"},
|
||||
type = "utility",
|
||||
enabledByDefault = false
|
||||
)
|
||||
public class ZoneIndicatorsPlugin extends Plugin
|
||||
|
||||
Reference in New Issue
Block a user