runecraft: add essence pouch

runecraft: add essence pouch

original code:
https://github.com/Adam-/runelite-plugins/blob/esspouch
This commit is contained in:
xKylee
2020-01-13 23:00:53 +00:00
parent 63b98542a8
commit 1fde1726e1
5 changed files with 480 additions and 30 deletions

View File

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

View File

@@ -0,0 +1,68 @@
/*
* Copyright (c) 2019 Hydrox6 <ikada@protonmail.ch>
* Copyright (c) 2019 Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.runecraft;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import javax.inject.Inject;
import net.runelite.api.widgets.WidgetItem;
import net.runelite.client.ui.overlay.WidgetItemOverlay;
import net.runelite.client.ui.overlay.components.TextComponent;
class EssencePouchOverlay extends WidgetItemOverlay
{
@Inject
EssencePouchOverlay()
{
showOnInventory();
}
@Override
public void renderItemOverlay(Graphics2D graphics, int itemId, WidgetItem itemWidget)
{
final Pouch pouch = Pouch.forItem(itemId);
if (pouch == null)
{
return;
}
final Rectangle bounds = itemWidget.getCanvasBounds();
final TextComponent textComponent = new TextComponent();
textComponent.setPosition(new Point(bounds.x - 1, bounds.y + 8));
textComponent.setColor(Color.CYAN);
if (pouch.isUnknown())
{
textComponent.setText("?");
}
else
{
textComponent.setText(Integer.toString(pouch.getHolding()));
}
textComponent.render(graphics);
}
}

View File

@@ -0,0 +1,118 @@
/*
* Copyright (c) 2019 Hydrox6 <ikada@protonmail.ch>
* Copyright (c) 2019 Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.runecraft;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import net.runelite.api.ItemID;
enum Pouch
{
SMALL(3),
MEDIUM(6, 3),
LARGE(9, 7),
GIANT(12, 9);
private final int baseHoldAmount;
private final int degradedBaseHoldAmount;
@Getter(AccessLevel.PACKAGE)
@Setter(AccessLevel.PACKAGE)
private int holding;
@Getter(AccessLevel.PACKAGE)
private boolean degraded;
@Getter(AccessLevel.PACKAGE)
@Setter(AccessLevel.PACKAGE)
private boolean unknown = true;
Pouch(int holdAmount)
{
this(holdAmount, -1);
}
Pouch(int holdAmount, int degradedHoldAmount)
{
this.baseHoldAmount = holdAmount;
this.degradedBaseHoldAmount = degradedHoldAmount;
}
static Pouch forItem(int itemId)
{
switch (itemId)
{
case ItemID.SMALL_POUCH:
return SMALL;
case ItemID.MEDIUM_POUCH:
case ItemID.MEDIUM_POUCH_5511:
return MEDIUM;
case ItemID.LARGE_POUCH:
case ItemID.LARGE_POUCH_5513:
return LARGE;
case ItemID.GIANT_POUCH:
case ItemID.GIANT_POUCH_5515:
return GIANT;
default:
return null;
}
}
int getHoldAmount()
{
return degraded ? degradedBaseHoldAmount : baseHoldAmount;
}
int getRemaining()
{
final int holdAmount = degraded ? degradedBaseHoldAmount : baseHoldAmount;
return holdAmount - holding;
}
void addHolding(int delta)
{
holding += delta;
final int holdAmount = degraded ? degradedBaseHoldAmount : baseHoldAmount;
if (holding < 0)
{
holding = 0;
}
if (holding > holdAmount)
{
holding = holdAmount;
}
}
void degrade(boolean state)
{
if (state != degraded)
{
degraded = state;
final int holdAmount = degraded ? degradedBaseHoldAmount : baseHoldAmount;
holding = Math.min(holding, holdAmount);
}
}
}

View File

@@ -107,6 +107,18 @@ public interface RunecraftConfig extends Config
return true;
}
@ConfigItem(
keyName = "essenceOverlay",
name = "Show number of essence in pouch",
description = "This will show how many essence in your pouch.",
position = 7,
titleSection = "utilTitle"
)
default boolean essenceOverlay()
{
return true;
}
@ConfigTitleSection(
keyName = "riftsTitle",
name = "Rifts",

View File

@@ -24,10 +24,16 @@
*/
package net.runelite.client.plugins.runecraft;
import static java.lang.Math.min;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Provides;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.AccessLevel;
@@ -50,6 +56,7 @@ import net.runelite.api.events.DecorativeObjectSpawned;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.GameTick;
import net.runelite.api.events.ItemContainerChanged;
import net.runelite.api.events.MenuOptionClicked;
import net.runelite.api.events.NpcDespawned;
import net.runelite.api.events.NpcSpawned;
import net.runelite.client.Notifier;
@@ -99,39 +106,52 @@ public class RunecraftPlugin extends Plugin
ItemID.LARGE_POUCH_5513,
ItemID.GIANT_POUCH_5515
);
private static final int INVENTORY_SIZE = 28;
private static final Pattern POUCH_CHECK_MESSAGE = Pattern.compile("^There (?:is|are) ([a-z]+)(?: pure)? essences? in this pouch\\.$");
private static final ImmutableMap<String, Integer> TEXT_TO_NUMBER = ImmutableMap.<String, Integer>builder()
.put("no", 0)
.put("one", 1)
.put("two", 2)
.put("three", 3)
.put("four", 4)
.put("five", 5)
.put("six", 6)
.put("seven", 7)
.put("eight", 8)
.put("nine", 9)
.put("ten", 10)
.put("eleven", 11)
.put("twelve", 12)
.build();
@Inject
private Client client;
@Inject
private OverlayManager overlayManager;
@Inject
private AbyssOverlay abyssOverlay;
@Inject
private AbyssMinimapOverlay abyssMinimapOverlay;
@Inject
private RunecraftOverlay runecraftOverlay;
@Inject
private PouchOverlay pouchOverlay;
@Inject
private RunecraftConfig config;
@Inject
private Notifier notifier;
@Inject
private MenuManager menuManager;
@Inject
private EventBus eventBus;
private final Deque<ClickOperation> clickedItems = new ArrayDeque<>();
private final Deque<ClickOperation> checkedPouches = new ArrayDeque<>();
private final Set<AbyssRifts> rifts = new HashSet<>();
private final Set<DecorativeObject> abyssObjects = new HashSet<>();
private int lastEssence;
private int lastSpace;
@Inject
private Client client;
@Inject
private OverlayManager overlayManager;
@Inject
private AbyssOverlay abyssOverlay;
@Inject
private AbyssMinimapOverlay abyssMinimapOverlay;
@Inject
private RunecraftOverlay runecraftOverlay;
@Inject
private EssencePouchOverlay essencePouchOverlay;
@Inject
private PouchOverlay pouchOverlay;
@Inject
private RunecraftConfig config;
@Inject
private Notifier notifier;
@Inject
private MenuManager menuManager;
@Inject
private EventBus eventBus;
private boolean degradedPouchInInventory;
private boolean degradingNotification;
private boolean essPouch;
@@ -140,6 +160,7 @@ public class RunecraftPlugin extends Plugin
private boolean showClickBox;
private boolean showRifts;
private boolean degradeOverlay;
private boolean essenceOverlay;
private boolean medDegrade;
private boolean largeDegrade;
private boolean giantDegrade;
@@ -162,7 +183,17 @@ public class RunecraftPlugin extends Plugin
overlayManager.add(abyssOverlay);
overlayManager.add(abyssMinimapOverlay);
overlayManager.add(runecraftOverlay);
overlayManager.add(essencePouchOverlay);
handleSwaps();
for (Pouch pouch : Pouch.values())
{
pouch.setHolding(0);
pouch.setUnknown(true);
pouch.degrade(false);
}
lastEssence = lastSpace = -1;
}
@Override
@@ -174,6 +205,7 @@ public class RunecraftPlugin extends Plugin
overlayManager.remove(abyssOverlay);
overlayManager.remove(abyssMinimapOverlay);
overlayManager.remove(runecraftOverlay);
overlayManager.remove(essencePouchOverlay);
removeSwaps();
}
@@ -256,6 +288,153 @@ public class RunecraftPlugin extends Plugin
}
}
}
if (InventoryID.INVENTORY.getId() != event.getContainerId())
{
return;
}
final Item[] items = event.getItemContainer().getItems();
int newEss = 0;
int newSpace = 0;
// Count ess/space, and change pouch states
for (Item item : items)
{
switch (item.getId())
{
case ItemID.PURE_ESSENCE:
newEss += 1;
break;
case -1:
newSpace += 1;
break;
case ItemID.MEDIUM_POUCH:
case ItemID.LARGE_POUCH:
case ItemID.GIANT_POUCH:
Pouch pouch = Pouch.forItem(item.getId());
pouch.degrade(false);
break;
case ItemID.MEDIUM_POUCH_5511:
case ItemID.LARGE_POUCH_5513:
case ItemID.GIANT_POUCH_5515:
pouch = Pouch.forItem(item.getId());
pouch.degrade(true);
break;
}
}
if (items.length < INVENTORY_SIZE)
{
// Pad newSpace for unallocated inventory slots
newSpace += INVENTORY_SIZE - items.length;
}
if (clickedItems.isEmpty())
{
lastSpace = newSpace;
lastEssence = newEss;
return;
}
if (lastEssence == -1 || lastSpace == -1)
{
lastSpace = newSpace;
lastEssence = newEss;
clickedItems.clear();
return;
}
final int tick = client.getTickCount();
int essence = lastEssence;
int space = lastSpace;
while (essence != newEss)
{
ClickOperation op = clickedItems.poll();
if (op == null)
{
break;
}
if (tick > op.tick)
{
continue;
}
Pouch pouch = op.pouch;
final boolean fill = op.delta > 0;
// How much ess can either be deposited or withdrawn
final int required = fill ? pouch.getRemaining() : pouch.getHolding();
// Bound to how much ess or free space we actually have, and optionally negate
final int essenceGot = op.delta * min(required, fill ? essence : space);
// if we have enough essence or space to fill or empty the entire pouch, it no
// longer becomes unknown
if (pouch.isUnknown() && (fill ? essence : space) >= pouch.getHoldAmount())
{
pouch.setUnknown(false);
}
essence -= essenceGot;
space += essenceGot;
pouch.addHolding(essenceGot);
}
if (!clickedItems.isEmpty())
{
return;
}
lastSpace = newSpace;
lastEssence = newEss;
}
@Subscribe
public void onMenuOptionClicked(MenuOptionClicked event)
{
switch (event.getMenuOpcode())
{
case ITEM_FIRST_OPTION:
case ITEM_SECOND_OPTION:
case ITEM_THIRD_OPTION:
case ITEM_FOURTH_OPTION:
case ITEM_FIFTH_OPTION:
case GROUND_ITEM_THIRD_OPTION: // Take
break;
default:
return;
}
final int id = event.getIdentifier();
final Pouch pouch = Pouch.forItem(id);
if (pouch == null)
{
return;
}
final int tick = client.getTickCount() + 3;
switch (event.getOption())
{
case "Fill":
clickedItems.add(new ClickOperation(pouch, tick, 1));
break;
case "Empty":
clickedItems.add(new ClickOperation(pouch, tick, -1));
break;
case "Check":
checkedPouches.add(new ClickOperation(pouch, tick));
break;
case "Take":
// Dropping pouches clears them, so clear when picked up
pouch.setHolding(0);
break;
}
}
@Subscribe
@@ -287,6 +466,28 @@ public class RunecraftPlugin extends Plugin
{
notifier.notify(POUCH_DECAYED_NOTIFICATION_MESSAGE);
}
if (!checkedPouches.isEmpty())
{
Matcher matcher = POUCH_CHECK_MESSAGE.matcher(event.getMessage());
if (matcher.matches())
{
final int num = TEXT_TO_NUMBER.get(matcher.group(1));
// Keep getting operations until we get a valid one
do
{
final ClickOperation op = checkedPouches.pop();
if (op.tick >= client.getTickCount())
{
Pouch pouch = op.pouch;
pouch.setHolding(num);
pouch.setUnknown(false);
break;
}
}
while (!checkedPouches.isEmpty());
}
}
}
@Subscribe
@@ -414,6 +615,16 @@ public class RunecraftPlugin extends Plugin
this.showRifts = config.showRifts();
this.showClickBox = config.showClickBox();
this.degradeOverlay = config.degradeOverlay();
this.essenceOverlay = config.essenceOverlay();
if (this.essenceOverlay)
{
overlayManager.add(essencePouchOverlay);
}
else
{
overlayManager.remove(essencePouchOverlay);
}
if (this.degradeOverlay)
{