runelite-client: add volcanic mine plugin

This commit is contained in:
l2-
2017-11-17 17:36:06 -05:00
committed by Adam
parent 2e3fc669bb
commit a93ebf9028
7 changed files with 970 additions and 0 deletions

View File

@@ -48,6 +48,7 @@ class WidgetID
static final int PRIVATE_CHAT = 163;
static final int CHATBOX_GROUP_ID = 162;
static final int WORLD_MAP_MENU_GROUP_ID = 160;
static final int VOLCANIC_MINE_GROUP_ID = 611;
static class WorldMap
{
@@ -188,4 +189,20 @@ class WidgetID
static final int WEAPON_NAME = 1;
static final int LEVEL = 2;
}
static class VolcanicMine
{
static final int GENERAL_INFOBOX_GROUP_ID = 4;
static final int TIME_LEFT = 8;
static final int POINTS = 10;
static final int STABILITY = 12;
static final int PLAYER_COUNT = 14;
static final int VENTS_INFOBOX_GROUP_ID = 15;
static final int VENT_A_PERCENTAGE = 19;
static final int VENT_B_PERCENTAGE = 20;
static final int VENT_C_PERCENTAGE = 21;
static final int VENT_A_STATUS = 23;
static final int VENT_B_STATUS = 24;
static final int VENT_C_STATUS = 25;
}
}

View File

@@ -61,6 +61,19 @@ public enum WidgetInfo
PESTCONTROL_ACTIVITY_BAR(WidgetID.PESTRCONTROL_GROUP_ID, WidgetID.PestControl.ACTIVITY_BAR),
PESTCONTROL_ACTIVITY_PROGRESS(WidgetID.PESTRCONTROL_GROUP_ID, WidgetID.PestControl.ACTIVITY_PROGRESS),
VOLCANICMINE_GENERAL_INFOBOX_GROUP(WidgetID.VOLCANIC_MINE_GROUP_ID, WidgetID.VolcanicMine.GENERAL_INFOBOX_GROUP_ID),
VOLCANICMINE_TIME_LEFT(WidgetID.VOLCANIC_MINE_GROUP_ID, WidgetID.VolcanicMine.TIME_LEFT),
VOLCANICMINE_POINTS(WidgetID.VOLCANIC_MINE_GROUP_ID, WidgetID.VolcanicMine.POINTS),
VOLCANICMINE_STABILITY(WidgetID.VOLCANIC_MINE_GROUP_ID, WidgetID.VolcanicMine.STABILITY),
VOLCANICMINE_PLAYER_COUNT(WidgetID.VOLCANIC_MINE_GROUP_ID, WidgetID.VolcanicMine.PLAYER_COUNT),
VOLCANICMINE_VENTS_INFOBOX_GROUP(WidgetID.VOLCANIC_MINE_GROUP_ID, WidgetID.VolcanicMine.VENTS_INFOBOX_GROUP_ID),
VOLCANICMINE_VENT_A_PERCENTAGE(WidgetID.VOLCANIC_MINE_GROUP_ID, WidgetID.VolcanicMine.VENT_A_PERCENTAGE),
VOLCANICMINE_VENT_B_PERCENTAGE(WidgetID.VOLCANIC_MINE_GROUP_ID, WidgetID.VolcanicMine.VENT_B_PERCENTAGE),
VOLCANICMINE_VENT_C_PERCENTAGE(WidgetID.VOLCANIC_MINE_GROUP_ID, WidgetID.VolcanicMine.VENT_C_PERCENTAGE),
VOLCANICMINE_VENT_A_STATUS(WidgetID.VOLCANIC_MINE_GROUP_ID, WidgetID.VolcanicMine.VENT_A_STATUS),
VOLCANICMINE_VENT_B_STATUS(WidgetID.VOLCANIC_MINE_GROUP_ID, WidgetID.VolcanicMine.VENT_B_STATUS),
VOLCANICMINE_VENT_C_STATUS(WidgetID.VOLCANIC_MINE_GROUP_ID, WidgetID.VolcanicMine.VENT_C_STATUS),
CLAN_CHAT_TITLE(WidgetID.CLAN_CHAT_GROUP_ID, WidgetID.ClanChat.TITLE),
CLAN_CHAT_NAME(WidgetID.CLAN_CHAT_GROUP_ID, WidgetID.ClanChat.NAME),
CLAN_CHAT_OWNER(WidgetID.CLAN_CHAT_GROUP_ID, WidgetID.ClanChat.OWNER),

