HotColdClue: Refactor to use enums for temperatures

This commit is contained in:
Jordan Atwood
2019-06-12 22:41:13 -07:00
committed by Adam
parent 3904b7c4c6
commit 5a6b39036d
5 changed files with 319 additions and 90 deletions

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2018, Eadgars Ruse <https://github.com/Eadgars-Ruse>
* Copyright (c) 2019, Jordan Atwood <nightfirecat@protonmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -36,8 +37,8 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import lombok.Getter;
import net.runelite.api.NPC;
import net.runelite.api.coords.LocalPoint;
@@ -47,6 +48,8 @@ import net.runelite.client.plugins.cluescrolls.ClueScrollPlugin;
import static net.runelite.client.plugins.cluescrolls.ClueScrollWorldOverlay.IMAGE_Z_OFFSET;
import net.runelite.client.plugins.cluescrolls.clues.hotcold.HotColdArea;
import net.runelite.client.plugins.cluescrolls.clues.hotcold.HotColdLocation;
import net.runelite.client.plugins.cluescrolls.clues.hotcold.HotColdTemperature;
import net.runelite.client.plugins.cluescrolls.clues.hotcold.HotColdTemperatureChange;
import net.runelite.client.ui.overlay.OverlayUtil;
import net.runelite.client.ui.overlay.components.LineComponent;
import net.runelite.client.ui.overlay.components.PanelComponent;
@@ -55,9 +58,6 @@ import net.runelite.client.ui.overlay.components.TitleComponent;
@Getter
public class HotColdClue extends ClueScroll implements LocationClueScroll, LocationsClueScroll, TextClueScroll, NpcClueScroll
{
private static final Pattern INITIAL_STRANGE_DEVICE_MESSAGE = Pattern.compile("The device is (.*)");
private static final Pattern STRANGE_DEVICE_MESSAGE = Pattern.compile("The device is (.*), (.*) last time\\.");
private static final Pattern FINAL_STRANGE_DEVICE_MESSAGE = Pattern.compile("The device is visibly shaking.*");
private static final HotColdClue CLUE =
new HotColdClue("Buried beneath the ground, who knows where it's found. Lucky for you, A man called Jorral may have a clue.",
"Jorral",
@@ -231,52 +231,31 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat
public boolean update(final String message, final ClueScrollPlugin plugin)
{
if (!message.startsWith("The device is"))
final HotColdTemperature temperature = HotColdTemperature.of(message);
if (temperature == null)
{
return false;
}
Matcher m1 = FINAL_STRANGE_DEVICE_MESSAGE.matcher(message);
Matcher m2 = STRANGE_DEVICE_MESSAGE.matcher(message);
Matcher m3 = INITIAL_STRANGE_DEVICE_MESSAGE.matcher(message);
final WorldPoint localWorld = plugin.getClient().getLocalPlayer().getWorldLocation();
// the order that these pattern matchers are checked is important
if (m1.find())
if (localWorld == null)
{
// final location for hot cold clue has been found
WorldPoint localWorld = plugin.getClient().getLocalPlayer().getWorldLocation();
if (localWorld != null)
{
markFinalSpot(localWorld);
return true;
}
}
else if (m2.find())
{
String temperature = m2.group(1);
String difference = m2.group(2);
WorldPoint localWorld = plugin.getClient().getLocalPlayer().getWorldLocation();
if (localWorld != null)
{
updatePossibleArea(localWorld, temperature, difference);
return true;
}
}
else if (m3.find())
{
String temperature = m3.group(1);
WorldPoint localWorld = plugin.getClient().getLocalPlayer().getWorldLocation();
if (localWorld != null)
{
updatePossibleArea(localWorld, temperature, "");
return true;
}
return false;
}
return false;
if (temperature == HotColdTemperature.VISIBLY_SHAKING)
{
markFinalSpot(localWorld);
}
else
{
final HotColdTemperatureChange temperatureChange = HotColdTemperatureChange.of(message);
updatePossibleArea(localWorld, temperature, temperatureChange);
}
return true;
}
@Override
@@ -286,7 +265,7 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat
digLocations.clear();
}
private void updatePossibleArea(WorldPoint currentWp, String temperature, String difference)
private void updatePossibleArea(@Nonnull final WorldPoint worldPoint, @Nonnull final HotColdTemperature temperature, @Nullable final HotColdTemperatureChange temperatureChange)
{
this.location = null;
@@ -295,73 +274,41 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat
digLocations.addAll(Arrays.asList(HotColdLocation.values()));
}
int maxSquaresAway = 5000;
int minSquaresAway = 0;
switch (temperature)
{
// when the strange device reads a temperature, that means that the center of the final dig location
// is a range of squares away from the player's current location (Chebyshev AKA Chess-board distance)
case "ice cold":
maxSquaresAway = 5000;
minSquaresAway = 500;
break;
case "very cold":
maxSquaresAway = 499;
minSquaresAway = 200;
break;
case "cold":
maxSquaresAway = 199;
minSquaresAway = 150;
break;
case "warm":
maxSquaresAway = 149;
minSquaresAway = 100;
break;
case "hot":
maxSquaresAway = 99;
minSquaresAway = 70;
break;
case "very hot":
maxSquaresAway = 69;
minSquaresAway = 30;
break;
case "incredibly hot":
maxSquaresAway = 29;
minSquaresAway = 5;
break;
}
// when the strange device reads a temperature, that means that the center of the final dig location
// is a range of squares away from the player's current location (Chebyshev AKA Chess-board distance)
int maxSquaresAway = temperature.getMaxDistance();
int minSquaresAway = temperature.getMinDistance();
// rectangle r1 encompasses all of the points that are within the max possible distance from the player
Point p1 = new Point(currentWp.getX() - maxSquaresAway, currentWp.getY() - maxSquaresAway);
Point p1 = new Point(worldPoint.getX() - maxSquaresAway, worldPoint.getY() - maxSquaresAway);
Rectangle r1 = new Rectangle((int) p1.getX(), (int) p1.getY(), 2 * maxSquaresAway + 1, 2 * maxSquaresAway + 1);
// rectangle r2 encompasses all of the points that are within the min possible distance from the player
Point p2 = new Point(currentWp.getX() - minSquaresAway, currentWp.getY() - minSquaresAway);
Point p2 = new Point(worldPoint.getX() - minSquaresAway, worldPoint.getY() - minSquaresAway);
Rectangle r2 = new Rectangle((int) p2.getX(), (int) p2.getY(), 2 * minSquaresAway + 1, 2 * minSquaresAway + 1);
// eliminate from consideration dig spots that lie entirely within the min range or entirely outside of the max range
digLocations.removeIf(entry -> r2.contains(entry.getRect()) || !r1.intersects(entry.getRect()));
// if a previous world point has been recorded, we can consider the warmer/colder result from the strange device
if (lastWorldPoint != null)
if (lastWorldPoint != null && temperatureChange != null)
{
switch (difference)
switch (temperatureChange)
{
case "but colder than":
case COLDER:
// eliminate spots that are absolutely warmer
digLocations.removeIf(entry -> isFirstPointCloserRect(currentWp, lastWorldPoint, entry.getRect()));
digLocations.removeIf(entry -> isFirstPointCloserRect(worldPoint, lastWorldPoint, entry.getRect()));
break;
case "and warmer than":
case WARMER:
// eliminate spots that are absolutely colder
digLocations.removeIf(entry -> isFirstPointCloserRect(lastWorldPoint, currentWp, entry.getRect()));
digLocations.removeIf(entry -> isFirstPointCloserRect(lastWorldPoint, worldPoint, entry.getRect()));
break;
case "and the same temperature as":
case SAME:
// I couldn't figure out a clean implementation for this case
// not necessary for quickly determining final location
}
}
lastWorldPoint = currentWp;
lastWorldPoint = worldPoint;
}
private boolean isFirstPointCloserRect(WorldPoint firstWp, WorldPoint secondWp, Rectangle2D r)

