rogues den plugin: Improve Rogue's Den overlay (#1212)

This patch changes the Rogue's Den plugin to have a more guide-like
overlay, displaying the location of tiles to stand on, obstacles to
interact with, etc.

Co-authored-by: Jordan Atwood <jordan.atwood423@gmail.com>
This commit is contained in:
Owain van Brakel
2019-08-01 05:29:54 +02:00
committed by Ganom
parent bbf6bb8850
commit e09eeb5748
4 changed files with 379 additions and 82 deletions

View File

@@ -24,41 +24,171 @@
*/
package net.runelite.client.plugins.roguesden;
import com.google.common.collect.Sets;
import java.util.Set;
import static net.runelite.api.NullObjectID.NULL_7235;
import static net.runelite.api.ObjectID.BLADE_7252;
import static net.runelite.api.ObjectID.CONTORTION_BARS;
import static net.runelite.api.ObjectID.FLOOR;
import static net.runelite.api.ObjectID.FLOOR_7230;
import static net.runelite.api.ObjectID.FLOOR_7245;
import static net.runelite.api.ObjectID.LEDGE_7240;
import static net.runelite.api.ObjectID.PENDULUM;
import static net.runelite.api.ObjectID.SPINNING_BLADES_7224;
import static net.runelite.api.ObjectID.WALL_7228;
import static net.runelite.api.ObjectID.WALL_7229;
import static net.runelite.api.ObjectID.WALL_7248;
import static net.runelite.api.ObjectID.WALL_7249;
import java.awt.Color;
import java.util.HashMap;
import java.util.Map;
import lombok.Getter;
import net.runelite.api.coords.WorldPoint;
import static net.runelite.api.ObjectID.*;
class Obstacles
{
static final Set<Integer> OBSTACLE_IDS_HULL = Sets.newHashSet(
SPINNING_BLADES_7224,
CONTORTION_BARS,
PENDULUM,
WALL_7249, /*Wall crushers*/
WALL_7248, /*Wall blade*/
LEDGE_7240, /*Ledge climb*/
NULL_7235 /*Wall safe*/
);
static final Map<WorldPoint, Obstacle> TILE_MAP = new HashMap<>();
static final Obstacle[] OBSTACLES =
{
new Obstacle(3050, 4997, "Enter"),
new Obstacle(3049, 4997, CONTORTION_BARS),
new Obstacle(3039, 4999, "Stand"),
new Obstacle(3029, 5003, "Run"),
new Obstacle(3024, 5001, "Open", GRILL_7255),
new Obstacle(3011, 5005, "Run"),
new Obstacle(3004, 5003, "Run"),
static final Set<Integer> OBSTACLE_IDS_TILE = Sets.newHashSet(
FLOOR, /*Floor spikes*/
WALL_7228, /*Wall spikes*/
WALL_7229, /*Wall spears*/
FLOOR_7245, /*Pressure pad a*/
FLOOR_7230, /*Pressure pad b*/
BLADE_7252, /*Floor blade*/
7239 /*Bridge [Ground object]*/
);
new Obstacle(2994, 5004, "Climb"),
new Obstacle(2993, 5004, LEDGE_7240),
new Obstacle(2994, 5005, "Climb"),
new Obstacle(2993, 5005, LEDGE_7240),
new Obstacle(2969, 5016, "Stand"),
new Obstacle(2969, 5017, "Stand"),
new Obstacle(2969, 5018, "Stand"),
new Obstacle(2969, 5019, "Stand"),
new Obstacle(2958, 5031, "Cross"),
new Obstacle(2962, 5050, "Stand"),
new Obstacle(2963, 5056, "Run"),
new Obstacle(2957, 5068, "Enter"),
new Obstacle(2957, 5069, PASSAGEWAY),
new Obstacle(2955, 5094, "Enter"),
new Obstacle(2955, 5095, PASSAGEWAY),
new Obstacle(2963, 5105, "Stand"),
new Obstacle(2972, 5098, "Enter"),
new Obstacle(2972, 5097, PASSAGEWAY),
new Obstacle(2972, 5094, "Open"),
new Obstacle(2972, 5094, GRILL_7255),
new Obstacle(2982, 5087, "Climb"),
new Obstacle(2983, 5087, LEDGE_7240),
new Obstacle(2982, 5090, "Climb"),
new Obstacle(2983, 5090, LEDGE_7240),
new Obstacle(2993, 5088, "Search"),
new Obstacle(2993, 5087, WALL_7249),
new Obstacle(2997, 5088, "Run"),
new Obstacle(2993, 5089, "Search"),
new Obstacle(2993, 5089, WALL_7249),
new Obstacle(2997, 5089, "Run"),
new Obstacle(3006, 5088, "Run"),
new Obstacle(3018, 5080, "Take"),
new Obstacle(3023, 5082, "Open", DOOR_7234),
// Maze
new Obstacle(3030, 5079, GRILL_7255),
new Obstacle(3032, 5078, GRILL_7255),
new Obstacle(3036, 5076, GRILL_7255),
new Obstacle(3039, 5079, GRILL_7255),
new Obstacle(3042, 5076, GRILL_7255),
new Obstacle(3044, 5069, GRILL_7255),
new Obstacle(3041, 5068, GRILL_7255),
new Obstacle(3040, 5070, GRILL_7255),
new Obstacle(3038, 5069, GRILL_7255),
new Obstacle(3028, 5033, "Stand"),
new Obstacle(3024, 5033, "Run"),
new Obstacle(3028, 5034, "Stand"),
new Obstacle(3024, 5034, "Run"),
new Obstacle(3015, 5033, "Open", GRILL_7255),
new Obstacle(3010, 5033, "Run/Open", GRILL_7255),
new Obstacle(3000, 5034, "Run"),
new Obstacle(2992, 5045, "Stand"),
new Obstacle(2992, 5053, "Run"),
new Obstacle(2992, 5067, "Stand"),
new Obstacle(2992, 5075, "Run"),
new Obstacle(3009, 5063, "Take"),
new Obstacle(3028, 5056, "Run"),
new Obstacle(3028, 5047, "Walk"),
new Obstacle(3018, 5047, "Crack", WALL_SAFE_7237),
// Start of 80+ thieving shortcut
new Obstacle(2967, 5061, "80 Thieving", DOOR_7246),
new Obstacle(2967, 5066, "80 Thieving", DOOR_7246),
new Obstacle(2974, 5061, "Enter"),
new Obstacle(2974, 5060, CONTORTION_BARS),
new Obstacle(2989, 5057, "Open", GRILL_7255),
new Obstacle(2989, 5058, "Open", GRILL_7255),
// The 3x3 square around the spinning blade in the middle of the maze
new AvoidObstacle(2977, 5090), new AvoidObstacle(2978, 5090), new AvoidObstacle(2979, 5090),
new AvoidObstacle(2977, 5089), new AvoidObstacle(2978, 5089), new AvoidObstacle(2979, 5089),
new AvoidObstacle(2977, 5088), new AvoidObstacle(2978, 5088), new AvoidObstacle(2979, 5088),
new TipObstacle(3014, 5063, "Stun NPC"),
new TipObstacle(2992, 5057, "Continue North"), // Hint for 80 thieving shortcut
};
@Getter
static class Obstacle
{
private WorldPoint tile;
private String hint;
private int objectId = -1;
private final Color tileColor = Color.GREEN;
// Highlights tile and shows a hint
private Obstacle(int x, int y, String hint)
{
tile = new WorldPoint(x, y, 1);
this.hint = hint;
}
// Doesn't highlight tile, but instead highlights object of objectId found on tile
private Obstacle(int x, int y, int objectId)
{
this(x, y, "");
this.objectId = objectId;
TILE_MAP.put(new WorldPoint(x, y, 1), this);
}
// Doesn't highlight tile, but instead highlights object of objectId found on tile and shows a hint
private Obstacle(int x, int y, String hint, int objectId)
{
this(x, y, objectId);
this.hint = hint;
}
}
private static class AvoidObstacle extends Obstacle
{
@Getter
private final Color tileColor = Color.RED;
private AvoidObstacle(int x, int y)
{
super(x, y, "AVOID");
}
}
private static class TipObstacle extends Obstacle
{
@Getter
private final Color tileColor = Color.ORANGE;
private TipObstacle(int x, int y, String hint)
{
super(x, y, hint);
}
}
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright (c) 2018, Jordan Atwood <jordan.atwood423@gmail.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.roguesden;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import javax.inject.Inject;
import net.runelite.api.Client;
import net.runelite.api.Perspective;
import net.runelite.api.Point;
import net.runelite.api.coords.LocalPoint;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer;
import net.runelite.client.ui.overlay.OverlayPosition;
import net.runelite.client.ui.overlay.OverlayUtil;
class RoguesDenMinimapOverlay extends Overlay
{
private Client client;
private RoguesDenPlugin plugin;
@Inject
public RoguesDenMinimapOverlay(Client client, RoguesDenPlugin plugin)
{
setPosition(OverlayPosition.DYNAMIC);
setLayer(OverlayLayer.ABOVE_WIDGETS);
this.client = client;
this.plugin = plugin;
}
@Override
public Dimension render(Graphics2D graphics)
{
if (!plugin.isHasGem())
{
return null;
}
for (Obstacles.Obstacle obstacle : Obstacles.OBSTACLES)
{
final LocalPoint localPoint = LocalPoint.fromWorld(client, obstacle.getTile());
if (localPoint == null || obstacle.getTile().getPlane() != client.getPlane())
{
continue;
}
final Point minimapPoint = Perspective.localToMinimap(client, localPoint);
if (minimapPoint != null)
{
OverlayUtil.renderMinimapLocation(graphics, minimapPoint, obstacle.getObjectId() == -1 ? Color.GREEN : Color.RED);
}
}
return null;
}
}

View File

@@ -28,10 +28,15 @@ import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.geom.Area;
import javax.inject.Inject;
import javax.inject.Singleton;
import net.runelite.api.Client;
import net.runelite.api.GameObject;
import net.runelite.api.Perspective;
import net.runelite.api.Point;
import net.runelite.api.coords.LocalPoint;
import net.runelite.client.graphics.ModelOutlineRenderer;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer;
import net.runelite.client.ui.overlay.OverlayPosition;
@@ -39,18 +44,22 @@ import net.runelite.client.ui.overlay.OverlayPosition;
@Singleton
public class RoguesDenOverlay extends Overlay
{
private static final int MAX_DISTANCE = 2350;
private static final Color OBJECT_BORDER_COLOR = Color.RED;
private static final Color OBJECT_COLOR = new Color(OBJECT_BORDER_COLOR.getRed(), OBJECT_BORDER_COLOR.getGreen(), OBJECT_BORDER_COLOR.getBlue(), 50);
private static final Color OBJECT_BORDER_HOVER_COLOR = OBJECT_BORDER_COLOR.darker();
private final Client client;
private final RoguesDenPlugin plugin;
private final ModelOutlineRenderer modelOutliner;
@Inject
public RoguesDenOverlay(final Client client, final RoguesDenPlugin plugin)
public RoguesDenOverlay(final Client client, final RoguesDenPlugin plugin, ModelOutlineRenderer modelOutliner)
{
setPosition(OverlayPosition.DYNAMIC);
setLayer(OverlayLayer.ABOVE_SCENE);
this.client = client;
this.plugin = plugin;
this.modelOutliner = modelOutliner;
}
@Override
@@ -61,33 +70,74 @@ public class RoguesDenOverlay extends Overlay
return null;
}
LocalPoint playerLocation = client.getLocalPlayer().getLocalLocation();
plugin.getObstaclesHull().forEach((obstacle, tile) ->
{
if (tile.getPlane() == client.getPlane() && obstacle.getLocalLocation().distanceTo(playerLocation) < MAX_DISTANCE)
if (tile.getPlane() == client.getPlane())
{
Polygon p = tile.getGameObjects()[0].getConvexHull();
if (p != null)
final Area clickBox = obstacle.getClickbox();
if (clickBox != null)
{
graphics.setColor(Color.CYAN);
graphics.drawPolygon(p);
final Point mouse = client.getMouseCanvasPosition();
if (clickBox.contains(mouse.getX(), mouse.getY()))
{
graphics.setColor(OBJECT_BORDER_HOVER_COLOR);
}
else
{
graphics.setColor(OBJECT_BORDER_COLOR);
}
graphics.draw(clickBox);
graphics.setColor(OBJECT_COLOR);
graphics.fill(clickBox);
}
else
{
Polygon p;
if (obstacle instanceof GameObject)
{
p = ((GameObject) obstacle).getConvexHull();
}
else
{
p = obstacle.getCanvasTilePoly();
}
if (p != null)
{
graphics.setColor(OBJECT_COLOR);
graphics.drawPolygon(p);
}
}
}
});
plugin.getObstaclesTile().forEach((obstacle, tile) ->
for (Obstacles.Obstacle obstacle : Obstacles.OBSTACLES)
{
if (tile.getPlane() == client.getPlane() && obstacle.getLocalLocation().distanceTo(playerLocation) < MAX_DISTANCE)
final LocalPoint localPoint = LocalPoint.fromWorld(client, obstacle.getTile());
if (localPoint == null || obstacle.getTile().getPlane() != client.getPlane())
{
Polygon p = obstacle.getCanvasTilePoly();
if (p != null)
continue;
}
if (!obstacle.getHint().isEmpty())
{
final Polygon polygon = Perspective.getCanvasTilePoly(client, localPoint);
if (polygon != null)
{
graphics.setColor(Color.CYAN);
graphics.drawPolygon(p);
graphics.setColor(obstacle.getTileColor());
graphics.drawPolygon(polygon);
}
}
});
final Point textLocation = Perspective.getCanvasTextLocation(client, graphics, localPoint, obstacle.getHint(), 0);
if (textLocation != null)
{
graphics.setColor(Color.LIGHT_GRAY);
graphics.drawString(obstacle.getHint(), textLocation.getX(), textLocation.getY());
}
}
return null;
}