View File

@@ -0,0 +1,65 @@
/*
* Copyright (c) 2017, 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.volcanicminehelper;
import java.time.Duration;
public enum LavaPlatform
{
STAGE_1(30998, 90),
STAGE_2(30999, 45),
STAGE_3(31000, 5);
private final int objectId;
private final Duration time;
LavaPlatform(int objectId, int time)
{
this.objectId = objectId;
this.time = Duration.ofSeconds(time);
}
public int getObjectId()
{
return objectId;
}
public Duration getTime()
{
return time;
}
public static LavaPlatform fromId(int id)
{
for (LavaPlatform lavaPlatform : values())
{
if (lavaPlatform.objectId == id)
{
return lavaPlatform;
}
}
return null;
}
}

View File

@@ -0,0 +1,204 @@
/*
* Copyright (c) 2017. l2-
*
* 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.volcanicminehelper;
import java.awt.Color;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
@ConfigGroup(
keyName = "VolcanicMine",
name = "Volcanic mine",
description = "Configuration for the volcanic mine plugin"
)
public interface VolcanicMineConfig extends Config
{
@ConfigItem(
position = 0,
keyName = "enabled",
name = "Enable",
description = "Configures whether the volcanic mine plugin is displayed"
)
default boolean enabled()
{
return true;
}
@ConfigItem(
position = 1,
keyName = "tray",
name = "Send Tray Notification",
description = "Toggles tray notifications"
)
default boolean sendTrayNotification()
{
return true;
}
@ConfigItem(
position = 2,
keyName = "focused",
name = "Alert When Focused",
description = "Toggles idle notifications for when the client is focused"
)
default boolean alertWhenFocused()
{
return true;
}
@ConfigItem(
position = 3,
keyName = "request",
name = "Request Window Focus",
description = "Toggles window focus request"
)
default boolean requestFocus()
{
return true;
}
@ConfigItem(
position = 4,
keyName = "prayerHelper",
name = "shows prayer",
description = "Shows when you need to use protection prayers"
)
default boolean prayerHelperEnabled()
{
return true;
}
@ConfigItem(
position = 5,
keyName = "platformColorLow",
name = "PlatformColor low risk",
description = "Configures the color for the platformOverlay"
)
default Color platformColorLow()
{
return Color.GREEN;
}
@ConfigItem(
position = 6,
keyName = "platformColorMed",
name = "PlatformColor med risk",
description = "Configures the color for the platformOverlay"
)
default Color platformColorMed()
{
return Color.YELLOW;
}
@ConfigItem(
position = 7,
keyName = "platformColorHigh",
name = "PlatformColor high risk",
description = "Configures the color for the platformOverlay"
)
default Color platformColorHigh()
{
return Color.decode("#FF3333");
}
@ConfigItem(
position = 8,
keyName = "platformTimerThreshold",
name = "Platform timer notification threshold",
description = "At what time does the plugin notify (in seconds), set to -1 to disable"
)
default int platformTimerThreshold()
{
return 20;
}
@ConfigItem(
position = 9,
keyName = "timeLeftThreshold",
name = "Time left threshold",
description = "At what time does the plugin notify (in seconds), set to -1 to disable"
)
default int timerThreshold()
{
return 40;
}
@ConfigItem(
position = 9,
keyName = "stabilityThreshold",
name = "Stability threshold",
description = "At what stability does the plugin notify (in percentage), set to -1 to disable"
)
default int stabilityPercentageThreshold()
{
return 30;
}
@ConfigItem(
position = 10,
keyName = "prayer",
name = "Prayer warning",
description = "Protect prayer warning setting"
)
default WarningMode prayerWarning()
{
return WarningMode.INGAME_AND_NOTIFICATION;
}
@ConfigItem(
position = 11,
keyName = "hotTiles",
name = "Hot Tile warning",
description = "Hot tile warning setting"
)
default WarningMode hotTileWarning()
{
return WarningMode.INGAME_AND_NOTIFICATION;
}
@ConfigItem(
position = 12,
keyName = "timerWarning",
name = "timer warning",
description = "timer low warning setting"
)
default WarningMode timerWarning()
{
return WarningMode.INGAME_AND_NOTIFICATION;
}
@ConfigItem(
position = 13,
keyName = "stabilityWarning",
name = "stability warning",
description = "stability low warning setting"
)
default WarningMode stabilityWarning()
{
return WarningMode.INGAME_AND_NOTIFICATION;
}
}

View File

@@ -0,0 +1,406 @@
/*
* Copyright (c) 2017. l2-
*
* 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.volcanicminehelper;
import com.google.common.eventbus.Subscribe;
import com.google.inject.Binder;
import com.google.inject.Provides;
import java.awt.Color;
import static java.lang.Math.abs;
import net.runelite.api.Client;
import net.runelite.api.GameObject;
import net.runelite.api.GameState;
import net.runelite.api.NPC;
import net.runelite.api.Player;
import net.runelite.api.Point;
import net.runelite.api.Region;
import net.runelite.api.Tile;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.RuneLite;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.events.ConfigChanged;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.task.Schedule;
import net.runelite.client.ui.overlay.Overlay;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import javax.inject.Inject;
import java.time.Duration;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import net.runelite.api.Prayer;
import net.runelite.api.Query;
import net.runelite.api.queries.NPCQuery;
@PluginDescriptor(
name = "Volcanic mine helper"
)
public class VolcanicMineHelperPlugin extends Plugin
{
private static final Logger logger = LoggerFactory.getLogger(VolcanicMineHelperPlugin.class);
private static final int REGION_SIZE = 104;
private static final int MAX_DISTANCE = 2400;
private static final int LAVA_ID = 30997;
private static final int LAVA_BEAST_ATTACK_RANGE = 1400;
private static final String LAVA_BEAST = "Lava beast";
private static final Pattern coltagPattern = Pattern.compile("((<col=([0-f]){6}>)|(<\\/col>))");
@Inject
@Nullable
Client client;
@Inject
RuneLite runeLite;
@Inject
VolcanicMineConfig config;
@Inject
VolcanicMineOverlay overlay;
private Map<Tile, Instant> objectTimerMap = new HashMap<>();
private boolean drawRangePray = false;
private boolean isAboutToFall = false;
private boolean isAboutToCollapse = false;
private boolean timerRunningLow = false;
private boolean isInside = false;
private int stabilityPercentageThreshold;
@Override
public void configure(Binder binder)
{
binder.bind(VolcanicMineOverlay.class);
}
@Provides
VolcanicMineConfig provideConfig(ConfigManager configManager)
{
return configManager.getConfig(VolcanicMineConfig.class);
}
@Override
protected void startUp() throws Exception
{
if (config.stabilityPercentageThreshold() >= -1 && config.stabilityPercentageThreshold() <= 100)
{
stabilityPercentageThreshold = config.stabilityPercentageThreshold();
}
}
public Boolean getInside()
{
return isInside;
}
public VolcanicMineConfig getConfig()
{
return config;
}
public Map<Tile, Instant> getObjectTimerMap()
{
return objectTimerMap;
}
public Boolean getDrawRangePray()
{
return drawRangePray;
}
@Override
public Overlay getOverlay()
{
return overlay;
}
@Subscribe
public void onConfigChanged(ConfigChanged event)
{
if (config.stabilityPercentageThreshold() >= -1 && config.stabilityPercentageThreshold() <= 100)
{
stabilityPercentageThreshold = config.stabilityPercentageThreshold();
}
}
@Schedule(
period = 600,
unit = ChronoUnit.MILLIS
)
public void update()
{
if (client.getGameState() != GameState.LOGGED_IN || !config.enabled())
{
return;
}
isInside = isInside();
if (!isInside)
{
return;
}
lookForGameObjects();
cleanMap();
//-- it is unlikely more than 1 of the following notifications will be triggered in 1 update call.
//-- it is possible so maybe send 1 notification per update max which contains the message(s)?
//check if in range of a lava beast
boolean lastRangePray = drawRangePray;
drawRangePray = lavaBeastInRange(client.getLocalPlayer());
if (!client.isPrayerActive(Prayer.PROTECT_FROM_MISSILES) && drawRangePray && !lastRangePray)
{
warnPlayer(config.prayerWarning(), "Turn on prayer!");
}
//check if about to fall into lava
boolean lastIsAboutToFall = isAboutToFall;
isAboutToFall = isAboutToFall(client.getLocalPlayer().getLocalLocation());
if (isAboutToFall && !lastIsAboutToFall)
{
warnPlayer(config.hotTileWarning(), "Watch out for the lava!");
}
//check if timer is about to run out
boolean lastTimerRunningLow = timerRunningLow;
timerRunningLow = isTimerRunningLow();
if (timerRunningLow && !lastTimerRunningLow)
{
warnPlayer(config.timerWarning(), "Time to bail!");
}
//check if stability is low
boolean lastIsAboutToCollapse = isAboutToCollapse;
isAboutToCollapse = isAboutToCollapse();
if (isAboutToCollapse && !lastIsAboutToCollapse)
{
warnPlayer(config.stabilityWarning(), "Stability is low!");
}
}
private boolean isAboutToCollapse()
{
Widget widget = client.getWidget(WidgetInfo.VOLCANICMINE_STABILITY);
if (widget != null && !widget.isHidden())
{
try
{
if (Integer.parseInt(removeColTags(widget.getText().replace("%", ""))) < stabilityPercentageThreshold) //sanitize of col tags
{
return true;
}
}
catch (NumberFormatException ex)
{
logger.debug("Failed to retrieve stability percentage", ex);
}
}
return false;
}
private boolean isTimerRunningLow()
{
Widget widget = client.getWidget(WidgetInfo.VOLCANICMINE_TIME_LEFT);
if (widget != null && !widget.isHidden())
{
try
{
if (timeToSeconds(widget.getText()) < config.timerThreshold())
{
return true;
}
}
catch (NumberFormatException ex)
{
logger.debug("Failed to retrieve time left", ex);
}
}
return false;
}
private boolean isAboutToFall(Point point)
{
Instant now = Instant.now();
for (Tile tile : objectTimerMap.keySet())
{
if (tile.getGameObjects() != null
&& tile.getGameObjects()[0] != null
&& tile.getGameObjects()[0].getLocalLocation().equals(point)
&& objectTimerMap.get(tile).isAfter(now) //in case the entry hasn't been removed from the hashmap, ignore.
&& Duration.between(now, objectTimerMap.get(tile)).getSeconds() < config.platformTimerThreshold())
{
return true;
}
}
return false;
}
private boolean isInside()
{
Widget widget = client.getWidget(WidgetInfo.VOLCANICMINE_GENERAL_INFOBOX_GROUP);
return widget != null && !widget.isHidden();
}
private boolean lavaBeastInRange(Player player)
{
Query query = new NPCQuery()
.nameEquals(LAVA_BEAST)
.isWithinArea(player.getLocalLocation(), LAVA_BEAST_ATTACK_RANGE);
NPC[] npcs = runeLite.runQuery(query);
return npcs.length > 0;
}
private void warnPlayer(WarningMode warningMode, String warning)
{
if (warningMode == WarningMode.INGAME || warningMode == WarningMode.INGAME_AND_NOTIFICATION)
{
client.sendGameMessage(getColTag(config.platformColorHigh()) + "Volcanic Mine helper: " + warning);
}
if (warningMode == WarningMode.NOTIFICATION || warningMode == WarningMode.INGAME_AND_NOTIFICATION)
{
sendNotification(warning);
}
}
private void sendNotification(String message)
{
if (!config.alertWhenFocused() && runeLite.getGui().isFocused())
{
return;
}
if (config.requestFocus())
{
runeLite.getGui().requestFocus();
}
if (config.sendTrayNotification())
{
runeLite.notify(message);
}
}
private void lookForGameObjects()
{
Player player = client.getLocalPlayer();
Region region = client.getRegion();
Tile[][][] tiles = region.getTiles();
int z = client.getPlane();
for (int x = 0; x < REGION_SIZE; ++x)
{
for (int y = 0; y < REGION_SIZE; ++y)
{
Tile tile = tiles[z][x][y];
if (tile == null)
{
continue;
}
lookForPlatforms(tile, player);
}
}
}
private void lookForPlatforms(Tile tile, Player player)
{
Point playerLocation = player.getLocalLocation();
GameObject[] gameObjects = tile.getGameObjects();
if (gameObjects == null)
{
return;
}
for (GameObject gameObject : gameObjects)
{
if (gameObject == null)
{
continue;
}
LavaPlatform lavaPlatform = LavaPlatform.fromId(gameObject.getId());
Point objectLocation = gameObject.getLocalLocation();
if (lavaPlatform == null
|| abs(playerLocation.getX() - objectLocation.getX()) > MAX_DISTANCE
|| abs(playerLocation.getY() - objectLocation.getY()) > MAX_DISTANCE)
{
continue;
}
Instant now = Instant.now();
Instant vanishTime = now.plus(lavaPlatform.getTime());
Instant returnInstant = objectTimerMap.putIfAbsent(tile, vanishTime);
if (returnInstant != null)
{
if (returnInstant.isBefore(now)
|| vanishTime.isBefore(returnInstant))
{
objectTimerMap.replace(tile, vanishTime);
}
}
}
}
private void cleanMap()
{
//remove the timers which hit 0
objectTimerMap = objectTimerMap.entrySet().stream()
.filter(entry -> Instant.now().isBefore(entry.getValue()))
.filter(v -> v.getKey().getGameObjects() != null && v.getKey().getGameObjects()[0] != null && v.getKey().getGameObjects()[0].getId() != LAVA_ID)
.collect(Collectors.toMap(Entry::getKey, Entry::getValue));
}
public static int timeToSeconds(String s) throws NumberFormatException
{
String[] time = s.split(":", 2);
if (time.length < 2)
{
return Integer.parseInt(time[0]);
}
return Integer.parseInt(time[0]) * 60 + Integer.parseInt(time[1]);
}
public static String getColTag(Color color)
{
return color == null ? "" : "<col=" + Integer.toHexString(color.getRGB() & 0xFFFFFF) + ">";
}
public static String removeColTags(String s)
{
StringBuffer result = new StringBuffer();
Matcher m = coltagPattern.matcher(s);
while (m.find())
{
m.appendReplacement(result, "");
}
m.appendTail(result);
return result.toString();
}
}

View File

@@ -0,0 +1,218 @@
/*
* Copyright (c) 2017. l2-
*
* 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.volcanicminehelper;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.io.IOException;
import java.io.InputStream;
import java.time.Duration;
import java.time.Instant;
import javax.annotation.Nullable;
import javax.imageio.ImageIO;
import javax.inject.Inject;
import net.runelite.api.Client;
import net.runelite.api.GameObject;
import net.runelite.api.GameState;
import net.runelite.api.Point;
import net.runelite.api.Prayer;
import net.runelite.api.Region;
import net.runelite.api.Tile;
import net.runelite.client.ui.FontManager;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayPosition;
import net.runelite.client.ui.overlay.OverlayUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class VolcanicMineOverlay extends Overlay
{
private static final Logger logger = LoggerFactory.getLogger(VolcanicMineHelperPlugin.class);
private static final int THRESH_LOW = 45;
private static final int THRESH_MED = 5;
private static final int REGION_SIZE = 104;
private static final int Z_OFFSET_TIMER = 25;
private static final String PROTECT_MESSAGE = "Protect!";
private final VolcanicMineHelperPlugin plugin;
private final VolcanicMineConfig config;
private final Client client;
private Image protectFromMissilesImg;
@Inject
VolcanicMineOverlay(@Nullable Client client, VolcanicMineHelperPlugin plugin, VolcanicMineConfig config)
{
super(OverlayPosition.DYNAMIC);
this.client = client;
this.plugin = plugin;
this.config = config;
}
@Override
public Dimension render(Graphics2D graphics)
{
if (client == null || client.getGameState() != GameState.LOGGED_IN || !plugin.getInside() || !config.enabled())
{
return null;
}
Font font = FontManager.getRunescapeFont();
if (font != null)
{
graphics.setFont(font);
}
renderTileObjects(graphics);
renderRangePrayer(graphics);
return null;
}
private void renderRangePrayer(Graphics2D graphics)
{
if (client.getViewportWidget() == null || !plugin.getDrawRangePray() || !config.prayerHelperEnabled())
{
return;
}
Image protectFromMissiles = getProtectFromMissilesImage();
if (protectFromMissiles == null)
{
return;
}
Rectangle viewport = client.getViewportWidget().getBounds();
Rectangle stringBounds = graphics.getFontMetrics().getStringBounds(PROTECT_MESSAGE, graphics).getBounds();
int x = (int) (viewport.getX() + viewport.getWidth());
int y = (int) (viewport.getY() + viewport.getHeight());
int width = (int) stringBounds.getWidth() + 6;
int height = (int) (protectFromMissiles.getHeight(null) + stringBounds.getHeight()) + 5;
Rectangle rectangle = new Rectangle(x - width, y - height, width, height);
graphics.setColor(new Color(255, 255, 255, 150));
graphics.fillRect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
graphics.setColor(client.isPrayerActive(Prayer.PROTECT_FROM_MISSILES) ? Color.GREEN : Color.WHITE);
graphics.drawRect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
graphics.drawImage(protectFromMissiles, x - protectFromMissiles.getWidth(null) - 10, y - protectFromMissiles.getHeight(null) - 15, null);
graphics.drawString(PROTECT_MESSAGE, x - (int) stringBounds.getWidth() - 2, y);
}
//this is less efficient than drawing from the map however this is more accurate as it doesn't draw false positives (tiles which are not in the current region).
private void renderTileObjects(Graphics2D graphics)
{
Region region = client.getRegion();
Tile[][][] tiles = region.getTiles();
int z = client.getPlane();
for (int x = 0; x < REGION_SIZE; ++x)
{
for (int y = 0; y < REGION_SIZE; ++y)
{
Tile tile = tiles[z][x][y];
if (tile == null)
{
continue;
}
renderGameObjects(graphics, tile);
}
}
}
private void renderGameObjects(Graphics2D graphics, Tile tile)
{
GameObject[] gameObjects = tile.getGameObjects();
if (gameObjects == null)
{
return;
}
for (GameObject gameObject : gameObjects)
{
if (gameObject != null && plugin.getObjectTimerMap().containsKey(tile))
{
Duration duration = Duration.between(Instant.now(), plugin.getObjectTimerMap().get(tile));
if (!duration.isNegative())
{
long seconds = duration.getSeconds();
int minutes = (int) seconds / 60;
String text = String.format("%d:%02d", minutes, seconds % 60); // format as m:ss
Color color;
if (seconds > THRESH_LOW)
{
color = config.platformColorLow();;
}
else if (seconds > THRESH_MED)
{
color = config.platformColorMed();
}
else
{
color = config.platformColorHigh();
}
Point location = gameObject.getCanvasTextLocation(graphics, text, Z_OFFSET_TIMER);
if (location != null)
{
OverlayUtil.renderTextLocation(graphics, location, text, color);
return; //only 1 timer per tile
}
}
}
}
}
public Image getProtectFromMissilesImage()
{
if (protectFromMissilesImg == null)
{
String path = "/prayers/protect_from_missiles.png";
protectFromMissilesImg = getImage(path);
}
return protectFromMissilesImg;
}
private Image getImage(String path)
{
Image image = null;
try
{
InputStream in = VolcanicMineOverlay.class.getResourceAsStream(path);
image = ImageIO.read(in);
}
catch (IOException e)
{
logger.warn("Error loading image", e);
}
return image;
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright (c) 2017. l2-
*
* 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.volcanicminehelper;
public enum WarningMode
{
OFF("Off"),
INGAME("Ingame message"),
NOTIFICATION("Windows notification"),
INGAME_AND_NOTIFICATION("Ingame & notification");
private final String name;
WarningMode(String name)
{
this.name = name;
}
@Override
public String toString()
{
return name;
}
}