Skip to content

Commit

Permalink
Merge pull request runelite#11420 from while-loop/loottracker-clue-sc…
Browse files Browse the repository at this point in the history
…roll

loot-tracker: make clue scroll drops stackable
  • Loading branch information
deathbeam authored May 3, 2020
2 parents 1da967f + e5a7f9a commit c2d855d
Show file tree
Hide file tree
Showing 3 changed files with 232 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* Copyright (c) 2020, Anthony <https://github.com/while-loop>
* 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.loottracker;

import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import lombok.Getter;
import net.runelite.api.ItemComposition;
import net.runelite.api.ItemID;
import net.runelite.client.game.ItemManager;
import net.runelite.client.game.ItemStack;

@Getter
public enum LootTrackerMapping
{
CLUE_SCROLL_BEGINNER("Clue scroll (beginner)", ItemID.CLUE_SCROLL_BEGINNER),
CLUE_SCROLL_EASY("Clue scroll (easy)", ItemID.CLUE_SCROLL_EASY),
CLUE_SCROLL_MEDIUM("Clue scroll (medium)", ItemID.CLUE_SCROLL_MEDIUM),
CLUE_SCROLL_HARD("Clue scroll (hard)", ItemID.CLUE_SCROLL_HARD),
CLUE_SCROLL_ELITE("Clue scroll (elite)", ItemID.CLUE_SCROLL_ELITE),
CLUE_SCROLL_MASTER("Clue scroll (master)", ItemID.CLUE_SCROLL_MASTER);

private final String name;
private final int baseId;

LootTrackerMapping(String name, int baseId)
{
this.name = name;
this.baseId = baseId;
}

private static final ImmutableMap<String, LootTrackerMapping> MAPPINGS;

static
{
ImmutableMap.Builder<String, LootTrackerMapping> map = ImmutableMap.builder();
for (LootTrackerMapping mapping : values())
{
map.put(mapping.name, mapping);
}
MAPPINGS = map.build();
}

public static int map(int itemId, ItemManager itemManager)
{
ItemComposition itemComp = itemManager.getItemComposition(itemId);
if (itemComp == null || Strings.isNullOrEmpty(itemComp.getName()))
{
return itemId;
}

if (!MAPPINGS.containsKey(itemComp.getName()))
{
return itemId;
}

return MAPPINGS.get(itemComp.getName()).baseId;
}

public static ItemStack map(ItemStack item, ItemManager itemManager)
{
int baseId = map(item.getId(), itemManager);
if (baseId == item.getId())
{
return item;
}

return new ItemStack(baseId, item.getQuantity(), item.getLocation());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -207,12 +207,14 @@ public class LootTrackerPlugin extends Plugin
private LootTrackerClient lootTrackerClient;
private final List<LootRecord> queuedLoots = new ArrayList<>();

private static Collection<ItemStack> stack(Collection<ItemStack> items)
@VisibleForTesting
Collection<ItemStack> stack(Collection<ItemStack> items)
{
final List<ItemStack> list = new ArrayList<>();

for (final ItemStack item : items)
for (ItemStack item : items)
{
item = LootTrackerMapping.map(item, itemManager);
int quantity = 0;
for (final ItemStack i : list)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,14 @@
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
import javax.inject.Inject;
import lombok.AllArgsConstructor;
import net.runelite.api.ChatMessageType;
import net.runelite.api.Client;
import net.runelite.api.ItemComposition;
import net.runelite.api.ItemID;
import net.runelite.api.IterableHashTable;
import net.runelite.api.MessageNode;
Expand All @@ -52,6 +55,7 @@
import net.runelite.http.api.loottracker.LootRecordType;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
Expand All @@ -64,6 +68,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;

@RunWith(MockitoJUnitRunner.class)
public class LootTrackerPluginTest
Expand Down Expand Up @@ -145,6 +150,137 @@ public void testFirstClue()
assertEquals(LootRecordType.EVENT, lootTrackerPlugin.lootRecordType);
}

private static ItemStack is(int id, int q)
{
return new ItemStack(id, q, null);
}

@Test
public void testClueStacks()
{
String beg = "Clue scroll (beginner)";
String easy = "Clue scroll (easy)";
String med = "Clue scroll (medium)";
String hard = "Clue scroll (hard)";
String elite = "Clue scroll (elite)";
String master = "Clue scroll (master)";
Map<Integer, String> idsToName = ImmutableMap.<Integer, String>builder()
.put(ItemID.CLUE_SCROLL_BEGINNER, beg)
.put(ItemID.CLUE_SCROLL_EASY, easy)
.put(ItemID.CLUE_SCROLL_EASY_2719, easy)
.put(ItemID.CLUE_SCROLL_EASY_23153, easy)
.put(ItemID.CLUE_SCROLL_MEDIUM, med)
.put(ItemID.CLUE_SCROLL_MEDIUM_3599, med)
.put(ItemID.CLUE_SCROLL_MEDIUM_2817, med)
.put(ItemID.CLUE_SCROLL_MEDIUM_3602, med)
.put(ItemID.CLUE_SCROLL_MEDIUM_12045, med)
.put(ItemID.CLUE_SCROLL_MEDIUM_12065, med)
.put(ItemID.CLUE_SCROLL_HARD, hard)
.put(ItemID.CLUE_SCROLL_HARD_3520, hard)
.put(ItemID.CLUE_SCROLL_HARD_3550, hard)
.put(ItemID.CLUE_SCROLL_HARD_23045, hard)
.put(ItemID.CLUE_SCROLL_ELITE, elite)
.put(ItemID.CLUE_SCROLL_ELITE_19783, elite)
.put(ItemID.CLUE_SCROLL_ELITE_21524, elite)
.put(ItemID.CLUE_SCROLL_ELITE_12096, elite)
.put(ItemID.CLUE_SCROLL_MASTER, master)
.put(ItemID.RUNE_PLATEBODY, "Rune platebody")
.put(ItemID.AMETHYST_ARROW, "Amethyst arrow")
.put(ItemID.GRACEFUL_HOOD_13579, "Graceful hood")
.put(ItemID.RUNITE_ORE, "Runite ore")
.put(ItemID.RUNITE_ORE + 1, "Runite ore")
.put(0, "null")
.build();

@AllArgsConstructor
class Case
{
private final List<ItemStack> drops;
private final List<ItemStack> expected;
}

Case[] cases = {
new Case(
Arrays.asList(
is(ItemID.CLUE_SCROLL_MEDIUM, 1),
is(ItemID.CLUE_SCROLL_MEDIUM_3602, 1)),
Collections.singletonList(
is(ItemID.CLUE_SCROLL_MEDIUM, 2))
),
new Case(
Arrays.asList(
// graceful isn't a drop, but it is an item w/ variations that we're not tracking.
is(ItemID.GRACEFUL_HOOD_13579, 1),
is(ItemID.RUNE_PLATEBODY, 1),
is(ItemID.AMETHYST_ARROW, 125)),
Arrays.asList(
is(ItemID.GRACEFUL_HOOD_13579, 1),
is(ItemID.RUNE_PLATEBODY, 1),
is(ItemID.AMETHYST_ARROW, 125))
),
new Case(
Arrays.asList(
is(ItemID.CLUE_SCROLL_BEGINNER, 1),
is(ItemID.CLUE_SCROLL_ELITE_19783, 1),
is(ItemID.CLUE_SCROLL_MEDIUM_12045, 1),
is(ItemID.CLUE_SCROLL_MEDIUM_12065, 1),
is(ItemID.RUNITE_ORE, 25),
is(ItemID.RUNITE_ORE + 1, 10)), // noted rune ore
Arrays.asList(
is(ItemID.CLUE_SCROLL_BEGINNER, 1),
is(ItemID.CLUE_SCROLL_ELITE, 1),
is(ItemID.CLUE_SCROLL_MEDIUM, 2),
is(ItemID.RUNITE_ORE, 25),
is(ItemID.RUNITE_ORE + 1, 10)) // noted rune ore
),
new Case(
Arrays.asList(
is(ItemID.CLUE_SCROLL_BEGINNER, 1),
is(ItemID.CLUE_SCROLL_BEGINNER, 1),
is(ItemID.CLUE_SCROLL_EASY, 1),
is(ItemID.CLUE_SCROLL_EASY_2719, 1),
is(ItemID.CLUE_SCROLL_EASY_23153, 1),
is(ItemID.CLUE_SCROLL_MEDIUM, 1),
is(ItemID.CLUE_SCROLL_MEDIUM_12065, 1),
is(ItemID.CLUE_SCROLL_MEDIUM_2817, 1),
is(ItemID.CLUE_SCROLL_HARD, 1),
is(ItemID.CLUE_SCROLL_HARD_3550, 1),
is(ItemID.CLUE_SCROLL_HARD_23045, 1),
is(ItemID.CLUE_SCROLL_ELITE, 1),
is(ItemID.CLUE_SCROLL_ELITE_21524, 1),
is(ItemID.CLUE_SCROLL_ELITE_12096, 1),
is(ItemID.CLUE_SCROLL_MASTER, 1),
is(ItemID.CLUE_SCROLL_MASTER, 1)),
Arrays.asList(
is(ItemID.CLUE_SCROLL_BEGINNER, 2),
is(ItemID.CLUE_SCROLL_EASY, 3),
is(ItemID.CLUE_SCROLL_MEDIUM, 3),
is(ItemID.CLUE_SCROLL_HARD, 3),
is(ItemID.CLUE_SCROLL_ELITE, 3),
is(ItemID.CLUE_SCROLL_MASTER, 2))
),
};

for (int i = 0; i < cases.length; i++)
{
Case tc = cases[i];
when(itemManager.getItemComposition(anyInt())).thenAnswer((Answer<ItemComposition>) invocationOnMock ->
{
int itemId = invocationOnMock.getArgument(0);
if (!idsToName.containsKey(itemId))
{
fail("item id not in names map: " + itemId);
}

ItemComposition c = mock(ItemComposition.class);
when(c.getName()).thenReturn(idsToName.get(itemId));
return c;
});

assertEquals("Test case: " + (i + 1), tc.expected, lootTrackerPlugin.stack(tc.drops));
}
}

@Test
public void testHerbiboarHerbSack()
{
Expand Down

0 comments on commit c2d855d

Please sign in to comment.