View File

@@ -25,18 +25,19 @@
package net.runelite.client.plugins.roguesden;
import java.util.HashMap;
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.AccessLevel;
import lombok.Getter;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.InventoryID;
import net.runelite.api.Item;
import net.runelite.api.ItemID;
import static net.runelite.api.ItemID.MYSTIC_JEWEL;
import net.runelite.api.Tile;
import net.runelite.api.TileObject;
import net.runelite.api.coords.WorldPoint;
import net.runelite.api.events.DecorativeObjectChanged;
import net.runelite.api.events.DecorativeObjectDespawned;
import net.runelite.api.events.DecorativeObjectSpawned;
import net.runelite.api.events.GameObjectChanged;
import net.runelite.api.events.GameObjectDespawned;
import net.runelite.api.events.GameObjectSpawned;
@@ -45,24 +46,27 @@ import net.runelite.api.events.GroundObjectChanged;
import net.runelite.api.events.GroundObjectDespawned;
import net.runelite.api.events.GroundObjectSpawned;
import net.runelite.api.events.ItemContainerChanged;
import net.runelite.api.events.WallObjectChanged;
import net.runelite.api.events.WallObjectDespawned;
import net.runelite.api.events.WallObjectSpawned;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.overlay.OverlayManager;
import net.runelite.client.util.ItemUtil;
@PluginDescriptor(
name = "Rogues' Den",
description = "Mark tiles and clickboxes to help traverse the maze",
tags = {"agility", "maze", "minigame", "overlay", "thieving"}
name = "Rogues' Den",
description = "Mark tiles and clickboxes to help traverse the maze",
tags = {"agility", "maze", "minigame", "overlay", "thieving"}
)
@Singleton
public class RoguesDenPlugin extends Plugin
{
@Getter(AccessLevel.PACKAGE)
private final Map<TileObject, Tile> obstaclesHull = new HashMap<>();
private final HashMap<TileObject, Tile> obstaclesHull = new HashMap<>();
@Getter(AccessLevel.PACKAGE)
private final Map<TileObject, Tile> obstaclesTile = new HashMap<>();
private final HashMap<TileObject, Tile> obstaclesTile = new HashMap<>();
@Getter(AccessLevel.PACKAGE)
private boolean hasGem;
@@ -76,6 +80,9 @@ public class RoguesDenPlugin extends Plugin
@Inject
private RoguesDenOverlay overlay;
@Inject
private RoguesDenMinimapOverlay minimapOverlay;
@Inject
private EventBus eventBus;
@@ -85,6 +92,7 @@ public class RoguesDenPlugin extends Plugin
addSubscriptions();
overlayManager.add(overlay);
overlayManager.add(minimapOverlay);
}
@Override
@@ -93,6 +101,7 @@ public class RoguesDenPlugin extends Plugin
eventBus.unregister(this);
overlayManager.remove(overlay);
overlayManager.remove(minimapOverlay);
obstaclesHull.clear();
obstaclesTile.clear();
hasGem = false;
@@ -108,6 +117,12 @@ public class RoguesDenPlugin extends Plugin
eventBus.subscribe(GroundObjectChanged.class, this, this::onGroundObjectChanged);
eventBus.subscribe(GroundObjectDespawned.class, this, this::onGroundObjectDespawned);
eventBus.subscribe(GameStateChanged.class, this, this::onGameStateChanged);
eventBus.subscribe(WallObjectSpawned.class, this, this::onWallObjectSpawned);
eventBus.subscribe(WallObjectChanged.class, this, this::onWallObjectChanged);
eventBus.subscribe(WallObjectDespawned.class, this, this::onWallObjectDespawned);
eventBus.subscribe(DecorativeObjectSpawned.class, this, this::onDecorativeObjectSpawned);
eventBus.subscribe(DecorativeObjectChanged.class, this, this::onDecorativeObjectChanged);
eventBus.subscribe(DecorativeObjectDespawned.class, this, this::onDecorativeObjectDespawned);
}
private void onItemContainerChanged(ItemContainerChanged event)
@@ -117,16 +132,16 @@ public class RoguesDenPlugin extends Plugin
return;
}
for (Item item : event.getItemContainer().getItems())
{
if (item.getId() == ItemID.MYSTIC_JEWEL)
{
hasGem = true;
return;
}
}
hasGem = ItemUtil.containsItemId(event.getItemContainer().getItems(), MYSTIC_JEWEL);
}
hasGem = false;
private void onGameStateChanged(GameStateChanged event)
{
if (event.getGameState() == GameState.LOADING)
{
obstaclesHull.clear();
obstaclesTile.clear();
}
}
private void onGameObjectSpawned(GameObjectSpawned event)
@@ -159,27 +174,48 @@ public class RoguesDenPlugin extends Plugin
onTileObject(event.getTile(), event.getGroundObject(), null);
}
private void onGameStateChanged(GameStateChanged event)
private void onWallObjectSpawned(WallObjectSpawned event)
{
if (event.getGameState() == GameState.LOADING)
{
obstaclesHull.clear();
obstaclesTile.clear();
}
onTileObject(event.getTile(), null, event.getWallObject());
}
private void onTileObject(Tile tile, TileObject oldObject, TileObject newObject)
private void onWallObjectChanged(WallObjectChanged event)
{
onTileObject(event.getTile(), event.getPrevious(), event.getWallObject());
}
private void onWallObjectDespawned(WallObjectDespawned event)
{
onTileObject(event.getTile(), event.getWallObject(), null);
}
private void onDecorativeObjectSpawned(DecorativeObjectSpawned event)
{
onTileObject(event.getTile(), null, event.getDecorativeObject());
}
private void onDecorativeObjectChanged(DecorativeObjectChanged event)
{
onTileObject(event.getTile(), event.getPrevious(), event.getDecorativeObject());
}
private void onDecorativeObjectDespawned(DecorativeObjectDespawned event)
{
onTileObject(event.getTile(), event.getDecorativeObject(), null);
}
private void onTileObject(final Tile tile, final TileObject oldObject, final TileObject newObject)
{
obstaclesHull.remove(oldObject);
if (newObject != null && Obstacles.OBSTACLE_IDS_HULL.contains(newObject.getId()))
if (newObject != null)
{
obstaclesHull.put(newObject, tile);
}
WorldPoint point = tile.getWorldLocation();
obstaclesTile.remove(oldObject);
if (newObject != null && Obstacles.OBSTACLE_IDS_TILE.contains(newObject.getId()))
{
obstaclesTile.put(newObject, tile);
Obstacles.Obstacle obstacle = Obstacles.TILE_MAP.get(point);
if (obstacle != null && obstacle.getObjectId() == newObject.getId())
{
obstaclesHull.put(newObject, tile);
}
}
}
}