Addeds arrow api, quest helper plugin, changed raids etc (#81)
* add a skull timer * fix the feature and check edge cases * Add config option and a check for deadman worlds * add support for NPE * Add reskulling on players and the BH shop skull option * Add skull notifier plugin * move to idle notification plugin * remove old plugin * fix plugin and change default config option to false * fix to try and fix travis * should fix travis * indentation fix and adds a method for the logic * fix config * fix config #2 * Stop a NPE from happening on log in * actually fix NPE * fix notifications on first tick * Remove raids timer infobox and add tooltip to points widget * Add get widget overlay * client: add custom arrow API Currently supports: Minimap Arbitrary World Point NPCs (by ID, and multiple per arrow) Objects (by ID, and multiple per arrow) TODO: Add world map point support * Add quest helper * Add Npc Talk Step to quest helper * Add Cooks Assistant quest helper * Add Imp Catcher to quest helper * Add Dig Step to quest helper * Add X Marks The Spot to quest helper * Adds back skull timer
This commit is contained in:
@@ -66,6 +66,8 @@ import net.runelite.client.ui.RuneLiteSplashScreen;
|
||||
import net.runelite.client.ui.overlay.OverlayManager;
|
||||
import net.runelite.client.ui.overlay.OverlayRenderer;
|
||||
import net.runelite.client.ui.overlay.WidgetOverlay;
|
||||
import net.runelite.client.ui.overlay.arrow.ArrowMinimapOverlay;
|
||||
import net.runelite.client.ui.overlay.arrow.ArrowWorldOverlay;
|
||||
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
|
||||
import net.runelite.client.ui.overlay.infobox.InfoBoxOverlay;
|
||||
import net.runelite.client.ui.overlay.tooltip.TooltipOverlay;
|
||||
@@ -148,6 +150,12 @@ public class RuneLite
|
||||
@Inject
|
||||
private Provider<WorldMapOverlay> worldMapOverlay;
|
||||
|
||||
@Inject
|
||||
private Provider<ArrowWorldOverlay> arrowWorldOverlay;
|
||||
|
||||
@Inject
|
||||
private Provider<ArrowMinimapOverlay> arrowMinimapOverlay;
|
||||
|
||||
@Inject
|
||||
private Provider<LootManager> lootManager;
|
||||
|
||||
@@ -323,6 +331,8 @@ public class RuneLite
|
||||
overlayManager.add(infoBoxOverlay.get());
|
||||
overlayManager.add(worldMapOverlay.get());
|
||||
overlayManager.add(tooltipOverlay.get());
|
||||
overlayManager.add(arrowWorldOverlay.get());
|
||||
overlayManager.add(arrowMinimapOverlay.get());
|
||||
}
|
||||
|
||||
// Start plugins
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
package net.runelite.client.plugins.example;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashSet;
|
||||
import javax.inject.Inject;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.GameState;
|
||||
import net.runelite.api.ItemID;
|
||||
import net.runelite.api.Point;
|
||||
import net.runelite.api.SpriteID;
|
||||
import net.runelite.api.coords.WorldPoint;
|
||||
import net.runelite.client.callback.ClientThread;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.game.SpriteManager;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
import net.runelite.client.plugins.PluginDescriptor;
|
||||
import net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit;
|
||||
import net.runelite.client.ui.overlay.arrow.ArrowPoint;
|
||||
import net.runelite.client.ui.overlay.arrow.ArrowPointManager;
|
||||
import net.runelite.client.ui.overlay.arrow.ArrowType;
|
||||
|
||||
@PluginDescriptor(
|
||||
name = "ArrowTest",
|
||||
developerPlugin = true
|
||||
)
|
||||
public class ExamplePlugin extends Plugin
|
||||
{
|
||||
@Inject
|
||||
private ArrowPointManager arrowPointManager;
|
||||
|
||||
@Inject
|
||||
private SpriteManager spriteManager;
|
||||
|
||||
@Inject
|
||||
private ItemManager itemManager;
|
||||
|
||||
@Inject
|
||||
private Client client;
|
||||
|
||||
@Inject
|
||||
private ClientThread clientThread;
|
||||
|
||||
private boolean firstLogin = true;
|
||||
|
||||
@Override
|
||||
public void startUp() throws Exception
|
||||
{
|
||||
clientThread.invokeLater(this::loadArrows);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutDown()
|
||||
{
|
||||
arrowPointManager.clear();
|
||||
}
|
||||
|
||||
public void loadArrows()
|
||||
{
|
||||
if (client.getGameState() != GameState.LOGGED_IN)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BufferedImage i = spriteManager.getSprite(SpriteID.MINIMAP_GUIDE_ARROW_YELLOW, 0);
|
||||
|
||||
BufferedImage i3 = spriteManager.getSprite(SpriteID.RED_GUIDE_ARROW, 0);
|
||||
AffineTransform at = new AffineTransform();
|
||||
at.concatenate(AffineTransform.getScaleInstance(1, -1));
|
||||
at.concatenate(AffineTransform.getTranslateInstance(0, -i3.getHeight()));
|
||||
BufferedImage i4 = new BufferedImage(i3.getWidth(), i3.getHeight(), BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g = i4.createGraphics();
|
||||
g.transform(at);
|
||||
g.drawImage(i3, 0, 0, null);
|
||||
g.dispose();
|
||||
|
||||
Point i3Offset = new Point(0, i3.getHeight() / -2);
|
||||
|
||||
ArrowPoint one = ArrowPoint.builder()
|
||||
.worldPoint(new WorldPoint(1554, 3551, 0))
|
||||
.minimapImage(i4)
|
||||
.worldImage(i)
|
||||
.minimapImageOffset(i3Offset)
|
||||
.types(EnumSet.of(ArrowType.MINIMAP, ArrowType.WORLD_POINT))
|
||||
.build();
|
||||
//arrowPointManager.add(this, one);
|
||||
|
||||
ArrowPoint two = ArrowPoint.builder()
|
||||
.worldPoint(new WorldPoint(1544, 3580, 0))
|
||||
.minimapImage(i4)
|
||||
.worldImage(i)
|
||||
.minimapImageOffset(i3Offset)
|
||||
.types(EnumSet.of(ArrowType.MINIMAP, ArrowType.WORLD_POINT))
|
||||
.build();
|
||||
//arrowPointManager.add(this, two);
|
||||
|
||||
ArrowPoint three = ArrowPoint.builder()
|
||||
.worldPoint(new WorldPoint(1571, 3541, 0))
|
||||
.minimapImage(i4)
|
||||
.worldImage(i)
|
||||
.minimapImageOffset(i3Offset)
|
||||
.types(EnumSet.of(ArrowType.MINIMAP, ArrowType.WORLD_POINT))
|
||||
.build();
|
||||
//arrowPointManager.add(this, three);
|
||||
|
||||
HashSet<Integer> NPCs = new HashSet<>();
|
||||
NPCs.add(6910);
|
||||
|
||||
ArrowPoint npcone = ArrowPoint.builder()
|
||||
.worldPoint(new WorldPoint(1545, 3595, 0))
|
||||
.minimapImage(i4)
|
||||
.worldImage(i)
|
||||
.minimapImageOffset(i3Offset)
|
||||
.npcIDs(NPCs)
|
||||
.types(EnumSet.of(ArrowType.MINIMAP, ArrowType.NPC))
|
||||
.build();
|
||||
//arrowPointManager.add(this, npcone);
|
||||
|
||||
HashSet<Integer> NPCs2 = new HashSet<>();
|
||||
NPCs2.add(6889);
|
||||
NPCs2.add(6883);
|
||||
NPCs2.add(6885);
|
||||
|
||||
ArrowPoint npctwo = ArrowPoint.builder()
|
||||
.worldPoint(new WorldPoint(1551, 3561, 0))
|
||||
.minimapImage(i4)
|
||||
.worldImage(i)
|
||||
.minimapImageOffset(i3Offset)
|
||||
.worldImageOffset(new Point(0, -i4.getHeight()))
|
||||
.npcIDs(NPCs2)
|
||||
.types(EnumSet.of(ArrowType.MINIMAP, ArrowType.NPC))
|
||||
.build();
|
||||
//arrowPointManager.add(this, npctwo);
|
||||
|
||||
HashSet<Integer> OBJs = new HashSet<>();
|
||||
OBJs.add(STASHUnit.SHAYZIEN_WAR_TENT);
|
||||
|
||||
ArrowPoint objone = ArrowPoint.builder()
|
||||
.worldPoint(new WorldPoint(1550, 3541, 0))
|
||||
.minimapImage(i4)
|
||||
.worldImage(i)
|
||||
.minimapImageOffset(i3Offset)
|
||||
.worldImageOffset(new Point(0, -i4.getHeight()))
|
||||
.objectIDs(OBJs)
|
||||
.types(EnumSet.of(ArrowType.MINIMAP, ArrowType.OBJECT))
|
||||
.build();
|
||||
arrowPointManager.add(this, objone);
|
||||
|
||||
BufferedImage i5 = itemManager.getImage(ItemID.BONES);
|
||||
|
||||
ArrowPoint four = ArrowPoint.builder()
|
||||
.worldPoint(new WorldPoint(1517, 3553, 0))
|
||||
.minimapImage(i5)
|
||||
.worldImage(i5)
|
||||
.minimapImagePointToTarget(false)
|
||||
.types(EnumSet.of(ArrowType.MINIMAP, ArrowType.WORLD_POINT))
|
||||
.build();
|
||||
//arrowPointManager.add(this, four);
|
||||
}
|
||||
}
|
||||
@@ -64,11 +64,33 @@ public interface IdleNotifierConfig extends Config
|
||||
return true;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
position = 4,
|
||||
keyName = "skullNotification",
|
||||
name = "Skull Notification",
|
||||
description = "Receive a notification when you skull."
|
||||
)
|
||||
default boolean showSkullNotification()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
position = 5,
|
||||
keyName = "unskullNotification",
|
||||
name = "Unskull Notification",
|
||||
description = "Receive a notification when you unskull."
|
||||
)
|
||||
default boolean showUnskullNotification()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "timeout",
|
||||
name = "Idle Notification Delay (ms)",
|
||||
description = "The notification delay after the player is idle",
|
||||
position = 4
|
||||
position = 6
|
||||
)
|
||||
default int getIdleNotificationDelay()
|
||||
{
|
||||
@@ -79,7 +101,7 @@ public interface IdleNotifierConfig extends Config
|
||||
keyName = "hitpoints",
|
||||
name = "Hitpoints Notification Threshold",
|
||||
description = "The amount of hitpoints to send a notification at. A value of 0 will disable notification.",
|
||||
position = 5
|
||||
position = 7
|
||||
)
|
||||
default int getHitpointsThreshold()
|
||||
{
|
||||
@@ -90,7 +112,7 @@ public interface IdleNotifierConfig extends Config
|
||||
keyName = "prayer",
|
||||
name = "Prayer Notification Threshold",
|
||||
description = "The amount of prayer points to send a notification at. A value of 0 will disable notification.",
|
||||
position = 6
|
||||
position = 8
|
||||
)
|
||||
default int getPrayerThreshold()
|
||||
{
|
||||
@@ -100,7 +122,7 @@ public interface IdleNotifierConfig extends Config
|
||||
@ConfigItem(
|
||||
keyName = "oxygen",
|
||||
name = "Oxygen Notification Threshold",
|
||||
position = 7,
|
||||
position = 9,
|
||||
description = "The amount of remaining oxygen to send a notification at. A value of 0 will disable notification."
|
||||
)
|
||||
default int getOxygenThreshold()
|
||||
@@ -111,7 +133,7 @@ public interface IdleNotifierConfig extends Config
|
||||
@ConfigItem(
|
||||
keyName = "spec",
|
||||
name = "Special Attack Energy Notification Threshold",
|
||||
position = 8,
|
||||
position = 10,
|
||||
description = "The amount of spec energy reached to send a notification at. A value of 0 will disable notification."
|
||||
)
|
||||
default int getSpecEnergyThreshold()
|
||||
|
||||
@@ -31,6 +31,7 @@ import java.awt.*;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import javax.inject.Inject;
|
||||
import net.runelite.api.Actor;
|
||||
@@ -44,8 +45,10 @@ import net.runelite.api.NPC;
|
||||
import net.runelite.api.NPCComposition;
|
||||
import net.runelite.api.Player;
|
||||
import net.runelite.api.Skill;
|
||||
import net.runelite.api.SkullIcon;
|
||||
import net.runelite.api.VarPlayer;
|
||||
import net.runelite.api.Varbits;
|
||||
import net.runelite.api.WorldType;
|
||||
import net.runelite.api.events.AnimationChanged;
|
||||
import net.runelite.api.events.GameStateChanged;
|
||||
import net.runelite.api.events.GameTick;
|
||||
@@ -100,6 +103,8 @@ public class IdleNotifierPlugin extends Plugin
|
||||
private Instant sixHourWarningTime;
|
||||
private boolean ready;
|
||||
private boolean lastInteractWasCombat;
|
||||
private SkullIcon lastTickSkull = null;
|
||||
private boolean isFirstTick = true;
|
||||
|
||||
@Provides
|
||||
IdleNotifierConfig provideConfig(ConfigManager configManager)
|
||||
@@ -327,9 +332,13 @@ public class IdleNotifierPlugin extends Plugin
|
||||
{
|
||||
case LOGIN_SCREEN:
|
||||
resetTimers();
|
||||
isFirstTick = true;
|
||||
break;
|
||||
case HOPPING:
|
||||
isFirstTick = true;
|
||||
ready = true;
|
||||
break;
|
||||
case LOGGING_IN:
|
||||
case HOPPING:
|
||||
case CONNECTION_LOST:
|
||||
ready = true;
|
||||
break;
|
||||
@@ -381,6 +390,8 @@ public class IdleNotifierPlugin extends Plugin
|
||||
@Subscribe
|
||||
public void onGameTick(GameTick event)
|
||||
{
|
||||
skullNotifier();
|
||||
|
||||
final Player local = client.getLocalPlayer();
|
||||
final Duration waitDuration = Duration.ofMillis(config.getIdleNotificationDelay());
|
||||
lastCombatCountdown = Math.max(lastCombatCountdown - 1, 0);
|
||||
@@ -666,4 +677,31 @@ public class IdleNotifierPlugin extends Plugin
|
||||
lastInteract = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void skullNotifier()
|
||||
{
|
||||
final Player local = client.getLocalPlayer();
|
||||
SkullIcon currentTickSkull = local.getSkullIcon();
|
||||
EnumSet worldTypes = client.getWorldType();
|
||||
if (!(worldTypes.contains(WorldType.DEADMAN) || worldTypes.contains(WorldType.SEASONAL_DEADMAN)))
|
||||
{
|
||||
if (!isFirstTick)
|
||||
{
|
||||
if (config.showSkullNotification() && lastTickSkull == null && currentTickSkull == SkullIcon.SKULL)
|
||||
{
|
||||
notifier.notify("[" + local.getName() + "] is now skulled!");
|
||||
}
|
||||
else if (config.showUnskullNotification() && lastTickSkull == SkullIcon.SKULL && currentTickSkull == null)
|
||||
{
|
||||
notifier.notify("[" + local.getName() + "] is now unskulled!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
isFirstTick = false;
|
||||
}
|
||||
|
||||
lastTickSkull = currentTickSkull;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Trevor <https://github.com/Trevor159>
|
||||
* 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.questhelper;
|
||||
|
||||
import lombok.Getter;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.InventoryID;
|
||||
import net.runelite.api.Item;
|
||||
|
||||
public class ItemRequirement
|
||||
{
|
||||
@Getter
|
||||
private int id;
|
||||
@Getter
|
||||
private int quantity;
|
||||
private boolean equip;
|
||||
|
||||
public ItemRequirement(int id)
|
||||
{
|
||||
this(id, 1);
|
||||
}
|
||||
|
||||
public ItemRequirement(int id, int quantity)
|
||||
{
|
||||
this.id = id;
|
||||
this.quantity = quantity;
|
||||
equip = false;
|
||||
}
|
||||
|
||||
public ItemRequirement(int id, int quantity, boolean equip)
|
||||
{
|
||||
this(id, quantity);
|
||||
this.equip = equip;
|
||||
}
|
||||
|
||||
public boolean check(Client client)
|
||||
{
|
||||
Item[] items;
|
||||
if (equip)
|
||||
{
|
||||
items = client.getItemContainer(InventoryID.EQUIPMENT).getItems();
|
||||
}
|
||||
else
|
||||
{
|
||||
items = client.getItemContainer(InventoryID.INVENTORY).getItems();
|
||||
}
|
||||
|
||||
int tempQuantity = quantity;
|
||||
for (Item item : items)
|
||||
{
|
||||
if (item.getId() == id)
|
||||
{
|
||||
if (item.getQuantity() >= tempQuantity)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
tempQuantity -= item.getQuantity();
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Trevor <https://github.com/Trevor159>
|
||||
* 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.questhelper;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import net.runelite.api.Quest;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface QuestDescriptor
|
||||
{
|
||||
Quest quest();
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Trevor <https://github.com/Trevor159>
|
||||
* 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.questhelper;
|
||||
|
||||
import com.google.inject.Binder;
|
||||
import com.google.inject.CreationException;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Module;
|
||||
import java.util.Map;
|
||||
import javax.inject.Inject;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.Quest;
|
||||
import net.runelite.api.QuestState;
|
||||
import net.runelite.client.eventbus.EventBus;
|
||||
import net.runelite.client.plugins.questhelper.steps.QuestStep;
|
||||
|
||||
public abstract class QuestHelper implements Module
|
||||
{
|
||||
@Inject
|
||||
private Client client;
|
||||
|
||||
@Inject
|
||||
private EventBus eventBus;
|
||||
|
||||
@Getter
|
||||
protected QuestStep currentStep;
|
||||
|
||||
protected Map<Integer, QuestStep> steps;
|
||||
protected Injector injector;
|
||||
@Getter
|
||||
@Setter
|
||||
private Quest quest;
|
||||
protected int var;
|
||||
|
||||
@Override
|
||||
public void configure(Binder binder)
|
||||
{
|
||||
}
|
||||
|
||||
protected void startUp() throws Exception
|
||||
{
|
||||
steps = loadSteps();
|
||||
instantiateSteps();
|
||||
var = getVar();
|
||||
startUpStep(var);
|
||||
}
|
||||
|
||||
protected void shutDown() throws Exception
|
||||
{
|
||||
steps = null;
|
||||
shutDownStep();
|
||||
}
|
||||
|
||||
protected void startUpStep(int i) throws Exception
|
||||
{
|
||||
if (steps.containsKey(i))
|
||||
{
|
||||
QuestStep step = steps.get(i);
|
||||
currentStep = step;
|
||||
eventBus.register(currentStep);
|
||||
currentStep.startUp();
|
||||
}
|
||||
else
|
||||
{
|
||||
currentStep = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected void shutDownStep() throws Exception
|
||||
{
|
||||
if (currentStep != null)
|
||||
{
|
||||
eventBus.unregister(currentStep);
|
||||
currentStep.shutDown();
|
||||
currentStep = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateQuest() throws Exception
|
||||
{
|
||||
shutDownStep();
|
||||
if (!isCompleted())
|
||||
{
|
||||
currentStep = steps.get(getVar());
|
||||
currentStep.startUp();
|
||||
}
|
||||
else
|
||||
{
|
||||
currentStep = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected void instantiateSteps()
|
||||
{
|
||||
for (QuestStep step : steps.values())
|
||||
{
|
||||
try
|
||||
{
|
||||
injector.injectMembers(step);
|
||||
}
|
||||
catch (CreationException ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isCompleted()
|
||||
{
|
||||
return (quest.getState(client) == QuestState.FINISHED);
|
||||
}
|
||||
|
||||
protected int getVar()
|
||||
{
|
||||
return quest.getVar(client);
|
||||
}
|
||||
|
||||
protected abstract Map<Integer, QuestStep> loadSteps();
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017, Seth <Sethtroll3@gmail.com>
|
||||
* Copyright (c) 2018, Lotto <https://github.com/devLotto>
|
||||
* Copyright (c) 2019, Trevor <https://github.com/Trevor159>
|
||||
* 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 HOLDER 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.questhelper;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics2D;
|
||||
import javax.inject.Inject;
|
||||
import net.runelite.client.ui.overlay.Overlay;
|
||||
import net.runelite.client.ui.overlay.OverlayPriority;
|
||||
import net.runelite.client.ui.overlay.components.ComponentConstants;
|
||||
import net.runelite.client.ui.overlay.components.PanelComponent;
|
||||
|
||||
public class QuestHelperOverlay extends Overlay
|
||||
{
|
||||
public static final Color TITLED_CONTENT_COLOR = new Color(190, 190, 190);
|
||||
|
||||
private final QuestHelperPlugin plugin;
|
||||
private final PanelComponent panelComponent = new PanelComponent();
|
||||
|
||||
@Inject
|
||||
public QuestHelperOverlay(QuestHelperPlugin plugin)
|
||||
{
|
||||
this.plugin = plugin;
|
||||
setPriority(OverlayPriority.LOW);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension render(Graphics2D graphics)
|
||||
{
|
||||
QuestHelper questHelper = plugin.getSelectedQuest();
|
||||
|
||||
if (questHelper == null || questHelper.getCurrentStep() == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
panelComponent.getChildren().clear();
|
||||
panelComponent.setPreferredSize(new Dimension(ComponentConstants.STANDARD_WIDTH, 0));
|
||||
|
||||
questHelper.getCurrentStep().makeOverlayHint(panelComponent, plugin);
|
||||
|
||||
return panelComponent.render(graphics);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Trevor <https://github.com/Trevor159>
|
||||
* 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.questhelper;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.reflect.ClassPath;
|
||||
import com.google.inject.Binder;
|
||||
import com.google.inject.CreationException;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Module;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.inject.Inject;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.GameState;
|
||||
import net.runelite.api.Quest;
|
||||
import net.runelite.api.events.GameStateChanged;
|
||||
import net.runelite.api.events.VarbitChanged;
|
||||
import net.runelite.api.events.WidgetLoaded;
|
||||
import net.runelite.api.widgets.Widget;
|
||||
import net.runelite.api.widgets.WidgetID;
|
||||
import net.runelite.api.widgets.WidgetInfo;
|
||||
import net.runelite.client.RuneLite;
|
||||
import net.runelite.client.eventbus.EventBus;
|
||||
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;
|
||||
|
||||
@PluginDescriptor(
|
||||
name = "Quest Helper",
|
||||
description = "Helps you with your quests"
|
||||
)
|
||||
@Slf4j
|
||||
public class QuestHelperPlugin extends Plugin
|
||||
{
|
||||
@Inject
|
||||
private Client client;
|
||||
|
||||
@Inject
|
||||
private EventBus eventBus;
|
||||
|
||||
@Inject
|
||||
private OverlayManager overlayManager;
|
||||
|
||||
@Inject
|
||||
private QuestHelperOverlay questHelperOverlay;
|
||||
|
||||
@Inject
|
||||
private QuestHelperWorldOverlay questHelperWorldOverlay;
|
||||
|
||||
private static final String QUEST_PACKAGE = "net.runelite.client.plugins.questhelper.quests";
|
||||
private Map<String, QuestHelper> quests;
|
||||
|
||||
@Getter
|
||||
private QuestHelper selectedQuest = null;
|
||||
|
||||
@Override
|
||||
protected void startUp() throws IOException
|
||||
{
|
||||
if (client.getGameState() == GameState.LOGGED_IN)
|
||||
{
|
||||
if (quests == null)
|
||||
{
|
||||
quests = scanAndInstantiate(getClass().getClassLoader(), QUEST_PACKAGE);
|
||||
}
|
||||
}
|
||||
overlayManager.add(questHelperOverlay);
|
||||
overlayManager.add(questHelperWorldOverlay);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void shutDown() throws Exception
|
||||
{
|
||||
overlayManager.remove(questHelperOverlay);
|
||||
overlayManager.remove(questHelperWorldOverlay);
|
||||
quests = null;
|
||||
shutDownQuest();
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onWidgetLoaded(WidgetLoaded event) throws Exception
|
||||
{
|
||||
int groupId = event.getGroupId();
|
||||
if (groupId == WidgetID.DIARY_QUEST_GROUP_ID)
|
||||
{
|
||||
Widget widget = client.getWidget(WidgetInfo.DIARY_QUEST_WIDGET_TITLE);
|
||||
String questname = Text.removeTags(widget.getText());
|
||||
if (quests.containsKey(questname))
|
||||
{
|
||||
QuestHelper widgetQuest = quests.get(questname);
|
||||
if (selectedQuest == null || !selectedQuest.equals(widgetQuest))
|
||||
{
|
||||
shutDownQuest();
|
||||
startUpQuest(widgetQuest);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onGameStateChanged(GameStateChanged event) throws IOException
|
||||
{
|
||||
if (event.getGameState() == GameState.LOGGED_IN)
|
||||
{
|
||||
if (quests == null)
|
||||
{
|
||||
quests = scanAndInstantiate(getClass().getClassLoader(), QUEST_PACKAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onVarbitChanged(VarbitChanged event) throws Exception
|
||||
{
|
||||
if (selectedQuest != null && selectedQuest.var != selectedQuest.getVar())
|
||||
{
|
||||
selectedQuest.var = selectedQuest.getVar();
|
||||
selectedQuest.updateQuest();
|
||||
if (selectedQuest.getCurrentStep() == null)
|
||||
{
|
||||
shutDownQuest();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void startUpQuest(QuestHelper questHelper) throws Exception
|
||||
{
|
||||
if (!questHelper.isCompleted())
|
||||
{
|
||||
selectedQuest = questHelper;
|
||||
eventBus.register(selectedQuest);
|
||||
selectedQuest.startUp();
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedQuest = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void shutDownQuest() throws Exception
|
||||
{
|
||||
if (selectedQuest != null)
|
||||
{
|
||||
selectedQuest.shutDown();
|
||||
eventBus.unregister(selectedQuest);
|
||||
selectedQuest = null;
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, QuestHelper> scanAndInstantiate(ClassLoader classLoader, String packageName) throws IOException
|
||||
{
|
||||
Map<Quest, Class<? extends QuestHelper>> quests = new HashMap<>();
|
||||
|
||||
Map<String, QuestHelper> scannedQuests = new HashMap<>();
|
||||
ClassPath classPath = ClassPath.from(classLoader);
|
||||
|
||||
ImmutableSet<ClassPath.ClassInfo> classes = packageName == null ? classPath.getAllClasses()
|
||||
: classPath.getTopLevelClassesRecursive(packageName);
|
||||
for (ClassPath.ClassInfo classInfo : classes)
|
||||
{
|
||||
Class<?> clazz = classInfo.load();
|
||||
QuestDescriptor questDescriptor = clazz.getAnnotation(QuestDescriptor.class);
|
||||
|
||||
if (questDescriptor == null)
|
||||
{
|
||||
if (clazz.getSuperclass() == QuestHelper.class)
|
||||
{
|
||||
log.warn("Class {} is a quest helper, but has no quest descriptor",
|
||||
clazz);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (clazz.getSuperclass() != QuestHelper.class)
|
||||
{
|
||||
log.warn("Class {} has quest descriptor, but is not a quest helper",
|
||||
clazz);
|
||||
continue;
|
||||
}
|
||||
|
||||
Class<QuestHelper> questClass = (Class<QuestHelper>) clazz;
|
||||
quests.put(questDescriptor.quest(), questClass);
|
||||
}
|
||||
|
||||
for (Map.Entry<Quest, Class<? extends QuestHelper>> questClazz : quests.entrySet())
|
||||
{
|
||||
QuestHelper questHelper;
|
||||
try
|
||||
{
|
||||
questHelper = instantiate((Class<QuestHelper>) questClazz.getValue(), questClazz.getKey());
|
||||
}
|
||||
catch (QuestInstantiationException ex)
|
||||
{
|
||||
log.warn("Error instantiating quest helper!", ex);
|
||||
continue;
|
||||
}
|
||||
|
||||
scannedQuests.put(questClazz.getKey().getName(), questHelper);
|
||||
}
|
||||
|
||||
return scannedQuests;
|
||||
}
|
||||
|
||||
private QuestHelper instantiate(Class<QuestHelper> clazz, Quest quest) throws QuestInstantiationException
|
||||
{
|
||||
QuestHelper questHelper;
|
||||
try
|
||||
{
|
||||
questHelper = clazz.newInstance();
|
||||
questHelper.setQuest(quest);
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException ex)
|
||||
{
|
||||
throw new QuestInstantiationException(ex);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Module questModule = (Binder binder) ->
|
||||
{
|
||||
binder.bind(clazz).toInstance(questHelper);
|
||||
binder.install(questHelper);
|
||||
};
|
||||
Injector questInjector = RuneLite.getInjector().createChildInjector(questModule);
|
||||
questInjector.injectMembers(questHelper);
|
||||
questHelper.injector = questInjector;
|
||||
}
|
||||
catch (CreationException ex)
|
||||
{
|
||||
throw new QuestInstantiationException(ex);
|
||||
}
|
||||
|
||||
log.debug("Loaded quest helper {}", clazz.getSimpleName());
|
||||
return questHelper;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Morgan Lewis <https://github.com/MESLewis>
|
||||
* Copyright (c) 2019, Trevor <https://github.com/Trevor159>
|
||||
* 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.questhelper;
|
||||
|
||||
import java.awt.Graphics;
|
||||
import java.awt.image.BufferedImage;
|
||||
import net.runelite.api.Point;
|
||||
import net.runelite.api.coords.WorldPoint;
|
||||
import net.runelite.client.ui.overlay.worldmap.WorldMapPoint;
|
||||
import net.runelite.client.util.ImageUtil;
|
||||
|
||||
public class QuestHelperWorldMapPoint extends WorldMapPoint
|
||||
{
|
||||
private final BufferedImage questWorldImage;
|
||||
private final Point questWorldImagePoint;
|
||||
private final BufferedImage questImage;
|
||||
|
||||
public QuestHelperWorldMapPoint(final WorldPoint worldPoint, BufferedImage image)
|
||||
{
|
||||
super(worldPoint, null);
|
||||
|
||||
BufferedImage mapArrow = ImageUtil.getResourceStreamFromClass(getClass(), "/util/clue_arrow.png");
|
||||
questWorldImage = new BufferedImage(mapArrow.getWidth(), mapArrow.getHeight(), BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics graphics = questWorldImage.getGraphics();
|
||||
graphics.drawImage(mapArrow, 0, 0, null);
|
||||
int buffer = mapArrow.getWidth() / 2 - image.getWidth() / 2;
|
||||
buffer = buffer < 0 ? 0 : buffer;
|
||||
graphics.drawImage(image, buffer, buffer, null);
|
||||
questWorldImagePoint = new Point(questWorldImage.getWidth() / 2, questWorldImage.getHeight());
|
||||
|
||||
this.questImage = image;
|
||||
this.setSnapToEdge(true);
|
||||
this.setJumpOnClick(true);
|
||||
this.setImage(questWorldImage);
|
||||
this.setImagePoint(questWorldImagePoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEdgeSnap()
|
||||
{
|
||||
this.setImage(questImage);
|
||||
this.setImagePoint(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEdgeUnsnap()
|
||||
{
|
||||
this.setImage(questWorldImage);
|
||||
this.setImagePoint(questWorldImagePoint);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Lotto <https://github.com/devLotto>
|
||||
* Copyright (c) 2019, Trevor <https://github.com/Trevor159>
|
||||
* 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.questhelper;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics2D;
|
||||
import javax.inject.Inject;
|
||||
import net.runelite.client.ui.overlay.Overlay;
|
||||
import net.runelite.client.ui.overlay.OverlayLayer;
|
||||
import net.runelite.client.ui.overlay.OverlayPosition;
|
||||
|
||||
public class QuestHelperWorldOverlay extends Overlay
|
||||
{
|
||||
public static final int IMAGE_Z_OFFSET = 30;
|
||||
|
||||
public static final Color CLICKBOX_BORDER_COLOR = Color.CYAN;
|
||||
public static final Color CLICKBOX_HOVER_BORDER_COLOR = CLICKBOX_BORDER_COLOR.darker();
|
||||
public static final Color CLICKBOX_FILL_COLOR = new Color(0, 255, 0, 20);
|
||||
|
||||
private final QuestHelperPlugin plugin;
|
||||
|
||||
@Inject
|
||||
public QuestHelperWorldOverlay(QuestHelperPlugin plugin)
|
||||
{
|
||||
setPosition(OverlayPosition.DYNAMIC);
|
||||
setLayer(OverlayLayer.ABOVE_SCENE);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension render(Graphics2D graphics)
|
||||
{
|
||||
QuestHelper quest = plugin.getSelectedQuest();
|
||||
|
||||
if (quest != null && quest.getCurrentStep() != null)
|
||||
{
|
||||
quest.getCurrentStep().makeWorldOverlayHint(graphics, plugin);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017, Adam <Adam@sigterm.info>
|
||||
* Copyright (c) 2019, Trevor <https://github.com/Trevor159>
|
||||
* 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.questhelper;
|
||||
|
||||
public class QuestInstantiationException extends Exception
|
||||
{
|
||||
public QuestInstantiationException(Throwable cause)
|
||||
{
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Trevor <https://github.com/Trevor159>
|
||||
* 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.questhelper.quests.cooksassistant;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import net.runelite.api.ItemID;
|
||||
import net.runelite.api.NpcID;
|
||||
import net.runelite.api.Quest;
|
||||
import net.runelite.api.coords.WorldPoint;
|
||||
import net.runelite.client.plugins.questhelper.ItemRequirement;
|
||||
import net.runelite.client.plugins.questhelper.QuestHelper;
|
||||
import net.runelite.client.plugins.questhelper.steps.NpcTalkStep;
|
||||
import net.runelite.client.plugins.questhelper.steps.QuestStep;
|
||||
import net.runelite.client.plugins.questhelper.QuestDescriptor;
|
||||
|
||||
@QuestDescriptor(
|
||||
quest = Quest.COOKS_ASSISTANT
|
||||
)
|
||||
public class CooksAssistant extends QuestHelper
|
||||
{
|
||||
@Override
|
||||
protected Map<Integer, QuestStep> loadSteps()
|
||||
{
|
||||
Map<Integer, QuestStep> steps = new HashMap<>();
|
||||
|
||||
steps.put(0, new NpcTalkStep(this, NpcID.COOK_4626, new WorldPoint(3206, 3214, 0),
|
||||
"Give the Cook in Lumbridge Castle's kitchen the required items to finish the quest.",
|
||||
new ItemRequirement(ItemID.BUCKET_OF_MILK), new ItemRequirement(ItemID.POT_OF_FLOUR),
|
||||
new ItemRequirement(ItemID.EGG)));
|
||||
|
||||
steps.put(1, steps.get(0));
|
||||
|
||||
return steps;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Trevor <https://github.com/Trevor159>
|
||||
* 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.questhelper.quests.impcatcher;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import net.runelite.api.ItemID;
|
||||
import net.runelite.api.NpcID;
|
||||
import net.runelite.api.Quest;
|
||||
import net.runelite.api.coords.WorldPoint;
|
||||
import net.runelite.client.plugins.questhelper.ItemRequirement;
|
||||
import net.runelite.client.plugins.questhelper.QuestHelper;
|
||||
import net.runelite.client.plugins.questhelper.steps.NpcTalkStep;
|
||||
import net.runelite.client.plugins.questhelper.steps.QuestStep;
|
||||
import net.runelite.client.plugins.questhelper.QuestDescriptor;
|
||||
|
||||
@QuestDescriptor(
|
||||
quest = Quest.IMP_CATCHER
|
||||
)
|
||||
public class ImpCatcher extends QuestHelper
|
||||
{
|
||||
@Override
|
||||
protected Map<Integer, QuestStep> loadSteps()
|
||||
{
|
||||
Map<Integer, QuestStep> steps = new HashMap<>();
|
||||
|
||||
steps.put(0, new NpcTalkStep(this, NpcID.WIZARD_MIZGOG, new WorldPoint(3103, 3163, 2),
|
||||
"Talk to Wizard Mizgog on the top floor of the Wizards' Tower with the required items to finish the quest.",
|
||||
new ItemRequirement(ItemID.BLACK_BEAD), new ItemRequirement(ItemID.WHITE_BEAD),
|
||||
new ItemRequirement(ItemID.RED_BEAD), new ItemRequirement(ItemID.YELLOW_BEAD)));
|
||||
|
||||
steps.put(1, steps.get(0));
|
||||
|
||||
return steps;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Trevor <https://github.com/Trevor159>
|
||||
* 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.questhelper.quests.xmarksthespot;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import net.runelite.api.ItemID;
|
||||
import net.runelite.api.NpcID;
|
||||
import net.runelite.api.Quest;
|
||||
import net.runelite.api.coords.WorldPoint;
|
||||
import net.runelite.client.plugins.questhelper.ItemRequirement;
|
||||
import net.runelite.client.plugins.questhelper.QuestHelper;
|
||||
import net.runelite.client.plugins.questhelper.steps.DigStep;
|
||||
import net.runelite.client.plugins.questhelper.steps.NpcTalkStep;
|
||||
import net.runelite.client.plugins.questhelper.steps.QuestStep;
|
||||
import net.runelite.client.plugins.questhelper.QuestDescriptor;
|
||||
|
||||
@QuestDescriptor(
|
||||
quest = Quest.X_MARKS_THE_SPOT
|
||||
)
|
||||
public class XMarksTheSpot extends QuestHelper
|
||||
{
|
||||
@Override
|
||||
protected Map<Integer, QuestStep> loadSteps()
|
||||
{
|
||||
Map<Integer, QuestStep> steps = new HashMap<>();
|
||||
|
||||
steps.put(0, new NpcTalkStep(this, NpcID.VEOS_8484, new WorldPoint(3228, 3242, 0),
|
||||
"Talk to Veos in The Sheared Ram pub in Lumbridge to start the quest."));
|
||||
|
||||
steps.put(1, steps.get(0));
|
||||
|
||||
steps.put(2, new DigStep(this, new WorldPoint(3230, 3209, 0),
|
||||
"Dig north of Bob's Brilliant Axes, on the west side of the plant against the wall of his house.",
|
||||
new ItemRequirement(ItemID.TREASURE_SCROLL)));
|
||||
|
||||
steps.put(3, new DigStep(this, new WorldPoint(3203, 3212, 0),
|
||||
"Dig behind Lumbridge Castle, just outside the kitchen door.",
|
||||
new ItemRequirement(ItemID.TREASURE_SCROLL_23068)));
|
||||
|
||||
steps.put(4, new DigStep(this, new WorldPoint(3109, 3264, 0),
|
||||
"Dig north-west of the Draynor Village jail, just by the wheat farm.",
|
||||
new ItemRequirement(ItemID.MYSTERIOUS_ORB_23069)));
|
||||
|
||||
steps.put(5, new DigStep(this, new WorldPoint(3078, 3259, 0),
|
||||
"Dig in the pig pen just west where Martin the Master Gardener is.",
|
||||
new ItemRequirement(ItemID.TREASURE_SCROLL_23070)));
|
||||
|
||||
steps.put(6, new NpcTalkStep(this, NpcID.VEOS_8484, new WorldPoint(3054, 3245, 0),
|
||||
"Talk to Veos directly south of the Rusty Anchor Inn in Port Sarim to finish the quest.",
|
||||
new ItemRequirement(ItemID.ANCIENT_CASKET)));
|
||||
|
||||
steps.put(7, new NpcTalkStep(this, NpcID.VEOS_8484, new WorldPoint(3054, 3245, 0),
|
||||
"Talk to Veos directly south of the Rusty Anchor Inn in Port Sarim to finish the quest."));
|
||||
|
||||
return steps;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Trevor <https://github.com/Trevor159>
|
||||
* 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.questhelper.steps;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.inject.Inject;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.ItemID;
|
||||
import net.runelite.api.coords.LocalPoint;
|
||||
import net.runelite.api.coords.WorldPoint;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.plugins.questhelper.ItemRequirement;
|
||||
import net.runelite.client.plugins.questhelper.QuestHelper;
|
||||
import net.runelite.client.plugins.questhelper.QuestHelperPlugin;
|
||||
import net.runelite.client.plugins.questhelper.QuestHelperWorldMapPoint;
|
||||
import net.runelite.client.ui.overlay.OverlayUtil;
|
||||
import net.runelite.client.ui.overlay.components.LineComponent;
|
||||
import net.runelite.client.ui.overlay.components.PanelComponent;
|
||||
import net.runelite.client.ui.overlay.worldmap.WorldMapPointManager;
|
||||
|
||||
public class DigStep extends QuestStep
|
||||
{
|
||||
@Inject
|
||||
Client client;
|
||||
|
||||
@Inject
|
||||
ItemManager itemManager;
|
||||
|
||||
@Inject
|
||||
WorldMapPointManager worldMapPointManager;
|
||||
|
||||
private final WorldPoint worldPoint;
|
||||
private final List<ItemRequirement> itemRequirements = new ArrayList<>();
|
||||
|
||||
public DigStep(QuestHelper questHelper, WorldPoint worldPoint, String text, ItemRequirement... itemRequirements)
|
||||
{
|
||||
super(questHelper, text);
|
||||
this.worldPoint = worldPoint;
|
||||
this.itemRequirements.add(0, new ItemRequirement(ItemID.SPADE));
|
||||
Collections.addAll(this.itemRequirements, itemRequirements);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startUp() throws Exception
|
||||
{
|
||||
worldMapPointManager.add(new QuestHelperWorldMapPoint(worldPoint, getQuestImage()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutDown() throws Exception
|
||||
{
|
||||
worldMapPointManager.removeIf(QuestHelperWorldMapPoint.class::isInstance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void makeOverlayHint(PanelComponent panelComponent, QuestHelperPlugin plugin)
|
||||
{
|
||||
super.makeOverlayHint(panelComponent, plugin);
|
||||
|
||||
panelComponent.getChildren().add(LineComponent.builder().left("Required Items:").build());
|
||||
for (ItemRequirement itemRequirement : itemRequirements)
|
||||
{
|
||||
String text = itemRequirement.getQuantity() + " x " + itemManager.getItemComposition(itemRequirement.getId()).getName();
|
||||
Color color;
|
||||
if (itemRequirement.check(client))
|
||||
{
|
||||
color = Color.GREEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
color = Color.RED;
|
||||
}
|
||||
panelComponent.getChildren().add(LineComponent.builder()
|
||||
.left(text)
|
||||
.leftColor(color)
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void makeWorldOverlayHint(Graphics2D graphics, QuestHelperPlugin plugin)
|
||||
{
|
||||
LocalPoint localLocation = LocalPoint.fromWorld(client, worldPoint);
|
||||
|
||||
if (localLocation == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
OverlayUtil.renderTileOverlay(client, graphics, localLocation, getSpadeImage(), Color.ORANGE);
|
||||
}
|
||||
|
||||
private BufferedImage getSpadeImage()
|
||||
{
|
||||
return itemManager.getImage(ItemID.SPADE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Trevor <https://github.com/Trevor159>
|
||||
* 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.questhelper.steps;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import javax.inject.Inject;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.NPC;
|
||||
import net.runelite.api.coords.WorldPoint;
|
||||
import net.runelite.api.events.NpcDespawned;
|
||||
import net.runelite.api.events.NpcSpawned;
|
||||
import net.runelite.client.eventbus.Subscribe;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.plugins.questhelper.ItemRequirement;
|
||||
import net.runelite.client.plugins.questhelper.QuestHelper;
|
||||
import net.runelite.client.plugins.questhelper.QuestHelperPlugin;
|
||||
import net.runelite.client.plugins.questhelper.QuestHelperWorldMapPoint;
|
||||
import static net.runelite.client.plugins.questhelper.QuestHelperWorldOverlay.IMAGE_Z_OFFSET;
|
||||
import net.runelite.client.ui.overlay.OverlayUtil;
|
||||
import net.runelite.client.ui.overlay.components.LineComponent;
|
||||
import net.runelite.client.ui.overlay.components.PanelComponent;
|
||||
import net.runelite.client.ui.overlay.worldmap.WorldMapPointManager;
|
||||
|
||||
public class NpcTalkStep extends QuestStep
|
||||
{
|
||||
@Inject
|
||||
protected Client client;
|
||||
|
||||
@Inject
|
||||
protected ItemManager itemManager;
|
||||
|
||||
@Inject
|
||||
protected WorldMapPointManager worldMapPointManager;
|
||||
|
||||
private int npcID;
|
||||
private WorldPoint worldPoint;
|
||||
private List<NPC> npcsToHighlight = new ArrayList<>();
|
||||
List<ItemRequirement> itemRequirements;
|
||||
|
||||
public NpcTalkStep(QuestHelper questHelper, int npcID, WorldPoint worldPoint, String text, ItemRequirement... itemRequirements)
|
||||
{
|
||||
super(questHelper, text);
|
||||
this.npcID = npcID;
|
||||
this.worldPoint = worldPoint;
|
||||
this.itemRequirements = Arrays.asList(itemRequirements);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startUp() throws Exception
|
||||
{
|
||||
for (NPC npc : client.getNpcs())
|
||||
{
|
||||
if (npcID == npc.getId())
|
||||
{
|
||||
npcsToHighlight.add(npc);
|
||||
}
|
||||
}
|
||||
worldMapPointManager.add(new QuestHelperWorldMapPoint(worldPoint, getQuestImage()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutDown() throws Exception
|
||||
{
|
||||
npcsToHighlight.clear();
|
||||
worldMapPointManager.removeIf(QuestHelperWorldMapPoint.class::isInstance);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onNpcSpawned(NpcSpawned event)
|
||||
{
|
||||
if (event.getNpc().getId() == npcID)
|
||||
{
|
||||
npcsToHighlight.add(event.getNpc());
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onNpcDespawned(NpcDespawned event)
|
||||
{
|
||||
if (npcsToHighlight.contains(event.getNpc()))
|
||||
{
|
||||
npcsToHighlight.remove(event.getNpc());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void makeOverlayHint(PanelComponent panelComponent, QuestHelperPlugin plugin)
|
||||
{
|
||||
super.makeOverlayHint(panelComponent, plugin);
|
||||
|
||||
if (itemRequirements.isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
panelComponent.getChildren().add(LineComponent.builder().left("Required Items:").build());
|
||||
for (ItemRequirement itemRequirement : itemRequirements)
|
||||
{
|
||||
String text = itemRequirement.getQuantity() + " x " + itemManager.getItemComposition(itemRequirement.getId()).getName();
|
||||
Color color;
|
||||
if (itemRequirement.check(client))
|
||||
{
|
||||
color = Color.GREEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
color = Color.RED;
|
||||
}
|
||||
panelComponent.getChildren().add(LineComponent.builder()
|
||||
.left(text)
|
||||
.leftColor(color)
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void makeWorldOverlayHint(Graphics2D graphics, QuestHelperPlugin plugin)
|
||||
{
|
||||
if (!worldPoint.isInScene(client))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (npcsToHighlight.isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (NPC npc : npcsToHighlight)
|
||||
{
|
||||
OverlayUtil.renderActorOverlayImage(graphics, npc, getQuestImage(), Color.CYAN, IMAGE_Z_OFFSET);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Trevor <https://github.com/Trevor159>
|
||||
* 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.questhelper.steps;
|
||||
|
||||
import com.google.inject.Binder;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Module;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import net.runelite.api.SpriteID;
|
||||
import net.runelite.client.game.SpriteManager;
|
||||
import net.runelite.client.plugins.questhelper.QuestHelper;
|
||||
import static net.runelite.client.plugins.questhelper.QuestHelperOverlay.TITLED_CONTENT_COLOR;
|
||||
import net.runelite.client.plugins.questhelper.QuestHelperPlugin;
|
||||
import net.runelite.client.ui.overlay.components.LineComponent;
|
||||
import net.runelite.client.ui.overlay.components.PanelComponent;
|
||||
import net.runelite.client.ui.overlay.components.TitleComponent;
|
||||
|
||||
public abstract class QuestStep implements Module
|
||||
{
|
||||
@Inject
|
||||
SpriteManager spriteManager;
|
||||
|
||||
private final String text;
|
||||
private final QuestHelper questHelper;
|
||||
|
||||
public QuestStep(QuestHelper questHelper, String text)
|
||||
{
|
||||
this.text = text;
|
||||
this.questHelper = questHelper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(Binder binder)
|
||||
{
|
||||
}
|
||||
|
||||
public void startUp() throws Exception
|
||||
{
|
||||
}
|
||||
|
||||
public void shutDown() throws Exception
|
||||
{
|
||||
}
|
||||
|
||||
public void makeOverlayHint(PanelComponent panelComponent, QuestHelperPlugin plugin)
|
||||
{
|
||||
panelComponent.getChildren().add(TitleComponent.builder().text(questHelper.getQuest().getName()).build());
|
||||
|
||||
panelComponent.getChildren().add(LineComponent.builder().left("Step:").build());
|
||||
panelComponent.getChildren().add(LineComponent.builder()
|
||||
.left(text)
|
||||
.leftColor(TITLED_CONTENT_COLOR)
|
||||
.build());
|
||||
}
|
||||
|
||||
public abstract void makeWorldOverlayHint(Graphics2D graphics, QuestHelperPlugin plugin);
|
||||
|
||||
public BufferedImage getQuestImage()
|
||||
{
|
||||
return spriteManager.getSprite(SpriteID.TAB_QUESTS, 0);
|
||||
}
|
||||
}
|
||||
@@ -38,8 +38,8 @@ public interface RaidsConfig extends Config
|
||||
@ConfigItem(
|
||||
position = 0,
|
||||
keyName = "raidsTimer",
|
||||
name = "Display elapsed raid time",
|
||||
description = "Display elapsed raid time"
|
||||
name = "Level time tooltip",
|
||||
description = "Displays your level times as a tooltip on the points overlay"
|
||||
)
|
||||
default boolean raidsTimer()
|
||||
{
|
||||
|
||||
@@ -31,7 +31,6 @@ import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.text.DecimalFormat;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
@@ -57,11 +56,13 @@ import net.runelite.api.Tile;
|
||||
import net.runelite.api.VarPlayer;
|
||||
import net.runelite.api.Varbits;
|
||||
import net.runelite.api.events.ChatMessage;
|
||||
import net.runelite.api.events.ClientTick;
|
||||
import net.runelite.api.events.ConfigChanged;
|
||||
import net.runelite.api.events.VarbitChanged;
|
||||
import net.runelite.api.events.WidgetHiddenChanged;
|
||||
import net.runelite.api.widgets.Widget;
|
||||
import net.runelite.api.widgets.WidgetInfo;
|
||||
import net.runelite.api.widgets.WidgetInfo;
|
||||
import net.runelite.client.callback.ClientThread;
|
||||
import net.runelite.client.chat.ChatColorType;
|
||||
import net.runelite.client.chat.ChatMessageBuilder;
|
||||
@@ -81,9 +82,13 @@ import net.runelite.client.plugins.raids.solver.RotationSolver;
|
||||
import net.runelite.client.ui.DrawManager;
|
||||
import net.runelite.client.ui.FontManager;
|
||||
import net.runelite.client.ui.overlay.OverlayManager;
|
||||
import net.runelite.client.ui.overlay.WidgetOverlay;
|
||||
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
|
||||
import net.runelite.client.ui.overlay.tooltip.Tooltip;
|
||||
import net.runelite.client.ui.overlay.tooltip.TooltipManager;
|
||||
import net.runelite.client.util.Text;
|
||||
import net.runelite.client.util.HotkeyListener;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
@PluginDescriptor(
|
||||
name = "Chambers Of Xeric",
|
||||
@@ -95,9 +100,6 @@ import net.runelite.client.util.HotkeyListener;
|
||||
public class RaidsPlugin extends Plugin
|
||||
{
|
||||
private static final int LOBBY_PLANE = 3;
|
||||
private static final String RAID_START_MESSAGE = "The raid has begun!";
|
||||
private static final String LEVEL_COMPLETE_MESSAGE = "level complete!";
|
||||
private static final String RAID_COMPLETE_MESSAGE = "Congratulations - your raid is complete!";
|
||||
private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("###.##");
|
||||
static final DecimalFormat POINTS_FORMAT = new DecimalFormat("#,###");
|
||||
private static final String SPLIT_REGEX = "\\s*,\\s*";
|
||||
@@ -106,6 +108,8 @@ public class RaidsPlugin extends Plugin
|
||||
|
||||
@Inject
|
||||
private ItemManager itemManager;
|
||||
private static final Pattern LEVEL_COMPLETE_REGEX = Pattern.compile("(.+) level complete! Duration: ([0-9:]+)");
|
||||
private static final Pattern RAID_COMPLETE_REGEX = Pattern.compile("Congratulations - your raid is complete! Duration: ([0-9:]+)");
|
||||
|
||||
@Inject
|
||||
private ChatMessageManager chatMessageManager;
|
||||
@@ -146,6 +150,9 @@ public class RaidsPlugin extends Plugin
|
||||
@Inject
|
||||
private KeyManager keyManager;
|
||||
|
||||
@Inject
|
||||
private TooltipManager tooltipManager;
|
||||
|
||||
@Getter
|
||||
private final ArrayList<String> roomWhitelist = new ArrayList<>();
|
||||
|
||||
@@ -167,7 +174,12 @@ public class RaidsPlugin extends Plugin
|
||||
@Getter
|
||||
private boolean inRaidChambers;
|
||||
|
||||
private RaidsTimer timer;
|
||||
private int upperTime = -1;
|
||||
private int middleTime = -1;
|
||||
private int lowerTime = -1;
|
||||
private int raidTime = -1;
|
||||
private WidgetOverlay widgetOverlay;
|
||||
private String tooltip;
|
||||
|
||||
@Provides
|
||||
RaidsConfig provideConfig(ConfigManager configManager)
|
||||
@@ -188,6 +200,7 @@ public class RaidsPlugin extends Plugin
|
||||
overlayManager.add(pointsOverlay);
|
||||
updateLists();
|
||||
clientThread.invokeLater(() -> checkRaidPresence(true));
|
||||
widgetOverlay = overlayManager.getWidgetOverlay(WidgetInfo.RAIDS_POINTS_INFOBOX);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -195,16 +208,16 @@ public class RaidsPlugin extends Plugin
|
||||
{
|
||||
overlayManager.remove(overlay);
|
||||
overlayManager.remove(pointsOverlay);
|
||||
infoBoxManager.removeInfoBox(timer);
|
||||
inRaidChambers = false;
|
||||
widgetOverlay = null;
|
||||
raid = null;
|
||||
timer = null;
|
||||
|
||||
final Widget widget = client.getWidget(WidgetInfo.RAIDS_POINTS_INFOBOX);
|
||||
if (widget != null)
|
||||
{
|
||||
widget.setHidden(false);
|
||||
}
|
||||
reset();
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
@@ -215,12 +228,6 @@ public class RaidsPlugin extends Plugin
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getKey().equals("raidsTimer"))
|
||||
{
|
||||
updateInfoBoxState();
|
||||
return;
|
||||
}
|
||||
|
||||
updateLists();
|
||||
clientThread.invokeLater(() -> checkRaidPresence(true));
|
||||
}
|
||||
@@ -253,25 +260,33 @@ public class RaidsPlugin extends Plugin
|
||||
if (inRaidChambers && event.getType() == ChatMessageType.FRIENDSCHATNOTIFICATION)
|
||||
{
|
||||
String message = Text.removeTags(event.getMessage());
|
||||
Matcher matcher;
|
||||
|
||||
if (config.raidsTimer() && message.startsWith(RAID_START_MESSAGE))
|
||||
matcher = LEVEL_COMPLETE_REGEX.matcher(message);
|
||||
if (matcher.find())
|
||||
{
|
||||
timer = new RaidsTimer(spriteManager.getSprite(TAB_QUESTS_BROWN_RAIDING_PARTY, 0), this, Instant.now());
|
||||
infoBoxManager.addInfoBox(timer);
|
||||
}
|
||||
|
||||
if (timer != null && message.contains(LEVEL_COMPLETE_MESSAGE))
|
||||
{
|
||||
timer.timeFloor();
|
||||
}
|
||||
|
||||
if (message.startsWith(RAID_COMPLETE_MESSAGE))
|
||||
{
|
||||
if (timer != null)
|
||||
String floor = matcher.group(1);
|
||||
int time = timeToSeconds(matcher.group(2));
|
||||
if (floor.equals("Upper"))
|
||||
{
|
||||
timer.timeOlm();
|
||||
timer.setStopped(true);
|
||||
upperTime = time;
|
||||
}
|
||||
else if (floor.equals("Middle"))
|
||||
{
|
||||
middleTime = time;
|
||||
}
|
||||
else if (floor.equals("Lower"))
|
||||
{
|
||||
lowerTime = time;
|
||||
}
|
||||
updateTooltip();
|
||||
}
|
||||
|
||||
matcher = RAID_COMPLETE_REGEX.matcher(message);
|
||||
if (matcher.find())
|
||||
{
|
||||
raidTime = timeToSeconds(matcher.group(1));
|
||||
updateTooltip();
|
||||
|
||||
if (config.pointsMessage())
|
||||
{
|
||||
@@ -306,6 +321,23 @@ public class RaidsPlugin extends Plugin
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onClientTick(ClientTick event)
|
||||
{
|
||||
if (!config.raidsTimer()
|
||||
|| !client.getGameState().equals(GameState.LOGGED_IN)
|
||||
|| tooltip == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
final Point mousePosition = client.getMouseCanvasPosition();
|
||||
if (widgetOverlay.getBounds().contains(mousePosition.getX(), mousePosition.getY()))
|
||||
{
|
||||
tooltipManager.add(new Tooltip(tooltip));
|
||||
}
|
||||
}
|
||||
|
||||
private void checkRaidPresence(boolean force)
|
||||
{
|
||||
if (client.getGameState() != GameState.LOGGED_IN)
|
||||
@@ -318,7 +350,6 @@ public class RaidsPlugin extends Plugin
|
||||
if (force || inRaidChambers != setting)
|
||||
{
|
||||
inRaidChambers = setting;
|
||||
updateInfoBoxState();
|
||||
|
||||
if (inRaidChambers)
|
||||
{
|
||||
@@ -343,9 +374,14 @@ public class RaidsPlugin extends Plugin
|
||||
overlay.setScoutOverlayShown(true);
|
||||
sendRaidLayoutMessage();
|
||||
}
|
||||
else if (!config.scoutOverlayAtBank())
|
||||
else
|
||||
{
|
||||
overlay.setScoutOverlayShown(false);
|
||||
if (!config.scoutOverlayAtBank())
|
||||
{
|
||||
overlay.setScoutOverlayShown(false);
|
||||
}
|
||||
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -378,30 +414,6 @@ public class RaidsPlugin extends Plugin
|
||||
.build());
|
||||
}
|
||||
|
||||
private void updateInfoBoxState()
|
||||
{
|
||||
if (timer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (inRaidChambers && config.raidsTimer())
|
||||
{
|
||||
if (!infoBoxManager.getInfoBoxes().contains(timer))
|
||||
{
|
||||
infoBoxManager.addInfoBox(timer);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
infoBoxManager.removeInfoBox(timer);
|
||||
}
|
||||
|
||||
if (!inRaidChambers)
|
||||
{
|
||||
timer = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateLists()
|
||||
{
|
||||
@@ -700,4 +712,94 @@ public class RaidsPlugin extends Plugin
|
||||
|
||||
return room;
|
||||
}
|
||||
|
||||
public void reset()
|
||||
{
|
||||
raid = null;
|
||||
upperTime = -1;
|
||||
middleTime = -1;
|
||||
lowerTime = -1;
|
||||
raidTime = -1;
|
||||
tooltip = null;
|
||||
}
|
||||
|
||||
private int timeToSeconds(String s)
|
||||
{
|
||||
int seconds = -1;
|
||||
String[] split = s.split(":");
|
||||
if (split.length == 2)
|
||||
{
|
||||
seconds = Integer.parseInt(split[0]) * 60 + Integer.parseInt(split[1]);
|
||||
}
|
||||
if (split.length == 3)
|
||||
{
|
||||
seconds = Integer.parseInt(split[0]) * 3600 + Integer.parseInt(split[1]) * 60 + Integer.parseInt(split[2]);
|
||||
}
|
||||
return seconds;
|
||||
}
|
||||
|
||||
private String secondsToTime(int seconds)
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
if (seconds >= 3600)
|
||||
{
|
||||
builder.append((int)Math.floor(seconds / 3600) + ";");
|
||||
}
|
||||
seconds %= 3600;
|
||||
if (builder.toString().equals(""))
|
||||
{
|
||||
builder.append((int)Math.floor(seconds / 60));
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.append(StringUtils.leftPad(String.valueOf((int)Math.floor(seconds / 60)), 2, '0'));
|
||||
}
|
||||
builder.append(":");
|
||||
seconds %= 60;
|
||||
builder.append(StringUtils.leftPad(String.valueOf(seconds), 2, '0'));
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private void updateTooltip()
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
if (upperTime == -1)
|
||||
{
|
||||
tooltip = null;
|
||||
return;
|
||||
}
|
||||
builder.append("Upper level: " + secondsToTime(upperTime));
|
||||
if (middleTime == -1)
|
||||
{
|
||||
if (lowerTime == -1)
|
||||
{
|
||||
tooltip = builder.toString();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.append("</br>Lower level: " + secondsToTime(lowerTime - upperTime));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.append("</br>Middle level: " + secondsToTime(middleTime - upperTime));
|
||||
if (lowerTime == -1)
|
||||
{
|
||||
tooltip = builder.toString();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.append("</br>Lower level: " + secondsToTime(lowerTime - middleTime));
|
||||
}
|
||||
}
|
||||
if (raidTime == -1)
|
||||
{
|
||||
tooltip = builder.toString();
|
||||
return;
|
||||
}
|
||||
builder.append("</br>Olm: " + secondsToTime(raidTime - lowerTime));
|
||||
tooltip = builder.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,150 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Kamiel
|
||||
* 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.raids;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import lombok.Setter;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
import net.runelite.client.ui.overlay.infobox.InfoBox;
|
||||
|
||||
public class RaidsTimer extends InfoBox
|
||||
{
|
||||
private final Instant startTime;
|
||||
private Instant floorTime;
|
||||
private LocalTime time;
|
||||
private LocalTime firstFloorTime;
|
||||
private LocalTime secondFloorTime;
|
||||
private LocalTime thirdFloorTime;
|
||||
private LocalTime olmTime;
|
||||
|
||||
@Setter
|
||||
private boolean stopped;
|
||||
|
||||
public RaidsTimer(BufferedImage image, Plugin plugin, Instant startTime)
|
||||
{
|
||||
super(image, plugin);
|
||||
this.startTime = startTime;
|
||||
floorTime = startTime;
|
||||
stopped = false;
|
||||
}
|
||||
|
||||
public void timeFloor()
|
||||
{
|
||||
Duration elapsed = Duration.between(floorTime, Instant.now());
|
||||
|
||||
if (firstFloorTime == null)
|
||||
{
|
||||
firstFloorTime = LocalTime.ofSecondOfDay(elapsed.getSeconds());
|
||||
}
|
||||
else if (secondFloorTime == null)
|
||||
{
|
||||
secondFloorTime = LocalTime.ofSecondOfDay(elapsed.getSeconds());
|
||||
}
|
||||
else if (thirdFloorTime == null)
|
||||
{
|
||||
thirdFloorTime = LocalTime.ofSecondOfDay(elapsed.getSeconds());
|
||||
}
|
||||
|
||||
floorTime = Instant.now();
|
||||
}
|
||||
|
||||
public void timeOlm()
|
||||
{
|
||||
Duration elapsed = Duration.between(floorTime, Instant.now());
|
||||
olmTime = LocalTime.ofSecondOfDay(elapsed.getSeconds());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText()
|
||||
{
|
||||
if (startTime == null)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
if (!stopped)
|
||||
{
|
||||
Duration elapsed = Duration.between(startTime, Instant.now());
|
||||
time = LocalTime.ofSecondOfDay(elapsed.getSeconds());
|
||||
}
|
||||
|
||||
if (time.getHour() > 0)
|
||||
{
|
||||
return time.format(DateTimeFormatter.ofPattern("HH:mm"));
|
||||
}
|
||||
|
||||
return time.format(DateTimeFormatter.ofPattern("mm:ss"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getTextColor()
|
||||
{
|
||||
if (stopped)
|
||||
{
|
||||
return Color.GREEN;
|
||||
}
|
||||
|
||||
return Color.WHITE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTooltip()
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("Elapsed raid time: ");
|
||||
builder.append(time.format(DateTimeFormatter.ofPattern("HH:mm:ss")));
|
||||
|
||||
if (firstFloorTime != null)
|
||||
{
|
||||
builder.append("</br>First floor: ");
|
||||
builder.append(firstFloorTime.format(DateTimeFormatter.ofPattern("mm:ss")));
|
||||
}
|
||||
|
||||
if (secondFloorTime != null)
|
||||
{
|
||||
builder.append("</br>Second floor: ");
|
||||
builder.append(secondFloorTime.format(DateTimeFormatter.ofPattern("mm:ss")));
|
||||
}
|
||||
|
||||
if (thirdFloorTime != null)
|
||||
{
|
||||
builder.append("</br>Third floor: ");
|
||||
builder.append(thirdFloorTime.format(DateTimeFormatter.ofPattern("mm:ss")));
|
||||
}
|
||||
|
||||
if (olmTime != null)
|
||||
{
|
||||
builder.append("</br>Olm: ");
|
||||
builder.append(olmTime.format(DateTimeFormatter.ofPattern("mm:ss")));
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,7 @@ import lombok.Getter;
|
||||
import net.runelite.api.MenuAction;
|
||||
import net.runelite.api.events.MenuOptionClicked;
|
||||
import net.runelite.api.widgets.WidgetItem;
|
||||
import net.runelite.api.widgets.WidgetInfo;
|
||||
import net.runelite.client.config.ConfigGroup;
|
||||
import net.runelite.client.config.ConfigManager;
|
||||
import net.runelite.client.config.RuneLiteConfig;
|
||||
@@ -364,4 +365,21 @@ public class OverlayManager
|
||||
final String locationKey = overlay.getName() + OVERLAY_CONFIG_PREFERRED_POSITION;
|
||||
return configManager.getConfiguration(RUNELITE_CONFIG_GROUP_NAME, locationKey, OverlayPosition.class);
|
||||
}
|
||||
|
||||
public WidgetOverlay getWidgetOverlay(final WidgetInfo info)
|
||||
{
|
||||
for (Overlay o : overlays)
|
||||
{
|
||||
if (o instanceof WidgetOverlay)
|
||||
{
|
||||
WidgetOverlay overlay = (WidgetOverlay) o;
|
||||
if (overlay.getWidgetInfo().equals(info))
|
||||
{
|
||||
return overlay;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,7 @@ import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.Getter;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.widgets.Widget;
|
||||
import net.runelite.api.widgets.WidgetInfo;
|
||||
@@ -64,6 +65,7 @@ public class WidgetOverlay extends Overlay
|
||||
}
|
||||
|
||||
private final Client client;
|
||||
@Getter
|
||||
private final WidgetInfo widgetInfo;
|
||||
private final Rectangle parentBounds = new Rectangle();
|
||||
|
||||
|
||||
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Hydrox6 <ikada@protonmail.ch>
|
||||
* 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.ui.overlay.arrow;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.GameObject;
|
||||
import net.runelite.api.NPC;
|
||||
import net.runelite.api.Perspective;
|
||||
import net.runelite.api.Point;
|
||||
import net.runelite.api.coords.LocalPoint;
|
||||
import net.runelite.api.coords.WorldPoint;
|
||||
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.OverlayPriority;
|
||||
|
||||
@Singleton
|
||||
@Slf4j
|
||||
public class ArrowMinimapOverlay extends Overlay
|
||||
{
|
||||
private static final int MINIMAP_VISIBLE_RANGE = 17 * 128;
|
||||
|
||||
private final ArrowPointManager arrowPointManager;
|
||||
private final Client client;
|
||||
|
||||
@Inject
|
||||
private ArrowMinimapOverlay(Client client, ArrowPointManager arrowPointManager)
|
||||
{
|
||||
this.client = client;
|
||||
this.arrowPointManager = arrowPointManager;
|
||||
setPosition(OverlayPosition.DYNAMIC);
|
||||
setPriority(OverlayPriority.HIGH);
|
||||
setLayer(OverlayLayer.ALWAYS_ON_TOP);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension render(Graphics2D graphics)
|
||||
{
|
||||
|
||||
final Collection<ArrowPoint> points = arrowPointManager.getArrowPoints().values();
|
||||
|
||||
if (points.isEmpty())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
final LocalPoint localPlayerPos = client.getLocalPlayer().getLocalLocation();
|
||||
final WorldPoint worldPlayerPos = WorldPoint.fromLocal(client, localPlayerPos);
|
||||
|
||||
for (ArrowPoint arrowPoint : points)
|
||||
{
|
||||
final WorldPoint worldPoint = arrowPoint.getWorldPoint();
|
||||
|
||||
if (worldPoint.distanceTo(worldPlayerPos) < arrowPoint.getVisibleRange())
|
||||
{
|
||||
LocalPoint fallBackPoint = LocalPoint.fromWorld(client, worldPoint);
|
||||
if (arrowPoint.types.contains(ArrowType.NPC))
|
||||
{
|
||||
boolean found = false;
|
||||
for (NPC npc : client.getCachedNPCs())
|
||||
{
|
||||
if (npc != null && arrowPoint.getNpcIDs().contains(npc.getId()))
|
||||
{
|
||||
found = true;
|
||||
renderMinimapArrow(graphics, arrowPoint, npc.getLocalLocation(), localPlayerPos, worldPlayerPos);
|
||||
}
|
||||
}
|
||||
if (found || fallBackPoint == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
renderMinimapArrow(graphics, arrowPoint, null, localPlayerPos, worldPlayerPos);
|
||||
}
|
||||
else if (arrowPoint.types.contains(ArrowType.OBJECT))
|
||||
{
|
||||
|
||||
ArrayList<GameObject> objects = ArrowUtil.getObjects(client, arrowPoint.getObjectIDs());
|
||||
if (objects.isEmpty() && fallBackPoint != null)
|
||||
{
|
||||
renderMinimapArrow(graphics, arrowPoint, null, localPlayerPos, worldPlayerPos);
|
||||
continue;
|
||||
}
|
||||
for (GameObject object : objects)
|
||||
{
|
||||
renderMinimapArrow(graphics, arrowPoint, object.getLocalLocation(), localPlayerPos, worldPlayerPos);
|
||||
}
|
||||
}
|
||||
else if (arrowPoint.types.contains(ArrowType.WORLD_POINT))
|
||||
{
|
||||
renderMinimapArrow(graphics, arrowPoint, null, localPlayerPos, worldPlayerPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void renderMinimapArrow(Graphics2D graphics, ArrowPoint arrowPoint, LocalPoint localPoint, LocalPoint localPlayerPos, WorldPoint worldPlayerPos)
|
||||
{
|
||||
final BufferedImage minimapImage = arrowPoint.getMinimapImage();
|
||||
final WorldPoint worldPoint = arrowPoint.getWorldPoint();
|
||||
final Point minimapImageOffset = arrowPoint.getMinimapImageOffset();
|
||||
|
||||
if (localPoint != null && localPlayerPos.distanceTo(localPoint) < MINIMAP_VISIBLE_RANGE)
|
||||
{
|
||||
final Point minimapLoc = Perspective.getMiniMapImageLocation(client, localPoint, minimapImage);
|
||||
if (minimapLoc != null)
|
||||
{
|
||||
graphics.drawImage(minimapImage, minimapLoc.getX() + minimapImageOffset.getX(), minimapLoc.getY() + minimapImageOffset.getY(), null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!arrowPoint.isMinimapUseFallback())
|
||||
{
|
||||
return;
|
||||
}
|
||||
final Point minimapPlayerPos = Perspective.localToMinimap(client, localPlayerPos);
|
||||
double cameraAngle = ((client.getCameraYaw()) / 2048.0) * 2 * Math.PI;
|
||||
//Use localPoint if it's available for a smoother rotation
|
||||
double theta;
|
||||
if (localPoint != null)
|
||||
{
|
||||
theta = Math.atan2(localPoint.getX() - localPlayerPos.getX(), localPlayerPos.getY() - localPoint.getY());
|
||||
}
|
||||
else
|
||||
{
|
||||
theta = Math.atan2(worldPoint.getX() - worldPlayerPos.getX(), worldPlayerPos.getY() - worldPoint.getY());
|
||||
}
|
||||
|
||||
AffineTransform at = new AffineTransform();
|
||||
if (arrowPoint.isMinimapImagePointToTarget())
|
||||
{
|
||||
at.translate(minimapPlayerPos.getX(), minimapPlayerPos.getY());
|
||||
at.rotate(cameraAngle - theta);
|
||||
at.translate(0, 66);
|
||||
at.translate(minimapImageOffset.getX() - minimapImage.getWidth() / 2, minimapImageOffset.getY() - minimapImage.getHeight() / 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Get the correct position as if it were rotated
|
||||
at.rotate(cameraAngle - theta);
|
||||
at.translate(0, 66);
|
||||
double dX = at.getTranslateX();
|
||||
double dY = at.getTranslateY();
|
||||
//Then apply that position to an un-rotated transform
|
||||
at = new AffineTransform();
|
||||
at.translate(minimapPlayerPos.getX(), minimapPlayerPos.getY());
|
||||
at.translate(dX, dY);
|
||||
at.translate(minimapImageOffset.getX() - minimapImage.getWidth() / 2, minimapImageOffset.getY() - minimapImage.getHeight() / 2);
|
||||
}
|
||||
|
||||
graphics.drawImage(minimapImage, at, null);
|
||||
}
|
||||
}
|
||||
|
||||
private void renderMinimapArrowNPC(Graphics2D graphics, ArrowPoint arrowPoint, NPC npc, LocalPoint localPlayerPos, WorldPoint worldPlayerPos)
|
||||
{
|
||||
final BufferedImage minimapImage = arrowPoint.getMinimapImage();
|
||||
final WorldPoint worldPoint = arrowPoint.getWorldPoint();
|
||||
LocalPoint localPoint;
|
||||
if (npc != null)
|
||||
{
|
||||
localPoint = LocalPoint.fromWorld(client, worldPoint);
|
||||
if (localPoint != null)
|
||||
{
|
||||
//For whatever reason, LocalPoint.fromWorld returns a point (-1, -1) from the actual point
|
||||
localPoint = new LocalPoint(localPoint.getX() + 1, localPoint.getY() + 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
localPoint = npc.getLocalLocation();
|
||||
}
|
||||
|
||||
renderMinimapArrow(graphics, arrowPoint, localPoint, localPlayerPos, worldPlayerPos);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Morgan Lewis <https://github.com/MESLewis>
|
||||
* 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.ui.overlay.arrow;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashSet;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NonNull;
|
||||
import net.runelite.api.Point;
|
||||
import net.runelite.api.coords.WorldPoint;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public class ArrowPoint
|
||||
{
|
||||
/**
|
||||
* Can define a point to mark, or be used as a fallback when an object or an NPC is outside of the scene
|
||||
*/
|
||||
@NonNull
|
||||
private WorldPoint worldPoint;
|
||||
|
||||
private HashSet<Integer> npcIDs;
|
||||
|
||||
private HashSet<Integer> objectIDs;
|
||||
|
||||
/**
|
||||
* The regions that an NPC or Object has to be in to be marked (eg. Exam Centre locked chest Hard Clue requires
|
||||
* killing a Barbarian in Barbarian Village, or Konar Slayer requires killing monsters in a certain area)
|
||||
*/
|
||||
private HashSet<Integer> region;
|
||||
|
||||
private BufferedImage worldImage;
|
||||
@Builder.Default
|
||||
private Point worldImageOffset = new Point(0, 0);
|
||||
@Builder.Default
|
||||
private Color tileColor = Color.RED;
|
||||
|
||||
private BufferedImage minimapImage;
|
||||
@Builder.Default
|
||||
private Point minimapImageOffset = new Point(0, 0);
|
||||
/**
|
||||
* Whether the minimap arrow should rotate. Set to false if not using an arrow
|
||||
*/
|
||||
@Builder.Default
|
||||
private boolean minimapImagePointToTarget = true;
|
||||
@Builder.Default
|
||||
private int visibleRange = 128;
|
||||
/**
|
||||
* Whether the minimap arrow should use the fallback point. Useful when there are multiple locations that could be
|
||||
* used as a fallback (eg. Seers' Village locked draw Medium Clue, where you need to kill any chicken for a key)
|
||||
*/
|
||||
@Builder.Default
|
||||
private boolean minimapUseFallback = true;
|
||||
|
||||
/**
|
||||
* A Set of what arrows should be rendered
|
||||
*/
|
||||
@NonNull
|
||||
EnumSet<ArrowType> types;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Morgan Lewis <https://github.com/MESLewis>
|
||||
* 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.ui.overlay.arrow;
|
||||
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import javax.inject.Singleton;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import net.runelite.api.events.NpcSpawned;
|
||||
import net.runelite.client.eventbus.Subscribe;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
|
||||
@Singleton
|
||||
public class ArrowPointManager
|
||||
{
|
||||
@Getter(AccessLevel.PACKAGE)
|
||||
private final Multimap<Plugin, ArrowPoint> arrowPoints = HashMultimap.create();
|
||||
|
||||
public void add(Plugin plugin, ArrowPoint arrowPoint)
|
||||
{
|
||||
arrowPoints.put(plugin, arrowPoint);
|
||||
}
|
||||
|
||||
public void remove(Plugin plugin, ArrowPoint arrowPoint)
|
||||
{
|
||||
arrowPoints.remove(plugin, arrowPoint);
|
||||
}
|
||||
|
||||
public void clear(Plugin plugin)
|
||||
{
|
||||
arrowPoints.removeAll(plugin);
|
||||
}
|
||||
|
||||
public void clear()
|
||||
{
|
||||
arrowPoints.clear();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package net.runelite.client.ui.overlay.arrow;
|
||||
|
||||
public enum ArrowType
|
||||
{
|
||||
MINIMAP,
|
||||
NPC,
|
||||
OBJECT,
|
||||
WORLD_MAP,
|
||||
WORLD_POINT
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package net.runelite.client.ui.overlay.arrow;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.GameObject;
|
||||
import net.runelite.api.ObjectComposition;
|
||||
import net.runelite.api.Scene;
|
||||
import net.runelite.api.Tile;
|
||||
|
||||
class ArrowUtil
|
||||
{
|
||||
static ArrayList<GameObject> getObjects(final Client client, HashSet<Integer> objectIDs)
|
||||
{
|
||||
final Scene scene = client.getScene();
|
||||
final Tile[][] tiles = scene.getTiles()[client.getPlane()];
|
||||
final ArrayList<GameObject> found = new ArrayList<>();
|
||||
|
||||
for (Tile[] tiles2 : tiles)
|
||||
{
|
||||
for (Tile tile : tiles2)
|
||||
{
|
||||
for (GameObject object : tile.getGameObjects())
|
||||
{
|
||||
if (object == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (objectIDs.contains(object.getId()))
|
||||
{
|
||||
found.add(object);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check impostors
|
||||
final ObjectComposition comp = client.getObjectDefinition(object.getId());
|
||||
final ObjectComposition impostor = comp.getImpostorIds() != null ? comp.getImpostor() : comp;
|
||||
|
||||
if (impostor != null && objectIDs.contains(impostor.getId()))
|
||||
{
|
||||
found.add(object);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Hydrox6 <ikada@protonmail.ch>
|
||||
* 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.ui.overlay.arrow;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Polygon;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.GameObject;
|
||||
import net.runelite.api.NPC;
|
||||
import net.runelite.api.Perspective;
|
||||
import net.runelite.api.Point;
|
||||
import net.runelite.api.coords.LocalPoint;
|
||||
import net.runelite.api.coords.WorldPoint;
|
||||
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.OverlayPriority;
|
||||
import net.runelite.client.ui.overlay.OverlayUtil;
|
||||
|
||||
@Singleton
|
||||
@Slf4j
|
||||
public class ArrowWorldOverlay extends Overlay
|
||||
{
|
||||
private static final int Z_OFFSET = 20;
|
||||
|
||||
private final ArrowPointManager arrowPointManager;
|
||||
private final Client client;
|
||||
|
||||
@Inject
|
||||
private ArrowWorldOverlay(Client client, ArrowPointManager arrowPointManager)
|
||||
{
|
||||
this.client = client;
|
||||
this.arrowPointManager = arrowPointManager;
|
||||
setPosition(OverlayPosition.DYNAMIC);
|
||||
setPriority(OverlayPriority.HIGHEST);
|
||||
setLayer(OverlayLayer.UNDER_WIDGETS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension render(Graphics2D graphics)
|
||||
{
|
||||
final Collection<ArrowPoint> points = arrowPointManager.getArrowPoints().values();
|
||||
|
||||
if (points.isEmpty())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
WorldPoint playerLocation = client.getLocalPlayer().getWorldLocation();
|
||||
|
||||
for (ArrowPoint arrowPoint : points)
|
||||
{
|
||||
WorldPoint point = arrowPoint.getWorldPoint();
|
||||
|
||||
if (point.distanceTo(playerLocation) < client.getScene().getDrawDistance())
|
||||
{
|
||||
LocalPoint fallBackPoint = LocalPoint.fromWorld(client, point);
|
||||
if (arrowPoint.types.contains(ArrowType.NPC))
|
||||
{
|
||||
boolean found = false;
|
||||
for (NPC npc : client.getCachedNPCs())
|
||||
{
|
||||
if (npc != null && arrowPoint.getNpcIDs().contains(npc.getId()))
|
||||
{
|
||||
found = true;
|
||||
renderWorldArrow(graphics, arrowPoint, npc.getLocalLocation(), npc.getLogicalHeight() + Z_OFFSET);
|
||||
}
|
||||
}
|
||||
if (found || fallBackPoint == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
renderWorldArrow(graphics, arrowPoint, fallBackPoint);
|
||||
}
|
||||
else if (arrowPoint.types.contains(ArrowType.OBJECT))
|
||||
{
|
||||
|
||||
ArrayList<GameObject> objects = ArrowUtil.getObjects(client, arrowPoint.getObjectIDs());
|
||||
if (objects.isEmpty() && fallBackPoint != null)
|
||||
{
|
||||
renderWorldArrow(graphics, arrowPoint, fallBackPoint);
|
||||
continue;
|
||||
}
|
||||
for (GameObject object : objects)
|
||||
{
|
||||
if (object.getRenderable().getModel() == null)
|
||||
{
|
||||
renderWorldArrow(graphics, arrowPoint, object.getLocalLocation(), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
renderWorldArrow(graphics, arrowPoint, object.getLocalLocation(), object.getRenderable().getModel().getModelHeight() + Z_OFFSET);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (arrowPoint.types.contains(ArrowType.WORLD_POINT))
|
||||
{
|
||||
renderWorldArrow(graphics, arrowPoint, fallBackPoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void renderWorldArrow(Graphics2D graphics, ArrowPoint arrowPoint, LocalPoint localPoint)
|
||||
{
|
||||
renderWorldArrow(graphics, arrowPoint, localPoint, 0);
|
||||
}
|
||||
|
||||
private void renderWorldArrow(Graphics2D graphics, ArrowPoint arrowPoint, LocalPoint localPoint, int zOffset)
|
||||
{
|
||||
final BufferedImage worldImage = arrowPoint.getWorldImage();
|
||||
//Draw Tile
|
||||
Polygon poly = Perspective.getCanvasTilePoly(client, localPoint);
|
||||
if (poly != null)
|
||||
{
|
||||
OverlayUtil.renderPolygon(graphics, poly, arrowPoint.getTileColor());
|
||||
}
|
||||
|
||||
Point worldIconOffset = arrowPoint.getWorldImageOffset();
|
||||
//Draw World Arrow
|
||||
Point canvasPoint = Perspective.getCanvasImageLocation(client, localPoint, worldImage, zOffset);
|
||||
if (canvasPoint != null)
|
||||
{
|
||||
graphics.drawImage(worldImage, canvasPoint.getX() + worldIconOffset.getX(), canvasPoint.getY() + worldIconOffset.getY(), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user