diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/roguesden/Obstacles.java b/runelite-client/src/main/java/net/runelite/client/plugins/roguesden/Obstacles.java index 59c2c9428e..62fd01bcc0 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/roguesden/Obstacles.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/roguesden/Obstacles.java @@ -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 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 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 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); + } + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/roguesden/RoguesDenMinimapOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/roguesden/RoguesDenMinimapOverlay.java new file mode 100644 index 0000000000..4dc0c11b9e --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/roguesden/RoguesDenMinimapOverlay.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2018, Jordan Atwood + * 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; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/roguesden/RoguesDenOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/roguesden/RoguesDenOverlay.java index e76f6c4f70..2a4775fdce 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/roguesden/RoguesDenOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/roguesden/RoguesDenOverlay.java @@ -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; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/roguesden/RoguesDenPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/roguesden/RoguesDenPlugin.java index 469a1ff4cd..e77b5e2019 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/roguesden/RoguesDenPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/roguesden/RoguesDenPlugin.java @@ -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 obstaclesHull = new HashMap<>(); + private final HashMap obstaclesHull = new HashMap<>(); @Getter(AccessLevel.PACKAGE) - private final Map obstaclesTile = new HashMap<>(); + private final HashMap 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); + } } } } \ No newline at end of file