loottracker: Track herbiboar loot with an open herb sack
When looting the herbiboar with an open herb sack, instead of receiving the herbs to your inventory, the herbs are deposited to the sack directly and the player receives chat messages indicating the herbs they received. This commit adds support for reading those chat messages when looting the herbiboar. This change incidentally fixes an issue which arose when the open herb sack was introduced to the game where any inventory change after looting the herbiboar would be tracked as herbiboar loot, such as drinking a stamina potion. Closes #10655 Fixes #10718
This commit is contained in:
@@ -63,6 +63,7 @@ import net.runelite.api.GameState;
|
||||
import net.runelite.api.InventoryID;
|
||||
import net.runelite.api.ItemComposition;
|
||||
import net.runelite.api.ItemContainer;
|
||||
import net.runelite.api.MessageNode;
|
||||
import net.runelite.api.NPC;
|
||||
import net.runelite.api.Player;
|
||||
import net.runelite.api.SpriteID;
|
||||
@@ -116,8 +117,10 @@ public class LootTrackerPlugin extends Plugin
|
||||
private static final int THEATRE_OF_BLOOD_REGION = 12867;
|
||||
|
||||
// Herbiboar loot handling
|
||||
private static final String HERBIBOAR_LOOTED_MESSAGE = "You harvest herbs from the herbiboar, whereupon it escapes.";
|
||||
@VisibleForTesting
|
||||
static final String HERBIBOAR_LOOTED_MESSAGE = "You harvest herbs from the herbiboar, whereupon it escapes.";
|
||||
private static final String HERBIBOAR_EVENT = "Herbiboar";
|
||||
private static final Pattern HERBIBOAR_HERB_SACK_PATTERN = Pattern.compile(".+(Grimy .+?) herb.+");
|
||||
|
||||
// Hespori loot handling
|
||||
private static final String HESPORI_LOOTED_MESSAGE = "You have successfully cleared this patch for new crops.";
|
||||
@@ -500,10 +503,14 @@ public class LootTrackerPlugin extends Plugin
|
||||
|
||||
if (message.equals(HERBIBOAR_LOOTED_MESSAGE))
|
||||
{
|
||||
if (processHerbiboarHerbSackLoot(event.getTimestamp()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
eventType = HERBIBOAR_EVENT;
|
||||
lootRecordType = LootRecordType.EVENT;
|
||||
takeInventorySnapshot();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -677,6 +684,34 @@ public class LootTrackerPlugin extends Plugin
|
||||
}
|
||||
}
|
||||
|
||||
private boolean processHerbiboarHerbSackLoot(int timestamp)
|
||||
{
|
||||
List<ItemStack> herbs = new ArrayList<>();
|
||||
|
||||
for (MessageNode messageNode : client.getMessages())
|
||||
{
|
||||
if (messageNode.getTimestamp() != timestamp
|
||||
|| messageNode.getType() != ChatMessageType.SPAM)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Matcher matcher = HERBIBOAR_HERB_SACK_PATTERN.matcher(messageNode.getValue());
|
||||
if (matcher.matches())
|
||||
{
|
||||
herbs.add(new ItemStack(itemManager.search(matcher.group(1)).get(0).getId(), 1, client.getLocalPlayer().getLocalLocation()));
|
||||
}
|
||||
}
|
||||
|
||||
if (herbs.isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
addLoot(HERBIBOAR_EVENT, -1, LootRecordType.EVENT, herbs);
|
||||
return true;
|
||||
}
|
||||
|
||||
void toggleItem(String name, boolean ignore)
|
||||
{
|
||||
final Set<String> ignoredItemSet = new HashSet<>(ignoredItems);
|
||||
|
||||
@@ -24,32 +24,66 @@
|
||||
*/
|
||||
package net.runelite.client.plugins.loottracker;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.testing.fieldbinder.Bind;
|
||||
import com.google.inject.testing.fieldbinder.BoundFieldModule;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import javax.inject.Inject;
|
||||
import net.runelite.api.ChatMessageType;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.ItemID;
|
||||
import net.runelite.api.IterableHashTable;
|
||||
import net.runelite.api.MessageNode;
|
||||
import net.runelite.api.Player;
|
||||
import net.runelite.api.coords.WorldPoint;
|
||||
import net.runelite.api.events.ChatMessage;
|
||||
import net.runelite.client.account.SessionManager;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.game.ItemStack;
|
||||
import net.runelite.client.game.SpriteManager;
|
||||
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
|
||||
import net.runelite.http.api.item.ItemPrice;
|
||||
import net.runelite.http.api.loottracker.LootRecordType;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import org.mockito.Mock;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class LootTrackerPluginTest
|
||||
{
|
||||
private static final Map<Integer, String> HERB_IDS_TO_NAMES = ImmutableMap.<Integer, String>builder()
|
||||
.put(ItemID.GRIMY_GUAM_LEAF, "Grimy guam leaf")
|
||||
.put(ItemID.GRIMY_MARRENTILL, "Grimy marrentill")
|
||||
.put(ItemID.GRIMY_TARROMIN, "Grimy tarromin")
|
||||
.put(ItemID.GRIMY_HARRALANDER, "Grimy harralander")
|
||||
.put(ItemID.GRIMY_RANARR_WEED, "Grimy ranarr weed")
|
||||
.put(ItemID.GRIMY_IRIT_LEAF, "Grimy irit leaf")
|
||||
.put(ItemID.GRIMY_AVANTOE, "Grimy avantoe")
|
||||
.put(ItemID.GRIMY_KWUARM, "Grimy kwuarm")
|
||||
.put(ItemID.GRIMY_SNAPDRAGON, "Grimy snapdragon")
|
||||
.put(ItemID.GRIMY_CADANTINE, "Grimy cadantine")
|
||||
.put(ItemID.GRIMY_LANTADYME, "Grimy lantadyme")
|
||||
.put(ItemID.GRIMY_DWARF_WEED, "Grimy dwarf weed")
|
||||
.put(ItemID.GRIMY_TORSTOL, "Grimy torstol")
|
||||
.build();
|
||||
|
||||
@Mock
|
||||
@Bind
|
||||
private ScheduledExecutorService scheduledExecutorService;
|
||||
@@ -77,6 +111,10 @@ public class LootTrackerPluginTest
|
||||
@Bind
|
||||
private SessionManager sessionManager;
|
||||
|
||||
@Mock
|
||||
@Bind
|
||||
private ItemManager itemManager;
|
||||
|
||||
@Before
|
||||
public void setUp()
|
||||
{
|
||||
@@ -106,4 +144,49 @@ public class LootTrackerPluginTest
|
||||
assertEquals("Clue Scroll (Master)", lootTrackerPlugin.eventType);
|
||||
assertEquals(LootRecordType.EVENT, lootTrackerPlugin.lootRecordType);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHerbiboarHerbSack()
|
||||
{
|
||||
for (Map.Entry<Integer, String> herb : HERB_IDS_TO_NAMES.entrySet())
|
||||
{
|
||||
final int id = herb.getKey();
|
||||
final String name = herb.getValue();
|
||||
final String herbMessage = String.format("You put the %s herb into your herb sack.", name);
|
||||
final String herbFullMessage = String.format("Your herb sack is too full to hold the %s herb.", name);
|
||||
|
||||
final ItemPrice herbPrice = new ItemPrice();
|
||||
herbPrice.setId(id);
|
||||
herbPrice.setName(name);
|
||||
when(itemManager.search(name)).thenReturn(Collections.singletonList(herbPrice));
|
||||
|
||||
MessageNode node = mock(MessageNode.class);
|
||||
when(node.getType()).thenReturn(ChatMessageType.SPAM);
|
||||
when(node.getValue()).thenReturn(herbMessage);
|
||||
|
||||
MessageNode nodeFull = mock(MessageNode.class);
|
||||
when(nodeFull.getType()).thenReturn(ChatMessageType.SPAM);
|
||||
when(nodeFull.getValue()).thenReturn(herbFullMessage);
|
||||
|
||||
IterableHashTable<MessageNode> messageTable = mock(IterableHashTable.class);
|
||||
Iterator<MessageNode> mockIterator = mock(Iterator.class);
|
||||
when(mockIterator.hasNext()).thenReturn(true, true, false);
|
||||
when(mockIterator.next()).thenReturn(node).thenReturn(nodeFull);
|
||||
when(messageTable.iterator()).thenReturn(mockIterator);
|
||||
when(client.getMessages()).thenReturn(messageTable);
|
||||
|
||||
LootTrackerPlugin lootTrackerPluginSpy = spy(this.lootTrackerPlugin);
|
||||
doNothing().when(lootTrackerPluginSpy).addLoot(any(), anyInt(), any(), any(Collection.class));
|
||||
|
||||
ChatMessage chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", LootTrackerPlugin.HERBIBOAR_LOOTED_MESSAGE, "", 0);
|
||||
lootTrackerPluginSpy.onChatMessage(chatMessage);
|
||||
|
||||
verify(lootTrackerPluginSpy).addLoot("Herbiboar", -1, LootRecordType.EVENT, Arrays.asList(
|
||||
new ItemStack(id, 1, null),
|
||||
new ItemStack(id, 1, null)
|
||||
));
|
||||
// Check the event type is null, which means the plugin isn't waiting on an inventory change event
|
||||
assertNull(lootTrackerPlugin.eventType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user