View File

@@ -0,0 +1,84 @@
/*
* Copyright (c) 2019, Jordan Atwood <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.cluescrolls.clues.hotcold;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Getter;
@AllArgsConstructor
@Getter
public enum HotColdTemperature
{
ICE_COLD("ice cold", 500, 5000),
VERY_COLD("very cold", 200, 499),
COLD("cold", 150, 199),
WARM("warm", 100, 149),
HOT("hot", 70, 99),
VERY_HOT("very hot", 30, 69),
INCREDIBLY_HOT("incredibly hot", 5, 29),
VISIBLY_SHAKING("visibly shaking", 0, 4);
private final String text;
private final int minDistance;
private final int maxDistance;
private static final String DEVICE_USED_START_TEXT = "The device is ";
/**
* Gets the temperature corresponding to the passed string.
*
* @param message A string containing a temperature value
* @return The corresponding enum for the passed string.
* <p>
* Note that in cases where two temperature enums are equally likely to be the given temperature (say, two
* temperatures with identical text values), the behavior is undefined.
*/
public static HotColdTemperature of(final String message)
{
if (!message.startsWith(DEVICE_USED_START_TEXT))
{
return null;
}
final List<HotColdTemperature> possibleTemperatures = new ArrayList<>();
for (final HotColdTemperature temperature : values())
{
if (message.contains(temperature.getText()))
{
possibleTemperatures.add(temperature);
}
}
return possibleTemperatures.stream()
// For messages such as "The device is very cold", this will choose the Enum with text of greatest length so
// that VERY_COLD would be selected over COLD, though both Enums have matching text for this message.
.max(Comparator.comparingInt(x -> (x.getText()).length()))
.orElse(null);
}
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright (c) 2019, Jordan Atwood <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.cluescrolls.clues.hotcold;
import lombok.AllArgsConstructor;
@AllArgsConstructor
public enum HotColdTemperatureChange
{
WARMER("and warmer than"),
SAME("and the same temperature as"),
COLDER("but colder than");
private final String text;
public static HotColdTemperatureChange of(final String message)
{
if (!message.endsWith(" last time."))
{
return null;
}
for (final HotColdTemperatureChange change : values())
{
if (message.contains(change.text))
{
return change;
}
}
return null;
}
}