herbiboar: use guaranteed tracks when highlighting path

There's a set of guaranteed tracks that can be used when calculating the path
when tracking herbiboars. The tracks are listed on the osrs wiki.

Co-authored-by: Jordan Atwood <jordan.atwood423@gmail.com>
This commit is contained in:
dekvall
2019-12-26 05:34:04 +01:00
committed by Adam
parent 91ae43dd2d
commit 71e4b5d9ad
9 changed files with 641 additions and 295 deletions

View File

@@ -219,7 +219,14 @@ public enum Varbits
HB_TRAIL_31372(5750),
HB_FINISH(5766),
HB_STARTED(5767), //not working
/**
* Started hunting Herbiboar.
* <br>
* NOTE: This value remains at 0 even after starting a Herbiboar trail up until searching the first object along the
* hunting path.
*/
HB_STARTED(5767),
/**
* Barbarian Assault

View File

@@ -35,7 +35,7 @@ import net.runelite.client.ui.overlay.OverlayLayer;
import net.runelite.client.ui.overlay.OverlayPosition;
import net.runelite.client.ui.overlay.OverlayUtil;
public class HerbiboarMinimapOverlay extends Overlay
class HerbiboarMinimapOverlay extends Overlay
{
private final HerbiboarPlugin plugin;
private final HerbiboarConfig config;
@@ -52,29 +52,30 @@ public class HerbiboarMinimapOverlay extends Overlay
@Override
public Dimension render(Graphics2D graphics)
{
if (config.isTrailShown() && plugin.isInHerbiboarArea())
if (!config.isTrailShown() || !plugin.isInHerbiboarArea())
{
HerbiboarTrail currentTrail = plugin.getCurrentTrail();
int finishId = plugin.getFinishId();
Set<Integer> shownTrailIds = plugin.getShownTrails();
for (TileObject tileObject : plugin.getTrails().values())
{
int id = tileObject.getId();
Point minimapLocation = tileObject.getMinimapLocation();
if (minimapLocation == null)
{
continue;
}
if (shownTrailIds.contains(id) && (finishId > 0 || (currentTrail != null && currentTrail.getTrailId() != id && currentTrail.getTrailId() + 1 != id)))
{
OverlayUtil.renderMinimapLocation(graphics, minimapLocation, config.getTrailColor());
}
}
return null;
}
TrailToSpot nextTrail = plugin.getNextTrail();
int finishId = plugin.getFinishId();
Set<Integer> shownTrailIds = plugin.getShownTrails();
for (TileObject tileObject : plugin.getTrails().values())
{
int id = tileObject.getId();
Point minimapLocation = tileObject.getMinimapLocation();
if (minimapLocation == null)
{
continue;
}
if (shownTrailIds.contains(id) && (finishId > 0 || nextTrail != null && !nextTrail.getFootprintIds().contains(id)))
{
OverlayUtil.renderMinimapLocation(graphics, minimapLocation, config.getTrailColor());
}
}
return null;
}
}

View File

@@ -24,6 +24,7 @@
*/
package net.runelite.client.plugins.herbiboars;
import com.google.common.collect.Iterables;
import com.google.inject.Inject;
import java.awt.Color;
import java.awt.Dimension;
@@ -59,17 +60,14 @@ class HerbiboarOverlay extends Overlay
return null;
}
HerbiboarTrail currentTrail = plugin.getCurrentTrail();
HerbiboarSearchSpot.Group currentGroup = plugin.getCurrentGroup();
TrailToSpot nextTrail = plugin.getNextTrail();
int finishId = plugin.getFinishId();
// Draw start objects
if (config.isStartShown() && (currentTrail == null && finishId == 0))
if (config.isStartShown() && (currentGroup == null && finishId == 0))
{
plugin.getStarts().values().forEach((obj) ->
{
OverlayUtil.renderTileOverlay(graphics, obj, "", config.getStartColor());
});
plugin.getStarts().values().forEach((obj) -> OverlayUtil.renderTileOverlay(graphics, obj, "", config.getStartColor()));
}
// Draw trails
@@ -79,7 +77,7 @@ class HerbiboarOverlay extends Overlay
plugin.getTrails().values().forEach((x) ->
{
int id = x.getId();
if (shownTrailIds.contains(id) && (finishId > 0 || (currentTrail != null && currentTrail.getTrailId() != id && currentTrail.getTrailId() + 1 != id)))
if (shownTrailIds.contains(id) && (finishId > 0 || nextTrail != null && !nextTrail.getFootprintIds().contains(id)))
{
OverlayUtil.renderTileOverlay(graphics, x, "", config.getTrailColor());
}
@@ -87,35 +85,20 @@ class HerbiboarOverlay extends Overlay
}
// Draw trail objects (mushrooms, mud, etc)
if (config.isObjectShown() && currentTrail != null)
if (config.isObjectShown() && !(finishId > 0 || currentGroup == null))
{
int currentPath = plugin.getCurrentPath();
WorldPoint[] trailLocs = currentTrail.getObjectLocs(currentPath);
for (WorldPoint trailLoc : trailLocs)
if (plugin.isRuleApplicable())
{
if (trailLoc == null)
WorldPoint correct = Iterables.getLast(plugin.getCurrentPath()).getLocation();
TileObject object = plugin.getTrailObjects().get(correct);
drawObjectLocation(graphics, object, config.getObjectColor());
}
else
{
for (WorldPoint trailLoc : HerbiboarSearchSpot.getGroupLocations(plugin.getCurrentGroup()))
{
continue;
}
TileObject object = plugin.getTrailObjects().get(trailLoc);
if (object != null)
{
if (config.showClickBoxes())
{
Shape clickbox = object.getClickbox();
if (clickbox != null)
{
graphics.setColor(config.getObjectColor());
graphics.draw(clickbox);
graphics.setColor(new Color(255, 0, 255, 20));
graphics.fill(clickbox);
}
}
else
{
OverlayUtil.renderTileOverlay(graphics, object, "", config.getObjectColor());
}
TileObject object = plugin.getTrailObjects().get(trailLoc);
drawObjectLocation(graphics, object, config.getObjectColor());
}
}
}
@@ -125,27 +108,35 @@ class HerbiboarOverlay extends Overlay
{
WorldPoint finishLoc = plugin.getEndLocations().get(finishId - 1);
TileObject object = plugin.getTunnels().get(finishLoc);
if (object != null)
{
if (config.showClickBoxes())
{
Shape clickbox = object.getClickbox();
if (clickbox != null)
{
Color col = config.getObjectColor();
graphics.setColor(col);
graphics.draw(clickbox);
graphics.setColor(new Color(col.getRed(), col.getGreen(), col.getBlue(), 20));
graphics.fill(clickbox);
}
}
else
{
OverlayUtil.renderTileOverlay(graphics, object, "", config.getTunnelColor());
}
}
drawObjectLocation(graphics, object, config.getTunnelColor());
}
return null;
}
}
private void drawObjectLocation(Graphics2D graphics, TileObject object, Color color)
{
if (object == null)
{
return;
}
if (config.showClickBoxes())
{
Shape clickbox = object.getClickbox();
if (clickbox != null)
{
Color clickBoxColor = new Color(color.getRed(), color.getGreen(), color.getBlue(), 20);
graphics.setColor(color);
graphics.draw(clickbox);
graphics.setColor(clickBoxColor);
graphics.fill(clickbox);
}
}
else
{
OverlayUtil.renderTileOverlay(graphics, object, "", color);
}
}
}

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2017, Tyler <https://github.com/tylerthardy>
* Copyright (c) 2020, dekvall <https://github.com/dekvall>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -24,8 +25,10 @@
*/
package net.runelite.client.plugins.herbiboars;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.inject.Provides;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -33,14 +36,15 @@ import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.MenuAction;
import static net.runelite.api.ObjectID.DRIFTWOOD_30523;
import static net.runelite.api.ObjectID.MUSHROOM_30520;
import static net.runelite.api.ObjectID.ROCK_30519;
import static net.runelite.api.ObjectID.ROCK_30521;
import static net.runelite.api.ObjectID.ROCK_30522;
import net.runelite.api.Tile;
import net.runelite.api.TileObject;
import net.runelite.api.Varbits;
import net.runelite.api.coords.WorldPoint;
@@ -51,21 +55,27 @@ import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.GroundObjectChanged;
import net.runelite.api.events.GroundObjectDespawned;
import net.runelite.api.events.GroundObjectSpawned;
import net.runelite.api.events.MenuOptionClicked;
import net.runelite.api.events.VarbitChanged;
import net.runelite.client.callback.ClientThread;
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.ui.overlay.OverlayManager;
import net.runelite.client.util.Text;
import org.apache.commons.lang3.ArrayUtils;
@PluginDescriptor(
name = "Herbiboar",
description = "Highlight starting rocks, trails, and the objects to search at the end of each trail",
tags = {"herblore", "hunter", "skilling", "overlay"}
)
@Slf4j
@Getter
public class HerbiboarPlugin extends Plugin
{
private static final List<WorldPoint> END_LOCATIONS = Arrays.asList(
private static final List<WorldPoint> END_LOCATIONS = ImmutableList.of(
new WorldPoint(3693, 3798, 0),
new WorldPoint(3702, 3808, 0),
new WorldPoint(3703, 3826, 0),
@@ -77,7 +87,7 @@ public class HerbiboarPlugin extends Plugin
new WorldPoint(3681, 3863, 0)
);
private static final List<Integer> START_OBJECT_IDS = Arrays.asList(
private static final Set<Integer> START_OBJECT_IDS = ImmutableSet.of(
ROCK_30519,
MUSHROOM_30520,
ROCK_30521,
@@ -85,16 +95,19 @@ public class HerbiboarPlugin extends Plugin
DRIFTWOOD_30523
);
private static final int[] HERBIBOAR_REGIONS = {
private static final List<Integer> HERBIBOAR_REGIONS = ImmutableList.of(
14652,
14651,
14908,
14907
};
);
@Inject
private Client client;
@Inject
private ClientThread clientThread;
@Inject
private OverlayManager overlayManager;
@@ -104,39 +117,43 @@ public class HerbiboarPlugin extends Plugin
@Inject
private HerbiboarMinimapOverlay minimapOverlay;
@Getter
/**
* Objects which appear at the beginning of Herbiboar hunting trails
*/
private final Map<WorldPoint, TileObject> starts = new HashMap<>();
/**
* Herbiboar hunting "footstep" trail objects
*/
private final Map<WorldPoint, TileObject> trails = new HashMap<>();
/**
* Objects which trigger next trail (mushrooms, mud, seaweed, etc)
*/
private final Map<WorldPoint, TileObject> trailObjects = new HashMap<>();
/**
* Tunnel where the Herbiboar is hiding at the end of a trail
*/
private final Map<WorldPoint, TileObject> tunnels = new HashMap<>();
/**
* Trail object IDs which should be highlighted
*/
private final Set<Integer> shownTrails = new HashSet<>();
/**
* Sequence of herbiboar spots searched along the current trail
*/
private final List<HerbiboarSearchSpot> currentPath = Lists.newArrayList();
private boolean inHerbiboarArea;
@Getter
private Map<WorldPoint, TileObject> trails = new HashMap<>();
@Getter
private Map<WorldPoint, TileObject> tunnels = new HashMap<>();
@Getter
private Map<WorldPoint, TileObject> starts = new HashMap<>();
@Getter
private Map<WorldPoint, TileObject> trailObjects = new HashMap<>();
@Getter
@Setter
private Set<Integer> shownTrails = new HashSet<>();
@Getter
@Setter
private HerbiboarTrail currentTrail;
@Getter
@Setter
private int currentPath;
@Getter
@Setter
private TrailToSpot nextTrail;
private HerbiboarSearchSpot.Group currentGroup;
private int finishId;
private boolean started;
private WorldPoint startPoint;
private HerbiboarStart startSpot;
private boolean ruleApplicable;
@Provides
HerbiboarConfig getConfig(ConfigManager configManager)
HerbiboarConfig provideConfig(ConfigManager configManager)
{
return configManager.getConfig(HerbiboarConfig.class);
}
@@ -146,7 +163,15 @@ public class HerbiboarPlugin extends Plugin
{
overlayManager.add(overlay);
overlayManager.add(minimapOverlay);
inHerbiboarArea = checkArea();
if (client.getGameState() == GameState.LOGGED_IN)
{
clientThread.invokeLater(() ->
{
inHerbiboarArea = checkArea();
updateTrailData();
});
}
}
@Override
@@ -154,61 +179,105 @@ public class HerbiboarPlugin extends Plugin
{
overlayManager.remove(overlay);
overlayManager.remove(minimapOverlay);
resetTrailData();
clearCache();
inHerbiboarArea = false;
}
private void updateTrailData()
{
currentTrail = null;
currentPath = -1;
if (!isInHerbiboarArea())
{
return;
}
boolean pathActive = false;
boolean wasStarted = started;
// Get trail data
for (HerbiboarTrail trail : HerbiboarTrail.values())
for (HerbiboarSearchSpot spot : HerbiboarSearchSpot.values())
{
int trailId = trail.getTrailId();
int value = client.getVar(trail.getVarbit());
for (TrailToSpot trail : spot.getTrails())
{
int value = client.getVar(trail.getVarbit());
if (value > 0)
{
shownTrails.add(trailId);
shownTrails.add(trailId + 1);
}
if (value == 1 || value == 2)
{
currentTrail = trail;
currentPath = value;
if (value == trail.getValue())
{
// The trail after you have searched the spot
currentGroup = spot.getGroup();
nextTrail = trail;
// You never visit the same spot twice
if (!currentPath.contains(spot))
{
currentPath.add(spot);
}
}
else if (value > 0)
{
// The current trail
shownTrails.addAll(trail.getFootprintIds());
pathActive = true;
}
}
}
// Get finish data
finishId = client.getVar(Varbits.HB_FINISH);
if (finishId > 0 && currentTrail != null)
// The started varbit doesn't get set until the first spot of the rotation has been searched
// so we need to use the current group as an indicator of the rotation being started
started = client.getVar(Varbits.HB_STARTED) > 0 || currentGroup != null;
boolean finished = !pathActive && started;
if (!wasStarted && started)
{
shownTrails.add(currentTrail.getTrailId());
shownTrails.add(currentTrail.getTrailId() + 1);
currentTrail = null;
currentPath = -1;
startSpot = HerbiboarStart.from(startPoint);
}
int started = client.getVar(Varbits.HB_STARTED);
if (currentPath == -1 && finishId == 0 && started == 0)
ruleApplicable = HerbiboarRule.canApplyRule(startSpot, currentPath);
if (finished)
{
resetTrailData();
}
}
@Subscribe
public void onMenuOptionClicked(MenuOptionClicked menuOpt)
{
if (!inHerbiboarArea || started || MenuAction.GAME_OBJECT_FIRST_OPTION != menuOpt.getMenuAction())
{
return;
}
switch (Text.removeTags(menuOpt.getMenuTarget()))
{
case "Rock":
case "Mushroom":
case "Driftwood":
startPoint = WorldPoint.fromScene(client, menuOpt.getActionParam(), menuOpt.getWidgetId(), client.getPlane());
}
}
private void resetTrailData()
{
currentPath = 0;
currentTrail = null;
finishId = 0;
log.debug("Reset trail data");
shownTrails.clear();
currentPath.clear();
nextTrail = null;
currentGroup = null;
finishId = 0;
started = false;
startPoint = null;
startSpot = null;
ruleApplicable = false;
}
private void clearCache()
{
starts.clear();
trailObjects.clear();
trails.clear();
trailObjects.clear();
tunnels.clear();
}
@@ -233,57 +302,55 @@ public class HerbiboarPlugin extends Plugin
@Subscribe
public void onVarbitChanged(VarbitChanged event)
{
if (isInHerbiboarArea())
{
updateTrailData();
}
updateTrailData();
}
@Subscribe
public void onGameObjectSpawned(GameObjectSpawned event)
{
onGameObject(event.getTile(), null, event.getGameObject());
onTileObject(null, event.getGameObject());
}
@Subscribe
public void onGameObjectChanged(GameObjectChanged event)
{
onGameObject(event.getTile(), event.getPrevious(), event.getGameObject());
onTileObject(event.getPrevious(), event.getGameObject());
}
@Subscribe
public void onGameObjectDespawned(GameObjectDespawned event)
{
onGameObject(event.getTile(), event.getGameObject(), null);
onTileObject(event.getGameObject(), null);
}
@Subscribe
public void onGroundObjectSpawned(GroundObjectSpawned event)
{
onGroundObject(event.getTile(), null, event.getGroundObject());
onTileObject(null, event.getGroundObject());
}
@Subscribe
public void onGroundObjectChanged(GroundObjectChanged event)
{
onGroundObject(event.getTile(), event.getPrevious(), event.getGroundObject());
onTileObject(event.getPrevious(), event.getGroundObject());
}
@Subscribe
public void onGroundObjectDespawned(GroundObjectDespawned event)
{
onGroundObject(event.getTile(), event.getGroundObject(), null);
onTileObject(event.getGroundObject(), null);
}
// Store relevant GameObjects (starts, objects used to trigger next trails, and some tunnels)
private void onGameObject(Tile tile, TileObject oldObject, TileObject newObject)
// Store relevant GameObjects (starts, tracks on trails, objects used to trigger next trails, and tunnels)
private void onTileObject(TileObject oldObject, TileObject newObject)
{
if (oldObject != null)
{
WorldPoint oldLocation = oldObject.getWorldLocation();
starts.remove(oldLocation);
trails.remove(oldLocation);
trailObjects.remove(oldLocation);
tunnels.remove(oldLocation);
starts.remove(oldLocation);
}
if (newObject == null)
@@ -298,8 +365,15 @@ public class HerbiboarPlugin extends Plugin
return;
}
// Trails
if (HerbiboarSearchSpot.isTrail(newObject.getId()))
{
trails.put(newObject.getWorldLocation(), newObject);
return;
}
// GameObject to trigger next trail (mushrooms, mud, seaweed, etc)
if (HerbiboarTrail.getAllObjectLocs().contains(newObject.getWorldLocation()))
if (HerbiboarSearchSpot.isSearchSpot(newObject.getWorldLocation()))
{
trailObjects.put(newObject.getWorldLocation(), newObject);
return;
@@ -312,43 +386,20 @@ public class HerbiboarPlugin extends Plugin
}
}
// Store relevant GroundObjects (tracks on trails, and some tunnels)
private void onGroundObject(Tile tile, TileObject oldObject, TileObject newObject)
{
if (oldObject != null)
{
WorldPoint oldLocation = oldObject.getWorldLocation();
trails.remove(oldLocation);
tunnels.remove(oldLocation);
}
if (newObject == null)
{
return;
}
//Trails
if (HerbiboarTrail.getTrailIds().contains(newObject.getId()))
{
trails.put(newObject.getWorldLocation(), newObject);
return;
}
//Herbiboar tunnel
if (END_LOCATIONS.contains(newObject.getWorldLocation()))
{
tunnels.put(newObject.getWorldLocation(), newObject);
}
}
private boolean checkArea()
{
return client.getMapRegions() != null && Arrays.stream(client.getMapRegions())
.filter(x -> Arrays.stream(HERBIBOAR_REGIONS).anyMatch(y -> y == x))
.toArray().length > 0;
final int[] mapRegions = client.getMapRegions();
for (int region : HERBIBOAR_REGIONS)
{
if (ArrayUtils.contains(mapRegions, region))
{
return true;
}
}
return false;
}
public List<WorldPoint> getEndLocations()
List<WorldPoint> getEndLocations()
{
return END_LOCATIONS;
}

View File

@@ -0,0 +1,110 @@
/*
* Copyright (c) 2020, dekvall <https://github.com/dekvall>
* Copyright (c) 2020, Jordan <nightfirecat@protonmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.herbiboars;
import java.util.List;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
enum HerbiboarRule
{
A_SOUTH(HerbiboarSearchSpot.Group.A, HerbiboarStart.MIDDLE),
C_WEST(HerbiboarSearchSpot.Group.C, HerbiboarStart.MIDDLE),
D_WEST_1(HerbiboarSearchSpot.Group.D, HerbiboarStart.MIDDLE),
D_WEST_2(HerbiboarSearchSpot.Group.D, HerbiboarSearchSpot.Group.C),
E_NORTH(HerbiboarSearchSpot.Group.E, HerbiboarSearchSpot.Group.A),
F_EAST(HerbiboarSearchSpot.Group.F, HerbiboarSearchSpot.Group.G),
G_NORTH(HerbiboarSearchSpot.Group.G, HerbiboarSearchSpot.Group.F),
H_NORTH(HerbiboarSearchSpot.Group.H, HerbiboarSearchSpot.Group.D),
H_EAST(HerbiboarSearchSpot.Group.H, HerbiboarStart.DRIFTWOOD),
I_EAST(HerbiboarSearchSpot.Group.I, HerbiboarStart.LEPRECHAUN),
I_SOUTH_1(HerbiboarSearchSpot.Group.I, HerbiboarStart.GHOST_MUSHROOM),
I_SOUTH_2(HerbiboarSearchSpot.Group.I, HerbiboarStart.CAMP_ENTRANCE),
I_WEST(HerbiboarSearchSpot.Group.I, HerbiboarSearchSpot.Group.E),
;
private final HerbiboarSearchSpot.Group to;
private final HerbiboarStart fromStart;
private final HerbiboarSearchSpot.Group fromGroup;
HerbiboarRule(HerbiboarSearchSpot.Group to, HerbiboarSearchSpot.Group from)
{
this(to, null, from);
}
HerbiboarRule(HerbiboarSearchSpot.Group to, HerbiboarStart fromStart)
{
this(to, fromStart, null);
}
/**
* Returns whether the next {@link HerbiboarSearchSpot} can be deterministically selected based on the starting
* location and the path taken so far, based on the rules defined on the OSRS wiki.
*
* {@see https://oldschool.runescape.wiki/w/Herbiboar#Guaranteed_tracks}
*
* @param start Herbiboar's starting spot where the tracking path begins
* @param currentPath A list of {@link HerbiboarSearchSpot}s which have been searched thus far, and the next one to search
* @return {@code true} if a rule can be applied, {@code false} otherwise
*/
static boolean canApplyRule(HerbiboarStart start, List<HerbiboarSearchSpot> currentPath)
{
if (start == null || currentPath.isEmpty())
{
return false;
}
int lastIndex = currentPath.size() - 1;
HerbiboarSearchSpot.Group goingTo = currentPath.get(lastIndex).getGroup();
for (HerbiboarRule rule : values())
{
if (lastIndex > 0 && rule.matches(currentPath.get(lastIndex - 1).getGroup(), goingTo)
|| lastIndex == 0 && rule.matches(start, goingTo))
{
return true;
}
}
return false;
}
boolean matches(HerbiboarStart from, HerbiboarSearchSpot.Group to)
{
return this.matches(from, null, to);
}
boolean matches(HerbiboarSearchSpot.Group from, HerbiboarSearchSpot.Group to)
{
return this.matches(null, from, to);
}
boolean matches(HerbiboarStart fromStart, HerbiboarSearchSpot.Group fromGroup, HerbiboarSearchSpot.Group to)
{
return this.to == to
&& (fromStart != null && this.fromStart == fromStart || fromGroup != null && this.fromGroup == fromGroup);
}
}

View File

@@ -0,0 +1,180 @@
/*
* Copyright (c) 2020, dekvall <https://github.com/dekvall>
* Copyright (c) 2020, Jordan <nightfirecat@protonmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.herbiboars;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.Getter;
import static net.runelite.api.NullObjectID.*;
import net.runelite.api.Varbits;
import net.runelite.api.coords.WorldPoint;
@Getter
enum HerbiboarSearchSpot
{
// Wiki A location
A_MUSHROOM(Group.A, new WorldPoint(3670, 3889, 0),
new TrailToSpot(Varbits.HB_TRAIL_31318, 1, NULL_31318),
new TrailToSpot(Varbits.HB_TRAIL_31321, 1, NULL_31321)),
A_PATCH(Group.A, new WorldPoint(3672, 3890, 0),
new TrailToSpot(Varbits.HB_TRAIL_31306, 2, NULL_31306)),
// Wiki B location
B_SEAWEED(Group.B, new WorldPoint(3728, 3893, 0),
new TrailToSpot(Varbits.HB_TRAIL_31315, 2, NULL_31315),
new TrailToSpot(Varbits.HB_TRAIL_31318, 2, NULL_31318),
new TrailToSpot(Varbits.HB_TRAIL_31336, 1, NULL_31336),
new TrailToSpot(Varbits.HB_TRAIL_31339, 1, NULL_31339)),
// Wiki C location
C_MUSHROOM(Group.C, new WorldPoint(3697, 3875, 0),
new TrailToSpot(Varbits.HB_TRAIL_31303, 2, NULL_31303)),
C_PATCH(Group.C, new WorldPoint(3699, 3875, 0),
new TrailToSpot(Varbits.HB_TRAIL_31312, 1, NULL_31312),
new TrailToSpot(Varbits.HB_TRAIL_31315, 1, NULL_31315)),
// Wiki D location
D_PATCH(Group.D, new WorldPoint(3708, 3876, 0),
new TrailToSpot(Varbits.HB_TRAIL_31330, 1, NULL_31330),
new TrailToSpot(Varbits.HB_TRAIL_31333, 1, NULL_31333)),
D_SEAWEED(Group.D, new WorldPoint(3710, 3877, 0),
new TrailToSpot(Varbits.HB_TRAIL_31312, 2, NULL_31312),
new TrailToSpot(Varbits.HB_TRAIL_31339, 2, NULL_31339)),
// Wiki E location
E_MUSHROOM(Group.E, new WorldPoint(3668, 3865, 0),
new TrailToSpot(Varbits.HB_TRAIL_31342, 1, NULL_31342),
new TrailToSpot(Varbits.HB_TRAIL_31345, 1, NULL_31345)),
E_PATCH(Group.E, new WorldPoint(3667, 3862, 0),
new TrailToSpot(Varbits.HB_TRAIL_31321, 2, NULL_31321)),
// Wiki F location
F_MUSHROOM(Group.F, new WorldPoint(3681, 3860, 0),
new TrailToSpot(Varbits.HB_TRAIL_31324, 1, NULL_31324),
new TrailToSpot(Varbits.HB_TRAIL_31327, 1, NULL_31327),
new TrailToSpot(Varbits.HB_TRAIL_31342, 2, NULL_31342)),
F_PATCH(Group.F, new WorldPoint(3681, 3859, 0),
new TrailToSpot(Varbits.HB_TRAIL_31309, 2, NULL_31309)),
// Wiki G location
G_MUSHROOM(Group.G, new WorldPoint(3694, 3847, 0),
new TrailToSpot(Varbits.HB_TRAIL_31333, 2, NULL_31333),
new TrailToSpot(Varbits.HB_TRAIL_31354, 1, NULL_31354)),
G_PATCH(Group.G, new WorldPoint(3698, 3847, 0),
new TrailToSpot(Varbits.HB_TRAIL_31327, 2, NULL_31327)),
// Wiki H location
H_SEAWEED_EAST(Group.H, new WorldPoint(3715, 3851, 0),
new TrailToSpot(Varbits.HB_TRAIL_31357, 1, NULL_31357),
new TrailToSpot(Varbits.HB_TRAIL_31360, 1, NULL_31360)),
H_SEAWEED_WEST(Group.H, new WorldPoint(3713, 3850, 0),
new TrailToSpot(Varbits.HB_TRAIL_31330, 2, NULL_31330),
new TrailToSpot(Varbits.HB_TRAIL_31363, 1, NULL_31363)),
// Wiki I location
I_MUSHROOM(Group.I, new WorldPoint(3680, 3838, 0),
new TrailToSpot(Varbits.HB_TRAIL_31348, 1, NULL_31348),
new TrailToSpot(Varbits.HB_TRAIL_31351, 1, NULL_31351)),
I_PATCH(Group.I, new WorldPoint(3680, 3836, 0),
new TrailToSpot(Varbits.HB_TRAIL_31324, 2, NULL_31324),
new TrailToSpot(Varbits.HB_TRAIL_31345, 2, NULL_31345)),
// Wiki J location
J_PATCH(Group.J, new WorldPoint(3713, 3840, 0),
new TrailToSpot(Varbits.HB_TRAIL_31357, 2, NULL_31357),
new TrailToSpot(Varbits.HB_TRAIL_31372, 1, NULL_31372)),
// Wiki K location
K_PATCH(Group.K, new WorldPoint(3706, 3811, 0),
new TrailToSpot(Varbits.HB_TRAIL_31348, 2, NULL_31348),
new TrailToSpot(Varbits.HB_TRAIL_31366, 1, NULL_31366),
new TrailToSpot(Varbits.HB_TRAIL_31369, 1, NULL_31369)),
;
private static final ImmutableMultimap<Group, HerbiboarSearchSpot> GROUPS;
private static final Set<WorldPoint> SPOTS;
private static final Set<Integer> TRAILS;
static
{
ImmutableMultimap.Builder<Group, HerbiboarSearchSpot> groupBuilder = new ImmutableMultimap.Builder<>();
ImmutableSet.Builder<WorldPoint> spotBuilder = new ImmutableSet.Builder<>();
ImmutableSet.Builder<Integer> trailBuilder = new ImmutableSet.Builder<>();
for (HerbiboarSearchSpot spot : values())
{
groupBuilder.put(spot.getGroup(), spot);
spotBuilder.add(spot.getLocation());
for (TrailToSpot trail : spot.getTrails())
{
trailBuilder.addAll(trail.getFootprintIds());
}
}
GROUPS = groupBuilder.build();
SPOTS = spotBuilder.build();
TRAILS = trailBuilder.build();
}
private final Group group;
private final WorldPoint location;
private final List<TrailToSpot> trails;
HerbiboarSearchSpot(Group group, WorldPoint location, TrailToSpot... trails)
{
this.group = group;
this.location = location;
this.trails = ImmutableList.copyOf(trails);
}
/**
* Spots are placed in groups of two
*/
enum Group
{
A, B, C, D, E, F, G, H, I, J, K
}
static boolean isTrail(int id)
{
return TRAILS.contains(id);
}
static boolean isSearchSpot(WorldPoint location)
{
return SPOTS.contains(location);
}
static List<WorldPoint> getGroupLocations(Group group)
{
return GROUPS.get(group).stream().map(HerbiboarSearchSpot::getLocation).collect(Collectors.toList());
}
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright (c) 2020, dekvall <https://github.com/dekvall>
* 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.herbiboars;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import net.runelite.api.coords.WorldPoint;
@Getter
@RequiredArgsConstructor
enum HerbiboarStart
{
MIDDLE(new WorldPoint(3686, 3870, 0)),
LEPRECHAUN(new WorldPoint(3705, 3830, 0)),
CAMP_ENTRANCE(new WorldPoint(3704, 3810, 0)),
GHOST_MUSHROOM(new WorldPoint(3695, 3800, 0)),
DRIFTWOOD(new WorldPoint(3751, 3850, 0)),
;
private final WorldPoint location;
static HerbiboarStart from(WorldPoint location)
{
for (final HerbiboarStart start : values())
{
if (start.getLocation().equals(location))
{
return start;
}
}
return null;
}
}

View File

@@ -1,109 +0,0 @@
/*
* Copyright (c) 2017, Tyler <https://github.com/tylerthardy>
* 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.herbiboars;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.runelite.api.Varbits;
import net.runelite.api.coords.WorldPoint;
//Location of GameObjects which show TRAIL_xxxxx when used
@AllArgsConstructor
public enum HerbiboarTrail
{
TRAIL_31303(31303, Varbits.HB_TRAIL_31303, null, new WorldPoint(3697, 3875, 0), null, new WorldPoint(3699, 3875, 0)),
TRAIL_31306(31306, Varbits.HB_TRAIL_31306, null, new WorldPoint(3672, 3890, 0), null, new WorldPoint(3670, 3889, 0)),
TRAIL_31309(31309, Varbits.HB_TRAIL_31309, null, new WorldPoint(3681, 3859, 0), null, new WorldPoint(3681, 3860, 0)),
TRAIL_31312(31312, Varbits.HB_TRAIL_31312, new WorldPoint(3699, 3875, 0), new WorldPoint(3710, 3877, 0), new WorldPoint(3697, 3875, 0), new WorldPoint(3708, 3876, 0)),
TRAIL_31315(31315, Varbits.HB_TRAIL_31315, new WorldPoint(3699, 3875, 0), new WorldPoint(3728, 3893, 0), new WorldPoint(3697, 3875, 0), null),
TRAIL_31318(31318, Varbits.HB_TRAIL_31318, new WorldPoint(3670, 3889, 0), new WorldPoint(3728, 3893, 0), new WorldPoint(3672, 3890, 0), null),
TRAIL_31321(31321, Varbits.HB_TRAIL_31321, new WorldPoint(3670, 3889, 0), new WorldPoint(3667, 3862, 0), new WorldPoint(3672, 3890, 0), new WorldPoint(3668, 3865, 0)),
TRAIL_31324(31324, Varbits.HB_TRAIL_31324, new WorldPoint(3681, 3860, 0), new WorldPoint(3680, 3836, 0), new WorldPoint(3681, 3859, 0), new WorldPoint(3680, 3838, 0)),
TRAIL_31327(31327, Varbits.HB_TRAIL_31327, new WorldPoint(3681, 3860, 0), new WorldPoint(3698, 3847, 0), new WorldPoint(3681, 3859, 0), new WorldPoint(3694, 3847, 0)),
TRAIL_31330(31330, Varbits.HB_TRAIL_31330, new WorldPoint(3708, 3876, 0), new WorldPoint(3713, 3850, 0), new WorldPoint(3710, 3877, 0), new WorldPoint(3715, 3851, 0)),
TRAIL_31333(31333, Varbits.HB_TRAIL_31333, new WorldPoint(3708, 3876, 0), new WorldPoint(3694, 3847, 0), new WorldPoint(3710, 3877, 0), new WorldPoint(3698, 3847, 0)),
TRAIL_31336(31336, Varbits.HB_TRAIL_31336, new WorldPoint(3728, 3893, 0), null, null, null),
TRAIL_31339(31339, Varbits.HB_TRAIL_31339, new WorldPoint(3728, 3893, 0), new WorldPoint(3710, 3877, 0), null, new WorldPoint(3708, 3876, 0)),
TRAIL_31342(31342, Varbits.HB_TRAIL_31342, new WorldPoint(3668, 3865, 0), new WorldPoint(3681, 3860, 0), new WorldPoint(3667, 3862, 0), new WorldPoint(3681, 3859, 0)),
TRAIL_31345(31345, Varbits.HB_TRAIL_31345, new WorldPoint(3668, 3865, 0), new WorldPoint(3680, 3836, 0), new WorldPoint(3667, 3862, 0), new WorldPoint(3680, 3838, 0)),
TRAIL_31348(31348, Varbits.HB_TRAIL_31348, new WorldPoint(3680, 3838, 0), new WorldPoint(3706, 3811, 0), new WorldPoint(3680, 3836, 0), null),
TRAIL_31351(31351, Varbits.HB_TRAIL_31351, new WorldPoint(3680, 3838, 0), null, new WorldPoint(3680, 3836, 0), null),
TRAIL_31354(31354, Varbits.HB_TRAIL_31354, new WorldPoint(3694, 3847, 0), null, new WorldPoint(3698, 3847, 0), null),
TRAIL_31357(31357, Varbits.HB_TRAIL_31357, new WorldPoint(3715, 3851, 0), new WorldPoint(3713, 3840, 0), new WorldPoint(3713, 3850, 0), null),
TRAIL_31360(31360, Varbits.HB_TRAIL_31360, new WorldPoint(3715, 3851, 0), null, new WorldPoint(3713, 3850, 0), null),
TRAIL_31363(31363, Varbits.HB_TRAIL_31363, new WorldPoint(3713, 3850, 0), null, new WorldPoint(3715, 3851, 0), null),
TRAIL_31366(31366, Varbits.HB_TRAIL_31366, null, null, null, null),
TRAIL_31369(31369, Varbits.HB_TRAIL_31369, new WorldPoint(3706, 3811, 0), null, null, null),
TRAIL_31372(31372, Varbits.HB_TRAIL_31372, new WorldPoint(3713, 3840, 0), null, null, null);
@Getter
private final int trailId;
@Getter
private final Varbits varbit;
private final WorldPoint objectLoc1;
private final WorldPoint objectLoc2;
private final WorldPoint objectLoc3;
private final WorldPoint objectLoc4;
@Getter
private static Set<Integer> trailIds = new HashSet<>();
@Getter
private static Set<WorldPoint> allObjectLocs = new HashSet<>();
static
{
for (HerbiboarTrail trail : values())
{
trailIds.add(trail.trailId);
trailIds.add(trail.trailId + 1);
allObjectLocs.addAll(Arrays.asList(trail.getObjectLocs(1)));
allObjectLocs.addAll(Arrays.asList(trail.getObjectLocs(2)));
}
}
public WorldPoint[] getObjectLocs(int varbitValue)
{
switch (varbitValue)
{
case 1:
return new WorldPoint[]{objectLoc1, objectLoc3};
case 2:
return new WorldPoint[]{objectLoc2, objectLoc4};
case 0:
default:
return new WorldPoint[]{};
}
}
@Override
public String toString()
{
return String.format("trailId=%s obj1=%s obj2=%s obj3=%s obj4=%s", trailId, objectLoc1, objectLoc2, objectLoc3, objectLoc4);
}
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright (c) 2020, dekvall <https://github.com/dekvall>
* Copyright (c) 2020, Jordan <nightfirecat@protonmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.herbiboars;
import com.google.common.collect.ImmutableSet;
import java.util.Set;
import lombok.Value;
import net.runelite.api.Varbits;
/**
* A representation of a trail of footsteps which appears when hunting for the Herbiboar.
*/
@Value
class TrailToSpot
{
/**
* The Varbit associated with the trail. When inactive, this Varbit's value should be less than
* {@link TrailToSpot#getValue()}. When this trail appears after searching a spot, this Varbit's value should be
* equal to that of {@link TrailToSpot#getValue()}. Once the next object along the trail has been searched, this
* Varbit's value will be greater than that of {@link TrailToSpot#getValue()}.
*/
private final Varbits varbit;
/**
* The cutoff reference value to compare against the value of {@link TrailToSpot#getVarbit()} to determine its state
* along the current trail.
*/
private final int value;
/**
* The object ID of the footprints which appear when the trail is made visible.
*/
private final int footprint;
Set<Integer> getFootprintIds()
{
return ImmutableSet.of(footprint, footprint + 1);
}
}