Merge pull request #3596 from Jasper-ketelaar/mta-plugin
Add MTA Plugin
This commit is contained in:
@@ -226,4 +226,11 @@ public interface Actor extends Renderable
|
||||
* @return the world area
|
||||
*/
|
||||
WorldArea getWorldArea();
|
||||
|
||||
/**
|
||||
* Gets the overhead text that is displayed above the actor
|
||||
*
|
||||
* @return the overhead text
|
||||
*/
|
||||
String getOverhead();
|
||||
}
|
||||
|
||||
@@ -6221,6 +6221,7 @@ public final class NpcID
|
||||
public static final int GALLOW = 6775;
|
||||
public static final int MAN_6776 = 6776;
|
||||
public static final int MAZE_GUARDIAN = 6777;
|
||||
public static final int MAZE_GUARDIAN_MOVING = 6778;
|
||||
public static final int MAZE_GUARDIAN_6779 = 6779;
|
||||
public static final int PILIAR = 6780;
|
||||
public static final int SHAYDA = 6781;
|
||||
|
||||
@@ -34,6 +34,8 @@ public class ProjectileID
|
||||
public static final int CANNONBALL = 53;
|
||||
public static final int GRANITE_CANNONBALL = 1443;
|
||||
|
||||
public static final int TELEKINETIC_SPELL = 143;
|
||||
|
||||
public static final int LIZARDMAN_SHAMAN_AOE = 1293;
|
||||
public static final int CRAZY_ARCHAEOLOGIST_AOE = 1260;
|
||||
public static final int ICE_DEMON_RANGED_AOE = 1324;
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
*/
|
||||
package net.runelite.api.coords;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
import lombok.Getter;
|
||||
import net.runelite.api.Client;
|
||||
@@ -643,4 +645,23 @@ public class WorldArea
|
||||
{
|
||||
return new WorldPoint(x, y, plane);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accumulates all the WorldPoints that this WorldArea contains and returns them as a list
|
||||
*
|
||||
* @return Returns the WorldPoints in this WorldArea
|
||||
*/
|
||||
public List<WorldPoint> toWorldPointList()
|
||||
{
|
||||
List<WorldPoint> list = new ArrayList<>(width * height);
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
list.add(new WorldPoint(getX() + x, getY() + y, getPlane()));
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
@@ -96,6 +96,10 @@ public class WidgetID
|
||||
public static final int KINGDOM_GROUP_ID = 392;
|
||||
public static final int BARROWS_GROUP_ID = 24;
|
||||
public static final int BLAST_MINE_GROUP_ID = 598;
|
||||
public static final int MTA_ALCHEMY_GROUP_ID = 194;
|
||||
public static final int MTA_ENCHANTMENT_GROUP_ID = 195;
|
||||
public static final int MTA_GRAVEYARD_GROUP_ID = 196;
|
||||
public static final int MTA_TELEKINETIC_GROUP_ID = 198;
|
||||
|
||||
static class WorldMap
|
||||
{
|
||||
@@ -507,4 +511,10 @@ public class WidgetID
|
||||
static final int BARROWS_POTENTIAL = 9;
|
||||
static final int BARROWS_REWARD_INVENTORY = 3;
|
||||
}
|
||||
|
||||
static class MTA
|
||||
{
|
||||
static final int BONUS_COMPONENT = 7;
|
||||
static final int BONUS_TEXT_COMPONENT = 12;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -327,8 +327,11 @@ public enum WidgetInfo
|
||||
BARROWS_BROTHERS(WidgetID.BARROWS_GROUP_ID, WidgetID.Barrows.BARROWS_BROTHERS),
|
||||
BARROWS_POTENTIAL(WidgetID.BARROWS_GROUP_ID, WidgetID.Barrows.BARROWS_POTENTIAL),
|
||||
BARROWS_REWARD_INVENTORY(WidgetID.BARROWS_REWARD_GROUP_ID, WidgetID.Barrows.BARROWS_REWARD_INVENTORY),
|
||||
|
||||
BLAST_MINE(WidgetID.BLAST_MINE_GROUP_ID, 0);
|
||||
|
||||
BLAST_MINE(WidgetID.BLAST_MINE_GROUP_ID, 0),
|
||||
|
||||
MTA_ENCHANTMENT_BONUS_TEXT(WidgetID.MTA_ENCHANTMENT_GROUP_ID, WidgetID.MTA.BONUS_TEXT_COMPONENT),
|
||||
MTA_ENCHANTMENT_BONUS(WidgetID.MTA_ENCHANTMENT_GROUP_ID, WidgetID.MTA.BONUS_COMPONENT);
|
||||
|
||||
private final int groupId;
|
||||
private final int childId;
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Jasper Ketelaar <Jasper0781@gmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.plugins.mta;
|
||||
|
||||
import net.runelite.client.config.Config;
|
||||
import net.runelite.client.config.ConfigGroup;
|
||||
import net.runelite.client.config.ConfigItem;
|
||||
|
||||
@ConfigGroup(
|
||||
keyName = "mta",
|
||||
name = "Mage Training Arena",
|
||||
description = "Configuration for the Mage Training Arena plugin"
|
||||
)
|
||||
public interface MTAConfig extends Config
|
||||
{
|
||||
@ConfigItem(
|
||||
keyName = "alchemy",
|
||||
name = "Enable alchemy room",
|
||||
description = "Configures whether or not the alchemy room overlay is enabled.",
|
||||
position = 0
|
||||
)
|
||||
default boolean alchemy()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "graveyard",
|
||||
name = "Enable graveyard room",
|
||||
description = "Configures whether or not the graveyard room overlay is enabled.",
|
||||
position = 1
|
||||
)
|
||||
default boolean graveyard()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "telekinetic",
|
||||
name = "Enable telekinetic room",
|
||||
description = "Configures whether or not the telekinetic room overlay is enabled.",
|
||||
position = 2
|
||||
)
|
||||
default boolean telekinetic()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "enchantment",
|
||||
name = "Enable enchantment room",
|
||||
description = "Configures whether or not the enchantment room overlay is enabled.",
|
||||
position = 3
|
||||
)
|
||||
default boolean enchantment()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Jasper Ketelaar <Jasper0781@gmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.plugins.mta;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics2D;
|
||||
import javax.inject.Inject;
|
||||
import net.runelite.client.ui.FontManager;
|
||||
import net.runelite.client.ui.overlay.Overlay;
|
||||
import net.runelite.client.ui.overlay.OverlayLayer;
|
||||
import net.runelite.client.ui.overlay.OverlayPosition;
|
||||
|
||||
public class MTAInventoryOverlay extends Overlay
|
||||
{
|
||||
private final MTAPlugin plugin;
|
||||
|
||||
@Inject
|
||||
public MTAInventoryOverlay(MTAPlugin plugin)
|
||||
{
|
||||
this.plugin = plugin;
|
||||
setPosition(OverlayPosition.DYNAMIC);
|
||||
setLayer(OverlayLayer.ABOVE_WIDGETS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension render(Graphics2D graphics)
|
||||
{
|
||||
for (MTARoom room : plugin.getRooms())
|
||||
{
|
||||
if (room.inside())
|
||||
{
|
||||
graphics.setFont(FontManager.getRunescapeBoldFont());
|
||||
room.over(graphics);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Jasper Ketelaar <Jasper0781@gmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.plugins.mta;
|
||||
|
||||
import com.google.common.eventbus.EventBus;
|
||||
import com.google.inject.Provides;
|
||||
import javax.inject.Inject;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.client.config.ConfigManager;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
import net.runelite.client.plugins.PluginDescriptor;
|
||||
import net.runelite.client.plugins.mta.alchemy.AlchemyRoom;
|
||||
import net.runelite.client.plugins.mta.enchantment.EnchantmentRoom;
|
||||
import net.runelite.client.plugins.mta.graveyard.GraveyardRoom;
|
||||
import net.runelite.client.plugins.mta.telekinetic.TelekineticRoom;
|
||||
import net.runelite.client.ui.overlay.OverlayManager;
|
||||
|
||||
@PluginDescriptor(name = "Mage Training Arena")
|
||||
public class MTAPlugin extends Plugin
|
||||
{
|
||||
@Inject
|
||||
private Client client;
|
||||
|
||||
@Inject
|
||||
private OverlayManager overlayManager;
|
||||
|
||||
@Inject
|
||||
private AlchemyRoom alchemyRoom;
|
||||
@Inject
|
||||
private GraveyardRoom graveyardRoom;
|
||||
@Inject
|
||||
private TelekineticRoom telekineticRoom;
|
||||
@Inject
|
||||
private EnchantmentRoom enchantmentRoom;
|
||||
|
||||
@Inject
|
||||
private EventBus eventBus;
|
||||
@Inject
|
||||
private MTASceneOverlay sceneOverlay;
|
||||
@Inject
|
||||
private MTAInventoryOverlay inventoryOverlay;
|
||||
|
||||
@Getter(AccessLevel.PROTECTED)
|
||||
private MTARoom[] rooms;
|
||||
|
||||
@Provides
|
||||
public MTAConfig getConfig(ConfigManager manager)
|
||||
{
|
||||
return manager.getConfig(MTAConfig.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startUp()
|
||||
{
|
||||
overlayManager.add(sceneOverlay);
|
||||
overlayManager.add(inventoryOverlay);
|
||||
|
||||
this.rooms = new MTARoom[]{alchemyRoom, graveyardRoom, telekineticRoom, enchantmentRoom};
|
||||
|
||||
for (MTARoom room : rooms)
|
||||
{
|
||||
eventBus.register(room);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutDown()
|
||||
{
|
||||
overlayManager.remove(sceneOverlay);
|
||||
overlayManager.remove(inventoryOverlay);
|
||||
|
||||
for (MTARoom room : rooms)
|
||||
{
|
||||
eventBus.unregister(room);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Jasper Ketelaar <Jasper0781@gmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.plugins.mta;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import javax.inject.Inject;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
|
||||
public abstract class MTARoom
|
||||
{
|
||||
@Getter(AccessLevel.PROTECTED)
|
||||
protected final MTAConfig config;
|
||||
|
||||
@Inject
|
||||
protected MTARoom(MTAConfig config)
|
||||
{
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public abstract boolean inside();
|
||||
|
||||
public void under(Graphics2D graphics2D)
|
||||
{
|
||||
}
|
||||
|
||||
public void over(Graphics2D graphics2D)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Jasper Ketelaar <Jasper0781@gmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.plugins.mta;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics2D;
|
||||
import javax.inject.Inject;
|
||||
import net.runelite.client.ui.FontManager;
|
||||
import net.runelite.client.ui.overlay.Overlay;
|
||||
import net.runelite.client.ui.overlay.OverlayLayer;
|
||||
import net.runelite.client.ui.overlay.OverlayPosition;
|
||||
|
||||
public class MTASceneOverlay extends Overlay
|
||||
{
|
||||
private final MTAPlugin plugin;
|
||||
|
||||
@Inject
|
||||
public MTASceneOverlay(MTAPlugin plugin)
|
||||
{
|
||||
this.plugin = plugin;
|
||||
setPosition(OverlayPosition.DYNAMIC);
|
||||
setLayer(OverlayLayer.ABOVE_SCENE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension render(Graphics2D graphics)
|
||||
{
|
||||
for (MTARoom room : plugin.getRooms())
|
||||
{
|
||||
if (room.inside())
|
||||
{
|
||||
graphics.setFont(FontManager.getRunescapeFont());
|
||||
room.under(graphics);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Jasper Ketelaar <Jasper0781@gmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.plugins.mta.alchemy;
|
||||
|
||||
import lombok.Getter;
|
||||
import net.runelite.api.ItemID;
|
||||
|
||||
public enum AlchemyItem
|
||||
{
|
||||
LEATHER_BOOTS("Leather Boots", ItemID.LEATHER_BOOTS_6893),
|
||||
ADAMANT_KITESHIELD("Adamant Kiteshield", ItemID.ADAMANT_KITESHIELD_6894),
|
||||
ADAMANT_MED_HELM("Helm", ItemID.ADAMANT_MED_HELM_6895),
|
||||
EMERALD("Emerald", ItemID.EMERALD_6896),
|
||||
RUNE_LONGSWORD("Rune Longsword", ItemID.RUNE_LONGSWORD_6897),
|
||||
EMPTY("", -1),
|
||||
POSSIBLY_EMPTY("", ItemID.CAKE_OF_GUIDANCE),
|
||||
UNKNOWN("Unknown", ItemID.CAKE_OF_GUIDANCE);
|
||||
|
||||
@Getter
|
||||
private final int id;
|
||||
@Getter
|
||||
private final String name;
|
||||
|
||||
AlchemyItem(String name, int id)
|
||||
{
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public static AlchemyItem find(String item)
|
||||
{
|
||||
for (AlchemyItem alchemyItem : values())
|
||||
{
|
||||
if (item.toLowerCase().contains(alchemyItem.name.toLowerCase()))
|
||||
{
|
||||
return alchemyItem;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,475 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Jasper Ketelaar <Jasper0781@gmail.com>
|
||||
* Copyright (c) 2018, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.plugins.mta.alchemy;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import javax.inject.Inject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.ChatMessageType;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.GameObject;
|
||||
import net.runelite.api.GameState;
|
||||
import static net.runelite.api.ObjectID.CUPBOARD_23678;
|
||||
import static net.runelite.api.ObjectID.CUPBOARD_23679;
|
||||
import static net.runelite.api.ObjectID.CUPBOARD_23680;
|
||||
import static net.runelite.api.ObjectID.CUPBOARD_23681;
|
||||
import static net.runelite.api.ObjectID.CUPBOARD_23682;
|
||||
import static net.runelite.api.ObjectID.CUPBOARD_23683;
|
||||
import static net.runelite.api.ObjectID.CUPBOARD_23684;
|
||||
import static net.runelite.api.ObjectID.CUPBOARD_23685;
|
||||
import static net.runelite.api.ObjectID.CUPBOARD_23686;
|
||||
import static net.runelite.api.ObjectID.CUPBOARD_23687;
|
||||
import static net.runelite.api.ObjectID.CUPBOARD_23688;
|
||||
import static net.runelite.api.ObjectID.CUPBOARD_23689;
|
||||
import static net.runelite.api.ObjectID.CUPBOARD_23690;
|
||||
import static net.runelite.api.ObjectID.CUPBOARD_23691;
|
||||
import static net.runelite.api.ObjectID.CUPBOARD_23692;
|
||||
import static net.runelite.api.ObjectID.CUPBOARD_23693;
|
||||
import net.runelite.api.Perspective;
|
||||
import net.runelite.api.Player;
|
||||
import net.runelite.api.Point;
|
||||
import net.runelite.api.coords.WorldPoint;
|
||||
import net.runelite.api.events.ChatMessage;
|
||||
import net.runelite.api.events.GameObjectSpawned;
|
||||
import net.runelite.api.events.GameStateChanged;
|
||||
import net.runelite.api.events.GameTick;
|
||||
import net.runelite.api.widgets.Widget;
|
||||
import net.runelite.api.widgets.WidgetID;
|
||||
import net.runelite.api.widgets.WidgetInfo;
|
||||
import net.runelite.api.widgets.WidgetItem;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.plugins.mta.MTAConfig;
|
||||
import net.runelite.client.plugins.mta.MTAPlugin;
|
||||
import net.runelite.client.plugins.mta.MTARoom;
|
||||
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
|
||||
|
||||
@Slf4j
|
||||
public class AlchemyRoom extends MTARoom
|
||||
{
|
||||
private static final int MTA_ALCH_REGION = 13462;
|
||||
|
||||
private static final int IMAGE_Z_OFFSET = 150;
|
||||
private static final int NUM_CUPBOARDS = 8;
|
||||
private static final int INFO_START = 5;
|
||||
private static final int BEST_POINTS = 30;
|
||||
|
||||
private static final String YOU_FOUND = "You found:";
|
||||
private static final String EMPTY = "The cupboard is empty.";
|
||||
|
||||
private final Cupboard[] cupboards = new Cupboard[NUM_CUPBOARDS];
|
||||
|
||||
private final MTAPlugin plugin;
|
||||
private final Client client;
|
||||
private final ItemManager itemManager;
|
||||
private final InfoBoxManager infoBoxManager;
|
||||
|
||||
private AlchemyItem best;
|
||||
private Cupboard suggestion;
|
||||
|
||||
@Inject
|
||||
private AlchemyRoom(Client client, MTAConfig config, MTAPlugin plugin, ItemManager itemManager, InfoBoxManager infoBoxManager)
|
||||
{
|
||||
super(config);
|
||||
this.client = client;
|
||||
this.plugin = plugin;
|
||||
this.itemManager = itemManager;
|
||||
this.infoBoxManager = infoBoxManager;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onGameTick(GameTick event)
|
||||
{
|
||||
if (!inside() || !config.alchemy())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AlchemyItem bestItem = getBest();
|
||||
if (best == null || best != bestItem)
|
||||
{
|
||||
if (best != null)
|
||||
{
|
||||
infoBoxManager.removeIf(e -> e instanceof AlchemyRoomTimer);
|
||||
infoBoxManager.addInfoBox(new AlchemyRoomTimer(plugin));
|
||||
}
|
||||
|
||||
log.debug("Item change to {}!", best);
|
||||
|
||||
best = bestItem;
|
||||
// Reset items to unknown
|
||||
Arrays.stream(cupboards)
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(e -> e.alchemyItem = AlchemyItem.UNKNOWN);
|
||||
}
|
||||
|
||||
Cupboard newSuggestion = getSuggestion();
|
||||
if (suggestion == null || newSuggestion == null || suggestion.alchemyItem != newSuggestion.alchemyItem)
|
||||
{
|
||||
suggestion = newSuggestion;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Subscribe
|
||||
public void onGameObjectSpawned(GameObjectSpawned event)
|
||||
{
|
||||
if (!inside())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameObject spawn = event.getGameObject();
|
||||
int cupboardId;
|
||||
|
||||
switch (spawn.getId())
|
||||
{
|
||||
// Closed and opened versions of each
|
||||
case CUPBOARD_23678:
|
||||
case CUPBOARD_23679:
|
||||
cupboardId = 0;
|
||||
break;
|
||||
|
||||
case CUPBOARD_23680:
|
||||
case CUPBOARD_23681:
|
||||
cupboardId = 1;
|
||||
break;
|
||||
|
||||
case CUPBOARD_23682:
|
||||
case CUPBOARD_23683:
|
||||
cupboardId = 2;
|
||||
break;
|
||||
|
||||
case CUPBOARD_23684:
|
||||
case CUPBOARD_23685:
|
||||
cupboardId = 3;
|
||||
break;
|
||||
|
||||
case CUPBOARD_23686:
|
||||
case CUPBOARD_23687:
|
||||
cupboardId = 4;
|
||||
break;
|
||||
|
||||
case CUPBOARD_23688:
|
||||
case CUPBOARD_23689:
|
||||
cupboardId = 5;
|
||||
break;
|
||||
|
||||
case CUPBOARD_23690:
|
||||
case CUPBOARD_23691:
|
||||
cupboardId = 6;
|
||||
break;
|
||||
|
||||
case CUPBOARD_23692:
|
||||
case CUPBOARD_23693:
|
||||
cupboardId = 7;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
|
||||
}
|
||||
Cupboard cupboard = cupboards[cupboardId];
|
||||
if (cupboard != null)
|
||||
{
|
||||
cupboard.gameObject = spawn;
|
||||
}
|
||||
else
|
||||
{
|
||||
cupboard = new Cupboard();
|
||||
cupboard.gameObject = spawn;
|
||||
cupboard.alchemyItem = AlchemyItem.UNKNOWN;
|
||||
cupboards[cupboardId] = cupboard;
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onGameStateChanged(GameStateChanged gameStateChanged)
|
||||
{
|
||||
if (gameStateChanged.getGameState() == GameState.LOGGED_IN)
|
||||
{
|
||||
if (!inside())
|
||||
{
|
||||
reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onChatMessage(ChatMessage wrapper)
|
||||
{
|
||||
if (!inside() || !config.alchemy())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
String message = wrapper.getMessage();
|
||||
|
||||
if (wrapper.getType() == ChatMessageType.SERVER)
|
||||
{
|
||||
if (message.contains(YOU_FOUND))
|
||||
{
|
||||
String item = message.replace(YOU_FOUND, "").trim();
|
||||
AlchemyItem alchemyItem = AlchemyItem.find(item);
|
||||
Cupboard clicked = getClicked();
|
||||
if (clicked.alchemyItem != alchemyItem)
|
||||
{
|
||||
fill(clicked, alchemyItem);
|
||||
}
|
||||
}
|
||||
else if (message.equals(EMPTY))
|
||||
{
|
||||
Cupboard clicked = getClicked();
|
||||
|
||||
int idx = Arrays.asList(cupboards).indexOf(clicked);
|
||||
for (int i = -2; i <= 2; ++i)
|
||||
{
|
||||
int j = (idx + i) % 8;
|
||||
if (j < 0)
|
||||
{
|
||||
j = 8 + j;
|
||||
}
|
||||
|
||||
Cupboard cupboard = cupboards[j];
|
||||
if (cupboard != null && cupboard.alchemyItem == AlchemyItem.UNKNOWN)
|
||||
{
|
||||
cupboard.alchemyItem = AlchemyItem.POSSIBLY_EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
clicked.alchemyItem = AlchemyItem.EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void reset()
|
||||
{
|
||||
Arrays.fill(cupboards, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inside()
|
||||
{
|
||||
Player player = client.getLocalPlayer();
|
||||
return player != null && player.getWorldLocation().getRegionID() == MTA_ALCH_REGION
|
||||
&& player.getWorldLocation().getPlane() == 2;
|
||||
}
|
||||
|
||||
private AlchemyItem getBest()
|
||||
{
|
||||
for (int i = 0; i < INFO_START; i++)
|
||||
{
|
||||
int index = i + INFO_START;
|
||||
|
||||
Widget textWidget = client.getWidget(WidgetID.MTA_ALCHEMY_GROUP_ID, index);
|
||||
|
||||
if (textWidget == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
String item = textWidget.getText().replace(":", "");
|
||||
Widget pointsWidget = client.getWidget(WidgetID.MTA_ALCHEMY_GROUP_ID, index + INFO_START);
|
||||
int points = Integer.parseInt(pointsWidget.getText());
|
||||
|
||||
if (points == BEST_POINTS)
|
||||
{
|
||||
return AlchemyItem.find(item);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private Cupboard getClicked()
|
||||
{
|
||||
Cupboard nearest = null;
|
||||
double distance = Double.MAX_VALUE;
|
||||
|
||||
WorldPoint mine = client.getLocalPlayer().getWorldLocation();
|
||||
|
||||
for (Cupboard cupboard : cupboards)
|
||||
{
|
||||
if (cupboard == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
double objectDistance = cupboard.gameObject.getWorldLocation().distanceTo(mine);
|
||||
|
||||
if (nearest == null || objectDistance < distance)
|
||||
{
|
||||
nearest = cupboard;
|
||||
distance = objectDistance;
|
||||
}
|
||||
}
|
||||
|
||||
return nearest;
|
||||
}
|
||||
|
||||
private void fill(Cupboard cupboard, AlchemyItem alchemyItem)
|
||||
{
|
||||
int idx = Arrays.asList(cupboards).indexOf(cupboard);
|
||||
assert idx != -1;
|
||||
|
||||
int itemIdx = alchemyItem.ordinal();
|
||||
|
||||
log.debug("Filling cupboard {} with {}", idx, alchemyItem);
|
||||
|
||||
for (int i = 0; i < NUM_CUPBOARDS; ++i)
|
||||
{
|
||||
int cupIdx = (idx + i) % NUM_CUPBOARDS;
|
||||
int itemIndex = (itemIdx + i) % NUM_CUPBOARDS;
|
||||
cupboards[cupIdx].alchemyItem = itemIndex <= 4 ? AlchemyItem.values()[itemIndex] : AlchemyItem.EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void under(Graphics2D graphics)
|
||||
{
|
||||
if (!getConfig().alchemy() || best == null || !inside())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
boolean found = false;
|
||||
|
||||
for (Cupboard cupboard : cupboards)
|
||||
{
|
||||
if (cupboard == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
GameObject object = cupboard.gameObject;
|
||||
AlchemyItem alchemyItem = cupboard.alchemyItem;
|
||||
|
||||
if (alchemyItem == AlchemyItem.EMPTY)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (alchemyItem == best)
|
||||
{
|
||||
client.setHintArrow(object.getWorldLocation());
|
||||
found = true;
|
||||
}
|
||||
|
||||
BufferedImage image = itemManager.getImage(alchemyItem.getId());
|
||||
Point canvasLoc = Perspective.getCanvasImageLocation(client, graphics, object.getLocalLocation(), image, IMAGE_Z_OFFSET);
|
||||
|
||||
if (canvasLoc != null)
|
||||
{
|
||||
graphics.drawImage(image, canvasLoc.getX(), canvasLoc.getY(), null);
|
||||
}
|
||||
}
|
||||
|
||||
if (!found && suggestion != null)
|
||||
{
|
||||
client.setHintArrow(suggestion.gameObject.getWorldLocation());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Cupboard getSuggestion()
|
||||
{
|
||||
// check if a cupboard has the best item in it
|
||||
if (best != null)
|
||||
{
|
||||
for (Cupboard cupboard : cupboards)
|
||||
{
|
||||
if (cupboard != null && cupboard.alchemyItem == best)
|
||||
{
|
||||
return cupboard;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise find the closest cupboard which can not be empty
|
||||
Cupboard nearest = null;
|
||||
int distance = -1;
|
||||
|
||||
WorldPoint mine = client.getLocalPlayer().getWorldLocation();
|
||||
|
||||
for (Cupboard cupboard : cupboards)
|
||||
{
|
||||
if (cupboard == null || cupboard.alchemyItem == AlchemyItem.EMPTY || cupboard.alchemyItem == AlchemyItem.POSSIBLY_EMPTY)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int objectDistance = (int) cupboard.gameObject.getWorldLocation().distanceTo(mine);
|
||||
|
||||
if (nearest == null || objectDistance < distance)
|
||||
{
|
||||
nearest = cupboard;
|
||||
distance = objectDistance;
|
||||
}
|
||||
}
|
||||
|
||||
return nearest;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void over(Graphics2D graphics)
|
||||
{
|
||||
if (!inside() || !config.alchemy() || best == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Widget inventory = client.getWidget(WidgetInfo.INVENTORY);
|
||||
if (inventory.isHidden())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (WidgetItem item : inventory.getWidgetItems())
|
||||
{
|
||||
if (item.getId() != best.getId())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
drawItem(graphics, item, Color.GREEN);
|
||||
}
|
||||
}
|
||||
|
||||
private void drawItem(Graphics2D graphics, WidgetItem item, Color border)
|
||||
{
|
||||
Rectangle bounds = item.getCanvasBounds();
|
||||
graphics.setColor(border);
|
||||
graphics.draw(bounds);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Jasper Ketelaar <Jasper0781@gmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.plugins.mta.alchemy;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import javax.imageio.ImageIO;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
import net.runelite.client.ui.overlay.infobox.Timer;
|
||||
|
||||
@Slf4j
|
||||
public class AlchemyRoomTimer extends Timer
|
||||
{
|
||||
private static final int RESET_PERIOD = 42;
|
||||
private static BufferedImage image;
|
||||
|
||||
public AlchemyRoomTimer(Plugin plugin)
|
||||
{
|
||||
super(RESET_PERIOD, ChronoUnit.SECONDS, getResetImage(), plugin);
|
||||
this.setTooltip("Time until items swap");
|
||||
}
|
||||
|
||||
private static BufferedImage getResetImage()
|
||||
{
|
||||
if (image != null)
|
||||
{
|
||||
return image;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
synchronized (ImageIO.class)
|
||||
{
|
||||
image = ImageIO.read(AlchemyRoomTimer.class.getResourceAsStream("reset.png"));
|
||||
}
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
log.warn(null, ex);
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.plugins.mta.alchemy;
|
||||
|
||||
import net.runelite.api.GameObject;
|
||||
|
||||
class Cupboard
|
||||
{
|
||||
GameObject gameObject;
|
||||
AlchemyItem alchemyItem;
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Jasper Ketelaar <Jasper0781@gmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.plugins.mta.enchantment;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.inject.Inject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.GameState;
|
||||
import net.runelite.api.Item;
|
||||
import net.runelite.api.ItemID;
|
||||
import net.runelite.api.ItemLayer;
|
||||
import net.runelite.api.Player;
|
||||
import net.runelite.api.Tile;
|
||||
import net.runelite.api.coords.WorldPoint;
|
||||
import net.runelite.api.events.GameStateChanged;
|
||||
import net.runelite.api.events.GameTick;
|
||||
import net.runelite.api.events.ItemLayerChanged;
|
||||
import net.runelite.client.plugins.mta.MTAConfig;
|
||||
import net.runelite.client.plugins.mta.MTARoom;
|
||||
|
||||
@Slf4j
|
||||
public class EnchantmentRoom extends MTARoom
|
||||
{
|
||||
private static final int MTA_ENCHANT_REGION = 13462;
|
||||
|
||||
private final Client client;
|
||||
private final List<WorldPoint> dragonstones = new ArrayList<>();
|
||||
|
||||
@Inject
|
||||
private EnchantmentRoom(MTAConfig config, Client client)
|
||||
{
|
||||
super(config);
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onGameStateChanged(GameStateChanged gameStateChanged)
|
||||
{
|
||||
if (gameStateChanged.getGameState() == GameState.LOGGED_IN)
|
||||
{
|
||||
if (!inside())
|
||||
{
|
||||
dragonstones.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onGameTick(GameTick event)
|
||||
{
|
||||
if (!inside() || !config.enchantment())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
WorldPoint nearest = findNearestStone();
|
||||
if (nearest != null)
|
||||
{
|
||||
client.setHintArrow(nearest);
|
||||
}
|
||||
}
|
||||
|
||||
private WorldPoint findNearestStone()
|
||||
{
|
||||
WorldPoint nearest = null;
|
||||
double dist = Double.MAX_VALUE;
|
||||
WorldPoint local = client.getLocalPlayer().getWorldLocation();
|
||||
for (WorldPoint worldPoint : dragonstones)
|
||||
{
|
||||
double currDist = local.distanceTo(worldPoint);
|
||||
if (nearest == null || currDist < dist)
|
||||
{
|
||||
dist = currDist;
|
||||
nearest = worldPoint;
|
||||
}
|
||||
}
|
||||
return nearest;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onItemLayerChanged(ItemLayerChanged event)
|
||||
{
|
||||
if (!inside())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Tile changed = event.getTile();
|
||||
ItemLayer itemLayer = changed.getItemLayer();
|
||||
WorldPoint worldPoint = changed.getWorldLocation();
|
||||
|
||||
List<Item> groundItems = changed.getGroundItems();
|
||||
if (groundItems == null)
|
||||
{
|
||||
boolean removed = dragonstones.remove(worldPoint);
|
||||
if (removed)
|
||||
{
|
||||
log.debug("Removed dragonstone at {}", worldPoint);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (Item item : changed.getGroundItems())
|
||||
{
|
||||
if (item.getId() == ItemID.DRAGONSTONE_6903)
|
||||
{
|
||||
log.debug("Adding dragonstone at {}", worldPoint);
|
||||
dragonstones.add(worldPoint);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
boolean removed = dragonstones.remove(worldPoint);
|
||||
if (removed)
|
||||
{
|
||||
log.debug("Removed dragonstone at {}", worldPoint);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inside()
|
||||
{
|
||||
Player player = client.getLocalPlayer();
|
||||
return player != null && player.getWorldLocation().getRegionID() == MTA_ENCHANT_REGION
|
||||
&& player.getWorldLocation().getPlane() == 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Jasper Ketelaar <Jasper0781@gmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.plugins.mta.graveyard;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.image.BufferedImage;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
import net.runelite.client.ui.overlay.infobox.Counter;
|
||||
|
||||
public class GraveyardCounter extends Counter
|
||||
{
|
||||
private int count;
|
||||
|
||||
public GraveyardCounter(BufferedImage image, Plugin plugin)
|
||||
{
|
||||
super(image, plugin, "0");
|
||||
}
|
||||
|
||||
public void setCount(int count)
|
||||
{
|
||||
this.count = count;
|
||||
this.setText(String.valueOf(count));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getTextColor()
|
||||
{
|
||||
if (count >= GraveyardRoom.MIN_SCORE)
|
||||
{
|
||||
return Color.GREEN;
|
||||
}
|
||||
else if (count == 0)
|
||||
{
|
||||
return Color.RED;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Color.ORANGE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Jasper Ketelaar <Jasper0781@gmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.plugins.mta.graveyard;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import java.awt.image.BufferedImage;
|
||||
import javax.inject.Inject;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.InventoryID;
|
||||
import net.runelite.api.Item;
|
||||
import net.runelite.api.ItemContainer;
|
||||
import static net.runelite.api.ItemID.ANIMALS_BONES;
|
||||
import static net.runelite.api.ItemID.ANIMALS_BONES_6905;
|
||||
import static net.runelite.api.ItemID.ANIMALS_BONES_6906;
|
||||
import static net.runelite.api.ItemID.ANIMALS_BONES_6907;
|
||||
import net.runelite.api.Player;
|
||||
import net.runelite.api.events.GameTick;
|
||||
import net.runelite.api.events.ItemContainerChanged;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.plugins.mta.MTAConfig;
|
||||
import net.runelite.client.plugins.mta.MTAPlugin;
|
||||
import net.runelite.client.plugins.mta.MTARoom;
|
||||
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
|
||||
|
||||
public class GraveyardRoom extends MTARoom
|
||||
{
|
||||
private static final int MTA_GRAVEYARD_REGION = 13462;
|
||||
|
||||
static final int MIN_SCORE = 16;
|
||||
|
||||
private final Client client;
|
||||
private final MTAPlugin plugin;
|
||||
private final ItemManager itemManager;
|
||||
private final InfoBoxManager infoBoxManager;
|
||||
private int score;
|
||||
|
||||
private GraveyardCounter counter;
|
||||
|
||||
@Inject
|
||||
private GraveyardRoom(MTAConfig config, Client client, MTAPlugin plugin,
|
||||
ItemManager itemManager, InfoBoxManager infoBoxManager)
|
||||
{
|
||||
super(config);
|
||||
this.client = client;
|
||||
this.plugin = plugin;
|
||||
this.itemManager = itemManager;
|
||||
this.infoBoxManager = infoBoxManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inside()
|
||||
{
|
||||
Player player = client.getLocalPlayer();
|
||||
return player != null && player.getWorldLocation().getRegionID() == MTA_GRAVEYARD_REGION
|
||||
&& player.getWorldLocation().getPlane() == 1;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onGameTick(GameTick tick)
|
||||
{
|
||||
if (!inside() || !config.graveyard())
|
||||
{
|
||||
if (this.counter != null)
|
||||
{
|
||||
infoBoxManager.removeIf(e -> e instanceof GraveyardCounter);
|
||||
this.counter = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void itemContainerChanged(ItemContainerChanged event)
|
||||
{
|
||||
if (!inside())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ItemContainer container = event.getItemContainer();
|
||||
|
||||
if (container == client.getItemContainer(InventoryID.INVENTORY))
|
||||
{
|
||||
this.score = score(container.getItems());
|
||||
|
||||
if (counter == null)
|
||||
{
|
||||
BufferedImage image = itemManager.getImage(ANIMALS_BONES);
|
||||
counter = new GraveyardCounter(image, plugin);
|
||||
infoBoxManager.addInfoBox(counter);
|
||||
}
|
||||
counter.setCount(score);
|
||||
}
|
||||
}
|
||||
|
||||
private int score(Item[] items)
|
||||
{
|
||||
int score = 0;
|
||||
|
||||
if (items == null)
|
||||
{
|
||||
return score;
|
||||
}
|
||||
|
||||
for (Item item : items)
|
||||
{
|
||||
score += getPoints(item.getId());
|
||||
}
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
private int getPoints(int id)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case ANIMALS_BONES:
|
||||
return 1;
|
||||
case ANIMALS_BONES_6905:
|
||||
return 2;
|
||||
case ANIMALS_BONES_6906:
|
||||
return 3;
|
||||
case ANIMALS_BONES_6907:
|
||||
return 4;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Jasper Ketelaar <Jasper0781@gmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.plugins.mta.telekinetic;
|
||||
|
||||
import net.runelite.api.coords.LocalPoint;
|
||||
|
||||
public enum Maze
|
||||
{
|
||||
MAZE_1(100, new LocalPoint(6848, 3904)),
|
||||
MAZE_2(124, new LocalPoint(4928, 6848)),
|
||||
MAZE_3(129, new LocalPoint(7104, 5312)),
|
||||
MAZE_4(53, new LocalPoint(6208, 4928)),
|
||||
MAZE_5(108, new LocalPoint(5056, 5184)),
|
||||
MAZE_6(121, new LocalPoint(3648, 5440)),
|
||||
MAZE_7(71, new LocalPoint(6080, 5696)),
|
||||
MAZE_8(98, new LocalPoint(5952, 7360)),
|
||||
MAZE_9(87, new LocalPoint(5184, 6208)),
|
||||
MAZE_10(91, new LocalPoint(5440, 9024));
|
||||
|
||||
private final int walls;
|
||||
private final LocalPoint start;
|
||||
|
||||
Maze(int walls, LocalPoint start)
|
||||
{
|
||||
this.walls = walls;
|
||||
this.start = start;
|
||||
}
|
||||
|
||||
public static Maze fromWalls(int walls)
|
||||
{
|
||||
for (Maze maze : values())
|
||||
{
|
||||
if (maze.getWalls() == walls)
|
||||
{
|
||||
return maze;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getWalls()
|
||||
{
|
||||
return walls;
|
||||
}
|
||||
|
||||
public LocalPoint getStart()
|
||||
{
|
||||
return start;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,512 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Jasper Ketelaar <Jasper0781@gmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.plugins.mta.telekinetic;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Polygon;
|
||||
import java.awt.Rectangle;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
import javax.inject.Inject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.GameState;
|
||||
import net.runelite.api.GroundObject;
|
||||
import net.runelite.api.NPC;
|
||||
import net.runelite.api.NpcID;
|
||||
import net.runelite.api.NullObjectID;
|
||||
import net.runelite.api.Perspective;
|
||||
import net.runelite.api.Projectile;
|
||||
import net.runelite.api.ProjectileID;
|
||||
import net.runelite.api.WallObject;
|
||||
import net.runelite.api.coords.Angle;
|
||||
import net.runelite.api.coords.Direction;
|
||||
import net.runelite.api.coords.LocalPoint;
|
||||
import net.runelite.api.coords.WorldArea;
|
||||
import net.runelite.api.coords.WorldPoint;
|
||||
import net.runelite.api.events.GameTick;
|
||||
import net.runelite.api.events.NpcDespawned;
|
||||
import net.runelite.api.events.NpcSpawned;
|
||||
import net.runelite.api.queries.GroundObjectQuery;
|
||||
import net.runelite.api.queries.WallObjectQuery;
|
||||
import net.runelite.api.widgets.WidgetID;
|
||||
import net.runelite.client.plugins.mta.MTAConfig;
|
||||
import net.runelite.client.plugins.mta.MTARoom;
|
||||
|
||||
@Slf4j
|
||||
public class TelekineticRoom extends MTARoom
|
||||
{
|
||||
private static final int TELEKINETIC_WALL = NullObjectID.NULL_10755;
|
||||
private static final int TELEKINETIC_FINISH = NullObjectID.NULL_23672;
|
||||
|
||||
private final Client client;
|
||||
|
||||
private Stack<Direction> moves = new Stack<>();
|
||||
private LocalPoint destination;
|
||||
private WorldPoint location;
|
||||
private Rectangle bounds;
|
||||
private NPC guardian;
|
||||
private Maze maze;
|
||||
|
||||
@Inject
|
||||
private TelekineticRoom(MTAConfig config, Client client)
|
||||
{
|
||||
super(config);
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onGameTick(GameTick event)
|
||||
{
|
||||
if (!config.telekinetic()
|
||||
|| !inside()
|
||||
|| client.getGameState() != GameState.LOGGED_IN)
|
||||
{
|
||||
maze = null;
|
||||
moves.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
WallObjectQuery qry = new WallObjectQuery()
|
||||
.idEquals(TELEKINETIC_WALL);
|
||||
WallObject[] result = qry.result(client);
|
||||
int length = result.length;
|
||||
|
||||
if (maze == null || length != maze.getWalls())
|
||||
{
|
||||
bounds = getBounds(result);
|
||||
maze = Maze.fromWalls(length);
|
||||
client.clearHintArrow();
|
||||
}
|
||||
else if (guardian != null)
|
||||
{
|
||||
WorldPoint current;
|
||||
if (guardian.getId() == NpcID.MAZE_GUARDIAN_MOVING)
|
||||
{
|
||||
destination = getGuardianDestination();
|
||||
current = WorldPoint.fromLocal(client, destination);
|
||||
}
|
||||
else
|
||||
{
|
||||
destination = null;
|
||||
current = guardian.getWorldLocation();
|
||||
}
|
||||
|
||||
//Prevent unnecessary updating when the guardian has not moved
|
||||
if (current.equals(location))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
log.debug("Updating guarding location {} -> {}", location, current);
|
||||
|
||||
location = current;
|
||||
|
||||
if (location.equals(finish()))
|
||||
{
|
||||
client.clearHintArrow();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (Projectile projectile : client.getProjectiles())
|
||||
{
|
||||
if (projectile.getId() == ProjectileID.TELEKINETIC_SPELL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
log.debug("Rebuilding moves due to guardian move");
|
||||
this.moves = build();
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
client.clearHintArrow();
|
||||
moves.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onNpcSpawned(NpcSpawned event)
|
||||
{
|
||||
NPC npc = event.getNpc();
|
||||
|
||||
if (npc.getId() == NpcID.MAZE_GUARDIAN)
|
||||
{
|
||||
guardian = npc;
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onNpcDespawned(NpcDespawned event)
|
||||
{
|
||||
NPC npc = event.getNpc();
|
||||
|
||||
if (npc == guardian)
|
||||
{
|
||||
guardian = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inside()
|
||||
{
|
||||
return client.getWidget(WidgetID.MTA_TELEKINETIC_GROUP_ID, 0) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void under(Graphics2D graphics2D)
|
||||
{
|
||||
if (inside() && maze != null && guardian != null)
|
||||
{
|
||||
if (destination != null)
|
||||
{
|
||||
graphics2D.setColor(Color.ORANGE);
|
||||
renderLocalPoint(graphics2D, destination);
|
||||
}
|
||||
if (!moves.isEmpty())
|
||||
{
|
||||
if (moves.peek() == getPosition())
|
||||
{
|
||||
graphics2D.setColor(Color.GREEN);
|
||||
}
|
||||
else
|
||||
{
|
||||
graphics2D.setColor(Color.RED);
|
||||
}
|
||||
|
||||
Polygon tile = Perspective.getCanvasTilePoly(client, guardian.getLocalLocation());
|
||||
if (tile != null)
|
||||
{
|
||||
graphics2D.drawPolygon(tile);
|
||||
}
|
||||
|
||||
WorldPoint optimal = optimal();
|
||||
|
||||
if (optimal != null)
|
||||
{
|
||||
client.setHintArrow(optimal);
|
||||
renderWorldPoint(graphics2D, optimal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private WorldPoint optimal()
|
||||
{
|
||||
WorldPoint current = client.getLocalPlayer().getWorldLocation();
|
||||
|
||||
Direction next = moves.pop();
|
||||
WorldArea areaNext = getIndicatorLine(next);
|
||||
WorldPoint nearestNext = nearest(areaNext, current);
|
||||
|
||||
if (moves.isEmpty())
|
||||
{
|
||||
moves.push(next);
|
||||
|
||||
return nearestNext;
|
||||
}
|
||||
|
||||
Direction after = moves.peek();
|
||||
moves.push(next);
|
||||
WorldArea areaAfter = getIndicatorLine(after);
|
||||
WorldPoint nearestAfter = nearest(areaAfter, nearestNext);
|
||||
|
||||
return nearest(areaNext, nearestAfter);
|
||||
}
|
||||
|
||||
private static int manhattan(WorldPoint point1, WorldPoint point2)
|
||||
{
|
||||
return Math.abs(point1.getX() - point2.getX()) + Math.abs(point2.getY() - point1.getY());
|
||||
}
|
||||
|
||||
private WorldPoint nearest(WorldArea area, WorldPoint worldPoint)
|
||||
{
|
||||
int dist = Integer.MAX_VALUE;
|
||||
WorldPoint nearest = null;
|
||||
|
||||
for (WorldPoint areaPoint : area.toWorldPointList())
|
||||
{
|
||||
int currDist = manhattan(areaPoint, worldPoint);
|
||||
if (nearest == null || dist > currDist)
|
||||
{
|
||||
nearest = areaPoint;
|
||||
dist = currDist;
|
||||
}
|
||||
}
|
||||
|
||||
return nearest;
|
||||
}
|
||||
|
||||
private void renderWorldPoint(Graphics2D graphics, WorldPoint worldPoint)
|
||||
{
|
||||
renderLocalPoint(graphics, LocalPoint.fromWorld(client, worldPoint));
|
||||
}
|
||||
|
||||
private void renderLocalPoint(Graphics2D graphics, LocalPoint local)
|
||||
{
|
||||
if (local != null)
|
||||
{
|
||||
Polygon canvasTilePoly = Perspective.getCanvasTilePoly(client, local);
|
||||
if (canvasTilePoly != null)
|
||||
{
|
||||
graphics.drawPolygon(canvasTilePoly);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Stack<Direction> build()
|
||||
{
|
||||
if (guardian.getId() == NpcID.MAZE_GUARDIAN_MOVING)
|
||||
{
|
||||
WorldPoint converted = WorldPoint.fromLocal(client, getGuardianDestination());
|
||||
return build(converted);
|
||||
}
|
||||
else
|
||||
{
|
||||
return build(guardian.getWorldLocation());
|
||||
}
|
||||
}
|
||||
|
||||
private LocalPoint getGuardianDestination()
|
||||
{
|
||||
Angle angle = new Angle(guardian.getOrientation());
|
||||
Direction facing = angle.getNearestDirection();
|
||||
return neighbour(guardian.getLocalLocation(), facing);
|
||||
}
|
||||
|
||||
private Stack<Direction> build(WorldPoint start)
|
||||
{
|
||||
LocalPoint finish = finish();
|
||||
|
||||
Queue<WorldPoint> visit = new LinkedList<>();
|
||||
Set<WorldPoint> closed = new HashSet<>();
|
||||
Map<WorldPoint, Integer> scores = new HashMap<>();
|
||||
Map<WorldPoint, WorldPoint> edges = new HashMap<>();
|
||||
scores.put(start, 0);
|
||||
visit.add(start);
|
||||
|
||||
while (!visit.isEmpty())
|
||||
{
|
||||
WorldPoint next = visit.poll();
|
||||
closed.add(next);
|
||||
|
||||
LocalPoint localNext = LocalPoint.fromWorld(client, next);
|
||||
LocalPoint[] neighbours = neighbours(localNext);
|
||||
|
||||
for (LocalPoint neighbour : neighbours)
|
||||
{
|
||||
if (neighbour == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
WorldPoint nghbWorld = WorldPoint.fromLocal(client, neighbour);
|
||||
|
||||
if (!nghbWorld.equals(next)
|
||||
&& !closed.contains(nghbWorld))
|
||||
{
|
||||
int score = scores.get(next) + 1;
|
||||
|
||||
if (!scores.containsKey(nghbWorld) || scores.get(nghbWorld) > score)
|
||||
{
|
||||
scores.put(nghbWorld, score);
|
||||
edges.put(nghbWorld, next);
|
||||
visit.add(nghbWorld);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return build(edges, WorldPoint.fromLocal(client, finish));
|
||||
}
|
||||
|
||||
private Stack<Direction> build(Map<WorldPoint, WorldPoint> edges, WorldPoint finish)
|
||||
{
|
||||
Stack<Direction> path = new Stack<>();
|
||||
WorldPoint current = finish;
|
||||
|
||||
while (edges.containsKey(current))
|
||||
{
|
||||
WorldPoint next = edges.get(current);
|
||||
|
||||
if (next.getX() > current.getX())
|
||||
{
|
||||
path.add(Direction.WEST);
|
||||
}
|
||||
else if (next.getX() < current.getX())
|
||||
{
|
||||
path.add(Direction.EAST);
|
||||
}
|
||||
else if (next.getY() > current.getY())
|
||||
{
|
||||
path.add(Direction.SOUTH);
|
||||
}
|
||||
else
|
||||
{
|
||||
path.add(Direction.NORTH);
|
||||
}
|
||||
|
||||
current = next;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
private LocalPoint[] neighbours(LocalPoint point)
|
||||
{
|
||||
return new LocalPoint[]
|
||||
{
|
||||
neighbour(point, Direction.NORTH), neighbour(point, Direction.SOUTH),
|
||||
neighbour(point, Direction.EAST), neighbour(point, Direction.WEST)
|
||||
};
|
||||
}
|
||||
|
||||
private LocalPoint neighbour(LocalPoint point, Direction direction)
|
||||
{
|
||||
WorldPoint worldPoint = WorldPoint.fromLocal(client, point);
|
||||
WorldArea area = new WorldArea(worldPoint, 1, 1);
|
||||
|
||||
int dx, dy;
|
||||
|
||||
switch (direction)
|
||||
{
|
||||
case NORTH:
|
||||
dx = 0;
|
||||
dy = 1;
|
||||
break;
|
||||
case SOUTH:
|
||||
dx = 0;
|
||||
dy = -1;
|
||||
break;
|
||||
case EAST:
|
||||
dx = 1;
|
||||
dy = 0;
|
||||
break;
|
||||
case WEST:
|
||||
dx = -1;
|
||||
dy = 0;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
while (area.canTravelInDirection(client, dx, dy))
|
||||
{
|
||||
worldPoint = area.toWorldPoint()
|
||||
.dx(dx)
|
||||
.dy(dy);
|
||||
area = new WorldArea(worldPoint, 1, 1);
|
||||
}
|
||||
|
||||
return LocalPoint.fromWorld(client, worldPoint);
|
||||
}
|
||||
|
||||
private LocalPoint finish()
|
||||
{
|
||||
GroundObjectQuery qry = new GroundObjectQuery()
|
||||
.idEquals(TELEKINETIC_FINISH);
|
||||
|
||||
GroundObject[] result = qry.result(client);
|
||||
|
||||
if (result.length > 0)
|
||||
{
|
||||
return result[0].getLocalLocation();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private Rectangle getBounds(WallObject[] walls)
|
||||
{
|
||||
int minX = Integer.MAX_VALUE;
|
||||
int minY = Integer.MAX_VALUE;
|
||||
|
||||
int maxX = Integer.MIN_VALUE;
|
||||
int maxY = Integer.MIN_VALUE;
|
||||
|
||||
for (WallObject wall : walls)
|
||||
{
|
||||
WorldPoint point = wall.getWorldLocation();
|
||||
minX = Math.min(minX, point.getX());
|
||||
minY = Math.min(minY, point.getY());
|
||||
|
||||
maxX = Math.max(maxX, point.getX());
|
||||
maxY = Math.max(maxY, point.getY());
|
||||
}
|
||||
|
||||
return new Rectangle(minX, minY, maxX - minX, maxY - minY);
|
||||
}
|
||||
|
||||
private Direction getPosition()
|
||||
{
|
||||
WorldPoint mine = client.getLocalPlayer().getWorldLocation();
|
||||
|
||||
if (mine.getY() >= bounds.getMaxY() && mine.getX() < bounds.getMaxX() && mine.getX() > bounds.getX())
|
||||
{
|
||||
return Direction.NORTH;
|
||||
}
|
||||
else if (mine.getY() <= bounds.getY() && mine.getX() < bounds.getMaxX() && mine.getX() > bounds.getX())
|
||||
{
|
||||
return Direction.SOUTH;
|
||||
}
|
||||
else if (mine.getX() >= bounds.getMaxX() && mine.getY() < bounds.getMaxY() && mine.getY() > bounds.getY())
|
||||
{
|
||||
return Direction.EAST;
|
||||
}
|
||||
else if (mine.getX() <= bounds.getX() && mine.getY() < bounds.getMaxY() && mine.getY() > bounds.getY())
|
||||
{
|
||||
return Direction.WEST;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private WorldArea getIndicatorLine(Direction direction)
|
||||
{
|
||||
switch (direction)
|
||||
{
|
||||
case NORTH:
|
||||
return new WorldArea(bounds.x + 1, (int) bounds.getMaxY(), bounds.width - 1, 1, 0);
|
||||
case SOUTH:
|
||||
return new WorldArea(bounds.x + 1, bounds.y, bounds.width - 1, 1, 0);
|
||||
case WEST:
|
||||
return new WorldArea(bounds.x, bounds.y + 1, 1, bounds.height - 1, 0);
|
||||
case EAST:
|
||||
return new WorldArea((int) bounds.getMaxX(), bounds.y + 1, 1, bounds.height - 1, 0);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
@@ -33,6 +33,7 @@ public interface RSActor extends RSRenderable, Actor
|
||||
int getRSInteracting();
|
||||
|
||||
@Import("overhead")
|
||||
@Override
|
||||
String getOverhead();
|
||||
|
||||
@Import("x")
|
||||
|
||||
Reference in New Issue
Block a user