poh, questlist, skybox, wiki, worldhopper, worldmap, zalcano

This commit is contained in:
therealunull
2020-12-16 16:03:03 -05:00
parent 5d7bf6aa54
commit b6f47eb581
66 changed files with 9457 additions and 28 deletions

View File

@@ -0,0 +1,122 @@
/*
* Copyright (c) 2018, Seth <Sethtroll3@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.poh;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.time.Duration;
import java.time.Instant;
import javax.inject.Inject;
import net.runelite.api.Client;
import net.runelite.api.Perspective;
import net.runelite.api.Point;
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.components.ProgressPieComponent;
class BurnerOverlay extends Overlay
{
private final Client client;
private final PohConfig config;
private final PohPlugin plugin;
@Inject
private BurnerOverlay(Client client, PohConfig config, PohPlugin plugin)
{
setPosition(OverlayPosition.DYNAMIC);
setLayer(OverlayLayer.ABOVE_SCENE);
this.client = client;
this.config = config;
this.plugin = plugin;
}
@Override
public Dimension render(Graphics2D graphics)
{
if (!config.showBurner())
{
return null;
}
plugin.getIncenseBurners().forEach((tile, burner) ->
{
if (tile.getPlane() != client.getPlane())
{
return;
}
if (!PohPlugin.BURNER_LIT.contains(burner.getId()))
{
return;
}
final Instant now = Instant.now();
final long startCountdown = Duration.between(burner.getStart(), now).getSeconds();
final double certainSec = burner.getCountdownTimer() - startCountdown;
long endCountdown = 0;
if (certainSec <= 0)
{
if (burner.getEnd() == null)
{
burner.setEnd(Instant.now());
}
endCountdown = Duration.between(burner.getEnd(), now).getSeconds();
}
final double randomSec = burner.getRandomTimer() - endCountdown;
final ProgressPieComponent pieComponent = new ProgressPieComponent();
final Point loc = Perspective.localToCanvas(client, tile.getLocalLocation(), tile.getPlane());
if (loc == null)
{
return;
}
pieComponent.setPosition(loc);
if (certainSec > 0)
{
pieComponent.setProgress(certainSec / burner.getCountdownTimer());
pieComponent.setFill(Color.GREEN);
pieComponent.setBorderColor(Color.GREEN);
pieComponent.render(graphics);
}
else if (randomSec > 0)
{
pieComponent.setProgress(randomSec / burner.getRandomTimer());
pieComponent.setFill(Color.ORANGE);
pieComponent.setBorderColor(Color.ORANGE);
pieComponent.render(graphics);
}
});
return null;
}
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) 2018, Tomas Slusny <slusnucky@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.poh;
import java.time.Instant;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@RequiredArgsConstructor
@AllArgsConstructor
class IncenseBurner
{
private final Instant start = Instant.now();
private final int id;
private double countdownTimer;
private double randomTimer;
private Instant end;
}

View File

@@ -0,0 +1,173 @@
/*
* Copyright (c) 2018, Seth <Sethtroll3@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.poh;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
@ConfigGroup("poh")
public interface PohConfig extends Config
{
@ConfigItem(
keyName = "showPortals",
name = "Show Portals",
description = "Configures whether to display teleport portals"
)
default boolean showPortals()
{
return true;
}
@ConfigItem(
keyName = "showAltar",
name = "Show Altar",
description = "Configures whether or not the altar is displayed"
)
default boolean showAltar()
{
return true;
}
@ConfigItem(
keyName = "showGlory",
name = "Show Glory mount",
description = "Configures whether or not the mounted glory is displayed"
)
default boolean showGlory()
{
return true;
}
@ConfigItem(
keyName = "showPools",
name = "Show Pools",
description = "Configures whether or not the pools are displayed"
)
default boolean showPools()
{
return true;
}
@ConfigItem(
keyName = "showRepairStand",
name = "Show Repair stand",
description = "Configures whether or not the repair stand is displayed"
)
default boolean showRepairStand()
{
return true;
}
@ConfigItem(
keyName = "showExitPortal",
name = "Show Exit portal",
description = "Configures whether or not the exit portal is displayed"
)
default boolean showExitPortal()
{
return true;
}
@ConfigItem(
keyName = "showBurner",
name = "Show Incense Burner timers",
description = "Configures whether or not unlit/lit burners are displayed"
)
default boolean showBurner()
{
return true;
}
@ConfigItem(
keyName = "showSpellbook",
name = "Show Spellbook altar",
description = "Configures whether or not the Spellbook altar is displayed"
)
default boolean showSpellbook()
{
return true;
}
@ConfigItem(
keyName = "showJewelleryBox",
name = "Show Jewellery Box",
description = "Configures whether or not the jewellery box is displayed"
)
default boolean showJewelleryBox()
{
return true;
}
@ConfigItem(
keyName = "showMagicTravel",
name = "Show Fairy/ Spirit Tree/ Obelisk",
description = "Configures whether or not the Fairy ring, Spirit tree or Obelisk is displayed"
)
default boolean showMagicTravel()
{
return true;
}
@ConfigItem(
keyName = "showPortalNexus",
name = "Show Portal Nexus",
description = "Configures whether or not the Portal Nexus is displayed"
)
default boolean showPortalNexus()
{
return true;
}
@ConfigItem(
keyName = "showDigsitePendant",
name = "Show Digsite Pendant",
description = "Configures whether or not the Digsite Pendant is displayed"
)
default boolean showDigsitePendant()
{
return true;
}
@ConfigItem(
keyName = "showXericsTalisman",
name = "Show Xeric's Talisman",
description = "Configures whether or not the Xeric's Talisman is displayed"
)
default boolean showXericsTalisman()
{
return true;
}
@ConfigItem(
keyName = "showMythicalCape",
name = "Show Mythical Cape",
description = "Configures whether or not the Mythical Cape is displayed"
)
default boolean showMythicalCape()
{
return true;
}
}

View File

@@ -0,0 +1,150 @@
/*
* Copyright (c) 2018, Seth <Sethtroll3@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.poh;
import com.google.common.collect.ImmutableMap;
import java.awt.image.BufferedImage;
import java.util.Map;
import lombok.Getter;
import static net.runelite.api.NullObjectID.*;
import static net.runelite.api.ObjectID.*;
import net.runelite.client.util.ImageUtil;
public enum PohIcons
{
EXITPORTAL("exitportal", PORTAL_4525),
VARROCK("varrock", NULL_13615, NULL_13622, NULL_13629),
FALADOR("falador", FALADOR_PORTAL, FALADOR_PORTAL_13624, FALADOR_PORTAL_13631),
LUMBRIDGE("lumbridge", LUMBRIDGE_PORTAL, LUMBRIDGE_PORTAL_13623, LUMBRIDGE_PORTAL_13630),
ARDOUGNE("ardougne", ARDOUGNE_PORTAL, ARDOUGNE_PORTAL_13626, ARDOUGNE_PORTAL_13633),
YANILLE("yanille", NULL_13620, NULL_13627, NULL_13634),
CAMELOT("camelot", NULL_13618, NULL_13625, NULL_13632),
LUNARISLE("lunarisle", LUNAR_ISLE_PORTAL, LUNAR_ISLE_PORTAL_29347, LUNAR_ISLE_PORTAL_29355),
WATERBIRTH("waterbirth", WATERBIRTH_ISLAND_PORTAL, WATERBIRTH_ISLAND_PORTAL_29350, WATERBIRTH_ISLAND_PORTAL_29358),
FISHINGGUILD("fishingguild", FISHING_GUILD_PORTAL, FISHING_GUILD_PORTAL_29351, FISHING_GUILD_PORTAL_29359),
SENNTISTEN("senntisten", SENNTISTEN_PORTAL, SENNTISTEN_PORTAL_29348, SENNTISTEN_PORTAL_29356),
KHARYLL("kharyll", KHARYRLL_PORTAL, KHARYRLL_PORTAL_29346, KHARYRLL_PORTAL_29354),
ANNAKARL("annakarl", ANNAKARL_PORTAL, ANNAKARL_PORTAL_29349, ANNAKARL_PORTAL_29357),
KOUREND("kourend", KOUREND_PORTAL, KOUREND_PORTAL_29353, KOUREND_PORTAL_29361),
MARIM("marim", MARIM_PORTAL, MARIM_PORTAL_29352, MARIM_PORTAL_29360),
TROLLSTRONGHOLD("trollstronghold", TROLL_STRONGHOLD_PORTAL, TROLL_STRONGHOLD_PORTAL_33180, TROLL_STRONGHOLD_PORTAL_33181),
GHORROCK("ghorrock", GHORROCK_PORTAL, GHORROCK_PORTAL_33436, GHORROCK_PORTAL_33439),
CARRALLANGAR("carrallangar", CARRALLANGAR_PORTAL, CARRALLANGAR_PORTAL_33437, CARRALLANGAR_PORTAL_33440),
CATHERBY("catherby", CATHERBY_PORTAL, CATHERBY_PORTAL_33435, CATHERBY_PORTAL_33438),
WEISS("weiss", WEISS_PORTAL, WEISS_PORTAL_37593, WEISS_PORTAL_37605),
APEATOLLDUNGEON("apeatolldungeon", APE_ATOLL_DUNGEON_PORTAL, APE_ATOLL_DUNGEON_PORTAL_37604, APE_ATOLL_DUNGEON_PORTAL_37616),
BARROWS("barrows", BARROWS_PORTAL, BARROWS_PORTAL_37603, BARROWS_PORTAL_37615),
BATTLEFRONT("battlefront", BATTLEFRONT_PORTAL, BATTLEFRONT_PORTAL_37596, BATTLEFRONT_PORTAL_37608),
CEMETERY("cemetery", CEMETERY_PORTAL, CEMETERY_PORTAL_37602, CEMETERY_PORTAL_37614),
DRAYNORMANOR("draynormanor", DRAYNOR_MANOR_PORTAL, DRAYNOR_MANOR_PORTAL_37595, DRAYNOR_MANOR_PORTAL_37607),
FENKENSTRAINSCASTLE("fenkenstrainscastle", FENKENSTRAINS_CASTLE_PORTAL, FENKENSTRAINS_CASTLE_PORTAL_37599, FENKENSTRAINS_CASTLE_PORTAL_37611),
HARMONYISLAND("harmonyisland", HARMONY_ISLAND_PORTAL, HARMONY_ISLAND_PORTAL_37601, HARMONY_ISLAND_PORTAL_37613),
LUMBRIDGEGRAVEYARD("lumbridgegraveyard", LUMBRIDGE_GRAVEYARD_PORTAL, LUMBRIDGE_GRAVEYARD_PORTAL_37594, LUMBRIDGE_GRAVEYARD_PORTAL_37606),
MINDALTAR("mindaltar", MIND_ALTAR_PORTAL, MIND_ALTAR_PORTAL_37597, MIND_ALTAR_PORTAL_37609),
SALVEGRAVEYARD("salvegraveyard", SALVE_GRAVEYARD_PORTAL, SALVE_GRAVEYARD_PORTAL_37598, SALVE_GRAVEYARD_PORTAL_37610),
WESTARDOUGNE("westardougne", WEST_ARDOUGNE_PORTAL, WEST_ARDOUGNE_PORTAL_37600, WEST_ARDOUGNE_PORTAL_37612),
ALTAR("altar",
ALTAR_13179, ALTAR_13180, ALTAR_13181, ALTAR_13182, ALTAR_13183, ALTAR_13184, ALTAR_13185, ALTAR_13186,
ALTAR_13187, ALTAR_13188, ALTAR_13189, ALTAR_13190, ALTAR_13191, ALTAR_13192, ALTAR_13193, ALTAR_13194,
ALTAR_13196, ALTAR_13197, ALTAR_13198, ALTAR_13199
),
POOLS("pool", POOL_OF_RESTORATION, POOL_OF_REVITALISATION, POOL_OF_REJUVENATION, FANCY_POOL_OF_REJUVENATION, ORNATE_POOL_OF_REJUVENATION),
GLORY("glory", AMULET_OF_GLORY),
REPAIR("repair", ARMOUR_REPAIR_STAND),
SPELLBOOKALTAR("spellbook", ANCIENT_ALTAR, LUNAR_ALTAR, DARK_ALTAR, NULL_29150),
JEWELLERYBOX("jewellery", NULL_29154, NULL_29155, NULL_29156),
MAGICTRAVEL("transportation", SPIRIT_TREE_29227, NULL_29228, NULL_29229, OBELISK_31554),
PORTALNEXUS("portalnexus",
PORTAL_NEXUS, PORTAL_NEXUS_33355, PORTAL_NEXUS_33356, PORTAL_NEXUS_33357, PORTAL_NEXUS_33358, PORTAL_NEXUS_33359, PORTAL_NEXUS_33360,
PORTAL_NEXUS_33361, PORTAL_NEXUS_33362, PORTAL_NEXUS_33363, PORTAL_NEXUS_33364, PORTAL_NEXUS_33365, PORTAL_NEXUS_33366, PORTAL_NEXUS_33367,
PORTAL_NEXUS_33368, PORTAL_NEXUS_33369, PORTAL_NEXUS_33370, PORTAL_NEXUS_33371, PORTAL_NEXUS_33372, PORTAL_NEXUS_33373, PORTAL_NEXUS_33374,
PORTAL_NEXUS_33375, PORTAL_NEXUS_33376, PORTAL_NEXUS_33377, PORTAL_NEXUS_33378, PORTAL_NEXUS_33379, PORTAL_NEXUS_33380, PORTAL_NEXUS_33381,
PORTAL_NEXUS_33382, PORTAL_NEXUS_33383, PORTAL_NEXUS_33384, PORTAL_NEXUS_33385, PORTAL_NEXUS_33386, PORTAL_NEXUS_33387, PORTAL_NEXUS_33388,
PORTAL_NEXUS_33389, PORTAL_NEXUS_33390, PORTAL_NEXUS_33391, PORTAL_NEXUS_33392, PORTAL_NEXUS_33393, PORTAL_NEXUS_33394, PORTAL_NEXUS_33395,
PORTAL_NEXUS_33396, PORTAL_NEXUS_33397, PORTAL_NEXUS_33398, PORTAL_NEXUS_33399, PORTAL_NEXUS_33400, PORTAL_NEXUS_33401, PORTAL_NEXUS_33402,
PORTAL_NEXUS_33403, PORTAL_NEXUS_33404, PORTAL_NEXUS_33405, PORTAL_NEXUS_33406, PORTAL_NEXUS_33407, PORTAL_NEXUS_33408, PORTAL_NEXUS_33409,
PORTAL_NEXUS_33410, PORTAL_NEXUS_33423, PORTAL_NEXUS_33424, PORTAL_NEXUS_33425, PORTAL_NEXUS_33426, PORTAL_NEXUS_33427, PORTAL_NEXUS_33428,
PORTAL_NEXUS_33429, PORTAL_NEXUS_33430, PORTAL_NEXUS_33431, PORTAL_NEXUS_37547, PORTAL_NEXUS_37548, PORTAL_NEXUS_37549, PORTAL_NEXUS_37550,
PORTAL_NEXUS_37551, PORTAL_NEXUS_37552, PORTAL_NEXUS_37553, PORTAL_NEXUS_37554, PORTAL_NEXUS_37555, PORTAL_NEXUS_37556, PORTAL_NEXUS_37557,
PORTAL_NEXUS_37558, PORTAL_NEXUS_37559, PORTAL_NEXUS_37560, PORTAL_NEXUS_37561, PORTAL_NEXUS_37562, PORTAL_NEXUS_37563, PORTAL_NEXUS_37564,
PORTAL_NEXUS_37565, PORTAL_NEXUS_37566, PORTAL_NEXUS_37567, PORTAL_NEXUS_37568, PORTAL_NEXUS_37569, PORTAL_NEXUS_37570, PORTAL_NEXUS_37571,
PORTAL_NEXUS_37572, PORTAL_NEXUS_37573, PORTAL_NEXUS_37574, PORTAL_NEXUS_37575, PORTAL_NEXUS_37576, PORTAL_NEXUS_37577, PORTAL_NEXUS_37578,
PORTAL_NEXUS_37579, PORTAL_NEXUS_37580
),
XERICSTALISMAN("xericstalisman",
XERICS_TALISMAN, XERICS_TALISMAN_33412, XERICS_TALISMAN_33413, XERICS_TALISMAN_33414, XERICS_TALISMAN_33415, XERICS_TALISMAN_33419
),
DIGSITEPENDANT("digsitependant",
DIGSITE_PENDANT, DIGSITE_PENDANT_33417, DIGSITE_PENDANT_33418, DIGSITE_PENDANT_33420
),
MYTHICALCAPE("mythicalcape", MYTHICAL_CAPE, MOUNTED_MYTHICAL_CAPE);
private static final Map<Integer, PohIcons> minimapIcons;
@Getter
private final String imageResource;
@Getter
private final int[] Ids;
private BufferedImage image;
static
{
ImmutableMap.Builder<Integer, PohIcons> builder = new ImmutableMap.Builder<>();
for (PohIcons icon : values())
{
for (Integer spotId : icon.getIds())
{
builder.put(spotId, icon);
}
}
minimapIcons = builder.build();
}
PohIcons(String imageResource, int... ids)
{
this.imageResource = imageResource;
this.Ids = ids;
}
public static PohIcons getIcon(int id)
{
return minimapIcons.get(id);
}
public BufferedImage getImage()
{
if (image != null)
{
return image;
}
image = ImageUtil.getResourceStreamFromClass(getClass(), getImageResource() + ".png");
return image;
}
}

View File

@@ -0,0 +1,154 @@
/*
* Copyright (c) 2018, Seth <Sethtroll3@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.poh;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.inject.Inject;
import lombok.Getter;
import net.runelite.api.Client;
import net.runelite.api.Perspective;
import net.runelite.api.coords.LocalPoint;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer;
import net.runelite.client.ui.overlay.OverlayPosition;
public class PohOverlay extends Overlay
{
private static final PohIcons[] PORTALS = {
PohIcons.LUMBRIDGE, PohIcons.FALADOR, PohIcons.VARROCK, PohIcons.CAMELOT, PohIcons.ARDOUGNE,
PohIcons.YANILLE, PohIcons.LUNARISLE, PohIcons.WATERBIRTH, PohIcons.FISHINGGUILD,
PohIcons.SENNTISTEN, PohIcons.KHARYLL, PohIcons.ANNAKARL, PohIcons.KOUREND, PohIcons.MARIM,
PohIcons.TROLLSTRONGHOLD, PohIcons.CARRALLANGAR, PohIcons.CATHERBY, PohIcons.WEISS, PohIcons.GHORROCK,
PohIcons.APEATOLLDUNGEON, PohIcons.BARROWS, PohIcons.BATTLEFRONT, PohIcons.CEMETERY, PohIcons.DRAYNORMANOR,
PohIcons.FENKENSTRAINSCASTLE, PohIcons.HARMONYISLAND, PohIcons.LUMBRIDGEGRAVEYARD, PohIcons.MINDALTAR, PohIcons.SALVEGRAVEYARD,
PohIcons.WESTARDOUGNE,
};
private static final int MAX_DISTANCE = 2350;
@Getter
private final List<PohIcons> iconList = new ArrayList<>();
private final Client client;
private final PohConfig config;
private final PohPlugin plugin;
@Inject
public PohOverlay(Client client, PohConfig config, PohPlugin plugin)
{
setPosition(OverlayPosition.DYNAMIC);
setLayer(OverlayLayer.ABOVE_WIDGETS);
this.client = client;
this.config = config;
this.plugin = plugin;
}
@Override
public Dimension render(Graphics2D graphics)
{
LocalPoint localLocation = client.getLocalPlayer().getLocalLocation();
plugin.getPohObjects().forEach((object, tile) ->
{
LocalPoint location = object.getLocalLocation();
if (tile.getPlane() == client.getPlane() && localLocation.distanceTo(location) <= MAX_DISTANCE)
{
PohIcons icon = PohIcons.getIcon(object.getId());
if (icon != null && iconList.contains(icon))
{
net.runelite.api.Point minimapLoc = Perspective.getMiniMapImageLocation(client, object.getLocalLocation(), icon.getImage());
if (minimapLoc != null)
{
graphics.drawImage(icon.getImage(), minimapLoc.getX(), minimapLoc.getY(), null);
}
}
}
});
return null;
}
public void updateConfig()
{
iconList.clear();
if (config.showPortals())
{
Collections.addAll(iconList, PORTALS);
}
if (config.showAltar())
{
iconList.add(PohIcons.ALTAR);
}
if (config.showGlory())
{
iconList.add(PohIcons.GLORY);
}
if (config.showRepairStand())
{
iconList.add(PohIcons.REPAIR);
}
if (config.showPools())
{
iconList.add(PohIcons.POOLS);
}
if (config.showExitPortal())
{
iconList.add(PohIcons.EXITPORTAL);
}
if (config.showSpellbook())
{
iconList.add(PohIcons.SPELLBOOKALTAR);
}
if (config.showJewelleryBox())
{
iconList.add(PohIcons.JEWELLERYBOX);
}
if (config.showMagicTravel())
{
iconList.add(PohIcons.MAGICTRAVEL);
}
if (config.showPortalNexus())
{
iconList.add(PohIcons.PORTALNEXUS);
}
if (config.showDigsitePendant())
{
iconList.add(PohIcons.DIGSITEPENDANT);
}
if (config.showXericsTalisman())
{
iconList.add(PohIcons.XERICSTALISMAN);
}
if (config.showMythicalCape())
{
iconList.add(PohIcons.MYTHICALCAPE);
}
}
}

View File

@@ -0,0 +1,250 @@
/*
* Copyright (c) 2018, Seth <Sethtroll3@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.poh;
import com.google.common.collect.Sets;
import com.google.inject.Provides;
import java.io.IOException;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ScheduledExecutorService;
import javax.inject.Inject;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Actor;
import net.runelite.api.AnimationID;
import net.runelite.api.Client;
import net.runelite.api.Constants;
import net.runelite.api.DecorativeObject;
import net.runelite.api.GameObject;
import net.runelite.api.GameState;
import net.runelite.api.ObjectID;
import net.runelite.api.Player;
import net.runelite.api.Tile;
import net.runelite.api.TileObject;
import net.runelite.api.coords.LocalPoint;
import net.runelite.api.events.AnimationChanged;
import net.runelite.client.events.ConfigChanged;
import net.runelite.api.events.DecorativeObjectDespawned;
import net.runelite.api.events.DecorativeObjectSpawned;
import net.runelite.api.events.GameObjectDespawned;
import net.runelite.api.events.GameObjectSpawned;
import net.runelite.api.events.GameStateChanged;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.game.HiscoreManager;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.overlay.OverlayManager;
import net.runelite.http.api.hiscore.HiscoreEndpoint;
import net.runelite.http.api.hiscore.HiscoreResult;
import net.runelite.http.api.hiscore.Skill;
@PluginDescriptor(
name = "Player-owned House",
description = "Show minimap icons and mark unlit/lit burners",
tags = {"construction", "poh", "minimap", "overlay"}
)
@Slf4j
public class PohPlugin extends Plugin
{
static final Set<Integer> BURNER_UNLIT = Sets.newHashSet(ObjectID.INCENSE_BURNER, ObjectID.INCENSE_BURNER_13210, ObjectID.INCENSE_BURNER_13212);
static final Set<Integer> BURNER_LIT = Sets.newHashSet(ObjectID.INCENSE_BURNER_13209, ObjectID.INCENSE_BURNER_13211, ObjectID.INCENSE_BURNER_13213);
@Getter(AccessLevel.PACKAGE)
private final Map<TileObject, Tile> pohObjects = new HashMap<>();
@Getter(AccessLevel.PACKAGE)
private final Map<Tile, IncenseBurner> incenseBurners = new HashMap<>();
@Inject
private OverlayManager overlayManager;
@Inject
private PohOverlay overlay;
@Inject
private Client client;
@Inject
private ScheduledExecutorService executor;
@Inject
private HiscoreManager hiscoreManager;
@Inject
private BurnerOverlay burnerOverlay;
@Provides
PohConfig getConfig(ConfigManager configManager)
{
return configManager.getConfig(PohConfig.class);
}
@Override
protected void startUp() throws Exception
{
overlayManager.add(overlay);
overlayManager.add(burnerOverlay);
overlay.updateConfig();
}
@Override
protected void shutDown() throws Exception
{
overlayManager.remove(overlay);
overlayManager.remove(burnerOverlay);
pohObjects.clear();
incenseBurners.clear();
}
@Subscribe
public void onConfigChanged(ConfigChanged event)
{
overlay.updateConfig();
}
@Subscribe
public void onGameObjectSpawned(GameObjectSpawned event)
{
final GameObject gameObject = event.getGameObject();
if (!BURNER_LIT.contains(gameObject.getId()) && !BURNER_UNLIT.contains(gameObject.getId()))
{
if (PohIcons.getIcon(gameObject.getId()) != null)
{
pohObjects.put(gameObject, event.getTile());
}
return;
}
final double countdownTimer = 130.0; // Minimum amount of seconds a burner will light
final double randomTimer = 30.0; // Minimum amount of seconds a burner will light
incenseBurners.put(event.getTile(), new IncenseBurner(gameObject.getId(), countdownTimer, randomTimer, null));
}
@Subscribe
public void onGameObjectDespawned(GameObjectDespawned event)
{
GameObject gameObject = event.getGameObject();
pohObjects.remove(gameObject);
}
@Subscribe
public void onDecorativeObjectSpawned(DecorativeObjectSpawned event)
{
DecorativeObject decorativeObject = event.getDecorativeObject();
if (PohIcons.getIcon(decorativeObject.getId()) != null)
{
pohObjects.put(decorativeObject, event.getTile());
}
}
@Subscribe
public void onDecorativeObjectDespawned(DecorativeObjectDespawned event)
{
DecorativeObject decorativeObject = event.getDecorativeObject();
pohObjects.remove(decorativeObject);
}
@Subscribe
public void onGameStateChanged(GameStateChanged event)
{
if (event.getGameState() == GameState.LOADING)
{
pohObjects.clear();
incenseBurners.clear();
}
}
@Subscribe
public void onAnimationChanged(AnimationChanged event)
{
final Actor actor = event.getActor();
final String actorName = actor.getName();
if (!(actor instanceof Player) || actor.getAnimation() != AnimationID.INCENSE_BURNER)
{
return;
}
final LocalPoint loc = actor.getLocalLocation();
// Find burner closest to player
incenseBurners.keySet()
.stream()
.min(Comparator.comparingInt(a -> loc.distanceTo(a.getLocalLocation())))
.ifPresent(tile ->
{
final IncenseBurner incenseBurner = incenseBurners.get(tile);
if (actor == client.getLocalPlayer())
{
int level = client.getRealSkillLevel(net.runelite.api.Skill.FIREMAKING);
updateBurner(incenseBurner, level);
}
else if (actorName != null)
{
lookupPlayer(actorName, incenseBurner);
}
});
}
private void lookupPlayer(String playerName, IncenseBurner incenseBurner)
{
executor.execute(() ->
{
try
{
final HiscoreResult playerStats = hiscoreManager.lookup(playerName, HiscoreEndpoint.NORMAL);
if (playerStats == null)
{
return;
}
final Skill fm = playerStats.getFiremaking();
final int level = fm.getLevel();
updateBurner(incenseBurner, Math.max(level, 1));
}
catch (IOException e)
{
log.warn("Error fetching Hiscore data " + e.getMessage());
}
});
}
private static void updateBurner(IncenseBurner incenseBurner, int fmLevel)
{
final double tickLengthSeconds = Constants.GAME_TICK_LENGTH / 1000.0;
incenseBurner.setCountdownTimer((200 + fmLevel) * tickLengthSeconds);
incenseBurner.setRandomTimer(fmLevel * tickLengthSeconds);
}
}

View File

@@ -0,0 +1,431 @@
/*
* Copyright (c) 2019 Spudjb <https://github.com/spudjb>
* 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.questlist;
import com.google.common.collect.ImmutableList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.EnumMap;
import java.util.List;
import java.util.stream.Collectors;
import javax.inject.Inject;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.ScriptID;
import net.runelite.api.SoundEffectID;
import net.runelite.api.SpriteID;
import net.runelite.api.VarClientInt;
import net.runelite.api.Varbits;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.ScriptPostFired;
import net.runelite.api.events.VarClientIntChanged;
import net.runelite.api.events.VarbitChanged;
import net.runelite.api.widgets.JavaScriptCallback;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.api.widgets.WidgetPositionMode;
import net.runelite.api.widgets.WidgetType;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.game.chatbox.ChatboxPanelManager;
import net.runelite.client.game.chatbox.ChatboxTextInput;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.util.Text;
@PluginDescriptor(
name = "Quest List",
description = "Adds searching and filtering to the quest list"
)
public class QuestListPlugin extends Plugin
{
private static final int ENTRY_PADDING = 8;
private static final List<String> QUEST_HEADERS = ImmutableList.of("Free Quests", "Members' Quests", "Miniquests");
private static final String MENU_OPEN = "Open";
private static final String MENU_CLOSE = "Close";
private static final String MENU_TOGGLE = "Toggle";
private static final String MENU_SEARCH = "Search";
private static final String MENU_SHOW = "Show";
@Inject
private Client client;
@Inject
private ChatboxPanelManager chatboxPanelManager;
@Inject
private ClientThread clientThread;
private ChatboxTextInput searchInput;
private Widget questSearchButton;
private Widget questHideButton;
private EnumMap<QuestContainer, Collection<QuestWidget>> questSet;
private QuestState currentFilterState;
@Override
protected void startUp()
{
currentFilterState = QuestState.ALL;
clientThread.invoke(this::addQuestButtons);
}
@Override
protected void shutDown()
{
currentFilterState = null;
Widget header = client.getWidget(WidgetInfo.QUESTLIST_BOX);
if (header != null)
{
header.deleteAllChildren();
}
}
@Subscribe
public void onGameStateChanged(GameStateChanged e)
{
if (e.getGameState() == GameState.LOGGING_IN)
{
currentFilterState = QuestState.ALL;
}
}
@Subscribe
public void onScriptPostFired(ScriptPostFired event)
{
if (event.getScriptId() != ScriptID.QUESTLIST_PROGRESS_LIST_SHOW)
{
return;
}
addQuestButtons();
}
private void addQuestButtons()
{
Widget header = client.getWidget(WidgetInfo.QUESTLIST_BOX);
if (header != null)
{
header.deleteAllChildren();
questSearchButton = header.createChild(-1, WidgetType.GRAPHIC);
questSearchButton.setSpriteId(SpriteID.GE_SEARCH);
questSearchButton.setOriginalWidth(18);
questSearchButton.setOriginalHeight(17);
questSearchButton.setXPositionMode(WidgetPositionMode.ABSOLUTE_RIGHT);
questSearchButton.setOriginalX(5);
questSearchButton.setOriginalY(0);
questSearchButton.setHasListener(true);
questSearchButton.setAction(1, MENU_OPEN);
questSearchButton.setOnOpListener((JavaScriptCallback) e -> openSearch());
questSearchButton.setName(MENU_SEARCH);
questSearchButton.revalidate();
questHideButton = header.createChild(-1, WidgetType.GRAPHIC);
redrawHideButton();
questHideButton.setOriginalWidth(13);
questHideButton.setOriginalHeight(13);
questHideButton.setXPositionMode(WidgetPositionMode.ABSOLUTE_RIGHT);
questHideButton.setOriginalX(24);
questHideButton.setOriginalY(2);
questHideButton.setHasListener(true);
questHideButton.setOnOpListener((JavaScriptCallback) e -> toggleHidden());
questHideButton.setAction(1, MENU_TOGGLE);
questHideButton.revalidate();
questSet = new EnumMap<>(QuestContainer.class);
updateFilter();
}
}
@Subscribe
public void onVarbitChanged(VarbitChanged varbitChanged)
{
if (isChatboxOpen() && !isOnQuestTab())
{
chatboxPanelManager.close();
}
}
@Subscribe
public void onVarClientIntChanged(VarClientIntChanged varClientIntChanged)
{
if (varClientIntChanged.getIndex() == VarClientInt.INVENTORY_TAB.getIndex())
{
if (isChatboxOpen() && !isOnQuestTab())
{
chatboxPanelManager.close();
}
}
}
private void toggleHidden()
{
QuestState[] questStates = QuestState.values();
int nextState = (currentFilterState.ordinal() + 1) % questStates.length;
currentFilterState = questStates[nextState];
redrawHideButton();
updateFilter();
client.playSoundEffect(SoundEffectID.UI_BOOP);
}
private void redrawHideButton()
{
questHideButton.setSpriteId(currentFilterState.getSpriteId());
questHideButton.setName(MENU_SHOW + " " + currentFilterState.getName());
}
private boolean isOnQuestTab()
{
return client.getVar(Varbits.QUEST_TAB) == 0 && client.getVar(VarClientInt.INVENTORY_TAB) == 2;
}
private boolean isChatboxOpen()
{
return searchInput != null && chatboxPanelManager.getCurrentInput() == searchInput;
}
private void closeSearch()
{
updateFilter("");
chatboxPanelManager.close();
client.playSoundEffect(SoundEffectID.UI_BOOP);
}
private void openSearch()
{
updateFilter("");
client.playSoundEffect(SoundEffectID.UI_BOOP);
questSearchButton.setAction(1, MENU_CLOSE);
questSearchButton.setOnOpListener((JavaScriptCallback) e -> closeSearch());
searchInput = chatboxPanelManager.openTextInput("Search quest list")
.onChanged(s -> clientThread.invokeLater(() -> updateFilter(s)))
.onDone(s -> false)
.onClose(() ->
{
clientThread.invokeLater(() -> updateFilter(""));
questSearchButton.setOnOpListener((JavaScriptCallback) e -> openSearch());
questSearchButton.setAction(1, MENU_OPEN);
})
.build();
}
private void updateFilter()
{
String filter = "";
if (isChatboxOpen())
{
filter = searchInput.getValue();
}
updateFilter(filter);
}
private void updateFilter(String filter)
{
filter = filter.toLowerCase();
final Widget container = client.getWidget(WidgetInfo.QUESTLIST_CONTAINER);
final Widget freeList = client.getWidget(QuestContainer.FREE_QUESTS.widgetInfo);
final Widget memberList = client.getWidget(QuestContainer.MEMBER_QUESTS.widgetInfo);
final Widget miniList = client.getWidget(QuestContainer.MINI_QUESTS.widgetInfo);
if (container == null || freeList == null || memberList == null || miniList == null)
{
return;
}
updateList(QuestContainer.FREE_QUESTS, filter);
updateList(QuestContainer.MEMBER_QUESTS, filter);
updateList(QuestContainer.MINI_QUESTS, filter);
memberList.setOriginalY(freeList.getOriginalY() + freeList.getOriginalHeight() + ENTRY_PADDING);
miniList.setOriginalY(memberList.getOriginalY() + memberList.getOriginalHeight() + ENTRY_PADDING);
// originalHeight is changed within updateList so revalidate all lists
freeList.revalidate();
memberList.revalidate();
miniList.revalidate();
int y = miniList.getRelativeY() + miniList.getHeight() + 10;
int newHeight;
if (container.getScrollHeight() > 0)
{
newHeight = (container.getScrollY() * y) / container.getScrollHeight();
}
else
{
newHeight = 0;
}
container.setScrollHeight(y);
container.revalidateScroll();
clientThread.invokeLater(() ->
client.runScript(
ScriptID.UPDATE_SCROLLBAR,
WidgetInfo.QUESTLIST_SCROLLBAR.getId(),
WidgetInfo.QUESTLIST_CONTAINER.getId(),
newHeight
));
}
private void updateList(QuestContainer questContainer, String filter)
{
Widget list = client.getWidget(questContainer.widgetInfo);
if (list == null)
{
return;
}
Collection<QuestWidget> quests = questSet.get(questContainer);
if (quests != null)
{
// Check to make sure the list hasn't been rebuild since we were last her
// Do this by making sure the list's dynamic children are the same as when we last saw them
if (quests.stream().noneMatch(w ->
{
Widget codeWidget = w.getQuest();
if (codeWidget == null)
{
return false;
}
return list.getChild(codeWidget.getIndex()) == codeWidget;
}))
{
quests = null;
}
}
if (quests == null)
{
// Find all of the widgets that we care about, sorting by their Y value
quests = Arrays.stream(list.getDynamicChildren())
.sorted(Comparator.comparing(Widget::getRelativeY))
.filter(w -> !QUEST_HEADERS.contains(w.getText()))
.map(w -> new QuestWidget(w, Text.removeTags(w.getText()).toLowerCase()))
.collect(Collectors.toList());
questSet.put(questContainer, quests);
}
// offset because of header
int y = 20;
for (QuestWidget questInfo : quests)
{
Widget quest = questInfo.getQuest();
QuestState questState = QuestState.getByColor(quest.getTextColor());
boolean hidden;
if (!filter.isEmpty())
{
// If searching, show result regardless of filtered state
hidden = !questInfo.getTitle().contains(filter);
}
else
{
// Otherwise hide if it doesn't match the filter state
if (currentFilterState == QuestState.NOT_COMPLETED)
{
hidden = questState == QuestState.COMPLETE;
}
else
{
hidden = currentFilterState != QuestState.ALL && questState != currentFilterState;
}
}
quest.setHidden(hidden);
quest.setOriginalY(y);
quest.revalidate();
if (!hidden)
{
y += quest.getHeight();
}
}
list.setOriginalHeight(y);
}
@AllArgsConstructor
@Getter
private enum QuestContainer
{
FREE_QUESTS(WidgetInfo.QUESTLIST_FREE_CONTAINER),
MEMBER_QUESTS(WidgetInfo.QUESTLIST_MEMBERS_CONTAINER),
MINI_QUESTS(WidgetInfo.QUESTLIST_MINIQUEST_CONTAINER);
private final WidgetInfo widgetInfo;
}
@AllArgsConstructor
@Getter
private enum QuestState
{
NOT_STARTED(0xff0000, "Not started", SpriteID.MINIMAP_ORB_HITPOINTS),
IN_PROGRESS(0xffff00, "In progress", SpriteID.MINIMAP_ORB_HITPOINTS_DISEASE),
COMPLETE(0xdc10d, "Completed", SpriteID.MINIMAP_ORB_HITPOINTS_POISON),
ALL(0, "All", SpriteID.MINIMAP_ORB_PRAYER),
NOT_COMPLETED(0, "Not Completed", SpriteID.MINIMAP_ORB_RUN);
private final int color;
private final String name;
private final int spriteId;
static QuestState getByColor(int color)
{
for (QuestState value : values())
{
if (value.getColor() == color)
{
return value;
}
}
return null;
}
}
@Data
@AllArgsConstructor
private static class QuestWidget
{
private Widget quest;
private String title;
}
}

View File

@@ -0,0 +1,515 @@
/*
* Copyright (c) 2019 Abex
* 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.skybox;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.runelite.api.Client;
class Skybox
{
@FunctionalInterface
public interface ChunkMapper
{
/**
* Gets the instance template chunk data for the specified point
*
* @see Client#getInstanceTemplateChunks
*/
int getTemplateChunk(int cx, int cy, int plane);
}
private static final double SQRT2 = Math.sqrt(2);
// How many stddev per direction we need to stay visibly continuous
// 511/512 accuracy
private static final double BLEND_DISTRIBUTION = 3.075;
// This has a worst case complexity of O((BLEND_RADUS*2)^2)
// BLEND_RADIUS is in chunks (8 tiles)
private static final int BLEND_RADIUS = 5;
// The maximum number of tiles that can be blended before becoming visibly discontinuous
private static final int MAX_BLEND = (int) ((BLEND_RADIUS * 8) / BLEND_DISTRIBUTION);
private static final int PLANE_ALL = 0b1111;
private static final Pattern PATTERN = Pattern.compile("^[ \\t]*(?<expr>" +
"//.*$|" + // //comment
"m[ \\t]*(?<mrx>[0-9]+)[ \\t]+(?<mry>[0-9]+)|" + // m <rx> <ry>
"r[ \\t]*(?<rx>[0-9]+)[ \\t]+(?<ry>[0-9]+)|" + // r <rx> <ry>
"R[ \\t]*(?<rx1>[0-9]+)[ \\t]+(?<ry1>[0-9]+)[ \\t]+(?<rx2>[0-9]+)[ \\t]+(?<ry2>[0-9]+)|" + // R <rx1> <ry1> <rx2> <ry2>
"c[ \\t]*(?<cx>[0-9-]+)[ \\t]+(?<cy>[0-9-]+)|" + // c <cx> <cy>
"C[ \\t]*(?<cx1>[0-9-]+)[ \\t]+(?<cy1>[0-9-]+)[ \\t]+(?<cx2>[0-9-]+)[ \\t]+(?<cy2>[0-9-]+)|" + // C <cx1> <cy1> <cx2> <cy2>
"#[ \\t]*(?<color>[0-9a-fA-F]{6}|[0-9a-fA-F]{3})|" + // #<RRGGBB> or #<RGB>
"p[ \\t]*(?<plane>all|0?[ \\t]*1?[ \\t]*2?[ \\t]*3?)|" + // p all or p<1><2><3><4>
"b[ \\t]*(?<blend>[0-9]+)|" + // b <blend>
"bounds[ \\t]+(?<bx1>[0-9]+)[ \\t]+(?<by1>[0-9]+)[ \\t]+(?<bx2>[0-9]+)[ \\t]+(?<by2>[0-9]+)" + // bounds <x0> <y0> <x1> <y1>
")[ \\t]*");
private final int[] chunks;
private final int[] planeOverrides;
private final int x1;
private final int y1;
private final int x2;
private final int y2;
private final int stride;
public Skybox(InputStream is, String filename) throws IOException
{
this(new InputStreamReader(is, StandardCharsets.UTF_8), filename);
}
public Skybox(Reader reader, String filename) throws IOException
{
int[] chunks = null;
int[] planeOverrides = new int[64];
int planeOverrideEnd = 0;
int x1 = 0, y1 = 0, x2 = 0, y2 = 0, stride = 0;
BufferedReader br = new BufferedReader(reader);
int lineNo = 1;
int color = 0;
int plane = PLANE_ALL;
int rx1 = 0, ry1 = 0, rx2 = 0, ry2 = 0;
try
{
Matcher m = PATTERN.matcher("");
for (String line; (line = br.readLine()) != null; lineNo++)
{
m.reset(line);
int end = 0;
while (end < line.length())
{
m.region(end, line.length());
if (!m.find())
{
throw new IllegalArgumentException("Unexpected: \"" + line.substring(end) + "\" (" + filename + ":" + lineNo + ")");
}
end = m.end();
String expr = m.group("expr");
if (expr == null || expr.length() <= 0 || expr.startsWith("//"))
{
continue;
}
if (chunks == null)
{
if (!expr.startsWith("bounds"))
{
throw new IllegalArgumentException("Expected bounds (" + filename + ":" + lineNo + ")");
}
x1 = Integer.parseInt(m.group("bx1")) * 8;
y1 = Integer.parseInt(m.group("by1")) * 8;
x2 = (Integer.parseInt(m.group("bx2")) + 1) * 8;
y2 = (Integer.parseInt(m.group("by2")) + 1) * 8;
stride = (x2 - x1);
chunks = new int[stride * (y2 - y1)];
Arrays.fill(chunks, -1);
continue;
}
char cha = expr.charAt(0);
switch (cha)
{
case '#':
String sColor = m.group("color");
int scolor = Integer.parseInt(sColor, 16);
int cr, cg, cb;
if (sColor.length() == 3)
{
// Expand #RGB to #RRGGBB
cr = scolor >> 8 & 0xF;
cr |= cr << 4;
cg = scolor >> 4 & 0xF;
cg |= cg << 4;
cb = scolor & 0xF;
cb |= cb << 4;
}
else
{
cr = scolor >> 16 & 0xFF;
cg = scolor >> 8 & 0xFF;
cb = scolor & 0xFF;
}
// Convert to YCoCg24 because it produces less blending artifacts due
// to mismatched skew rates
// See: https://stackoverflow.com/questions/10566668/lossless-rgb-to-ycbcr-transformation
byte cco = (byte) (cb - cr);
byte tmp = (byte) (cr + (cco >> 1));
byte ccg = (byte) (tmp - cg);
byte cy = (byte) (cg + (ccg >> 1));
color = color & 0xFF000000 | (cy & 0xFF) << 16 | (cco & 0xFF) << 8 | (ccg & 0xFF);
break;
case 'b':
int iblend = Integer.parseInt(m.group("blend"));
if (iblend < 0)
{
throw new IllegalArgumentException("Blend must be >=0 (" + filename + ":" + lineNo + ")");
}
if (iblend > MAX_BLEND)
{
throw new IllegalArgumentException("Blend must be <= " + MAX_BLEND + " (" + filename + ":" + lineNo + ")");
}
color = color & 0x00FFFFFF | iblend << 24;
break;
case 'm':
rx2 = rx1 = Integer.parseInt(m.group("mrx"));
ry2 = ry1 = Integer.parseInt(m.group("mry"));
break;
case 'p':
String planes = m.group("plane");
if ("all".equals(planes))
{
plane = PLANE_ALL;
}
else
{
plane = 0;
for (int i = 0; i < planes.length(); i++)
{
plane |= 1 << (planes.charAt(i) - '0');
}
}
break;
case 'r':
case 'R':
if (cha == 'r')
{
rx2 = rx1 = Integer.parseInt(m.group("rx"));
ry2 = ry1 = Integer.parseInt(m.group("ry"));
}
else
{
rx1 = Integer.parseInt(m.group("rx1"));
ry1 = Integer.parseInt(m.group("ry1"));
rx2 = Integer.parseInt(m.group("rx2"));
ry2 = Integer.parseInt(m.group("ry2"));
}
// fallthrough
case 'c':
case 'C':
int cx1 = rx1 * 8;
int cy1 = ry1 * 8;
int cx2 = rx2 * 8 + 7;
int cy2 = ry2 * 8 + 7;
if (cha == 'c')
{
cx2 = cx1 = cx1 + Integer.parseInt(m.group("cx"));
cy2 = cy1 = cy1 + Integer.parseInt(m.group("cy"));
}
else if (cha == 'C')
{
cx2 = cx1 + Integer.parseInt(m.group("cx2"));
cy2 = cy1 + Integer.parseInt(m.group("cy2"));
cx1 = cx1 + Integer.parseInt(m.group("cx1"));
cy1 = cy1 + Integer.parseInt(m.group("cy1"));
}
if (cx1 < x1 || cy1 < y1 || cx2 >= x2 || cy2 >= y2)
{
throw new IllegalArgumentException("Coordinate out of bounds (" + filename + ":" + lineNo + ")");
}
if (cx1 > cx2 || cy1 > cy2)
{
throw new IllegalArgumentException("First coord must be before second (" + filename + ":" + lineNo + ")");
}
for (int y = cy1; y <= cy2; y++)
{
int yoffset = stride * (y - y1);
for (int x = cx1; x <= cx2; x++)
{
int offset = (x - x1) + yoffset;
if (plane == PLANE_ALL)
{
chunks[offset] = color;
}
else
{
// We are not setting all planes in this chunk, so allocate a plane override section
// and add a pointer to it in the normal chunk's space. We do this because most chunks
// do not have plane-specific data
int ocv = chunks[offset];
int poptr;
if ((ocv & 0x8000_0000) != 0 && ocv != -1)
{
// Existing plane override
poptr = ocv & 0x7FFF_FFFF;
}
else
{
poptr = planeOverrideEnd;
planeOverrideEnd += 4;
if (planeOverrideEnd > planeOverrides.length)
{
planeOverrides = Arrays.copyOf(planeOverrides, planeOverrideEnd + 64);
}
chunks[offset] = poptr | 0x8000_0000;
for (int i = 0; i < 4; i++)
{
planeOverrides[poptr + i] = ocv;
}
}
for (int i = 0; i < 4; i++)
{
if ((plane & (1 << i)) != 0)
{
planeOverrides[poptr + i] = color;
}
}
}
}
}
break;
}
}
}
}
catch (NumberFormatException ex)
{
throw new IllegalArgumentException("Expected number (" + filename + ":" + lineNo + ")", ex);
}
if (chunks == null)
{
throw new IllegalArgumentException(filename + ": no data");
}
this.chunks = chunks;
this.planeOverrides = planeOverrides;
this.stride = stride;
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
}
private int chunkData(int cx, int cy, int plane, ChunkMapper chunkMapper)
{
if (chunkMapper != null)
{
int itp = chunkMapper.getTemplateChunk(cx, cy, plane);
if (itp == -1)
{
return -1;
}
cy = itp >> 3 & 0x7FF;
cx = itp >> 14 & 0x3FF;
plane = itp >> 24 & 0x3;
}
if (cx < x1)
{
cx = x1;
}
if (cx >= x2)
{
cx = x2 - 1;
}
if (cy < y1)
{
cy = y1;
}
if (cy >= y2)
{
cy = y2 - 1;
}
int cv = chunks[(stride * (cy - y1)) + (cx - x1)];
if (cv == -1)
{
return -1;
}
if ((cv & 0x8000_0000) != 0)
{
cv = planeOverrides[(cv & 0x7FFF_FFFF) | plane];
}
return cv;
}
/**
* Calculates the RGB color for a specific world coordinate. Arguments are floats for sub-tile accuracy.
*
* @param x Sample X coordinate in tiles
* @param y Samlpe Y coordinate in tiles
* @param x Player X coordinate in tiles
* @param y Player Y coordinate in tiles
* @param chunkMapper maps chunks to their instance templates, or null if not in an instance
*/
public int getColorForPoint(double x, double y, int px, int py, int plane, double brightness, ChunkMapper chunkMapper)
{
x /= 8.d;
y /= 8.d;
int centerChunkData = chunkData(px / 8, py / 8, plane, chunkMapper);
if (centerChunkData == -1)
{
// No data in the center chunk?
return 0;
}
double t = 0;
double ty = 0;
double tco = 0;
double tcg = 0;
int xmin = (int) (x - BLEND_RADIUS);
int xmax = (int) Math.ceil(x + BLEND_RADIUS);
int ymin = (int) (y - BLEND_RADIUS);
int ymax = (int) Math.ceil(y + BLEND_RADIUS);
for (int ucx = xmin; ucx < xmax; ucx++)
{
for (int ucy = ymin; ucy <= ymax; ucy++)
{
int val = chunkData(ucx, ucy, plane, chunkMapper);
if (val == -1)
{
continue;
}
// Get the blend value, add 1/8 tile to make sure we don't div/0, convert to chunks
double sigma = ((val >>> 24) + .125) / 8.d;
// Calculate how far we have to be away before we can discard this value without
// becoming visibly discontinuous
double minDist = 1 + (sigma * BLEND_DISTRIBUTION);
// Try to fast-fail
double dxl = ucx - x;
double dxh = dxl + 1.d;
if (dxl < -minDist || dxl > minDist)
{
continue;
}
double dyl = ucy - y;
double dyh = dyl + 1.d;
if (dyl < -minDist || dyh > minDist)
{
continue;
}
// Calculate integrate a gaussian distribution in each dimension for
// this chunk relative to the requested point
double erfdivc = sigma * SQRT2;
double m = (erf(dxl / erfdivc) - erf(dxh / erfdivc)) * (erf(dyl / erfdivc) - erf(dyh / erfdivc));
// Load our YCoCg24 values into floats
double vy = (val >>> 16 & 0xFF) / 255.d;
double vco = (byte) (val >>> 8) / 128.d;
double vcg = (byte) val / 128.d;
// And multiply by the weight
ty += vy * m;
tco += vco * m;
tcg += vcg * m;
t += m;
}
}
// Convert back to int range values, and bounds check while we are at it
byte ay = (byte) Math.min(Math.max(Math.round(ty / t * 255.d), 0), 255);
byte aco = (byte) Math.min(Math.max(Math.round(tco * 128.d / t), -128), 127);
byte acg = (byte) Math.min(Math.max(Math.round(tcg * 128.d / t), -128), 127);
// convert back to rgb from YCoCg24
int g = (ay - (acg >> 1)) & 0xFF;
int tmp = (g + acg) & 0xFF;
int r = (tmp - (aco >> 1)) & 0xFF;
int b = (r + aco) & 0xFF;
// increase brightness with HSB
float[] hsb = Color.RGBtoHSB(r, g, b, null);
hsb[2] = (float) Math.pow(hsb[2], brightness);
return 0xFFFFFF & Color.HSBtoRGB(hsb[0], hsb[1], hsb[2]);
}
/**
* Approximation of erf 'Gauss error function' which is used to calculate
* the cumulative distribution of a gaussian distribution.
* This is used to simulate a large kernel gaussian blur without having
* to sample the same chunk multiple times.
*/
private double erf(double x)
{
double ax = Math.abs(x);
double t = 1.d / (1.d + (ax * .3275911d));
double y = 1.d - ((((((1.061405429d * t) - 1.453152027d) * t) + 1.421413741d) * t - 0.284496736d) * t + 0.254829592d) * t * Math.exp(-ax * ax);
return Math.copySign(y, x);
}
/**
* Draws the skybox map to an image
*
* @param resolution The number of pixels per tile
* @param line How many tiles to put a line
* @param plane the plane (0-4) to render
*/
BufferedImage render(double resolution, int line, int plane, ChunkMapper chunkMapper)
{
int w = (int) (((x2 - x1) * 8) * resolution);
int h = (int) (((y2 - y1) * 8) * resolution);
BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
int lineEvery = line <= 0 ? Integer.MAX_VALUE : (int) (line * resolution);
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
int color;
if (x % lineEvery == 0 || y % lineEvery == 0)
{
color = 0x00FFFFFF;
}
else
{
double fx = (x1 * 8) + (x / resolution);
double fy = (y1 * 8) + (y / resolution);
color = getColorForPoint(fx, fy, (int) fx, (int) fy, plane, .8, chunkMapper);
}
img.setRGB(x, h - 1 - y, color | 0xFF000000);
}
}
return img;
}
}

View File

@@ -0,0 +1,154 @@
/*
* Copyright (c) 2019 Abex
* 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.skybox;
import com.google.inject.Inject;
import com.google.inject.Provides;
import java.awt.Color;
import java.io.IOException;
import net.runelite.api.Client;
import net.runelite.api.Constants;
import net.runelite.api.GameState;
import net.runelite.api.Player;
import net.runelite.api.coords.LocalPoint;
import net.runelite.api.events.BeforeRender;
import net.runelite.api.events.GameStateChanged;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
@PluginDescriptor(
name = "Skybox",
description = "Draws an oldschool styled skybox",
enabledByDefault = false,
tags = {"sky"}
)
public class SkyboxPlugin extends Plugin
{
@Inject
private Client client;
@Inject
private SkyboxPluginConfig config;
private Skybox skybox;
@Override
public void startUp() throws IOException
{
skybox = new Skybox(SkyboxPlugin.class.getResourceAsStream("skybox.txt"), "skybox.txt");
}
@Override
public void shutDown()
{
client.setSkyboxColor(0);
skybox = null;
}
@Provides
SkyboxPluginConfig provideConfig(ConfigManager configManager)
{
return configManager.getConfig(SkyboxPluginConfig.class);
}
private int mapChunk(int cx, int cy, int plane)
{
cx -= client.getBaseX() / 8;
cy -= client.getBaseY() / 8;
int[][] instanceTemplateChunks = client.getInstanceTemplateChunks()[plane];
// Blending can access this out of bounds, so do a range check
if (cx < 0 || cx >= instanceTemplateChunks.length || cy < 0 || cy >= instanceTemplateChunks[cx].length)
{
return -1;
}
return instanceTemplateChunks[cx][cy];
}
@Subscribe
public void onBeforeRender(BeforeRender r)
{
if (skybox == null || client.getGameState() != GameState.LOGGED_IN)
{
return;
}
Player player = client.getLocalPlayer();
if (player == null)
{
return;
}
Color overrideColor = player.getWorldLocation().getY() < Constants.OVERWORLD_MAX_Y
? config.customOverworldColor() : config.customOtherColor();
if (overrideColor != null)
{
client.setSkyboxColor(overrideColor.getRGB());
return;
}
int px, py;
if (client.getOculusOrbState() == 1)
{
px = client.getOculusOrbFocalPointX();
py = client.getOculusOrbFocalPointY();
}
else
{
LocalPoint p = player.getLocalLocation();
px = p.getX();
py = p.getY();
}
// Inverse of camera location / 2
int spx = -((client.getCameraX() - px) >> 1);
int spy = -((client.getCameraY() - py) >> 1);
int baseX = client.getBaseX();
int baseY = client.getBaseY();
client.setSkyboxColor(skybox.getColorForPoint(
baseX + ((px + spx) / 128.f),
baseY + ((py + spy) / 128.f),
baseX + (px / 128),
baseY + (py / 128),
client.getPlane(),
client.getTextureProvider().getBrightness(),
client.isInInstancedRegion() ? this::mapChunk : null
));
}
@Subscribe
public void onGameStateChanged(GameStateChanged gameStateChanged)
{
if (gameStateChanged.getGameState() == GameState.LOGIN_SCREEN)
{
client.setSkyboxColor(0);
}
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright (c) 2019 logarrhytmic <https://github.com/logarrhythmic>
* 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.skybox;
import java.awt.Color;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
@ConfigGroup("skybox")
public interface SkyboxPluginConfig extends Config
{
@ConfigItem(
keyName = "customOverworldColor",
name = "Overworld sky color",
description = "Sets the color to use for the sky in overworld areas.",
position = 1
)
Color customOverworldColor();
@ConfigItem(
keyName = "customOtherColor",
name = "Cave sky color",
description = "Sets the color to use for the sky in non-overworld areas.",
position = 2
)
Color customOtherColor();
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) 2020, Henry Darnell <hjdarnel@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.wiki;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
@ConfigGroup(WikiPlugin.CONFIG_GROUP_KEY)
public interface WikiConfig extends Config
{
@ConfigItem(
keyName = "leftClickSearch",
name = "Left Click Search",
description = "Swap left-click on the Wiki button to Search",
position = 1
)
default boolean leftClickSearch()
{
return false;
}
}

View File

@@ -0,0 +1,426 @@
/*
* Copyright (c) 2018 Abex
* 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.wiki;
import com.google.inject.Provides;
import java.util.Arrays;
import java.util.stream.Stream;
import javax.inject.Inject;
import javax.inject.Provider;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.MenuAction;
import net.runelite.api.MenuEntry;
import net.runelite.api.NPC;
import net.runelite.api.NPCComposition;
import net.runelite.api.ObjectComposition;
import net.runelite.api.SpriteID;
import net.runelite.api.coords.WorldPoint;
import net.runelite.api.events.MenuEntryAdded;
import net.runelite.api.events.MenuOptionClicked;
import net.runelite.api.events.WidgetHiddenChanged;
import net.runelite.api.events.WidgetLoaded;
import net.runelite.api.widgets.JavaScriptCallback;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetConfig;
import net.runelite.api.widgets.WidgetID;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.api.widgets.WidgetPositionMode;
import net.runelite.api.widgets.WidgetType;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.events.ConfigChanged;
import net.runelite.client.game.ItemManager;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.JagexColors;
import net.runelite.client.util.LinkBrowser;
import net.runelite.client.util.Text;
import okhttp3.HttpUrl;
@Slf4j
@PluginDescriptor(
name = "Wiki",
description = "Adds a Wiki button that takes you to the OSRS Wiki"
)
public class WikiPlugin extends Plugin
{
static final HttpUrl WIKI_BASE = HttpUrl.parse("https://oldschool.runescape.wiki");
static final HttpUrl WIKI_API = WIKI_BASE.newBuilder().addPathSegments("api.php").build();
static final String UTM_SORUCE_KEY = "utm_source";
static final String UTM_SORUCE_VALUE = "runelite";
private static final String MENUOP_WIKI = "Wiki";
@Inject
private WikiConfig config;
@Inject
private ClientThread clientThread;
@Inject
private Client client;
@Inject
private ItemManager itemManager;
@Inject
private Provider<WikiSearchChatboxTextInput> wikiSearchChatboxTextInputProvider;
private Widget icon;
private boolean wikiSelected = false;
static final String CONFIG_GROUP_KEY = "wiki";
@Provides
WikiConfig getConfig(ConfigManager configManager)
{
return configManager.getConfig(WikiConfig.class);
}
@Override
public void startUp()
{
clientThread.invokeLater(this::addWidgets);
}
@Override
public void shutDown()
{
clientThread.invokeLater(this::removeWidgets);
}
private void removeWidgets()
{
Widget minimapOrbs = client.getWidget(WidgetInfo.MINIMAP_ORBS);
if (minimapOrbs == null)
{
return;
}
Widget[] children = minimapOrbs.getChildren();
if (children == null || children.length < 1)
{
return;
}
children[0] = null;
Widget vanilla = client.getWidget(WidgetInfo.MINIMAP_WIKI_BANNER);
if (vanilla != null)
{
vanilla.setHidden(false);
}
onDeselect();
client.setSpellSelected(false);
}
@Subscribe
private void onWidgetLoaded(WidgetLoaded l)
{
if (l.getGroupId() == WidgetID.MINIMAP_GROUP_ID)
{
addWidgets();
}
}
private void addWidgets()
{
Widget minimapOrbs = client.getWidget(WidgetInfo.MINIMAP_ORBS);
if (minimapOrbs == null)
{
return;
}
Widget vanilla = client.getWidget(WidgetInfo.MINIMAP_WIKI_BANNER);
if (vanilla != null)
{
vanilla.setHidden(true);
}
icon = minimapOrbs.createChild(0, WidgetType.GRAPHIC);
icon.setSpriteId(SpriteID.WIKI_DESELECTED);
icon.setOriginalX(0);
icon.setOriginalY(0);
icon.setXPositionMode(WidgetPositionMode.ABSOLUTE_RIGHT);
icon.setYPositionMode(WidgetPositionMode.ABSOLUTE_BOTTOM);
icon.setOriginalWidth(40);
icon.setOriginalHeight(14);
icon.setTargetVerb("Lookup");
icon.setName("Wiki");
icon.setClickMask(WidgetConfig.USE_GROUND_ITEM | WidgetConfig.USE_ITEM | WidgetConfig.USE_NPC
| WidgetConfig.USE_OBJECT | WidgetConfig.USE_WIDGET);
icon.setNoClickThrough(true);
icon.setOnTargetEnterListener((JavaScriptCallback) ev ->
{
wikiSelected = true;
icon.setSpriteId(SpriteID.WIKI_SELECTED);
client.setAllWidgetsAreOpTargetable(true);
});
final int searchIndex = config.leftClickSearch() ? 4 : 5;
icon.setAction(searchIndex, "Search");
icon.setOnOpListener((JavaScriptCallback) ev ->
{
if (ev.getOp() == searchIndex + 1)
{
openSearchInput();
}
});
// This doesn't always run because we cancel the menuop
icon.setOnTargetLeaveListener((JavaScriptCallback) ev -> onDeselect());
icon.revalidate();
}
@Subscribe
private void onWidgetHiddenChanged(WidgetHiddenChanged ev)
{
if (ev.getWidget().getId() == WidgetInfo.MINIMAP_WIKI_BANNER.getId())
{
ev.getWidget().setHidden(true);
}
}
@Subscribe
public void onConfigChanged(ConfigChanged event)
{
if (event.getGroup().equals(CONFIG_GROUP_KEY))
{
clientThread.invokeLater(() ->
{
removeWidgets();
addWidgets();
});
}
}
private void onDeselect()
{
client.setAllWidgetsAreOpTargetable(false);
wikiSelected = false;
if (icon != null)
{
icon.setSpriteId(SpriteID.WIKI_DESELECTED);
}
}
@Subscribe
private void onMenuOptionClicked(MenuOptionClicked ev)
{
optarget:
if (wikiSelected)
{
onDeselect();
client.setSpellSelected(false);
ev.consume();
String type;
int id;
String name;
WorldPoint location;
switch (ev.getMenuAction())
{
case RUNELITE:
// This is a quest widget op
break optarget;
case CANCEL:
return;
case ITEM_USE_ON_WIDGET:
case SPELL_CAST_ON_GROUND_ITEM:
{
type = "item";
id = itemManager.canonicalize(ev.getId());
name = itemManager.getItemComposition(id).getName();
location = null;
break;
}
case SPELL_CAST_ON_NPC:
{
type = "npc";
NPC npc = client.getCachedNPCs()[ev.getId()];
NPCComposition nc = npc.getTransformedComposition();
id = nc.getId();
name = nc.getName();
location = npc.getWorldLocation();
break;
}
case SPELL_CAST_ON_GAME_OBJECT:
{
type = "object";
ObjectComposition lc = client.getObjectDefinition(ev.getId());
if (lc.getImpostorIds() != null)
{
lc = lc.getImpostor();
}
id = lc.getId();
name = lc.getName();
location = WorldPoint.fromScene(client, ev.getActionParam(), ev.getWidgetId(), client.getPlane());
break;
}
case SPELL_CAST_ON_WIDGET:
Widget w = getWidget(ev.getWidgetId(), ev.getActionParam());
if (w.getType() == WidgetType.GRAPHIC && w.getItemId() != -1)
{
type = "item";
id = itemManager.canonicalize(w.getItemId());
name = itemManager.getItemComposition(id).getName();
location = null;
break;
}
// fallthrough
default:
log.info("Unknown menu option: {} {} {}", ev, ev.getMenuAction(), ev.getMenuAction() == MenuAction.CANCEL);
return;
}
name = Text.removeTags(name);
HttpUrl.Builder urlBuilder = WIKI_BASE.newBuilder();
urlBuilder.addPathSegments("w/Special:Lookup")
.addQueryParameter("type", type)
.addQueryParameter("id", "" + id)
.addQueryParameter("name", name)
.addQueryParameter(UTM_SORUCE_KEY, UTM_SORUCE_VALUE);
if (location != null)
{
urlBuilder.addQueryParameter("x", "" + location.getX())
.addQueryParameter("y", "" + location.getY())
.addQueryParameter("plane", "" + location.getPlane());
}
HttpUrl url = urlBuilder.build();
LinkBrowser.browse(url.toString());
return;
}
if (ev.getMenuAction() == MenuAction.RUNELITE)
{
switch (ev.getMenuOption())
{
case MENUOP_WIKI:
LinkBrowser.browse(WIKI_BASE.newBuilder()
.addPathSegment("w")
.addPathSegment(Text.removeTags(ev.getMenuTarget()))
.addQueryParameter(UTM_SORUCE_KEY, UTM_SORUCE_VALUE)
.build().toString());
}
}
}
private void openSearchInput()
{
wikiSearchChatboxTextInputProvider.get()
.build();
}
private Widget getWidget(int wid, int index)
{
Widget w = client.getWidget(wid);
if (index != -1)
{
w = w.getChild(index);
}
return w;
}
@Subscribe
public void onMenuEntryAdded(MenuEntryAdded event)
{
int widgetIndex = event.getActionParam0();
int widgetID = event.getActionParam1();
MenuEntry[] menuEntries = client.getMenuEntries();
if (wikiSelected && event.getType() == MenuAction.SPELL_CAST_ON_WIDGET.getId())
{
Widget w = getWidget(widgetID, widgetIndex);
if (w.getType() == WidgetType.GRAPHIC && w.getItemId() != -1)
{
for (int ourEntry = menuEntries.length - 1;ourEntry >= 0; ourEntry--)
{
MenuEntry entry = menuEntries[ourEntry];
if (entry.getType() == MenuAction.SPELL_CAST_ON_WIDGET.getId())
{
int id = itemManager.canonicalize(w.getItemId());
String name = itemManager.getItemComposition(id).getName();
entry.setTarget(JagexColors.MENU_TARGET_TAG + name);
break;
}
}
client.setMenuEntries(menuEntries);
}
else
{
// we don't support this widget
// remove the last SPELL_CAST_ON_WIDGET; we can't blindly remove the top action because some other
// plugin might have added something on this same event, and we probably shouldn't remove that instead
MenuEntry[] oldEntries = menuEntries;
menuEntries = Arrays.copyOf(menuEntries, menuEntries.length - 1);
for (int ourEntry = oldEntries.length - 1;
ourEntry >= 2 && oldEntries[oldEntries.length - 1].getType() != MenuAction.SPELL_CAST_ON_WIDGET.getId();
ourEntry--)
{
menuEntries[ourEntry - 1] = oldEntries[ourEntry];
}
client.setMenuEntries(menuEntries);
}
}
if (WidgetInfo.TO_GROUP(widgetID) == WidgetInfo.SKILLS_CONTAINER.getGroupId())
{
Widget w = getWidget(widgetID, widgetIndex);
if (w.getActions() == null || w.getParentId() != WidgetInfo.SKILLS_CONTAINER.getId())
{
return;
}
String action = Stream.of(w.getActions())
.filter(s -> s != null && !s.isEmpty())
.findFirst().orElse(null);
if (action == null)
{
return;
}
menuEntries = Arrays.copyOf(menuEntries, menuEntries.length + 1);
MenuEntry menuEntry = menuEntries[menuEntries.length - 1] = new MenuEntry();
menuEntry.setTarget(action.replace("View ", "").replace(" guide", ""));
menuEntry.setOption(MENUOP_WIKI);
menuEntry.setParam0(widgetIndex);
menuEntry.setParam1(widgetID);
menuEntry.setType(MenuAction.RUNELITE.getId());
client.setMenuEntries(menuEntries);
}
}
}

View File

@@ -0,0 +1,313 @@
/*
* Copyright (c) 2018 Abex
* 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.wiki;
import com.google.common.collect.ImmutableList;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonParseException;
import com.google.gson.JsonParser;
import com.google.inject.Inject;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.inject.Named;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.widgets.JavaScriptCallback;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetPositionMode;
import net.runelite.api.widgets.WidgetSizeMode;
import net.runelite.api.widgets.WidgetTextAlignment;
import net.runelite.api.widgets.WidgetType;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.game.chatbox.ChatboxPanelManager;
import net.runelite.client.game.chatbox.ChatboxTextInput;
import net.runelite.client.ui.JagexColors;
import net.runelite.client.util.LinkBrowser;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
@Slf4j
public class WikiSearchChatboxTextInput extends ChatboxTextInput
{
private static final int LINE_HEIGHT = 20;
private static final int CHATBOX_HEIGHT = 120;
private static final int MAX_NUM_PREDICTIONS = (CHATBOX_HEIGHT / LINE_HEIGHT) - 2; // 1 title, 1 edit
private static final int PREDICTION_DEBOUNCE_DELAY_MS = 200;
private final ChatboxPanelManager chatboxPanelManager;
private final Gson gson = new Gson();
private Future<?> runningRequest = null;
private List<String> predictions = ImmutableList.of();
private int selectedPrediction = -1;
private String offPrediction = null;
@Inject
public WikiSearchChatboxTextInput(ChatboxPanelManager chatboxPanelManager, ClientThread clientThread,
ScheduledExecutorService scheduledExecutorService, @Named("developerMode") final boolean developerMode,
OkHttpClient okHttpClient)
{
super(chatboxPanelManager, clientThread);
this.chatboxPanelManager = chatboxPanelManager;
lines(1);
prompt("OSRS Wiki Search");
onDone(string ->
{
if (string != null && string.length() > 0)
{
search(string);
}
});
onChanged(searchString ->
{
selectedPrediction = -1;
Future<?> rr = runningRequest;
if (rr != null)
{
rr.cancel(false);
}
if (searchString.length() <= 1)
{
runningRequest = null;
clientThread.invokeLater(() ->
{
predictions = ImmutableList.of();
update();
});
return;
}
runningRequest = scheduledExecutorService.schedule(() ->
{
HttpUrl url = WikiPlugin.WIKI_API.newBuilder()
.addQueryParameter("action", "opensearch")
.addQueryParameter("search", searchString)
.addQueryParameter("redirects", "resolve")
.addQueryParameter("format", "json")
.addQueryParameter("warningsaserror", Boolean.toString(developerMode))
.build();
Request req = new Request.Builder()
.url(url)
.build();
okHttpClient.newCall(req).enqueue(new Callback()
{
@Override
public void onFailure(Call call, IOException e)
{
log.warn("error searching wiki", e);
}
@Override
public void onResponse(Call call, Response response) throws IOException
{
String body = response.body().string();
try // NOPMD: UseTryWithResources
{
JsonArray jar = new JsonParser().parse(body).getAsJsonArray();
List<String> apredictions = gson.fromJson(jar.get(1), new TypeToken<List<String>>()
{
}.getType());
if (apredictions.size() > MAX_NUM_PREDICTIONS)
{
apredictions = apredictions.subList(0, MAX_NUM_PREDICTIONS);
}
final List<String> bpredictions = apredictions;
clientThread.invokeLater(() ->
{
predictions = bpredictions;
update();
});
}
catch (JsonParseException | IllegalStateException | IndexOutOfBoundsException e)
{
log.warn("error parsing wiki response {}", body, e);
}
finally
{
response.close();
}
}
});
runningRequest = null;
}, PREDICTION_DEBOUNCE_DELAY_MS, TimeUnit.MILLISECONDS);
});
}
@Override
protected void update()
{
Widget container = chatboxPanelManager.getContainerWidget();
container.deleteAllChildren();
Widget promptWidget = container.createChild(-1, WidgetType.TEXT);
promptWidget.setText(getPrompt());
promptWidget.setTextColor(0x800000);
promptWidget.setFontId(getFontID());
promptWidget.setXPositionMode(WidgetPositionMode.ABSOLUTE_CENTER);
promptWidget.setOriginalX(0);
promptWidget.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP);
promptWidget.setOriginalY(5);
promptWidget.setOriginalHeight(LINE_HEIGHT);
promptWidget.setXTextAlignment(WidgetTextAlignment.CENTER);
promptWidget.setYTextAlignment(WidgetTextAlignment.CENTER);
promptWidget.setWidthMode(WidgetSizeMode.MINUS);
promptWidget.revalidate();
buildEdit(0, 5 + LINE_HEIGHT, container.getWidth(), LINE_HEIGHT);
Widget separator = container.createChild(-1, WidgetType.LINE);
separator.setXPositionMode(WidgetPositionMode.ABSOLUTE_CENTER);
separator.setOriginalX(0);
separator.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP);
separator.setOriginalY(4 + (LINE_HEIGHT * 2));
separator.setOriginalHeight(0);
separator.setOriginalWidth(16);
separator.setWidthMode(WidgetSizeMode.MINUS);
separator.revalidate();
for (int i = 0; i < predictions.size(); i++)
{
String pred = predictions.get(i);
int y = 6 + (LINE_HEIGHT * (2 + i));
Widget bg = container.createChild(-1, WidgetType.RECTANGLE);
bg.setTextColor(0x4444DD);
bg.setFilled(true);
bg.setXPositionMode(WidgetPositionMode.ABSOLUTE_CENTER);
bg.setOriginalX(1);
bg.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP);
bg.setOriginalY(y);
bg.setOriginalHeight(LINE_HEIGHT);
bg.setOriginalWidth(16);
bg.setWidthMode(WidgetSizeMode.MINUS);
bg.revalidate();
bg.setName(JagexColors.MENU_TARGET_TAG + pred);
bg.setAction(0, "Open");
bg.setHasListener(true);
bg.setOnOpListener((JavaScriptCallback) ev -> search(pred));
Widget text = container.createChild(-1, WidgetType.TEXT);
text.setText(pred);
text.setFontId(getFontID());
text.setXPositionMode(WidgetPositionMode.ABSOLUTE_CENTER);
text.setOriginalX(0);
text.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP);
text.setOriginalY(y);
text.setOriginalHeight(LINE_HEIGHT);
text.setXTextAlignment(WidgetTextAlignment.CENTER);
text.setYTextAlignment(WidgetTextAlignment.CENTER);
text.setWidthMode(WidgetSizeMode.MINUS);
text.revalidate();
if (i == selectedPrediction)
{
text.setTextColor(0xFFFFFF);
}
else
{
bg.setOpacity(255);
text.setTextColor(0x000000);
bg.setOnMouseRepeatListener((JavaScriptCallback) ev -> text.setTextColor(0xFFFFFF));
bg.setOnMouseLeaveListener((JavaScriptCallback) ev -> text.setTextColor(0x000000));
}
}
}
@Override
public void keyPressed(KeyEvent ev)
{
if (!chatboxPanelManager.shouldTakeInput())
{
return;
}
switch (ev.getKeyCode())
{
case KeyEvent.VK_UP:
ev.consume();
if (selectedPrediction > -1)
{
selectedPrediction--;
if (selectedPrediction == -1)
{
value(offPrediction);
}
else
{
value(predictions.get(selectedPrediction));
}
}
break;
case KeyEvent.VK_DOWN:
ev.consume();
if (selectedPrediction == -1)
{
offPrediction = getValue();
}
selectedPrediction++;
if (selectedPrediction >= predictions.size())
{
selectedPrediction = predictions.size() - 1;
}
if (selectedPrediction != -1)
{
value(predictions.get(selectedPrediction));
}
break;
default:
super.keyPressed(ev);
}
}
private void search(String search)
{
LinkBrowser.browse(WikiPlugin.WIKI_BASE.newBuilder()
.addQueryParameter("search", search)
.addQueryParameter(WikiPlugin.UTM_SORUCE_KEY, WikiPlugin.UTM_SORUCE_VALUE)
.build()
.toString());
chatboxPanelManager.close();
}
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright (c) 2019, Liam Edwards <http://github.com/Spedwards>
* 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.worldhopper;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import net.runelite.http.api.worlds.WorldRegion;
@NoArgsConstructor
@AllArgsConstructor
public enum RegionFilterMode
{
NONE,
AUSTRALIA(WorldRegion.AUSTRALIA),
GERMANY(WorldRegion.GERMANY),
UNITED_KINGDOM(WorldRegion.UNITED_KINGDOM)
{
@Override
public String toString()
{
return "U.K.";
}
},
UNITED_STATES(WorldRegion.UNITED_STATES_OF_AMERICA)
{
@Override
public String toString()
{
return "USA";
}
};
@Getter
private WorldRegion region;
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright (c) 2019, Shawn <http://github.com/DrRobosnarfen>
* 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.worldhopper;
public enum SubscriptionFilterMode
{
BOTH,
FREE,
MEMBERS
}

View File

@@ -0,0 +1,149 @@
/*
* Copyright (c) 2018, Lotto <https://github.com/devLotto>
* Copyright (c) 2019, gregg1494 <https://github.com/gregg1494>
* 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.worldhopper;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
import net.runelite.client.config.Keybind;
@ConfigGroup(WorldHopperConfig.GROUP)
public interface WorldHopperConfig extends Config
{
String GROUP = "worldhopper";
@ConfigItem(
keyName = "previousKey",
name = "Quick-hop previous",
description = "When you press this key you'll hop to the previous world",
position = 0
)
default Keybind previousKey()
{
return new Keybind(KeyEvent.VK_LEFT, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK);
}
@ConfigItem(
keyName = "nextKey",
name = "Quick-hop next",
description = "When you press this key you'll hop to the next world",
position = 1
)
default Keybind nextKey()
{
return new Keybind(KeyEvent.VK_RIGHT, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK);
}
@ConfigItem(
keyName = "quickhopOutOfDanger",
name = "Quick-hop out of dangerous worlds",
description = "Don't hop to a PVP/high risk world when quick-hopping",
position = 2
)
default boolean quickhopOutOfDanger()
{
return true;
}
@ConfigItem(
keyName = "quickHopRegionFilter",
name = "Quick-hop region",
description = "Limit quick-hopping to worlds of a specific region",
position = 3
)
default RegionFilterMode quickHopRegionFilter()
{
return RegionFilterMode.NONE;
}
@ConfigItem(
keyName = "showSidebar",
name = "Show world switcher sidebar",
description = "Show sidebar containing all worlds that mimics in-game interface",
position = 4
)
default boolean showSidebar()
{
return true;
}
@ConfigItem(
keyName = "ping",
name = "Show world ping",
description = "Shows ping to each game world",
position = 5
)
default boolean ping()
{
return true;
}
@ConfigItem(
keyName = "showMessage",
name = "Show world hop message in chat",
description = "Shows what world is being hopped to in the chat",
position = 6
)
default boolean showWorldHopMessage()
{
return true;
}
@ConfigItem(
keyName = "menuOption",
name = "Show Hop-to menu option",
description = "Adds Hop-to menu option to the friends list and friends chat members list",
position = 7
)
default boolean menuOption()
{
return true;
}
@ConfigItem(
keyName = "subscriptionFilter",
name = "Show subscription types",
description = "Only show free worlds, member worlds, or both types of worlds in sidebar",
position = 8
)
default SubscriptionFilterMode subscriptionFilter()
{
return SubscriptionFilterMode.BOTH;
}
@ConfigItem(
keyName = "displayPing",
name = "Display current ping",
description = "Displays ping to current game world",
position = 9
)
default boolean displayPing()
{
return false;
}
}

View File

@@ -0,0 +1,93 @@
/*
* Copyright (c) 2019, gregg1494 <https://github.com/gregg1494>
* 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.worldhopper;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import javax.inject.Inject;
import net.runelite.api.Client;
import net.runelite.api.Point;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
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;
class WorldHopperPingOverlay extends Overlay
{
private static final int Y_OFFSET = 11;
private static final int X_OFFSET = 1;
private final Client client;
private final WorldHopperPlugin worldHopperPlugin;
private final WorldHopperConfig worldHopperConfig;
@Inject
private WorldHopperPingOverlay(Client client, WorldHopperPlugin worldHopperPlugin, WorldHopperConfig worldHopperConfig)
{
this.client = client;
this.worldHopperPlugin = worldHopperPlugin;
this.worldHopperConfig = worldHopperConfig;
setLayer(OverlayLayer.ABOVE_WIDGETS);
setPriority(OverlayPriority.HIGH);
setPosition(OverlayPosition.DYNAMIC);
}
@Override
public Dimension render(Graphics2D graphics)
{
if (!worldHopperConfig.displayPing())
{
return null;
}
final int ping = worldHopperPlugin.getCurrentPing();
if (ping < 0)
{
return null;
}
final String text = ping + " ms";
final int textWidth = graphics.getFontMetrics().stringWidth(text);
final int textHeight = graphics.getFontMetrics().getAscent() - graphics.getFontMetrics().getDescent();
// Adjust ping offset for logout button
Widget logoutButton = client.getWidget(WidgetInfo.RESIZABLE_MINIMAP_LOGOUT_BUTTON);
int xOffset = X_OFFSET;
if (logoutButton != null && !logoutButton.isHidden())
{
xOffset += logoutButton.getWidth();
}
final int width = (int) client.getRealDimensions().getWidth();
final Point point = new Point(width - textWidth - xOffset, textHeight + Y_OFFSET);
OverlayUtil.renderTextLocation(graphics, point, text, Color.YELLOW);
return null;
}
}

View File

@@ -0,0 +1,852 @@
/*
* Copyright (c) 2017, Adam <Adam@sigterm.info>
* Copyright (c) 2018, Lotto <https://github.com/devLotto>
* Copyright (c) 2019, gregg1494 <https://github.com/gregg1494>
* 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.worldhopper;
import com.google.common.base.Stopwatch;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ObjectArrays;
import com.google.inject.Provides;
import java.awt.image.BufferedImage;
import java.time.Instant;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import javax.imageio.ImageIO;
import javax.inject.Inject;
import javax.swing.SwingUtilities;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.ChatMessageType;
import net.runelite.api.ChatPlayer;
import net.runelite.api.FriendsChatMember;
import net.runelite.api.FriendsChatManager;
import net.runelite.api.Client;
import net.runelite.api.Friend;
import net.runelite.api.GameState;
import net.runelite.api.MenuAction;
import net.runelite.api.MenuEntry;
import net.runelite.api.NameableContainer;
import net.runelite.api.Varbits;
import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.GameTick;
import net.runelite.api.events.MenuEntryAdded;
import net.runelite.api.events.PlayerMenuOptionClicked;
import net.runelite.api.events.VarbitChanged;
import net.runelite.api.events.WorldListLoad;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.chat.ChatColorType;
import net.runelite.client.chat.ChatMessageBuilder;
import net.runelite.client.chat.ChatMessageManager;
import net.runelite.client.chat.QueuedMessage;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.events.ConfigChanged;
import net.runelite.client.events.WorldsFetch;
import net.runelite.client.game.WorldService;
import net.runelite.client.input.KeyManager;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.plugins.worldhopper.ping.Ping;
import net.runelite.client.ui.ClientToolbar;
import net.runelite.client.ui.NavigationButton;
import net.runelite.client.ui.overlay.OverlayManager;
import net.runelite.client.util.ExecutorServiceExceptionLogger;
import net.runelite.client.util.HotkeyListener;
import net.runelite.client.util.Text;
import net.runelite.client.util.WorldUtil;
import net.runelite.http.api.worlds.World;
import net.runelite.http.api.worlds.WorldResult;
import net.runelite.http.api.worlds.WorldType;
import org.apache.commons.lang3.ArrayUtils;
@PluginDescriptor(
name = "World Hopper",
description = "Allows you to quickly hop worlds",
tags = {"ping", "switcher"}
)
@Slf4j
public class WorldHopperPlugin extends Plugin
{
private static final int REFRESH_THROTTLE = 60_000; // ms
private static final int MAX_PLAYER_COUNT = 1950;
private static final int DISPLAY_SWITCHER_MAX_ATTEMPTS = 3;
private static final String HOP_TO = "Hop-to";
private static final String KICK_OPTION = "Kick";
private static final ImmutableList<String> BEFORE_OPTIONS = ImmutableList.of("Add friend", "Remove friend", KICK_OPTION);
private static final ImmutableList<String> AFTER_OPTIONS = ImmutableList.of("Message");
@Inject
private Client client;
@Inject
private ConfigManager configManager;
@Inject
private ClientToolbar clientToolbar;
@Inject
private KeyManager keyManager;
@Inject
private ChatMessageManager chatMessageManager;
@Inject
private WorldHopperConfig config;
@Inject
private OverlayManager overlayManager;
@Inject
private WorldHopperPingOverlay worldHopperOverlay;
@Inject
private WorldService worldService;
private ScheduledExecutorService hopperExecutorService;
private NavigationButton navButton;
private WorldSwitcherPanel panel;
private net.runelite.api.World quickHopTargetWorld;
private int displaySwitcherAttempts = 0;
@Getter
private int lastWorld;
private int favoriteWorld1, favoriteWorld2;
private ScheduledFuture<?> pingFuture, currPingFuture;
private int currentWorld;
private Instant lastFetch;
@Getter(AccessLevel.PACKAGE)
private int currentPing;
private final Map<Integer, Integer> storedPings = new HashMap<>();
private final HotkeyListener previousKeyListener = new HotkeyListener(() -> config.previousKey())
{
@Override
public void hotkeyPressed()
{
hop(true);
}
};
private final HotkeyListener nextKeyListener = new HotkeyListener(() -> config.nextKey())
{
@Override
public void hotkeyPressed()
{
hop(false);
}
};
@Provides
WorldHopperConfig getConfig(ConfigManager configManager)
{
return configManager.getConfig(WorldHopperConfig.class);
}
@Override
protected void startUp() throws Exception
{
currentPing = -1;
keyManager.registerKeyListener(previousKeyListener);
keyManager.registerKeyListener(nextKeyListener);
panel = new WorldSwitcherPanel(this);
final BufferedImage icon;
synchronized (ImageIO.class)
{
icon = ImageIO.read(getClass().getResourceAsStream("icon.png"));
}
navButton = NavigationButton.builder()
.tooltip("World Switcher")
.icon(icon)
.priority(3)
.panel(panel)
.build();
if (config.showSidebar())
{
clientToolbar.addNavigation(navButton);
}
overlayManager.add(worldHopperOverlay);
panel.setFilterMode(config.subscriptionFilter());
// The plugin has its own executor for pings, as it blocks for a long time
hopperExecutorService = new ExecutorServiceExceptionLogger(Executors.newSingleThreadScheduledExecutor());
// Run the first-run ping
hopperExecutorService.execute(this::pingInitialWorlds);
// Give some initial delay - this won't run until after pingInitialWorlds finishes from tick() anyway
pingFuture = hopperExecutorService.scheduleWithFixedDelay(this::pingNextWorld, 15, 3, TimeUnit.SECONDS);
currPingFuture = hopperExecutorService.scheduleWithFixedDelay(this::pingCurrentWorld, 15, 1, TimeUnit.SECONDS);
// populate initial world list
updateList();
}
@Override
protected void shutDown() throws Exception
{
pingFuture.cancel(true);
pingFuture = null;
currPingFuture.cancel(true);
currPingFuture = null;
overlayManager.remove(worldHopperOverlay);
keyManager.unregisterKeyListener(previousKeyListener);
keyManager.unregisterKeyListener(nextKeyListener);
clientToolbar.removeNavigation(navButton);
hopperExecutorService.shutdown();
hopperExecutorService = null;
}
@Subscribe
public void onConfigChanged(final ConfigChanged event)
{
if (event.getGroup().equals(WorldHopperConfig.GROUP))
{
switch (event.getKey())
{
case "showSidebar":
if (config.showSidebar())
{
clientToolbar.addNavigation(navButton);
}
else
{
clientToolbar.removeNavigation(navButton);
}
break;
case "ping":
if (config.ping())
{
SwingUtilities.invokeLater(() -> panel.showPing());
}
else
{
SwingUtilities.invokeLater(() -> panel.hidePing());
}
break;
case "subscriptionFilter":
panel.setFilterMode(config.subscriptionFilter());
updateList();
break;
}
}
}
private void setFavoriteConfig(int world)
{
configManager.setConfiguration(WorldHopperConfig.GROUP, "favorite_" + world, true);
}
private boolean isFavoriteConfig(int world)
{
Boolean favorite = configManager.getConfiguration(WorldHopperConfig.GROUP, "favorite_" + world, Boolean.class);
return favorite != null && favorite;
}
private void clearFavoriteConfig(int world)
{
configManager.unsetConfiguration(WorldHopperConfig.GROUP, "favorite_" + world);
}
boolean isFavorite(World world)
{
int id = world.getId();
return id == favoriteWorld1 || id == favoriteWorld2 || isFavoriteConfig(id);
}
int getCurrentWorld()
{
return client.getWorld();
}
void hopTo(World world)
{
hop(world.getId());
}
void addToFavorites(World world)
{
log.debug("Adding world {} to favorites", world.getId());
setFavoriteConfig(world.getId());
panel.updateFavoriteMenu(world.getId(), true);
}
void removeFromFavorites(World world)
{
log.debug("Removing world {} from favorites", world.getId());
clearFavoriteConfig(world.getId());
panel.updateFavoriteMenu(world.getId(), false);
}
@Subscribe
public void onVarbitChanged(VarbitChanged varbitChanged)
{
int old1 = favoriteWorld1;
int old2 = favoriteWorld2;
favoriteWorld1 = client.getVar(Varbits.WORLDHOPPER_FAVROITE_1);
favoriteWorld2 = client.getVar(Varbits.WORLDHOPPER_FAVROITE_2);
if (old1 != favoriteWorld1 || old2 != favoriteWorld2)
{
SwingUtilities.invokeLater(panel::updateList);
}
}
@Subscribe
public void onMenuEntryAdded(MenuEntryAdded event)
{
if (!config.menuOption())
{
return;
}
int groupId = WidgetInfo.TO_GROUP(event.getActionParam1());
String option = event.getOption();
if (groupId == WidgetInfo.FRIENDS_LIST.getGroupId() || groupId == WidgetInfo.FRIENDS_CHAT.getGroupId())
{
boolean after;
if (AFTER_OPTIONS.contains(option))
{
after = true;
}
else if (BEFORE_OPTIONS.contains(option))
{
after = false;
}
else
{
return;
}
// Don't add entry if user is offline
ChatPlayer player = getChatPlayerFromName(event.getTarget());
WorldResult worldResult = worldService.getWorlds();
if (player == null || player.getWorld() == 0 || player.getWorld() == client.getWorld()
|| worldResult == null)
{
return;
}
World currentWorld = worldResult.findWorld(client.getWorld());
World targetWorld = worldResult.findWorld(player.getWorld());
if (targetWorld == null || currentWorld == null
|| (!currentWorld.getTypes().contains(WorldType.PVP) && targetWorld.getTypes().contains(WorldType.PVP)))
{
// Disable Hop-to a PVP world from a regular world
return;
}
final MenuEntry hopTo = new MenuEntry();
hopTo.setOption(HOP_TO);
hopTo.setTarget(event.getTarget());
hopTo.setType(MenuAction.RUNELITE.getId());
hopTo.setParam0(event.getActionParam0());
hopTo.setParam1(event.getActionParam1());
insertMenuEntry(hopTo, client.getMenuEntries(), after);
}
}
private void insertMenuEntry(MenuEntry newEntry, MenuEntry[] entries, boolean after)
{
MenuEntry[] newMenu = ObjectArrays.concat(entries, newEntry);
if (after)
{
int menuEntryCount = newMenu.length;
ArrayUtils.swap(newMenu, menuEntryCount - 1, menuEntryCount - 2);
}
client.setMenuEntries(newMenu);
}
@Subscribe
public void onPlayerMenuOptionClicked(PlayerMenuOptionClicked event)
{
if (!event.getMenuOption().equals(HOP_TO))
{
return;
}
ChatPlayer player = getChatPlayerFromName(event.getMenuTarget());
if (player != null)
{
hop(player.getWorld());
}
}
@Subscribe
public void onGameStateChanged(GameStateChanged gameStateChanged)
{
// If the player has disabled the side bar plugin panel, do not update the UI
if (config.showSidebar() && gameStateChanged.getGameState() == GameState.LOGGED_IN)
{
if (lastWorld != client.getWorld())
{
int newWorld = client.getWorld();
panel.switchCurrentHighlight(newWorld, lastWorld);
lastWorld = newWorld;
}
}
}
@Subscribe
public void onWorldListLoad(WorldListLoad worldListLoad)
{
if (!config.showSidebar())
{
return;
}
Map<Integer, Integer> worldData = new HashMap<>();
for (net.runelite.api.World w : worldListLoad.getWorlds())
{
worldData.put(w.getId(), w.getPlayerCount());
}
panel.updateListData(worldData);
this.lastFetch = Instant.now(); // This counts as a fetch as it updates populations
}
void refresh()
{
Instant now = Instant.now();
if (lastFetch != null && now.toEpochMilli() - lastFetch.toEpochMilli() < REFRESH_THROTTLE)
{
log.debug("Throttling world refresh");
return;
}
lastFetch = now;
worldService.refresh();
}
@Subscribe
public void onWorldsFetch(WorldsFetch worldsFetch)
{
updateList();
}
/**
* This method ONLY updates the list's UI, not the actual world list and data it displays.
*/
private void updateList()
{
WorldResult worldResult = worldService.getWorlds();
if (worldResult != null)
{
SwingUtilities.invokeLater(() -> panel.populate(worldResult.getWorlds()));
}
}
private void hop(boolean previous)
{
WorldResult worldResult = worldService.getWorlds();
if (worldResult == null || client.getGameState() != GameState.LOGGED_IN)
{
return;
}
World currentWorld = worldResult.findWorld(client.getWorld());
if (currentWorld == null)
{
return;
}
EnumSet<WorldType> currentWorldTypes = currentWorld.getTypes().clone();
// Make it so you always hop out of PVP and high risk worlds
if (config.quickhopOutOfDanger())
{
currentWorldTypes.remove(WorldType.PVP);
currentWorldTypes.remove(WorldType.HIGH_RISK);
}
// Don't regard these worlds as a type that must be hopped between
currentWorldTypes.remove(WorldType.BOUNTY);
currentWorldTypes.remove(WorldType.SKILL_TOTAL);
currentWorldTypes.remove(WorldType.LAST_MAN_STANDING);
List<World> worlds = worldResult.getWorlds();
int worldIdx = worlds.indexOf(currentWorld);
int totalLevel = client.getTotalLevel();
World world;
do
{
/*
Get the previous or next world in the list,
starting over at the other end of the list
if there are no more elements in the
current direction of iteration.
*/
if (previous)
{
worldIdx--;
if (worldIdx < 0)
{
worldIdx = worlds.size() - 1;
}
}
else
{
worldIdx++;
if (worldIdx >= worlds.size())
{
worldIdx = 0;
}
}
world = worlds.get(worldIdx);
// Check world region if filter is enabled
if (config.quickHopRegionFilter() != RegionFilterMode.NONE && world.getRegion() != config.quickHopRegionFilter().getRegion())
{
continue;
}
EnumSet<WorldType> types = world.getTypes().clone();
types.remove(WorldType.BOUNTY);
// Treat LMS world like casual world
types.remove(WorldType.LAST_MAN_STANDING);
if (types.contains(WorldType.SKILL_TOTAL))
{
try
{
int totalRequirement = Integer.parseInt(world.getActivity().substring(0, world.getActivity().indexOf(" ")));
if (totalLevel >= totalRequirement)
{
types.remove(WorldType.SKILL_TOTAL);
}
}
catch (NumberFormatException ex)
{
log.warn("Failed to parse total level requirement for target world", ex);
}
}
// Avoid switching to near-max population worlds, as it will refuse to allow the hop if the world is full
if (world.getPlayers() >= MAX_PLAYER_COUNT)
{
continue;
}
// Break out if we've found a good world to hop to
if (currentWorldTypes.equals(types))
{
break;
}
}
while (world != currentWorld);
if (world == currentWorld)
{
String chatMessage = new ChatMessageBuilder()
.append(ChatColorType.NORMAL)
.append("Couldn't find a world to quick-hop to.")
.build();
chatMessageManager.queue(QueuedMessage.builder()
.type(ChatMessageType.CONSOLE)
.runeLiteFormattedMessage(chatMessage)
.build());
}
else
{
hop(world.getId());
}
}
private void hop(int worldId)
{
WorldResult worldResult = worldService.getWorlds();
// Don't try to hop if the world doesn't exist
World world = worldResult.findWorld(worldId);
if (world == null)
{
return;
}
final net.runelite.api.World rsWorld = client.createWorld();
rsWorld.setActivity(world.getActivity());
rsWorld.setAddress(world.getAddress());
rsWorld.setId(world.getId());
rsWorld.setPlayerCount(world.getPlayers());
rsWorld.setLocation(world.getLocation());
rsWorld.setTypes(WorldUtil.toWorldTypes(world.getTypes()));
if (client.getGameState() == GameState.LOGIN_SCREEN)
{
// on the login screen we can just change the world by ourselves
client.changeWorld(rsWorld);
return;
}
if (config.showWorldHopMessage())
{
String chatMessage = new ChatMessageBuilder()
.append(ChatColorType.NORMAL)
.append("Quick-hopping to World ")
.append(ChatColorType.HIGHLIGHT)
.append(Integer.toString(world.getId()))
.append(ChatColorType.NORMAL)
.append("..")
.build();
chatMessageManager
.queue(QueuedMessage.builder()
.type(ChatMessageType.CONSOLE)
.runeLiteFormattedMessage(chatMessage)
.build());
}
quickHopTargetWorld = rsWorld;
displaySwitcherAttempts = 0;
}
@Subscribe
public void onGameTick(GameTick event)
{
if (quickHopTargetWorld == null)
{
return;
}
if (client.getWidget(WidgetInfo.WORLD_SWITCHER_LIST) == null)
{
client.openWorldHopper();
if (++displaySwitcherAttempts >= DISPLAY_SWITCHER_MAX_ATTEMPTS)
{
String chatMessage = new ChatMessageBuilder()
.append(ChatColorType.NORMAL)
.append("Failed to quick-hop after ")
.append(ChatColorType.HIGHLIGHT)
.append(Integer.toString(displaySwitcherAttempts))
.append(ChatColorType.NORMAL)
.append(" attempts.")
.build();
chatMessageManager
.queue(QueuedMessage.builder()
.type(ChatMessageType.CONSOLE)
.runeLiteFormattedMessage(chatMessage)
.build());
resetQuickHopper();
}
}
else
{
client.hopToWorld(quickHopTargetWorld);
resetQuickHopper();
}
}
@Subscribe
public void onChatMessage(ChatMessage event)
{
if (event.getType() != ChatMessageType.GAMEMESSAGE)
{
return;
}
if (event.getMessage().equals("Please finish what you're doing before using the World Switcher."))
{
resetQuickHopper();
}
}
private void resetQuickHopper()
{
displaySwitcherAttempts = 0;
quickHopTargetWorld = null;
}
private ChatPlayer getChatPlayerFromName(String name)
{
String cleanName = Text.removeTags(name);
// Search friends chat members first, because we can always get their world;
// friends worlds may be hidden if they have private off. (#5679)
FriendsChatManager friendsChatManager = client.getFriendsChatManager();
if (friendsChatManager != null)
{
FriendsChatMember member = friendsChatManager.findByName(cleanName);
if (member != null)
{
return member;
}
}
NameableContainer<Friend> friendContainer = client.getFriendContainer();
if (friendContainer != null)
{
return friendContainer.findByName(cleanName);
}
return null;
}
/**
* Ping all worlds. This takes a long time and is only run on first run.
*/
private void pingInitialWorlds()
{
WorldResult worldResult = worldService.getWorlds();
if (worldResult == null || !config.showSidebar() || !config.ping())
{
return;
}
Stopwatch stopwatch = Stopwatch.createStarted();
for (World world : worldResult.getWorlds())
{
int ping = ping(world);
SwingUtilities.invokeLater(() -> panel.updatePing(world.getId(), ping));
}
stopwatch.stop();
log.debug("Done pinging worlds in {}", stopwatch.elapsed());
}
/**
* Ping the next world
*/
private void pingNextWorld()
{
WorldResult worldResult = worldService.getWorlds();
if (worldResult == null || !config.showSidebar() || !config.ping())
{
return;
}
List<World> worlds = worldResult.getWorlds();
if (worlds.isEmpty())
{
return;
}
if (currentWorld >= worlds.size())
{
// Wrap back around
currentWorld = 0;
}
World world = worlds.get(currentWorld++);
// If we are displaying the ping overlay, there is a separate scheduled task for the current world
boolean displayPing = config.displayPing() && client.getGameState() == GameState.LOGGED_IN;
if (displayPing && client.getWorld() == world.getId())
{
return;
}
int ping = ping(world);
log.trace("Ping for world {} is: {}", world.getId(), ping);
SwingUtilities.invokeLater(() -> panel.updatePing(world.getId(), ping));
}
/**
* Ping the current world for the ping overlay
*/
private void pingCurrentWorld()
{
WorldResult worldResult = worldService.getWorlds();
// There is no reason to ping the current world if not logged in, as the overlay doesn't draw
if (worldResult == null || !config.displayPing() || client.getGameState() != GameState.LOGGED_IN)
{
return;
}
final World currentWorld = worldResult.findWorld(client.getWorld());
if (currentWorld == null)
{
log.debug("unable to find current world: {}", client.getWorld());
return;
}
currentPing = ping(currentWorld);
log.trace("Ping for current world is: {}", currentPing);
SwingUtilities.invokeLater(() -> panel.updatePing(currentWorld.getId(), currentPing));
}
Integer getStoredPing(World world)
{
if (!config.ping())
{
return null;
}
return storedPings.get(world.getId());
}
private int ping(World world)
{
int ping = Ping.ping(world);
storedPings.put(world.getId(), ping);
return ping;
}
}

View File

@@ -0,0 +1,405 @@
/*
* Copyright (c) 2018, Psikoi <https://github.com/Psikoi>
* 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.worldhopper;
import com.google.common.collect.Ordering;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import lombok.AccessLevel;
import lombok.Setter;
import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.DynamicGridLayout;
import net.runelite.client.ui.PluginPanel;
import net.runelite.http.api.worlds.World;
import net.runelite.http.api.worlds.WorldType;
class WorldSwitcherPanel extends PluginPanel
{
private static final Color ODD_ROW = new Color(44, 44, 44);
private static final int WORLD_COLUMN_WIDTH = 60;
private static final int PLAYERS_COLUMN_WIDTH = 40;
private static final int PING_COLUMN_WIDTH = 47;
private final JPanel listContainer = new JPanel();
private WorldTableHeader worldHeader;
private WorldTableHeader playersHeader;
private WorldTableHeader activityHeader;
private WorldTableHeader pingHeader;
private WorldOrder orderIndex = WorldOrder.WORLD;
private boolean ascendingOrder = true;
private final ArrayList<WorldTableRow> rows = new ArrayList<>();
private final WorldHopperPlugin plugin;
@Setter(AccessLevel.PACKAGE)
private SubscriptionFilterMode filterMode;
WorldSwitcherPanel(WorldHopperPlugin plugin)
{
this.plugin = plugin;
setBorder(null);
setLayout(new DynamicGridLayout(0, 1));
JPanel headerContainer = buildHeader();
listContainer.setLayout(new GridLayout(0, 1));
add(headerContainer);
add(listContainer);
}
void switchCurrentHighlight(int newWorld, int lastWorld)
{
for (WorldTableRow row : rows)
{
if (row.getWorld().getId() == newWorld)
{
row.recolour(true);
}
else if (row.getWorld().getId() == lastWorld)
{
row.recolour(false);
}
}
}
void updateListData(Map<Integer, Integer> worldData)
{
for (WorldTableRow worldTableRow : rows)
{
World world = worldTableRow.getWorld();
Integer playerCount = worldData.get(world.getId());
if (playerCount != null)
{
worldTableRow.updatePlayerCount(playerCount);
}
}
// If the list is being ordered by player count, then it has to be re-painted
// to properly display the new data
if (orderIndex == WorldOrder.PLAYERS)
{
updateList();
}
}
void updatePing(int world, int ping)
{
for (WorldTableRow worldTableRow : rows)
{
if (worldTableRow.getWorld().getId() == world)
{
worldTableRow.setPing(ping);
// If the panel is sorted by ping, re-sort it
if (orderIndex == WorldOrder.PING)
{
updateList();
}
break;
}
}
}
void hidePing()
{
for (WorldTableRow worldTableRow : rows)
{
worldTableRow.hidePing();
}
}
void showPing()
{
for (WorldTableRow worldTableRow : rows)
{
worldTableRow.showPing();
}
}
void updateList()
{
rows.sort((r1, r2) ->
{
switch (orderIndex)
{
case PING:
// Leave worlds with unknown ping at the bottom
return getCompareValue(r1, r2, row ->
{
int ping = row.getPing();
return ping > 0 ? ping : null;
});
case WORLD:
return getCompareValue(r1, r2, row -> row.getWorld().getId());
case PLAYERS:
return getCompareValue(r1, r2, WorldTableRow::getUpdatedPlayerCount);
case ACTIVITY:
// Leave empty activity worlds on the bottom of the list
return getCompareValue(r1, r2, row ->
{
String activity = row.getWorld().getActivity();
return !activity.equals("-") ? activity : null;
});
default:
return 0;
}
});
rows.sort((r1, r2) ->
{
boolean b1 = plugin.isFavorite(r1.getWorld());
boolean b2 = plugin.isFavorite(r2.getWorld());
return Boolean.compare(b2, b1);
});
listContainer.removeAll();
for (int i = 0; i < rows.size(); i++)
{
WorldTableRow row = rows.get(i);
row.setBackground(i % 2 == 0 ? ODD_ROW : ColorScheme.DARK_GRAY_COLOR);
listContainer.add(row);
}
listContainer.revalidate();
listContainer.repaint();
}
private int getCompareValue(WorldTableRow row1, WorldTableRow row2, Function<WorldTableRow, Comparable> compareByFn)
{
Ordering<Comparable> ordering = Ordering.natural();
if (!ascendingOrder)
{
ordering = ordering.reverse();
}
ordering = ordering.nullsLast();
return ordering.compare(compareByFn.apply(row1), compareByFn.apply(row2));
}
void updateFavoriteMenu(int world, boolean favorite)
{
for (WorldTableRow row : rows)
{
if (row.getWorld().getId() == world)
{
row.setFavoriteMenu(favorite);
}
}
}
void populate(List<World> worlds)
{
rows.clear();
for (int i = 0; i < worlds.size(); i++)
{
World world = worlds.get(i);
switch (filterMode)
{
case FREE:
if (world.getTypes().contains(WorldType.MEMBERS))
{
continue;
}
break;
case MEMBERS:
if (!world.getTypes().contains(WorldType.MEMBERS))
{
continue;
}
break;
}
rows.add(buildRow(world, i % 2 == 0, world.getId() == plugin.getCurrentWorld() && plugin.getLastWorld() != 0, plugin.isFavorite(world)));
}
updateList();
}
private void orderBy(WorldOrder order)
{
pingHeader.highlight(false, ascendingOrder);
worldHeader.highlight(false, ascendingOrder);
playersHeader.highlight(false, ascendingOrder);
activityHeader.highlight(false, ascendingOrder);
switch (order)
{
case PING:
pingHeader.highlight(true, ascendingOrder);
break;
case WORLD:
worldHeader.highlight(true, ascendingOrder);
break;
case PLAYERS:
playersHeader.highlight(true, ascendingOrder);
break;
case ACTIVITY:
activityHeader.highlight(true, ascendingOrder);
break;
}
orderIndex = order;
updateList();
}
/**
* Builds the entire table header.
*/
private JPanel buildHeader()
{
JPanel header = new JPanel(new BorderLayout());
JPanel leftSide = new JPanel(new BorderLayout());
JPanel rightSide = new JPanel(new BorderLayout());
pingHeader = new WorldTableHeader("Ping", orderIndex == WorldOrder.PING, ascendingOrder, plugin::refresh);
pingHeader.setPreferredSize(new Dimension(PING_COLUMN_WIDTH, 0));
pingHeader.addMouseListener(new MouseAdapter()
{
@Override
public void mousePressed(MouseEvent mouseEvent)
{
if (SwingUtilities.isRightMouseButton(mouseEvent))
{
return;
}
ascendingOrder = orderIndex != WorldOrder.PING || !ascendingOrder;
orderBy(WorldOrder.PING);
}
});
worldHeader = new WorldTableHeader("World", orderIndex == WorldOrder.WORLD, ascendingOrder, plugin::refresh);
worldHeader.setPreferredSize(new Dimension(WORLD_COLUMN_WIDTH, 0));
worldHeader.addMouseListener(new MouseAdapter()
{
@Override
public void mousePressed(MouseEvent mouseEvent)
{
if (SwingUtilities.isRightMouseButton(mouseEvent))
{
return;
}
ascendingOrder = orderIndex != WorldOrder.WORLD || !ascendingOrder;
orderBy(WorldOrder.WORLD);
}
});
playersHeader = new WorldTableHeader("#", orderIndex == WorldOrder.PLAYERS, ascendingOrder, plugin::refresh);
playersHeader.setPreferredSize(new Dimension(PLAYERS_COLUMN_WIDTH, 0));
playersHeader.addMouseListener(new MouseAdapter()
{
@Override
public void mousePressed(MouseEvent mouseEvent)
{
if (SwingUtilities.isRightMouseButton(mouseEvent))
{
return;
}
ascendingOrder = orderIndex != WorldOrder.PLAYERS || !ascendingOrder;
orderBy(WorldOrder.PLAYERS);
}
});
activityHeader = new WorldTableHeader("Activity", orderIndex == WorldOrder.ACTIVITY, ascendingOrder, plugin::refresh);
activityHeader.addMouseListener(new MouseAdapter()
{
@Override
public void mousePressed(MouseEvent mouseEvent)
{
if (SwingUtilities.isRightMouseButton(mouseEvent))
{
return;
}
ascendingOrder = orderIndex != WorldOrder.ACTIVITY || !ascendingOrder;
orderBy(WorldOrder.ACTIVITY);
}
});
leftSide.add(worldHeader, BorderLayout.WEST);
leftSide.add(playersHeader, BorderLayout.CENTER);
rightSide.add(activityHeader, BorderLayout.CENTER);
rightSide.add(pingHeader, BorderLayout.EAST);
header.add(leftSide, BorderLayout.WEST);
header.add(rightSide, BorderLayout.CENTER);
return header;
}
/**
* Builds a table row, that displays the world's information.
*/
private WorldTableRow buildRow(World world, boolean stripe, boolean current, boolean favorite)
{
WorldTableRow row = new WorldTableRow(world, current, favorite, plugin.getStoredPing(world),
world1 ->
{
plugin.hopTo(world1);
},
(world12, add) ->
{
if (add)
{
plugin.addToFavorites(world12);
}
else
{
plugin.removeFromFavorites(world12);
}
updateList();
}
);
row.setBackground(stripe ? ODD_ROW : ColorScheme.DARK_GRAY_COLOR);
return row;
}
/**
* Enumerates the multiple ordering options for the world list.
*/
private enum WorldOrder
{
WORLD,
PLAYERS,
ACTIVITY,
PING
}
}

View File

@@ -0,0 +1,148 @@
/*
* Copyright (c) 2018, Psikoi <https://github.com/Psikoi>
* 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.worldhopper;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import javax.annotation.Nonnull;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.FontManager;
import net.runelite.client.util.ImageUtil;
class WorldTableHeader extends JPanel
{
private static final ImageIcon ARROW_UP;
private static final ImageIcon HIGHLIGHT_ARROW_DOWN;
private static final ImageIcon HIGHLIGHT_ARROW_UP;
private static final Color ARROW_COLOR = ColorScheme.LIGHT_GRAY_COLOR;
private static final Color HIGHLIGHT_COLOR = ColorScheme.BRAND_ORANGE;
static
{
final BufferedImage arrowDown = ImageUtil.getResourceStreamFromClass(WorldHopperPlugin.class, "arrow_down.png");
final BufferedImage arrowUp = ImageUtil.rotateImage(arrowDown, Math.PI);
final BufferedImage arrowUpFaded = ImageUtil.luminanceOffset(arrowUp, -80);
ARROW_UP = new ImageIcon(arrowUpFaded);
final BufferedImage highlightArrowDown = ImageUtil.fillImage(arrowDown, HIGHLIGHT_COLOR);
final BufferedImage highlightArrowUp = ImageUtil.fillImage(arrowUp, HIGHLIGHT_COLOR);
HIGHLIGHT_ARROW_DOWN = new ImageIcon(highlightArrowDown);
HIGHLIGHT_ARROW_UP = new ImageIcon(highlightArrowUp);
}
private final JLabel textLabel = new JLabel();
private final JLabel arrowLabel = new JLabel();
// Determines if this header column is being used to order the list
private boolean ordering = false;
WorldTableHeader(String title, boolean ordered, boolean ascending, @Nonnull Runnable onRefresh)
{
setLayout(new BorderLayout(5, 0));
setBorder(new CompoundBorder(
BorderFactory.createMatteBorder(0, 0, 0, 1, ColorScheme.MEDIUM_GRAY_COLOR),
new EmptyBorder(0, 5, 0, 2)));
setBackground(ColorScheme.SCROLL_TRACK_COLOR);
addMouseListener(new MouseAdapter()
{
@Override
public void mouseEntered(MouseEvent mouseEvent)
{
textLabel.setForeground(HIGHLIGHT_COLOR);
if (!ordering)
{
arrowLabel.setIcon(HIGHLIGHT_ARROW_UP);
}
}
@Override
public void mouseExited(MouseEvent mouseEvent)
{
if (!ordering)
{
textLabel.setForeground(ARROW_COLOR);
arrowLabel.setIcon(ARROW_UP);
}
}
});
textLabel.setText(title);
textLabel.setFont(FontManager.getRunescapeSmallFont());
final JMenuItem refresh = new JMenuItem("Refresh worlds");
refresh.addActionListener(e ->
{
onRefresh.run();
});
final JPopupMenu popupMenu = new JPopupMenu();
popupMenu.setBorder(new EmptyBorder(5, 5, 5, 5));
popupMenu.add(refresh);
textLabel.setComponentPopupMenu(popupMenu);
setComponentPopupMenu(popupMenu);
highlight(ordered, ascending);
add(textLabel, BorderLayout.WEST);
add(arrowLabel, BorderLayout.EAST);
}
/**
* The labels inherit the parent's mouse listeners.
*/
@Override
public void addMouseListener(MouseListener mouseListener)
{
super.addMouseListener(mouseListener);
textLabel.addMouseListener(mouseListener);
arrowLabel.addMouseListener(mouseListener);
}
/**
* If this column header is being used to order, then it should be
* highlighted, changing it's font color and icon.
*/
public void highlight(boolean on, boolean ascending)
{
ordering = on;
arrowLabel.setIcon(on ? (ascending ? HIGHLIGHT_ARROW_DOWN : HIGHLIGHT_ARROW_UP) : ARROW_UP);
textLabel.setForeground(on ? HIGHLIGHT_COLOR : ARROW_COLOR);
}
}

View File

@@ -0,0 +1,364 @@
/*
* Copyright (c) 2018, Psikoi <https://github.com/Psikoi>
* 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.worldhopper;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.border.EmptyBorder;
import lombok.AccessLevel;
import lombok.Getter;
import net.runelite.client.ui.FontManager;
import net.runelite.client.util.ImageUtil;
import net.runelite.http.api.worlds.World;
import net.runelite.http.api.worlds.WorldRegion;
import net.runelite.http.api.worlds.WorldType;
class WorldTableRow extends JPanel
{
private static final ImageIcon FLAG_AUS;
private static final ImageIcon FLAG_UK;
private static final ImageIcon FLAG_US;
private static final ImageIcon FLAG_GER;
private static final int WORLD_COLUMN_WIDTH = 60;
private static final int PLAYERS_COLUMN_WIDTH = 40;
private static final int PING_COLUMN_WIDTH = 35;
private static final Color CURRENT_WORLD = new Color(66, 227, 17);
private static final Color DANGEROUS_WORLD = new Color(251, 62, 62);
private static final Color TOURNAMENT_WORLD = new Color(79, 145, 255);
private static final Color MEMBERS_WORLD = new Color(210, 193, 53);
private static final Color FREE_WORLD = new Color(200, 200, 200);
private static final Color LEAGUE_WORLD = new Color(133, 177, 178);
static
{
FLAG_AUS = new ImageIcon(ImageUtil.getResourceStreamFromClass(WorldHopperPlugin.class, "flag_aus.png"));
FLAG_UK = new ImageIcon(ImageUtil.getResourceStreamFromClass(WorldHopperPlugin.class, "flag_uk.png"));
FLAG_US = new ImageIcon(ImageUtil.getResourceStreamFromClass(WorldHopperPlugin.class, "flag_us.png"));
FLAG_GER = new ImageIcon(ImageUtil.getResourceStreamFromClass(WorldHopperPlugin.class, "flag_ger.png"));
}
private final JMenuItem favoriteMenuOption = new JMenuItem();
private JLabel worldField;
private JLabel playerCountField;
private JLabel activityField;
private JLabel pingField;
private final BiConsumer<World, Boolean> onFavorite;
@Getter
private final World world;
@Getter(AccessLevel.PACKAGE)
private int updatedPlayerCount;
private int ping;
private Color lastBackground;
WorldTableRow(World world, boolean current, boolean favorite, Integer ping, Consumer<World> onSelect, BiConsumer<World, Boolean> onFavorite)
{
this.world = world;
this.onFavorite = onFavorite;
this.updatedPlayerCount = world.getPlayers();
setLayout(new BorderLayout());
setBorder(new EmptyBorder(2, 0, 2, 0));
addMouseListener(new MouseAdapter()
{
@Override
public void mouseClicked(MouseEvent mouseEvent)
{
if (mouseEvent.getClickCount() == 2)
{
if (onSelect != null)
{
onSelect.accept(world);
}
}
}
@Override
public void mousePressed(MouseEvent mouseEvent)
{
if (mouseEvent.getClickCount() == 2)
{
setBackground(getBackground().brighter());
}
}
@Override
public void mouseReleased(MouseEvent mouseEvent)
{
if (mouseEvent.getClickCount() == 2)
{
setBackground(getBackground().darker());
}
}
@Override
public void mouseEntered(MouseEvent mouseEvent)
{
WorldTableRow.this.lastBackground = getBackground();
setBackground(getBackground().brighter());
}
@Override
public void mouseExited(MouseEvent mouseEvent)
{
setBackground(lastBackground);
}
});
setFavoriteMenu(favorite);
final JPopupMenu popupMenu = new JPopupMenu();
popupMenu.setBorder(new EmptyBorder(5, 5, 5, 5));
popupMenu.add(favoriteMenuOption);
setComponentPopupMenu(popupMenu);
JPanel leftSide = new JPanel(new BorderLayout());
JPanel rightSide = new JPanel(new BorderLayout());
leftSide.setOpaque(false);
rightSide.setOpaque(false);
JPanel worldField = buildWorldField();
worldField.setPreferredSize(new Dimension(WORLD_COLUMN_WIDTH, 0));
worldField.setOpaque(false);
JPanel pingField = buildPingField(ping);
pingField.setPreferredSize(new Dimension(PING_COLUMN_WIDTH, 0));
pingField.setOpaque(false);
JPanel playersField = buildPlayersField();
playersField.setPreferredSize(new Dimension(PLAYERS_COLUMN_WIDTH, 0));
playersField.setOpaque(false);
JPanel activityField = buildActivityField();
activityField.setBorder(new EmptyBorder(5, 5, 5, 5));
activityField.setOpaque(false);
recolour(current);
leftSide.add(worldField, BorderLayout.WEST);
leftSide.add(playersField, BorderLayout.CENTER);
rightSide.add(activityField, BorderLayout.CENTER);
rightSide.add(pingField, BorderLayout.EAST);
add(leftSide, BorderLayout.WEST);
add(rightSide, BorderLayout.CENTER);
}
void setFavoriteMenu(boolean favorite)
{
String favoriteAction = favorite ?
"Remove " + world.getId() + " from favorites" :
"Add " + world.getId() + " to favorites";
favoriteMenuOption.setText(favoriteAction);
for (ActionListener listener : favoriteMenuOption.getActionListeners())
{
favoriteMenuOption.removeActionListener(listener);
}
favoriteMenuOption.addActionListener(e ->
{
onFavorite.accept(world, !favorite);
});
}
void updatePlayerCount(int playerCount)
{
this.updatedPlayerCount = playerCount;
playerCountField.setText(playerCountString(playerCount));
}
private static String playerCountString(int playerCount)
{
return playerCount < 0 ? "OFF" : Integer.toString(playerCount);
}
void setPing(int ping)
{
this.ping = ping;
pingField.setText(ping <= 0 ? "-" : Integer.toString(ping));
}
void hidePing()
{
pingField.setText("-");
}
void showPing()
{
setPing(ping); // to update pingField
}
int getPing()
{
return ping;
}
public void recolour(boolean current)
{
playerCountField.setForeground(current ? CURRENT_WORLD : Color.WHITE);
pingField.setForeground(current ? CURRENT_WORLD : Color.WHITE);
if (current)
{
activityField.setForeground(CURRENT_WORLD);
worldField.setForeground(CURRENT_WORLD);
return;
}
else if (world.getTypes().contains(WorldType.PVP)
|| world.getTypes().contains(WorldType.HIGH_RISK)
|| world.getTypes().contains(WorldType.DEADMAN))
{
activityField.setForeground(DANGEROUS_WORLD);
}
else if (world.getTypes().contains(WorldType.LEAGUE))
{
activityField.setForeground(LEAGUE_WORLD);
}
else if (world.getTypes().contains(WorldType.TOURNAMENT))
{
activityField.setForeground(TOURNAMENT_WORLD);
}
else
{
activityField.setForeground(Color.WHITE);
}
worldField.setForeground(world.getTypes().contains(WorldType.MEMBERS) ? MEMBERS_WORLD : FREE_WORLD);
}
/**
* Builds the players list field (containing the amount of players logged in that world).
*/
private JPanel buildPlayersField()
{
JPanel column = new JPanel(new BorderLayout());
column.setBorder(new EmptyBorder(0, 5, 0, 5));
playerCountField = new JLabel(playerCountString(world.getPlayers()));
playerCountField.setFont(FontManager.getRunescapeSmallFont());
column.add(playerCountField, BorderLayout.WEST);
return column;
}
private JPanel buildPingField(Integer ping)
{
JPanel column = new JPanel(new BorderLayout());
column.setBorder(new EmptyBorder(0, 5, 0, 5));
pingField = new JLabel("-");
pingField.setFont(FontManager.getRunescapeSmallFont());
column.add(pingField, BorderLayout.EAST);
if (ping != null)
{
setPing(ping);
}
return column;
}
/**
* Builds the activity list field (containing that world's activity/theme).
*/
private JPanel buildActivityField()
{
JPanel column = new JPanel(new BorderLayout());
column.setBorder(new EmptyBorder(0, 5, 0, 5));
activityField = new JLabel(world.getActivity());
activityField.setFont(FontManager.getRunescapeSmallFont());
column.add(activityField, BorderLayout.WEST);
return column;
}
/**
* Builds the world list field (containing the country's flag and the world index).
*/
private JPanel buildWorldField()
{
JPanel column = new JPanel(new BorderLayout(7, 0));
column.setBorder(new EmptyBorder(0, 5, 0, 5));
worldField = new JLabel(world.getId() + "");
ImageIcon flagIcon = getFlag(world.getRegion());
if (flagIcon != null)
{
JLabel flag = new JLabel(flagIcon);
column.add(flag, BorderLayout.WEST);
}
column.add(worldField, BorderLayout.CENTER);
return column;
}
private static ImageIcon getFlag(WorldRegion region)
{
if (region == null)
{
return null;
}
switch (region)
{
case UNITED_STATES_OF_AMERICA:
return FLAG_US;
case UNITED_KINGDOM:
return FLAG_UK;
case AUSTRALIA:
return FLAG_AUS;
case GERMANY:
return FLAG_GER;
default:
return null;
}
}
}

View File

@@ -0,0 +1,40 @@
/*
* 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.worldhopper.ping;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
interface IPHlpAPI extends Library
{
IPHlpAPI INSTANCE = Native.loadLibrary("IPHlpAPI", IPHlpAPI.class);
Pointer IcmpCreateFile();
boolean IcmpCloseHandle(Pointer handle);
int IcmpSendEcho(Pointer IcmpHandle, int DestinationAddress, Pointer RequestData, short RequestSize, Pointer RequestOptions, IcmpEchoReply ReplyBuffer, int ReplySize, int Timeout);
}

View File

@@ -0,0 +1,61 @@
/*
* 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.worldhopper.ping;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.platform.win32.WinDef;
import java.util.Arrays;
import java.util.List;
public class IcmpEchoReply extends Structure
{
private static final int IP_OPTION_INFO_SIZE = 1 + 1 + 1 + 1 + (Native.POINTER_SIZE == 8 ? 12 : 4); // on 64bit vms add 4 byte padding
public static final int SIZE = 4 + 4 + 4 + 2 + 2 + Native.POINTER_SIZE + IP_OPTION_INFO_SIZE;
public WinDef.ULONG address;
public WinDef.ULONG status;
public WinDef.ULONG roundTripTime;
public WinDef.USHORT dataSize;
public WinDef.USHORT reserved;
public WinDef.PVOID data;
public WinDef.UCHAR ttl;
public WinDef.UCHAR tos;
public WinDef.UCHAR flags;
public WinDef.UCHAR optionsSize;
public WinDef.PVOID optionsData;
IcmpEchoReply(Pointer p)
{
super(p);
}
@Override
protected List<String> getFieldOrder()
{
return Arrays.asList("address", "status", "roundTripTime", "dataSize", "reserved", "data", "ttl", "tos", "flags", "optionsSize", "optionsData");
}
}

View File

@@ -0,0 +1,103 @@
/*
* 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.worldhopper.ping;
import com.sun.jna.Memory;
import com.sun.jna.Pointer;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import lombok.extern.slf4j.Slf4j;
import net.runelite.client.util.OSType;
import net.runelite.http.api.worlds.World;
@Slf4j
public class Ping
{
private static final String RUNELITE_PING = "RuneLitePing";
private static final int TIMEOUT = 2000;
private static final int PORT = 43594;
public static int ping(World world)
{
try
{
switch (OSType.getOSType())
{
case Windows:
return windowsPing(world);
default:
return tcpPing(world);
}
}
catch (IOException ex)
{
log.warn("error pinging", ex);
return -1;
}
}
private static int windowsPing(World world) throws UnknownHostException
{
IPHlpAPI ipHlpAPI = IPHlpAPI.INSTANCE;
Pointer ptr = ipHlpAPI.IcmpCreateFile();
InetAddress inetAddress = InetAddress.getByName(world.getAddress());
byte[] address = inetAddress.getAddress();
String dataStr = RUNELITE_PING;
int dataLength = dataStr.length() + 1;
Pointer data = new Memory(dataLength);
data.setString(0L, dataStr);
IcmpEchoReply icmpEchoReply = new IcmpEchoReply(new Memory(IcmpEchoReply.SIZE + dataLength));
assert icmpEchoReply.size() == IcmpEchoReply.SIZE;
int packed = (address[0] & 0xff) | ((address[1] & 0xff) << 8) | ((address[2] & 0xff) << 16) | ((address[3] & 0xff) << 24);
int ret = ipHlpAPI.IcmpSendEcho(ptr, packed, data, (short) (dataLength), Pointer.NULL, icmpEchoReply, IcmpEchoReply.SIZE + dataLength, TIMEOUT);
if (ret != 1)
{
ipHlpAPI.IcmpCloseHandle(ptr);
return -1;
}
int rtt = Math.toIntExact(icmpEchoReply.roundTripTime.longValue());
ipHlpAPI.IcmpCloseHandle(ptr);
return rtt;
}
private static int tcpPing(World world) throws IOException
{
try (Socket socket = new Socket())
{
socket.setSoTimeout(TIMEOUT);
InetAddress inetAddress = InetAddress.getByName(world.getAddress());
long start = System.nanoTime();
socket.connect(new InetSocketAddress(inetAddress, PORT));
long end = System.nanoTime();
return (int) ((end - start) / 1000000L);
}
}
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright (c) 2020, melky <https://github.com/melkypie>
* 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.worldmap;
import lombok.Getter;
import net.runelite.api.coords.WorldPoint;
@Getter
enum AgilityCourseLocation
{
AGILITY_PYRAMID("Agility Pyramid", new WorldPoint(3347, 2827, 0)),
AL_KHARID_ROOFTOP_COURSE("Al Kharid Rooftop Course", new WorldPoint(3272, 3195, 0)),
APE_ATOLL_AGILITY_COURSE("Ape Atoll Agility Course", new WorldPoint(2752, 2742, 0)),
ARDOUGNE_ROOFTOP_COURSE("Ardougne Rooftop Course", new WorldPoint(2673, 3298, 0)),
BARBARIAN_OUTPOST_AGILITY_COURSE("Barbarian Outpost Agility Course", new WorldPoint(2544, 3569, 0)),
BRIMHAVEN_AGILITY_ARENA("Brimhaven Agility Arena", new WorldPoint(2806, 3193, 0)),
CANIFIS_ROOFTOP_COURSE("Canifis Rooftop Course", new WorldPoint(3506, 3490, 0)),
DRAYNOR_VILLAGE_ROOFTOP_COURSE("Draynor Village Rooftop Course", new WorldPoint(3103, 3279, 0)),
FALADOR_ROOFTOP_COURSE("Falador Rooftop Course", new WorldPoint(3035, 3342, 0)),
GNOME_STRONGHOLD_AGILITY_COURSE("Gnome Stronghold Agility Course", new WorldPoint(2474, 3436, 0)),
PENGUIN_AGILITY_COURSE("Penguin Agility Course", new WorldPoint(2638, 4041, 0)),
POLLNIVNEACH_ROOFTOP_COURSE("Pollnivneach Rooftop Course", new WorldPoint(3350, 2963, 0)),
PRIFDDINAS_AGILITY_COURSE("Prifddinas Agility Course", new WorldPoint(3253, 6109, 0)),
RELLEKKA_ROOFTOP_COURSE("Rellekka Rooftop Course", new WorldPoint(2624, 3677, 0)),
SEERS_VILLAGE_ROOFTOP_COURSE("Seers' Village Rooftop Course", new WorldPoint(2728, 3488, 0)),
VARROCK_ROOFTOP_COURSE("Varrock Rooftop Course", new WorldPoint(3219, 3414, 0)),
WEREWOLF_AGILITY_COURSE("Werewolf Agility Course", new WorldPoint(3542, 3463, 0)),
WILDERNESS_AGILITY_COURSE("Wilderness Agility Course", new WorldPoint(2997, 3916, 0));
private final String tooltip;
private final WorldPoint location;
private final boolean rooftopCourse;
AgilityCourseLocation(String tooltip, WorldPoint location)
{
this.tooltip = tooltip;
this.location = location;
this.rooftopCourse = this.name().contains("ROOFTOP_COURSE");
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (c) 2020, melky <https://github.com/melkypie>
* 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.worldmap;
import java.awt.image.BufferedImage;
import net.runelite.client.ui.overlay.worldmap.WorldMapPoint;
class AgilityCoursePoint extends WorldMapPoint
{
AgilityCoursePoint(AgilityCourseLocation data, BufferedImage icon, boolean showTooltip)
{
super(data.getLocation(), icon);
if (showTooltip)
{
setTooltip(data.getTooltip());
}
}
}

View File

@@ -0,0 +1,43 @@
/*
* 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 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.worldmap;
import java.awt.image.BufferedImage;
import net.runelite.client.ui.overlay.worldmap.WorldMapPoint;
import net.runelite.client.game.AgilityShortcut;
class AgilityShortcutPoint extends WorldMapPoint
{
AgilityShortcutPoint(AgilityShortcut data, BufferedImage icon, boolean showTooltip)
{
super(data.getWorldMapLocation(), icon);
if (showTooltip)
{
setTooltip(data.getTooltip());
}
}
}

View File

@@ -0,0 +1,224 @@
/*
* Copyright (c) 2020, Arman S <https://github.com/Rman887>
* 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.worldmap;
import lombok.Getter;
import net.runelite.api.coords.WorldPoint;
@Getter
enum DungeonLocation
{
ABANDONED_MINE("Abandoned Mine", new WorldPoint(3439, 3232, 0)),
ABANDONED_MINE_SECRET("Abandoned Mine (secret entrance)", new WorldPoint(3452, 3244, 0)),
ANCIENT_CAVERN("Ancient Cavern", new WorldPoint(2511, 3508, 0)),
APE_ATOLL("Ape Atoll Dungeon", new WorldPoint(2762, 2703, 0)),
ARDOUGNE_CASTLE("Ardougne Castle basement", new WorldPoint(2569, 3296, 0)),
ARDOUGNE_RAT_PITS("Ardougne Rat Pits", new WorldPoint(2560, 3320, 0)),
ARDOUGNE_SEWERS_N("Ardougne Sewers", new WorldPoint(2631, 3294, 0)),
ARDOUGNE_SEWERS_S("Ardougne Sewers", new WorldPoint(2586, 3235, 0)),
ARDOUGNE_SEWERS_W("Ardougne Sewers", new WorldPoint(2528, 3303, 0)),
ASGARNIAN_ICE("Asgarnian Ice Dungeon", new WorldPoint(3007, 3150, 0)),
BRIMHAVEN_AGILITY("Brimhaven Agility Arena", new WorldPoint(2808, 3194, 0)),
BRIMHAVEN_N("Brimhaven Dungeon", new WorldPoint(2743, 3154, 0)),
BRIMHAVEN_S("Brimhaven Dungeon", new WorldPoint(2759, 3062, 0)),
BRIMSTAILS_CAVE("Brimstail's Cave", new WorldPoint(2402, 3419, 0)),
CATACOMBS_OF_KOUREND("Catacombs of Kourend", new WorldPoint(1636, 3673, 0)),
CHAMBERS_OF_XERIC("Chambers of Xeric", new WorldPoint(1232, 3573, 0)),
CHAMPIONS_CHALLENGE("Champions' Challenge", new WorldPoint(3188, 3355, 0)),
CHAOS_DRUID_TOWER("Chaos Druid Tower dungeon", new WorldPoint(2561, 3356, 0)),
CHASM_OF_FIRE("Chasm of Fire", new WorldPoint(1432, 3670, 0)),
CLOCK_TOWER("Clock Tower Dungeon", new WorldPoint(2568, 3229, 0)),
CORPOREAL_BEAST("Corporeal Beast cave", new WorldPoint(3202, 3681, 0)),
CORSAIR_COVE_E("Corsair Cove Dungeon", new WorldPoint(2522, 2861, 0)),
CORSAIR_COVE_N("Corsair Cove Dungeon", new WorldPoint(2482, 2891, 0)),
CRABCLAW_CAVES("Crabclaw Caves", new WorldPoint(1643, 3449, 0)),
CRABCLAW_CAVES_TUNNEL("Crabclaw Caves Tunnel (quest)", new WorldPoint(1643, 3449, 0)),
CRANDOR("Crandor Dungeon", new WorldPoint(2833, 3256, 0)),
CRASH_ISLAND("Crash Island Dungeon", new WorldPoint(2920, 2721, 0)),
DEEP_WILDERNESS("Deep Wilderness Dungeon", new WorldPoint(3044, 3924, 0)),
DRAYNOR_MANOR_E("Draynor Manor basement", new WorldPoint(3114, 3357, 0)),
DRAYNOR_MANOR_W("Draynor Manor basement", new WorldPoint(3091, 3362, 0)),
DRAYNOR_SEWERS_NW("Draynor Sewers", new WorldPoint(3083, 3272, 0)),
DRAYNOR_SEWERS_SE("Draynor Sewers", new WorldPoint(3117, 3244, 0)),
DWARVEN_MINE("Dwarven Mine", new WorldPoint(3017, 3450, 0)),
DWARVEN_MINE_STAIRS("Dwarven Mine", new WorldPoint(3058, 3377, 0)),
ECTOFUNTUS("Ectofuntus dungeon", new WorldPoint(3651, 3519, 0)),
EDGEVILLE("Edgeville Dungeon", new WorldPoint(3096, 3469, 0)),
EDGEVILLE_SHED("Edgeville Dungeon", new WorldPoint(3115, 3452, 0)),
EDGEVILLE_WILDERNESS("Edgeville Dungeon", new WorldPoint(3087, 3571, 0)),
ENTRANA("Entrana Dungeon", new WorldPoint(2819, 3374, 0)),
ETCETERIA("Miscellania and Etceteria Dungeon", new WorldPoint(2619, 3865, 0)),
FALADOR_MOLE_NW("Mole Hole", new WorldPoint(2985, 3387, 0)),
FALADOR_MOLE_SE("Mole Hole", new WorldPoint(2997, 3376, 0)),
FORSAKEN_TOWER("Forsaken Tower basement", new WorldPoint(1381, 3825, 0)),
FORTHOS_E("Forthos Dungeon", new WorldPoint(1701, 3574, 0)),
FORTHOS_W("Forthos Dungeon", new WorldPoint(1669, 3567, 0)),
FREMENNIK_SLAYER("Fremennik Slayer Dungeon", new WorldPoint(2796, 3615, 0)),
GOBLIN_CAVE("Goblin Cave", new WorldPoint(2622, 3393, 0)),
GOD_WARS("God Wars Dungeon", new WorldPoint(2917, 3747, 0)),
GRAND_TREE("Grand Tree Tunnels", new WorldPoint(2464, 3496, 0)),
GAUNTLET("The Gauntlet", new WorldPoint(3227, 6116, 0)),
HAM_HIDEOUT("H.A.M. Hideout", new WorldPoint(3164, 3252, 0)),
HEROES_GUILD("Heroes' Guild mine", new WorldPoint(2891, 3507, 0)),
HESPORI("Hespori Patch", new WorldPoint(1231, 3729, 0)),
ICE_QUEEN("Ice Queen's Lair", new WorldPoint(2846, 3516, 0)),
ICE_QUEEN_E("Ice Queen's Lair", new WorldPoint(2856, 3519, 0)),
ICE_QUEEN_W("Ice Queen's Lair", new WorldPoint(2822, 3510, 0)),
ICE_TROLL_E("Ice Troll Caves", new WorldPoint(2400, 3889, 0)),
ICE_TROLL_W("Ice Troll Caves", new WorldPoint(2315, 3894, 0)),
IORWERTH("Iorwerth Dungeon", new WorldPoint(3224, 6044, 0)),
IORWERTH_CAMP_CAVE("Iorwerth Camp cave", new WorldPoint(2200, 3262, 0)),
IORWERTH_CAMP_CAVE_PRIF("Iorwerth Camp cave", new WorldPoint(3224, 6014, 0)),
JOGRE("Jogre Dungeon", new WorldPoint(2824, 3118, 0)),
JORMUNGANDS_PRISON("Jormungand's Prison", new WorldPoint(2464, 4012, 0)),
KALPHITE_CAVE("Kalphite Cave", new WorldPoint(3319, 3122, 0)),
KALPHITE_LAIR("Kalphite Lair", new WorldPoint(3226, 3108, 0)),
KARAMJA_VOLCANO("Karamja Dungeon", new WorldPoint(2855, 3168, 0)),
KARUULM_SLAYER("Karuulm Slayer Dungeon", new WorldPoint(1308, 3807, 0)),
KING_BLACK_DRAGON("King Black Dragon Lair", new WorldPoint(3016, 3849, 0)),
KELDAGRIM("Keldagrim Entrance", new WorldPoint(2730, 3713, 0)),
KELDAGRIM_ENTRANCE_MOUNTAIN("Keldagrim Entrance", new WorldPoint(2795, 3718, 0)),
KRAKEN_BOSS("Kraken (boss)", new WorldPoint(2279, 10017, 0)),
KRAKEN_COVE("Kraken Cove", new WorldPoint(2277, 3611, 0)),
LAVA_MAZE("Lava Maze Dungeon", new WorldPoint(3068, 3856, 0)),
LEGENDS_GUILD("Legends' Guild dungeon", new WorldPoint(2723, 3375, 0)),
LIGHTHOUSE("Lighthouse basement", new WorldPoint(2508, 3644, 0)),
LIZARDMAN_CAVES("Lizardman Caves", new WorldPoint(1306, 3574, 0)),
LIZARDMAN_TEMPLE_E("Lizardman Temple", new WorldPoint(1329, 3669, 0)),
LIZARDMAN_TEMPLE_N("Lizardman Temple", new WorldPoint(1311, 3686, 0)),
LIZARDMAN_TEMPLE_S("Lizardman Temple", new WorldPoint(1313, 3663, 0)),
LIZARDMAN_TEMPLE_W("Lizardman Temple", new WorldPoint(1291, 3657, 0)),
LUMBRIDGE_CASTLE("Lumbridge Castle cellar", new WorldPoint(3208, 3218, 0)),
LUMBRIDGE_SWAMP("Lumbridge Swamp Caves", new WorldPoint(3168, 3172, 0)),
LUNAR_ISLE("Lunar Isle Mine", new WorldPoint(2141, 3944, 0)),
MAGE_ARENA("Mage Arena Bank", new WorldPoint(3089, 3956, 0)),
MELZARS_MAZE("Melzar's Maze basement", new WorldPoint(2923, 3250, 0)),
MINING_GUILD("Mining Guild basement", new WorldPoint(3018, 3339, 0)),
MISCELLANIA("Miscellania and Etceteria Dungeon", new WorldPoint(2508, 3846, 0)),
MOS_LE_HARMLESS("Mos Le'Harmless Cave", new WorldPoint(3747, 2973, 0)),
MOS_LE_HARMLESS_ISLAND_E("Mos Le'Harmless Cave", new WorldPoint(3829, 3062, 0)),
MOS_LE_HARMLESS_ISLAND_W("Mos Le'Harmless Cave", new WorldPoint(3814, 3062, 0)),
MOTHERLODE_MINE("Motherlode Mine", new WorldPoint(3059, 9764, 0)),
MOTHERLODE_MINE_GUILD("Motherlode Mine", new WorldPoint(3055, 9744, 0)),
MYREQUE_HIDEOUT_CANAFIS("Myreque Hideout", new WorldPoint(3494, 3464, 0)),
MYREQUE_HIDEOUT_SWAMP("Myreque Hideout", new WorldPoint(3508, 3448, 0)),
MYTH_GUILD("Myths' Guild dungeon", new WorldPoint(2456, 2847, 0)),
MYTH_GUILD_WRATH("Myths' Guild dungeon", new WorldPoint(2444, 2819, 0)),
OBSERVATORY_NE("Observatory Dungeon", new WorldPoint(2458, 3186, 0)),
OBSERVATORY_SW("Observatory Dungeon", new WorldPoint(2436, 3163, 0)),
OGRE_ENCLAVE("Ogre Enclave", new WorldPoint(2505, 3039, 0)),
OURANIA_CAVE("Ourania Cave", new WorldPoint(2451, 3231, 0)),
PATERDOMUS("Paterdomus basement", new WorldPoint(3404, 3506, 0)),
PORT_PHASMATYS_BREWERY("Port Phasmatys Brewery", new WorldPoint(3679, 3498, 0)),
PORT_SARIM_RAT_PITS("Port Sarim Rat Pits", new WorldPoint(3017, 3232, 0)),
QUIDAMORTEM_CAVE("Quidamortem Cave", new WorldPoint(1213, 3559, 0)),
RED_CHIN_HUNTING("Red chinchompa hunting ground", new WorldPoint(2525, 2894, 0)),
REVENANT_CAVES_N("Revenant Caves", new WorldPoint(3124, 3832, 0)),
REVENANT_CAVES_S("Revenant Caves", new WorldPoint(3074, 3655, 0)),
RIVER_ELID("River Elid Dungeon", new WorldPoint(3370, 3132, 0)),
RIVER_KELDA("River Kelda", new WorldPoint(2835, 10112, 0)),
SALT_MINE("Salt Mine", new WorldPoint(2866, 3941, 0)),
SCAVID_CAVES_N("Scavid Caves", new WorldPoint(2521, 3070, 0)),
SCAVID_CAVES_NE("Scavid Caves", new WorldPoint(2540, 3054, 0)),
SCAVID_CAVES_NEE("Scavid Caves", new WorldPoint(2552, 3054, 0)),
SCAVID_CAVES_E("Scavid Caves", new WorldPoint(2551, 3035, 0)),
SCAVID_CAVES_ISLAND_E("Scavid Caves (island)", new WorldPoint(2574, 3028, 0)),
SCAVID_CAVES_ISLAND_W("Scavid Caves (island)", new WorldPoint(2500, 2991, 0)),
SCAVID_CAVES_S("Scavid Caves", new WorldPoint(2528, 3014, 0)),
SCAVID_CAVES_SEE("Scavid Caves", new WorldPoint(2561, 3025, 0)),
SCORPIA_E("Scorpia cave", new WorldPoint(3243, 3949, 0)),
SCORPIA_N("Scorpia cave", new WorldPoint(3230, 3952, 0)),
SCORPIA_S("Scorpia cave", new WorldPoint(3231, 3936, 0)),
SHADE_CATACOMBS("Shade Catacombs", new WorldPoint(3484, 3321, 0)),
SHAYZIEN_CRYPTS("Shayzien Crypts", new WorldPoint(1482, 3549, 0)),
SHILO_VILLAGE_MINE("Shilo Village mine", new WorldPoint(2823, 3001, 0)),
SISTERHOOD_SANCTUARY("Sisterhood Sanctuary", new WorldPoint(3727, 3300, 0)),
SISTERHOOD_SANCTUARY_LAB("Sisterhood Sanctuary", new WorldPoint(3724, 3356, 0)),
SLAYER_TOWER("Slayer Tower basement", new WorldPoint(3416, 3535, 0)),
SLEPE_BASEMENT("Slepe basement", new WorldPoint(3718, 3307, 0)),
SMOKE_DEVIL("Smoke Devil Dungeon", new WorldPoint(2411, 3061, 0)),
SMOKE_DEVIL_BOSS("Thermonuclear Smoke Devil (boss)", new WorldPoint(2377, 9452, 0)),
SMOKE_DUNGEON("Smoke Dungeon", new WorldPoint(3309, 2962, 0)),
SOPHANEM("Sophanem Dungeon", new WorldPoint(3314, 2797, 0)),
SOURHOG_CAVE("Sourhog Cave", new WorldPoint(3149, 3347, 0)),
STRONGHOLD_OF_SECURITY("Stronghold of Security", new WorldPoint(3080, 3420, 0)),
STRONGHOLD_SLAYER("Stronghold Slayer Dungeon", new WorldPoint(2427, 3424, 0)),
TAVERLEY("Taverley Dungeon", new WorldPoint(2883, 3397, 0)),
TAVERLEY_ISLAND("Taverley Dungeon", new WorldPoint(2841, 3424, 0)),
TEMPLE_OF_IKOV("Temple of Ikov", new WorldPoint(2676, 3404, 0)),
THEATRE_OF_BLOOD("Theatre of Blood", new WorldPoint(3676, 3219, 0)),
TOLNAS_RIFT("Tolna's rift", new WorldPoint(3308, 3450, 0)),
TOWER_OF_LIFE("Tower of Life dungeon", new WorldPoint(2649, 3213, 0)),
TRAHAEARN_MINE("Trahaearn Mine", new WorldPoint(3270, 6049, 0)),
TREE_GNOME_VILLAGE("Tree Gnome Village Dungeon", new WorldPoint(2532, 3155, 0)),
TROLL_STRONGHOLD("Troll Stronghold", new WorldPoint(2838, 3690, 0)),
TROLL_STRONGHOLD_ROOF("Troll Stronghold", new WorldPoint(2830, 3677, 0)),
TROLL_STRONGHOLD_MOUNTAIN("Troll Stronghold", new WorldPoint(2826, 3647, 0)),
TUTORIAL_ISLAND_E("Tutorial Island mine", new WorldPoint(3110, 3126, 0)),
TUTORIAL_ISLAND_W("Tutorial Island mine", new WorldPoint(3087, 3119, 0)),
TZHAAR_CITY("TzHaar City (Mor Ul Rek)", new WorldPoint(2862, 9572, 0)),
UNDERGROUND_PASS_KANDARIN("Underground Pass", new WorldPoint(2312, 3215, 0)),
UNDERGROUND_PASS_TIRANNWN("Underground Pass", new WorldPoint(2433, 3315, 0)),
UNDERGROUND_PASS_TIRANNWN_PRIF("Underground Pass", new WorldPoint(3336, 5967, 0)),
UNDERWATER("Underwater", new WorldPoint(3765, 3898, 0)),
UZER("Ruins of Uzer basement", new WorldPoint(3492, 3090, 0)),
VARROCK_SEWERS("Varrock Sewers", new WorldPoint(3236, 3458, 0)),
VARROCK_SEWERS_ZOO("Varrock Sewers", new WorldPoint(3229, 3504, 0)),
VOLCANIC_MINE("Volcanic Mine", new WorldPoint(3815, 3808, 0)),
VTAM_CORP("VTAM Corporation", new WorldPoint(3243, 3383, 0)),
WARRENS("The Warrens", new WorldPoint(1812, 3745, 0)),
WARRIORS_GUILD("Warriors' Guild basement", new WorldPoint(2832, 3542, 0)),
WATERBIRTH("Waterbirth Dungeon", new WorldPoint(2520, 3740, 0)),
WATERBIRTH_MOUNTAIN("Waterbirth Dungeon", new WorldPoint(2542, 3741, 0)),
WATERBIRTH_SUBLEVELS("Waterbirth Dungeon (sub-levels)", new WorldPoint(2545, 10143, 0)),
WEISS_HOLE("Hole (shortcut to boat)", new WorldPoint(2853, 3944, 0)),
WEREWOLF_AGILITY("Werewolf Agility Course", new WorldPoint(3542, 3461, 0)),
WHITE_WOLF_TUNNEL_E("White Wolf Tunnel", new WorldPoint(2876, 3480, 0)),
WHITE_WOLF_TUNNEL_W("White Wolf Tunnel", new WorldPoint(2819, 3484, 0)),
WILDERNESS_AGILITY("Wilderness Agility Course Dungeon", new WorldPoint(3004, 3963, 0)),
WILDERNESS_GOD_WARS("Wilderness God Wars Dungeon", new WorldPoint(3016, 3739, 0)),
WILDERNESS_SLAYER_CAVE_NORTH("Wilderness Slayer Cave", new WorldPoint(3292, 3746, 0)),
WILDERNESS_SLAYER_CAVE_SOUTH("Wilderness Slayer Cave", new WorldPoint(3259, 3666, 0)),
WITCHAVEN("Witchaven Dungeon", new WorldPoint(2695, 3283, 0)),
WIZARDS_GUILD("Wizards' Guild basement", new WorldPoint(2593, 3085, 0)),
WIZARDS_TOWER("Wizards' Tower basement", new WorldPoint(3103, 3162, 0)),
WOODCUTTING_GUILD("Woodcutting Guild dungeon", new WorldPoint(1603, 3508, 0)),
WYVERN_CAVE("Wyvern Cave", new WorldPoint(3745, 3779, 0)),
WYVERN_CAVE_TASK("Wyvern Cave (task only)", new WorldPoint(3677, 3854, 0)),
YANILLE_AGILITY("Yanille Agility Dungeon", new WorldPoint(2568, 3122, 0)),
YANILLE_AGILITY_CITY("Yanille Agility Dungeon", new WorldPoint(2603, 3078, 0)),
ZALCANO("Zalcano's Prison", new WorldPoint(3280, 6059, 0)),
ZOGRE_CAVE("Zogre cave", new WorldPoint(2484, 3043, 0));
private final String tooltip;
private final WorldPoint location;
DungeonLocation(String tooltip, WorldPoint location)
{
this.tooltip = tooltip;
this.location = location;
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 2020, Arman S <https://github.com/Rman887>
* 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.worldmap;
import java.awt.image.BufferedImage;
import net.runelite.client.ui.overlay.worldmap.WorldMapPoint;
class DungeonPoint extends WorldMapPoint
{
DungeonPoint(DungeonLocation data, BufferedImage icon)
{
super(data.getLocation(), icon);
setTooltip(data.getTooltip());
}
}

View File

@@ -0,0 +1,80 @@
/*
* 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 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.worldmap;
import lombok.Getter;
import net.runelite.api.coords.WorldPoint;
@Getter
enum FairyRingLocation
{
AIR("AIR", new WorldPoint(2699, 3249, 0)),
AIQ("AIQ", new WorldPoint(2995, 3112, 0)),
AJR("AJR", new WorldPoint(2779, 3615, 0)),
AJS("AJS", new WorldPoint(2499, 3898, 0)),
AKQ("AKQ", new WorldPoint(2318, 3617, 0)),
AKS("AKS", new WorldPoint(2570, 2958, 0)),
ALP("ALP", new WorldPoint(2502, 3638, 0)),
ALQ("ALQ", new WorldPoint(3598, 3496, 0)),
ALS("ALS", new WorldPoint(2643, 3497, 0)),
BIP("BIP", new WorldPoint(3409, 3326, 0)),
BIQ("BIQ", new WorldPoint(3248, 3095, 0)),
BIS("BIS", new WorldPoint(2635, 3268, 0)),
BJS("BJS", new WorldPoint(2147, 3069, 0)),
BKP("BKP", new WorldPoint(2384, 3037, 0)),
BKR("BKR", new WorldPoint(3468, 3433, 0)),
BLP("BLP", new WorldPoint(2432, 5127, 0)),
BLR("BLR", new WorldPoint(2739, 3353, 0)),
CIP("CIP", new WorldPoint(2512, 3886, 0)),
CIR("CIR", new WorldPoint(1303, 3762, 0)),
CIQ("CIQ", new WorldPoint(2527, 3129, 0)),
CJR("CJR", new WorldPoint(2704, 3578, 0)),
CKR("CKR", new WorldPoint(2800, 3005, 0)),
CKS("CKS", new WorldPoint(3446, 3472, 0)),
CLP("CLP", new WorldPoint(3081, 3208, 0)),
CLS("CLS", new WorldPoint(2681, 3083, 0)),
DIP("DIP", new WorldPoint(3039, 4757, 0)),
DIS("DIS", new WorldPoint(3109, 3149, 0)),
DJP("DJP", new WorldPoint(2657, 3232, 0)),
DJR("DJR", new WorldPoint(1452, 3659, 0)),
DKP("DKP", new WorldPoint(2899, 3113, 0)),
DKR("DKR", new WorldPoint(3126, 3496, 0)),
DKS("DKS", new WorldPoint(2743, 3721, 0)),
DLQ("DLQ", new WorldPoint(3422, 3018, 0)),
DLR("DLR", new WorldPoint(2212, 3101, 0)),
CIS("CIS", new WorldPoint(1638, 3868, 0)),
CLR("CLR", new WorldPoint(2737, 2739, 0)),
ZANARIS("Zanaris", new WorldPoint(2411, 4436, 0));
private final String code;
private final WorldPoint location;
FairyRingLocation(String code, WorldPoint location)
{
this.code = code;
this.location = location;
}
}

View File

@@ -0,0 +1,42 @@
/*
* 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 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.worldmap;
import java.awt.image.BufferedImage;
import net.runelite.client.ui.overlay.worldmap.WorldMapPoint;
class FairyRingPoint extends WorldMapPoint
{
FairyRingPoint(FairyRingLocation data, BufferedImage icon, boolean showTooltip)
{
super(data.getLocation(), icon);
if (showTooltip)
{
setTooltip("Fairy Ring - " + data.getCode());
}
}
}

View File

@@ -0,0 +1,116 @@
/*
* Copyright (c) 2018, Torkel Velure <https://github.com/TorkelV>
* 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.worldmap;
import lombok.Getter;
import net.runelite.api.coords.WorldPoint;
@Getter
enum FarmingPatchLocation
{
ALLOTMENT("Allotment",
new WorldPoint(3793, 2836, 0),
new WorldPoint(1269, 3730, 0)
),
ALLOTMENT_FLOWER("Allotment/Flower", new WorldPoint(3289, 6100, 0)),
ALLOTMENT_HERB_FLOWER("Allotment/Herb/Flower",
new WorldPoint(1729, 3558, 0),
new WorldPoint(3598, 3524, 0),
new WorldPoint(3052, 3309, 0),
new WorldPoint(2810, 3462, 0),
new WorldPoint(2663, 3375, 0)
),
ANIMA_HERB("Anima/Herb", new WorldPoint(1235, 3724, 0)),
BELLADONNA("Belladonna", new WorldPoint(3084, 3356, 0)),
BUSH("Bush",
new WorldPoint(2938, 3223, 0),
new WorldPoint(2589, 3862, 0),
new WorldPoint(3182, 3356, 0),
new WorldPoint(2615, 3224, 0)
),
BUSH_FLOWER("Bush/Flower", new WorldPoint(1259, 3729, 0)),
CACTUS("Cactus",
new WorldPoint(3313, 3201, 0),
new WorldPoint(1264, 3745, 0)
),
CALQUAT("Calquat", new WorldPoint(2793, 3099, 0)),
CELASTRUS_FRUIT_TREE("Celastrus/Fruit Tree",
new WorldPoint(1242, 3755, 0)
),
CRYSTAL_TREE("Crystal Tree",
new WorldPoint(3292, 6120, 0)
),
FRUIT_TREE("Fruit Tree",
new WorldPoint(2487, 3181, 0),
new WorldPoint(2343, 3160, 0),
new WorldPoint(2472, 3445, 0),
new WorldPoint(2858, 3432, 0),
new WorldPoint(2765, 3211, 0)
),
GRAPES("Grapes", new WorldPoint(1807, 3555, 0)),
HARDWOOD("Hardwood",
new WorldPoint(3707, 3838, 0)
),
HERB("Herb",
new WorldPoint(3789, 2840, 0),
new WorldPoint(2847, 3933, 0),
new WorldPoint(2828, 3696, 0)
),
HESPORI("Hespori", new WorldPoint(1182, 10068, 0)),
HOPS("Hops",
new WorldPoint(2572, 3102, 0),
new WorldPoint(2661, 3523, 0),
new WorldPoint(3224, 3313, 0),
new WorldPoint(3812, 3334, 0)
),
MUSHROOM("Mushroom", new WorldPoint(3449, 3471, 0)),
REDWOOD("Redwood", new WorldPoint(1233, 3754, 0)),
SEAWEED("Seaweed", new WorldPoint(3730, 10271, 0)),
SPIRIT_TREE("Spirit Tree",
new WorldPoint(3056, 3259, 0),
new WorldPoint(1690, 3540, 0),
new WorldPoint(3614, 3856, 0),
new WorldPoint(2799, 3205, 0),
new WorldPoint(1254, 3753, 0)
),
TREE("Tree",
new WorldPoint(3226, 3457, 0),
new WorldPoint(2933, 3436, 0),
new WorldPoint(3189, 3233, 0),
new WorldPoint(2434, 3418, 0),
new WorldPoint(3005, 3375, 0),
new WorldPoint(1234, 3736, 0)
);
private final String tooltip;
private final WorldPoint[] locations;
FarmingPatchLocation(String description, WorldPoint... locations)
{
this.tooltip = "Farming patch - " + description;
this.locations = locations;
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (c) 2018, Torkel Velure <https://github.com/TorkelV>
* 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.worldmap;
import java.awt.image.BufferedImage;
import net.runelite.api.coords.WorldPoint;
import net.runelite.client.ui.overlay.worldmap.WorldMapPoint;
class FarmingPatchPoint extends WorldMapPoint
{
FarmingPatchPoint(WorldPoint point, String tooltip, BufferedImage icon)
{
super(point, icon);
setTooltip(tooltip);
}
}

View File

@@ -0,0 +1,189 @@
/*
* Copyright (c) 2020, melky <https://github.com/melkypie>
* 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.worldmap;
import java.util.Arrays;
import java.util.stream.Collectors;
import lombok.Getter;
import net.runelite.api.coords.WorldPoint;
import net.runelite.client.game.FishingSpot;
@Getter
enum FishingSpotLocation
{
AL_KHARID(FishingSpot.SHRIMP,
new WorldPoint(3274, 3140, 0), new WorldPoint(3266, 3148, 0)),
APE_ATOLL_SOUTH_WEST(FishingSpot.SHARK, new WorldPoint(2698, 2703, 0)),
BARBARIAN_OUTPOST(FishingSpot.SHRIMP,
new WorldPoint(2497, 3548, 0), new WorldPoint(2509, 3562, 0),
new WorldPoint(2514, 3575, 0)),
BARBARIAN_VILLAGE(FishingSpot.SALMON,
new WorldPoint(3103, 3424, 0), new WorldPoint(3109, 3433, 0)),
BRAINDEATH_ISLAND(FishingSpot.QUEST_RUM_DEAL,
new WorldPoint(2112, 5074, 0), new WorldPoint(2161, 5061, 0),
new WorldPoint(2172, 5074, 0)),
BRIMHAVEN_QUEST(FishingSpot.QUEST_TAI_BWO_WANNAI_TRIO, new WorldPoint(2767, 3165, 0)),
BURGH_DE_ROTT_SOUTH(FishingSpot.SHARK,
new WorldPoint(3472, 3192, 0), new WorldPoint(3486, 3182, 0),
new WorldPoint(3497, 3174, 0), new WorldPoint(3513, 3177, 0),
new WorldPoint(3528, 3164, 0), new WorldPoint(3537, 3177, 0),
new WorldPoint(3545, 3179, 0), new WorldPoint(3553, 3177, 0),
new WorldPoint(3559, 3173, 0), new WorldPoint(3564, 3174, 0)),
CATHERBY(new FishingSpot[]{FishingSpot.SHARK, FishingSpot.LOBSTER, FishingSpot.SHRIMP},
new WorldPoint(2836, 3431, 0), new WorldPoint(2844, 3429, 0),
new WorldPoint(2853, 3423, 0), new WorldPoint(2859, 3426, 0)),
DRAYNOR_VILLAGE(FishingSpot.SHRIMP, new WorldPoint(3084, 3228, 0)),
ENTRANA_CENTER(FishingSpot.SALMON,
new WorldPoint(2841, 3356, 0), new WorldPoint(2842, 3359, 0),
new WorldPoint(2847, 3361, 0)),
ENTRANA_DOCK(FishingSpot.SHRIMP,
new WorldPoint(2875, 3331, 0), new WorldPoint(2878, 3334, 0),
new WorldPoint(2878, 3339, 0), new WorldPoint(2875, 3342, 0)),
ETCETERIA_DOCK(FishingSpot.ETCETERIA_LOBSTER, new WorldPoint(2577, 3854, 0)),
FAIRY_RING_CKR(FishingSpot.KARAMBWANJI, new WorldPoint(2806, 3014, 0)),
FAIRY_RING_DKP(FishingSpot.KARAMBWAN,
new WorldPoint(2898, 3119, 0), new WorldPoint(2911, 3119, 0)),
FARMING_GUILD_SOUTH_EAST(FishingSpot.SALMON, new WorldPoint(1269, 3707, 0)),
FARMING_GUILD_SOUTH_WEST1(FishingSpot.SHARK, new WorldPoint(1209, 3687, 0)),
FARMING_GUILD_SOUTH_WEST2(FishingSpot.SHARK, new WorldPoint(1221, 3714, 0)),
FARMING_GUILD_WEST(FishingSpot.SHARK,
new WorldPoint(1199, 3736, 0), new WorldPoint(1208, 3749, 0)),
FELDIP_HILLS_SOUTH(FishingSpot.SHRIMP, new WorldPoint(2511, 2838, 0)),
FISHING_CONTEST(FishingSpot.QUEST_FISHING_CONTEST,
new WorldPoint(2626, 3415, 0), new WorldPoint(2631, 3425, 0),
new WorldPoint(2629, 3435, 0), new WorldPoint(2636, 3444, 0)),
FISHING_GUILD(new FishingSpot[]{FishingSpot.SHARK, FishingSpot.LOBSTER},
new WorldPoint(2604, 3423, 0), new WorldPoint(2605, 3417, 0),
new WorldPoint(2611, 3413, 0)),
FISHING_GUILD_PLATFORM(FishingSpot.MINNOW,
new WorldPoint(2609, 3444, 0), new WorldPoint(2617, 3444, 0)),
FISHING_PLATFORM(FishingSpot.SHRIMP,
new WorldPoint(2788, 3273, 0), new WorldPoint(2794, 3279, 0),
new WorldPoint(2793, 3283, 0)),
HOSIDIUS_CENTER(FishingSpot.SALMON, new WorldPoint(1715, 3612, 0)),
HOSIDIUS_EAST(new FishingSpot[]{FishingSpot.SHARK, FishingSpot.LOBSTER, FishingSpot.SHRIMP},
new WorldPoint(1817, 3603, 0), new WorldPoint(1827, 3605, 0),
new WorldPoint(1828, 3614, 0), new WorldPoint(1840, 3619, 0),
new WorldPoint(1838, 3595, 0)),
INFIRMARY_SOUTH(FishingSpot.SALMON, new WorldPoint(1584, 3566, 0)),
IORWERTH_CAMP_INSIDE(FishingSpot.SALMON, new WorldPoint(3239, 5997, 0)),
IORWERTH_CAMP_NORTH_INSIDE(FishingSpot.SHARK, new WorldPoint(3185, 6027, 0)),
IORWERTH_CAMP_NORTH_OUTSIDE(FishingSpot.SHARK, new WorldPoint(2161, 3275, 0)),
IORWERTH_CAMP_OUTSIDE(FishingSpot.SALMON, new WorldPoint(2215, 3245, 0)),
ISAFDAR_NORTH_EAST_INSIDE(FishingSpot.SALMON, new WorldPoint(3293, 6005, 0)),
ISAFDAR_NORTH_EAST_OUTSIDE(FishingSpot.SALMON, new WorldPoint(2269, 3253, 0)),
JATISZO(new FishingSpot[]{FishingSpot.SHARK, FishingSpot.LOBSTER},
new WorldPoint(2400, 3780, 0), new WorldPoint(2412, 3780, 0),
new WorldPoint(2419, 3789, 0)),
KINGSTOWN_EAST(FishingSpot.SALMON, new WorldPoint(1723, 3685, 0)),
LANDS_END_EAST(FishingSpot.SHRIMP, new WorldPoint(1534, 3414, 0)),
LANDS_END_WEST(new FishingSpot[]{FishingSpot.SHARK, FishingSpot.LOBSTER, FishingSpot.SHRIMP},
new WorldPoint(1484, 3432, 0)),
LUMBRIDGE_RIVER(FishingSpot.SALMON,
new WorldPoint(3238, 3241, 0), new WorldPoint(3237, 3253, 0)),
LUMBRIDGE_SWAMP_CAVE_EAST(FishingSpot.CAVE_EEL, new WorldPoint(3244, 9570, 0)),
LUMBRIDGE_SWAMP_CAVE_WEST(FishingSpot.CAVE_EEL, new WorldPoint(3153, 9544, 0)),
LUMBRIDGE_SWAMP_SOUTH_EAST(FishingSpot.SHRIMP, new WorldPoint(3244, 3153, 0)),
MARIM(FishingSpot.SHARK, new WorldPoint(2774, 2740, 0)),
MOLCH_ISLAND(FishingSpot.COMMON_TENCH, new WorldPoint(1370, 3632, 0)),
MORTTON(FishingSpot.SLIMY_EEL, new WorldPoint(3439, 3273, 0)),
MORT_MYRE_SWAMP_NORTH(FishingSpot.SLIMY_EEL,
new WorldPoint(3480, 3433, 0), new WorldPoint(3485, 3448, 0)),
MORT_MYRE_SWAMP_WEST(FishingSpot.SLIMY_EEL,
new WorldPoint(3425, 3409, 0), new WorldPoint(3432, 3415, 0)),
MOR_UL_REK(FishingSpot.INFERNAL_EEL,
new WorldPoint(2443, 5104, 0), new WorldPoint(2476, 5077, 0),
new WorldPoint(2537, 5086, 0)),
MOUNT_QUIDAMORTEM(FishingSpot.BARB_FISH,
new WorldPoint(1271, 3546, 0), new WorldPoint(1265, 3541, 0),
new WorldPoint(1253, 3542, 0)),
MUDSKIPPER_POINT(FishingSpot.SHRIMP,
new WorldPoint(2995, 3158, 0), new WorldPoint(2985, 3176, 0)),
MUSA_POINT(new FishingSpot[]{FishingSpot.LOBSTER, FishingSpot.SHRIMP}, new WorldPoint(2925, 3179, 0)),
MYTHS_GUILD_NORTH(FishingSpot.LOBSTER, new WorldPoint(2456, 2893, 0)),
OBSERVATORY_EAST(FishingSpot.SALMON, new WorldPoint(2466, 3151, 0)),
OTTOS_GROTTO(FishingSpot.BARB_FISH,
new WorldPoint(2500, 3509, 0), new WorldPoint(2504, 3495, 0),
new WorldPoint(2505, 3515, 0), new WorldPoint(2520, 3518, 0)),
PISCATORIS(FishingSpot.MONKFISH, new WorldPoint(2308, 3700, 0)),
PORT_PISCARILIUS_EAST(FishingSpot.ANGLERFISH, new WorldPoint(1831, 3773, 0)),
PORT_PISCARILIUS_WEST(new FishingSpot[]{FishingSpot.LOBSTER, FishingSpot.SHRIMP},
new WorldPoint(1762, 3796, 0), new WorldPoint(1745, 3802, 0)),
PRIFFDINAS_INSIDE_EAST(new FishingSpot[]{FishingSpot.SHARK, FishingSpot.LOBSTER},
new WorldPoint(3186, 6102, 0), new WorldPoint(3187, 6123, 0)),
PRIFFDINAS_INSIDE_NORTH(new FishingSpot[]{FishingSpot.SHARK, FishingSpot.LOBSTER},
new WorldPoint(3250, 6182, 0), new WorldPoint(3258, 6180, 0),
new WorldPoint(3258, 6197, 0)),
PRIFFDINAS_OUTSIDE_EAST(new FishingSpot[]{FishingSpot.SHARK, FishingSpot.LOBSTER},
new WorldPoint(2162, 3350, 0), new WorldPoint(2163, 3371, 0)),
PRIFFDINAS_OUTSIDE_NORTH(new FishingSpot[]{FishingSpot.SHARK, FishingSpot.LOBSTER},
new WorldPoint(2226, 3430, 0), new WorldPoint(2234, 3428, 0),
new WorldPoint(2234, 3445, 0)),
RELLEKKA_CENTER(FishingSpot.LOBSTER, new WorldPoint(2641, 3696, 0)),
RELLEKKA_NORTH_EAST(FishingSpot.SHARK, new WorldPoint(2649, 3708, 0)),
RELLEKKA_WEST(FishingSpot.SHRIMP, new WorldPoint(2632, 3694, 0)),
RIVER_ARDOUGNE(FishingSpot.SALMON,
new WorldPoint(2560, 3374, 0), new WorldPoint(2565, 3370, 0),
new WorldPoint(2526, 3412, 0), new WorldPoint(2536, 3405, 0),
new WorldPoint(2507, 3420, 0)),
SAND_CRAB_PENINSULA_NORTH(FishingSpot.SHARK, new WorldPoint(1675, 3490, 0)),
SAND_CRAB_PENINSULA_SOUTH(FishingSpot.SHRIMP, new WorldPoint(1676, 3469, 0)),
SAND_CRAB_PENINSULA_WEST(FishingSpot.LOBSTER, new WorldPoint(1668, 3479, 0)),
SEERS_VILLAGE(FishingSpot.SALMON,
new WorldPoint(2725, 3524, 0), new WorldPoint(2714, 3531, 0)),
SHILO_VILLAGE(FishingSpot.SALMON,
new WorldPoint(2854, 2977, 0), new WorldPoint(2858, 2973, 0)),
TAVERLEY_DUNGEON(FishingSpot.LAVA_EEL,
new WorldPoint(2893, 9764, 0), new WorldPoint(2889, 9766, 0),
new WorldPoint(2883, 9765, 0)),
TREE_GNOME_STRONGHOLD(FishingSpot.SALMON,
new WorldPoint(2389, 3422, 0), new WorldPoint(2382, 3415, 0)),
TUTORIAL_ISLAND(FishingSpot.TUTORIAL_SHRIMP, new WorldPoint(3100, 3091, 0)),
WATSON_HOUSE_SOUTH(FishingSpot.SALMON, new WorldPoint(1646, 3558, 0)),
WILDERNESS_BANDIT_CAMP(FishingSpot.SHRIMP, new WorldPoint(3049, 3704, 0)),
WILDERNESS_DARK_CRABS(FishingSpot.DARK_CRAB,
new WorldPoint(3362, 3802, 0), new WorldPoint(3347, 3813, 0)),
WILDERNESS_LAVA_MAZE(FishingSpot.LAVA_EEL, new WorldPoint(3071, 3840, 0)),
WILDERNESS_RESOURCE_AREA(FishingSpot.DARK_CRAB, new WorldPoint(3186, 3925, 0)),
ZUL_ANDRA(FishingSpot.SACRED_EEL,
new WorldPoint(2183, 3068, 0), new WorldPoint(2195, 3067, 0)),
;
private final WorldPoint[] locations;
private final String tooltip;
FishingSpotLocation(FishingSpot fishingSpot, WorldPoint... locations)
{
this.tooltip = fishingSpot.getWorldMapTooltip();
this.locations = locations;
}
FishingSpotLocation(FishingSpot[] fishingSpot, WorldPoint... locations)
{
this.tooltip = Arrays.stream(fishingSpot).map(FishingSpot::getWorldMapTooltip).collect(Collectors.joining(" / "));
this.locations = locations;
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (c) 2020, melky <https://github.com/melkypie>
* 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.worldmap;
import java.awt.image.BufferedImage;
import net.runelite.api.coords.WorldPoint;
import net.runelite.client.ui.overlay.worldmap.WorldMapPoint;
class FishingSpotPoint extends WorldMapPoint
{
FishingSpotPoint(WorldPoint point, String tooltip, BufferedImage icon)
{
super(point, icon);
setTooltip(tooltip);
}
}

View File

@@ -0,0 +1,136 @@
/*
* Copyright (c) 2020, melky <https://github.com/melkypie>
* 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.worldmap;
import com.google.common.base.Joiner;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.runelite.api.coords.WorldPoint;
@Getter
enum HunterAreaLocation
{
BONEYARD_HUNTER_AREA(new WorldPoint(3294, 3673, 0), HunterCreature.BLACK_SALAMANDER),
CANIFIS_HUNTER_AREA1(new WorldPoint(3553, 3438, 0), HunterCreature.SWAMP_LIZARD),
CANIFIS_HUNTER_AREA2(new WorldPoint(3535, 3445, 0), HunterCreature.SWAMP_LIZARD),
FALCONRY(new WorldPoint(2379, 3599, 0), HunterCreature.SPOTTED_KEBBIT, HunterCreature.DARK_KEBBIT,
HunterCreature.DASHING_KEBBIT, HunterCreature.GREATER_SIREN),
FELDIP_HUNTER_AREA(new WorldPoint(2557, 2912, 0), HunterCreature.CRIMSON_SWIFT, HunterCreature.FELDIP_WEASEL,
HunterCreature.TROPICAL_WAGTAIL, HunterCreature.SPINED_LARUPIA, HunterCreature.BARB_TAILED_KEBBIT,
HunterCreature.BLACK_WARLOCK, HunterCreature.CARNIVOROUS_CHINCHOMPA),
FOSSIL_ISLAND1(new WorldPoint(3693, 3800, 0), HunterCreature.HERBIBOAR),
FOSSIL_ISLAND2(new WorldPoint(3701, 3809, 0), HunterCreature.HERBIBOAR),
FOSSIL_ISLAND3(new WorldPoint(3703, 3829, 0), HunterCreature.HERBIBOAR),
FOSSIL_ISLAND4(new WorldPoint(3749, 3850, 0), HunterCreature.HERBIBOAR),
FOSSIL_ISLAND5(new WorldPoint(3684, 3870, 0), HunterCreature.HERBIBOAR),
FOSSIL_ISLAND_UNDERWATER(new WorldPoint(3743, 10295, 0), HunterCreature.FISH_SHOAL),
GWENITH_HUNTER_AREA_OUTSIDE(new WorldPoint(2269, 3408, 0), HunterCreature.CARNIVOROUS_CHINCHOMPA),
GWENITH_HUNTER_AREA_INSIDE(new WorldPoint(3293, 6160, 0), HunterCreature.CARNIVOROUS_CHINCHOMPA),
KARAMJA_HUNTER_AREA(new WorldPoint(2786, 3001, 0), HunterCreature.HORNED_GRAAHK),
KEBOS_SWAMP(new WorldPoint(1184, 3595, 0), HunterCreature.CRIMSON_SWIFT),
KOUREND_WOODLAND_CENTER(new WorldPoint(1512, 3478, 0), HunterCreature.RUBY_HARVEST),
KOUREND_WOODLAND_NORTH_WEST(new WorldPoint(1481, 3504, 0), HunterCreature.CHINCHOMPA),
KOUREND_WOODLAND_SOUTH(new WorldPoint(1556, 3436, 0), HunterCreature.COPPER_LONGTAIL),
LAKE_MOLCH(new WorldPoint(1363, 3632, 0), HunterCreature.BLUEGILL, HunterCreature.COMMON_TENCH,
HunterCreature.MOTTLED_EEL, HunterCreature.GREATER_SIREN),
OURANIA_HUNTER_AREA_EAST(new WorldPoint(2447, 3219, 0), HunterCreature.RED_SALAMANDER),
OURANIA_HUNTER_AREA_SOUTH(new WorldPoint(2475, 3240, 0), HunterCreature.RED_SALAMANDER),
PISCATORIS_HUNTER_AREA(new WorldPoint(2335, 3584, 0), HunterCreature.COMMON_KEBBIT, HunterCreature.COPPER_LONGTAIL,
HunterCreature.RUBY_HARVEST, HunterCreature.WILD_KEBBIT, HunterCreature.FERRET, HunterCreature.WHITE_RABBIT,
HunterCreature.PRICKLY_KEBBIT, HunterCreature.RAZOR_BACKED_KEBBIT, HunterCreature.CHINCHOMPA),
RELLEKA_HUNTER_AREA(new WorldPoint(2719, 3780, 0), HunterCreature.POLAR_KEBBIT, HunterCreature.CERULEAN_TWITCH,
HunterCreature.SAPPHIRE_GLACIALIS, HunterCreature.SNOWY_KNIGHT,
HunterCreature.SABRE_TOOTHED_KEBBIT, HunterCreature.SABRE_TOOTHED_KYATT),
SLEPE_NORTH(new WorldPoint(3677, 3405, 0), HunterCreature.SWAMP_LIZARD),
UZER_HUNTER_AREA(new WorldPoint(3401, 3104, 0), HunterCreature.GOLDEN_WARBLER, HunterCreature.DESERT_DEVIL,
HunterCreature.ORANGE_SALAMANDER),
WILDERNESS(new WorldPoint(3142, 3771, 0), HunterCreature.BLACK_CHINCHOMPA),
;
private final WorldPoint location;
private final String tooltip;
HunterAreaLocation(WorldPoint location, HunterCreature... creatures)
{
this.location = location;
this.tooltip = Joiner.on("<br>").join(creatures);
}
@AllArgsConstructor
private enum HunterCreature
{
BARB_TAILED_KEBBIT("Barb-tailed kebbit", 33),
BLACK_CHINCHOMPA("Black chinchompa", 73),
BLACK_SALAMANDER("Black salamander", 67),
BLACK_WARLOCK("Black warlock", 45),
BLUEGILL("Bluegill", 35),
CARNIVOROUS_CHINCHOMPA("Carnivorous chinchompa", 63),
CERULEAN_TWITCH("Cerulean twitch", 11),
CHINCHOMPA("Chinchompa", 53),
COMMON_KEBBIT("Common kebbit", 3),
COMMON_TENCH("Common tench", 51),
COPPER_LONGTAIL("Copper longtail", 9),
CRIMSON_SWIFT("Crimson swift", 1),
DARK_KEBBIT("Dark kebbit", 57),
DASHING_KEBBIT("Dashing kebbit", 69),
DESERT_DEVIL("Desert devil", 13),
FELDIP_WEASEL("Feldip Weasel", 7),
FERRET("Ferret", 27),
FISH_SHOAL("Fish shoal", 44),
GOLDEN_WARBLER("Golden warbler", 5),
GREATER_SIREN("Greater siren", 87),
HERBIBOAR("Herbiboar", 80),
HORNED_GRAAHK("Horned graahk", 41),
// IMP and MANIACAL_MONKEY do not have a specific hunter area
MOTTLED_EEL("Mottled eel", 68),
ORANGE_SALAMANDER("Orange salamander", 47),
POLAR_KEBBIT("Polar kebbit", 1),
PRICKLY_KEBBIT("Prickly kebbit", 37),
RAZOR_BACKED_KEBBIT("Razor-backed kebbit", 49),
RED_SALAMANDER("Red salamander", 59),
RUBY_HARVEST("Ruby harvest", 15),
SABRE_TOOTHED_KEBBIT("Sabre-toothed kebbit", 51),
SABRE_TOOTHED_KYATT("Sabre-toothed kyatt", 55),
SAPPHIRE_GLACIALIS("Sapphire glacialis", 25),
SNOWY_KNIGHT("Snowy knight", 35),
SPINED_LARUPIA("Spined larupia", 31),
SPOTTED_KEBBIT("Spotted kebbit", 43),
SWAMP_LIZARD("Swamp lizard", 29),
TROPICAL_WAGTAIL("Tropical wagtail", 19),
WHITE_RABBIT("White rabbit", 27),
WILD_KEBBIT("Wild kebbit", 23),
;
private String name;
private int level;
@Override
public String toString()
{
return name + " (" + level + ")";
}
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 2020, melky <https://github.com/melkypie>
* 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.worldmap;
import java.awt.image.BufferedImage;
import net.runelite.client.ui.overlay.worldmap.WorldMapPoint;
class HunterAreaPoint extends WorldMapPoint
{
HunterAreaPoint(HunterAreaLocation data, BufferedImage icon)
{
super(data.getLocation(), icon);
setTooltip(data.getTooltip());
}
}

View File

@@ -0,0 +1,80 @@
/*
* Copyright (c) 2020, Brooklyn <https://github.com/Broooklyn>
* 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.worldmap;
import lombok.Getter;
import net.runelite.api.coords.WorldPoint;
@Getter
enum KourendTaskLocation
{
ARCEUUS_LIBRARY_SOUTH("Arceuus Task (0%) - Library Assistance", new WorldPoint(1622, 3801, 0)),
ARCEUUS_LIBRARY_NORTH("Arceuus Task (0%) - Library Assistance", new WorldPoint(1638, 3817, 0)),
ARCEUUS_DENSE_ESSENCE("Arceuus Task (25%) - Dense Essence Mining", new WorldPoint(1757, 3852, 0)),
ARCEUUS_REANIMATE_CREATURES("Arceuus Task (60%) - Creature Reanimation", new WorldPoint(1714, 3883, 0)),
ARCEUUS_BLOOD_ALTAR("Arceuus Unlock (100%) - Blood Rune Crafting", new WorldPoint(1716, 3829, 0)),
ARCEUUS_SOUL_ALTAR("Arceuus Unlock (100%) - Soul Rune Crafting", new WorldPoint(1814, 3854, 0)),
HOSIDIUS_PLOUGH_NORTH("Hosidius Task (0%) - Ploughs", new WorldPoint(1770, 3550, 0)),
HOSIDIUS_PLOUGH_SOUTH("Hosidius Task (0%) - Ploughs", new WorldPoint(1769, 3528, 0)),
HOSIDUIS_FERTILISER("Hosidius Task (5%) - Making Fertilizer", new WorldPoint(1701, 3527, 0)),
HOSIDIUS_SPIRIT_TREE("Hosidius Unlock (35%) - Spirit Tree Patch", new WorldPoint(1695, 3545, 0)),
HOSIDIUS_MESS("Hosidius Task (45%) - Mess", new WorldPoint(1639, 3629, 0)),
HOSIDIUS_FARMING_PATCH("Hosidius Unlock (50%) - Disease Protection", new WorldPoint(1740, 3552, 0)),
HOSIDIUS_VINERY("Hosidius Task (65%) - Grape Planting", new WorldPoint(1804, 3564, 0)),
HOSIDIUS_TITHE_FARM("Hosidius Unlock (100%) - Tithe Farm", new WorldPoint(1802, 3499, 0)),
HOSIDIUS_KITCHEN("Hosidius Unlock (100%) - Kitchen", new WorldPoint(1678, 3618, 0)),
LOVAKENGJ_DYNAMITE("Lovakengj Task (0%) - Making Juniper Charcoal", new WorldPoint(1718, 3472, 0)),
LOVAKENGJ_SULFUR("Lovakengj Task (0%) - Mining Volcanic Sulphur", new WorldPoint(1437, 3861, 0)),
LOVAKENGJ_ARMOURER_T1("Lovakengj Task (30%) - Armourer (Tier 1)", new WorldPoint(1453, 3750, 0)),
LOVAKENGJ_ARMOURER_T2("Lovakengj Task (40%) - Armourer (Tier 2)", new WorldPoint(1436, 3784, 0)),
LOVAKENGJ_ARMOURER_T3("Lovakengj Task (50%) - Armourer (Tier 3)", new WorldPoint(1430, 3797, 0)),
LOVAKENGJ_ARMOURER_T4("Lovakengj Task (60%) - Armourer (Tier 4)", new WorldPoint(1460, 3763, 0)),
LOVAKENGJ_ARMOURER_T5("Lovakengj Task (70%) - Armourer (Tier 5)", new WorldPoint(1524, 3755, 0)),
LOVAKENGJ_BLAST_MINE("Lovakengj Unlock (100%) - Blast Mine", new WorldPoint(1488, 3865, 0)),
PISCARILIUS_CRANE_REPAIR("Piscarilius Task (0%) - Fishing Crane Repair", new WorldPoint(1820, 3742, 0)),
PISCARILIUS_FRESH_FISH("Piscarilius Task (15%) - Fish Delivery", new WorldPoint(1831, 3716, 0)),
PISCARILIUS_SANDWORMS("Piscarilius Task (30%) - Hunting Sandworms", new WorldPoint(1841, 3789, 0)),
PISCARILIUS_STEALING_ARTEFACTS("Piscarilius Task (75%) - Stealing Artefacts", new WorldPoint(1849, 3753, 0)),
SHAYZIEN_HEALING_SOLDIERS("Shayzien Task (0%) - Healing Wounded Soldiers", new WorldPoint(1572, 3581, 0)),
SHAYZIEN_LIZARDMEN_EAST("Shayzien Task (5%) - Killing Lizardmen", new WorldPoint(1570, 3668, 0)),
SHAYZIEN_LIZARDMEN_WEST("Shayzien Task (5%) - Killing Lizardmen", new WorldPoint(1471, 3686, 0)),
SHAYZIEN_ORGANIZED_CRIME("Shayzien Task (40%) - Organized Crime", new WorldPoint(1565, 3605, 0)),
SHAYZIEN_COMBAT_RING("Shayzien Task (60%) - Combat Ring", new WorldPoint(1539, 3589, 0)),
SHAYZIEN_LIZARDMAN_SHAMANS("Shayzien Unlock (100%) - Lizardman Shamans", new WorldPoint(1455, 3693, 0));
private final String tooltip;
private final WorldPoint location;
KourendTaskLocation(String tooltip, WorldPoint location)
{
this.tooltip = tooltip;
this.location = location;
}
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright (c) 2020, Brooklyn <https://github.com/Broooklyn>
* 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.worldmap;
import net.runelite.client.ui.overlay.worldmap.WorldMapPoint;
public class KourendTaskPoint extends WorldMapPoint
{
KourendTaskPoint(KourendTaskLocation data)
{
super(data.getLocation(), WorldMapPlugin.BLANK_ICON);
setTooltip(data.getTooltip());
}
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright (c) 2018, Magic fTail
* 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.worldmap;
import lombok.Getter;
import net.runelite.api.coords.WorldPoint;
@Getter
enum MinigameLocation
{
BARBARIAN_ASSAULT("Barbarian Assault", new WorldPoint(2531, 3569, 0)),
BURGH_DE_ROTT_RAMBLE("Burgh de Rott Ramble", new WorldPoint(3434, 3487, 0)),
CASTLE_WARS("Castle Wars", new WorldPoint(2439, 3092, 0)),
CASTLE_WARS_PORTAL("Castle Wars Portal", new WorldPoint(3140, 3626, 0)),
DUEL_ARENA("Duel Arena", new WorldPoint(3313, 3238, 0)),
MAGE_ARENA("Mage Arena", new WorldPoint(3095, 3957, 0)),
NIGHTMARE_ZONE("Nightmare Zone", new WorldPoint(2606, 3115, 0)),
PEST_CONTROL_NOVICE("Pest Control Novice", new WorldPoint(2660, 2637, 0)),
PEST_CONTROL_INTERMEDIATE("Pest Control Intermediate", new WorldPoint(2638, 2641, 0)),
PEST_CONTROL_VETERAN("Pest Control Veteran", new WorldPoint(2632, 2648, 0)),
TEMPLE_TREKKING("Temple Trekking", new WorldPoint(3479, 3240, 0)),
TZHAAR_FIGHT_CAVE("TzHaar Fight Cave", new WorldPoint(2437, 5168, 0)),
TZHAAR_FIGHT_PIT("TzHaar Fight Pit", new WorldPoint(2398, 5177, 0)),
LAST_MAN_STANDING("Last Man Standing", new WorldPoint(3138, 3635, 0)),
INFERNO("Inferno", new WorldPoint(2495, 5118, 0)),
BRIMHAVEN_AGILITY_ARENA("Brimhaven Agility Arena", new WorldPoint(2809, 3191, 0)),
FISHING_TRAWLER("Fishing Trawler", new WorldPoint(2667, 3163, 0)),
GNOME_BALL("Gnome Ball", new WorldPoint(2381, 3488, 0)),
GNOME_RESTAURANT("Gnome Restaurant", new WorldPoint(2436, 3502, 0)),
IMPETUOUS_IMPULSES("Impetuous Impulses", new WorldPoint(2425, 4445, 0)),
MAGE_TRAINING_ARENA("Mage Training Arena", new WorldPoint(3362, 3318, 0)),
PYRAMID_PLUNDER("Pyramid Plunder", new WorldPoint(3288, 2787, 0)),
RANGING_GUILD("Ranging Guild", new WorldPoint(2671, 3419, 0)),
ROGUES_DEN("Rogues' Den", new WorldPoint(2905, 3537, 0)),
SORCERESSS_GARDEN("Sorceress's Garden", new WorldPoint(3285, 3180, 0)),
TROUBLE_BREWING("Trouble Brewing", new WorldPoint(3811, 3021, 0)),
VOLCANIC_MINE("Volcanic Mine", new WorldPoint(3812, 3810, 0)),
TAI_BWO_WANNAI_CLEANUP("Tai Bwo Wannai Cleanup", new WorldPoint(2795, 3066, 0)),
BURTHORPE_GAMES_ROOM("Burthorpe Games Room", new WorldPoint(2900, 3565, 0)),
RAT_PITS_PORT_SARIM("Rat Pits", new WorldPoint(3015, 3232, 0)),
RAT_PITS_VARROCK("Rat Pits", new WorldPoint(3266, 3400, 0)),
RAT_PITS_ARDOUGNE("Rat Pits", new WorldPoint(2561, 3318, 0)),
RAT_PITS_KELDAGRIM("Rat Pits", new WorldPoint(2913, 10188, 0)),
TEARS_OF_GUTHIX("Tears of Guthix", new WorldPoint(3257, 9517, 0)),
CLAN_WARS("Clan Wars", new WorldPoint(3133, 3621, 0)),
ANIMATION_ROOM("Animation Room", new WorldPoint(2853, 3537, 0)),
DUMMY_ROOM("Dummy Room", new WorldPoint(2857, 3551, 0)),
CATAPULT_ROOM("Catapult Room", new WorldPoint(2842, 3545, 0)),
SHOT_PUT_ROOM("Shot Put Room", new WorldPoint(2863, 3550, 0)),
HALLOWED_SEPULCHRE("Hallowed Sepulchre", new WorldPoint(3653, 3386, 1)),
THE_GAUNTLET("The Gauntlet", new WorldPoint(3223, 12505, 1));
private final String tooltip;
private final WorldPoint location;
MinigameLocation(String tooltip, WorldPoint location)
{
this.tooltip = tooltip;
this.location = location;
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 2018, Magic fTail
* 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.worldmap;
import java.awt.image.BufferedImage;
import net.runelite.client.ui.overlay.worldmap.WorldMapPoint;
class MinigamePoint extends WorldMapPoint
{
MinigamePoint(MinigameLocation data, BufferedImage icon)
{
super(data.getLocation(), icon);
setTooltip(data.getTooltip());
}
}

View File

@@ -0,0 +1,278 @@
/*
* Copyright (c) 2020, dekvall <https://github.com/dekvall>
* 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.worldmap;
import com.google.common.base.Joiner;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Value;
import net.runelite.api.coords.WorldPoint;
@Getter
enum MiningSiteLocation
{
AGILITY_PYRAMID(new WorldPoint(3322, 2875, 0), new Rock(5, Ore.GOLD)),
// ABANDONED_MINE -- NOT AVAILABLE ON WORLDMAP
AL_KHARID_MINE_NORTH(new WorldPoint(3298, 3312, 0),
new Rock(3, Ore.COPPER), new Rock(1, Ore.TIN), new Rock(7, Ore.IRON), new Rock(5, Ore.SILVER),
new Rock(3, Ore.COAL), new Rock(3, Ore.MITHRIL), new Rock(2, Ore.ADAMANTITE)),
AL_KHARID_MINE_SOUTH(new WorldPoint(3298, 3282, 0), new Rock(2, Ore.IRON), new Rock(2, Ore.GOLD)),
ARANDAR(new WorldPoint(2322, 3269, 0), new Rock(8, Ore.LIMESTONE)),
ARANDAR_PRIFDDINAS_MAP(new WorldPoint(3346, 6021, 0), new Rock(8, Ore.LIMESTONE)),
ARCEUUS_NORTH(new WorldPoint(1763, 3860, 0), new Rock(1, Ore.DENSE_ESSENCE)),
ARCEUUS_SOUTH(new WorldPoint(1763, 3844, 0), new Rock(1, Ore.DENSE_ESSENCE)),
ARDOUGNE_SEWERS(new WorldPoint(2670, 9680, 0), new Rock(5, Ore.IRON), new Rock(5, Ore.COAL)),
ARDOUGNE_SOUTH_EAST(new WorldPoint(2599, 3232, 0), new Rock(6, Ore.IRON), new Rock(4, Ore.COAL)),
// ARZINIAN_MINE -- NOT AVAILABLE ON WORLD MAP
ASGARNIA_ICE_DUNGEON_EAST(new WorldPoint(3063, 9582, 0), new Rock(2, Ore.BLURITE)),
ASGARNIA_ICE_DUNGEON_WEST(new WorldPoint(3049, 9568, 0), new Rock(2, Ore.BLURITE)),
BANDIT_CAMP_MINE(new WorldPoint(3086, 3763, 0), new Rock(16, Ore.IRON), new Rock(20, Ore.COAL), new Rock(22, Ore.MITHRIL), new Rock(8, Ore.ADAMANTITE)),
BANDIT_CAMP_QUARRY(new WorldPoint(3171, 2912, 0), new Rock(4, Ore.CLAY), new Rock(2, Ore.COAL), new Rock(32, Ore.SANDSTONE), new Rock(28, Ore.GRANITE)),
BARBARIAN_VILLAGE(new WorldPoint(3078, 3421, 0), new Rock(5, Ore.TIN), new Rock(4, Ore.COAL)),
BATTLEFIELD(new WorldPoint(2471, 3255, 0), new Rock(2, Ore.COPPER), new Rock(1, Ore.TIN)),
BLAST_MINE_EAST(new WorldPoint(1502, 3869, 0), new Rock(20, Ore.HARD_ROCK)),
BLAST_MINE_NORTH(new WorldPoint(1485, 3882, 0), new Rock(17, Ore.HARD_ROCK)),
BLAST_MINE_WEST(new WorldPoint(1471, 3865, 0), new Rock(22, Ore.HARD_ROCK)),
BRIMHAVEN_NORTH(new WorldPoint(2732, 3225, 0), new Rock(10, Ore.GOLD)),
BRIMHAVEN_SOUTH_(new WorldPoint(2743, 3150, 0), new Rock(6, Ore.GOLD)),
CENTRAL_FREMENIK_ISLES(new WorldPoint(2374, 3850, 0), new Rock(7, Ore.COAL), new Rock(1, Ore.RUNITE)),
CITHAREDE_ABBEY(new WorldPoint(3400, 3170, 0), new Rock(3, Ore.IRON), new Rock (3, Ore.COAL)),
COAL_TRUCKS(new WorldPoint(2580, 3484, 0), new Rock(18, Ore.COAL)),
CRAFTING_GUILD(new WorldPoint(2939, 3283, 0), new Rock(6, Ore.CLAY), new Rock(6, Ore.SILVER), new Rock(7, Ore.GOLD)),
CRANDOR_NORTH_EAST(new WorldPoint(2860, 3287, 0), new Rock(3, Ore.GOLD)),
CRANDOR_NORTH_WEST(new WorldPoint(2831, 3296, 0), new Rock(7, Ore.COAL), new Rock(1, Ore.MITHRIL)),
CRANDOR_SOUTH_EAST(new WorldPoint(2835, 3245, 0), new Rock(3, Ore.COAL), new Rock(3, Ore.ADAMANTITE)),
CRANDOR_SOUTH_WEST(new WorldPoint(2819, 3247, 0), new Rock(7, Ore.MITHRIL)),
DAEYALT_ESSENCE_MINE(new WorldPoint(3631, 3340, 0), new Rock(3, Ore.DAEYALT_ESSENCE)),
DESERT_MINING_CAMP_SURFACE(new WorldPoint(3299, 3021, 0), true, new Rock(4, Ore.COPPER), new Rock(4, Ore.TIN), new Rock(3, Ore.IRON), new Rock(4, Ore.COAL)),
// DESERT_MINING_CAMP_UNDERGROUND -- NOT AVAILABLE ON WORLDMAP
DORGESH_KAAN_NORTH(new WorldPoint(3309, 9645, 0), new Rock(1, Ore.IRON), new Rock(9, Ore.SILVER)),
DORGESH_KAAN_SOUTH_EAST(new WorldPoint(3322, 9616, 0), new Rock(3, Ore.IRON)),
DORGESH_KAAN_SOUTH_WEST(new WorldPoint(3312, 9621, 0), new Rock(3, Ore.IRON)),
DORGESH_KAAN_WEST(new WorldPoint(3311, 9628, 0), new Rock(3, Ore.IRON), new Rock(2, Ore.SILVER)),
DWARVEN_EAST_BOTTOM(new WorldPoint(3039, 9763, 0),
new Rock(5, Ore.TIN), new Rock(2, Ore.IRON), new Rock(8, Ore.COAL), new Rock(2, Ore.GOLD), new Rock(1, Ore.ADAMANTITE)),
DWARVEN_EAST_MIDDLE(new WorldPoint(3037, 9775, 0),
new Rock(4, Ore.COPPER), new Rock(3, Ore.IRON), new Rock(3, Ore.COAL), new Rock(2, Ore.MITHRIL), new Rock(2, Ore.ADAMANTITE)),
DWARVEN_EAST_TOP(new WorldPoint(3051, 9820, 0), new Rock(2, Ore.CLAY), new Rock(3, Ore.TIN), new Rock(2, Ore.IRON)),
DWARVEN_WEST_BOTTOM(new WorldPoint(3028, 9809, 0), new Rock(3, Ore.CLAY), new Rock(4, Ore.COPPER)),
DWARVEN_WEST_TOP(new WorldPoint(3031, 9828, 0), new Rock(3, Ore.COPPER), new Rock(2, Ore.TIN), new Rock(2, Ore.IRON)),
FREMENIK_ISLES_EAST(new WorldPoint(2405, 3867, 0), new Rock(3, Ore.COPPER), new Rock(3, Ore.TIN), new Rock(4, Ore.COAL)),
EAGLES_OUTPOST(new WorldPoint(3424, 3164, 0), new Rock(7, Ore.CLAY)),
EDGEVILLE_DUNGEON(new WorldPoint(3138, 9874, 0),
new Rock(2, Ore.COPPER), new Rock(2, Ore.TIN), new Rock(3, Ore.IRON), new Rock(3, Ore.SILVER),
new Rock(6, Ore.COAL), new Rock(1, Ore.MITHRIL), new Rock(2, Ore.ADAMANTITE)),
// EVIL_CHICKEN_LAIR -- NOT AVAILABLE ON WORLD MAP
FALADOR_WEST(new WorldPoint(2907, 3362, 0),
new Rock(2, Ore.COPPER), new Rock(6, Ore.TIN), new Rock(3, Ore.IRON), new Rock(2, Ore.COAL)),
FELDIP_HILLS_EAST(new WorldPoint(2638, 2996, 0), new Rock(3, Ore.ROCK)),
FELDIP_HILLS_MIDDLE(new WorldPoint(2579, 2998, 0), new Rock(4, Ore.ROCK)),
FELDIP_HILLS_WEST(new WorldPoint(2567, 2961, 0), new Rock(3, Ore.ROCK)),
FIGHT_ARENA(new WorldPoint(2630, 3142, 0),
new Rock(4, Ore.CLAY), new Rock(2, Ore.COPPER), new Rock(7, Ore.TIN), new Rock(9, Ore.IRON),
new Rock(1, Ore.COAL), new Rock(2, Ore.MITHRIL)),
FOSSIL_ISLAND(new WorldPoint(3770, 3815, 0),
new Rock(7, Ore.IRON), new Rock(20, Ore.COAL), new Rock(3, Ore.MITHRIL), new Rock(5, Ore.ADAMANTITE),
new Rock(2, Ore.RUNITE)),
FREMENNIK_ISLES_WEST(new WorldPoint(2310, 3853, 0), new Rock(3, Ore.COPPER)),
FROZEN_WASTE_PLATEU_CENTER(new WorldPoint(2963, 3933, 0), new Rock(1, Ore.RUNITE)),
FROZEN_WASTE_PLATEU_NORTH(new WorldPoint(2975, 3937, 0), new Rock(1, Ore.RUNITE)),
FROZEN_WASTE_PLATEU_SOUTH(new WorldPoint(2947, 3914, 0), new Rock(1, Ore.RUNITE)),
GRAND_TREE(new WorldPoint(2489, 9916, 0),
new Rock(9, Ore.CLAY), new Rock(8, Ore.IRON), new Rock(4, Ore.SILVER), new Rock(11, Ore.COAL),
new Rock(4, Ore.GOLD), new Rock(4, Ore.MITHRIL), new Rock(3, Ore.ADAMANTITE)),
GWENITH(new WorldPoint(2163, 3415, 0), new Rock(10, Ore.GOLD)),
GWENITH_PRIFDDINAS_MAP(new WorldPoint(3187, 6167, 0), new Rock(10, Ore.GOLD)),
HEROES_GUILD_EAST_BOTTOM(new WorldPoint(2939, 9898, 0), new Rock(3, Ore.COAL), new Rock(2, Ore.RUNITE)),
HEROES_GUILD_EAST_TOP(new WorldPoint(2940, 9884, 0), new Rock(5, Ore.COAL)),
HEROES_GUILD_WEST_BOTTOM(new WorldPoint(2921, 9904, 0), new Rock(3, Ore.COAL)),
HEROES_GUILD_WEST_TOP(new WorldPoint(2914, 9916, 0), new Rock(2, Ore.MITHRIL), new Rock(2, Ore.ADAMANTITE)),
HOSIDIUS_MINE(new WorldPoint(1777, 3489, 0),
new Rock(10, Ore.CLAY), new Rock(11, Ore.COPPER), new Rock(4, Ore.TIN), new Rock(9, Ore.IRON),
new Rock(2, Ore.SILVER)),
ISAFDAR(new WorldPoint(2277, 3159, 0), new Rock(4, Ore.ADAMANTITE), new Rock(2, Ore.RUNITE)),
JATIZSO(new WorldPoint(2396, 3812, 0),
new Rock(11, Ore.TIN), new Rock(7, Ore.IRON), new Rock(8, Ore.COAL), new Rock(15, Ore.MITHRIL),
new Rock(11, Ore.ADAMANTITE)),
KARAMJA_JUNGLE(new WorldPoint(2848, 3033, 0),
new Rock(1, Ore.IRON), new Rock(1, Ore.SILVER), new Rock(1, Ore.COAL), new Rock(2, Ore.MITHRIL),
new Rock(2, Ore.ADAMANTITE)),
KARAMJA_VOLCANO(new WorldPoint(2856, 9579, 0), new Rock(4, Ore.GOLD)),
KEBOS_LOWLANDS(new WorldPoint(1211, 3657, 0), new Rock(4, Ore.ADAMANTITE), new Rock(5, Ore.MITHRIL)),
KELDAGRIM_ENTRANCE(new WorldPoint(2724, 3693, 0), new Rock(9, Ore.IRON), new Rock(2, Ore.MITHRIL)),
KELDAGRIM_NORTH_EAST(new WorldPoint(2937, 10232, 0), new Rock(9, Ore.COAL)),
KELDAGRIM_SOUTH_WEST_BOTTOM(new WorldPoint(2872, 10119, 0), new Rock(2, Ore.COPPER), new Rock(5, Ore.COAL)),
KELDAGRIM_SOUTH_WEST_MIDDLE(new WorldPoint(2818, 10156, 0), new Rock(4, Ore.IRON), new Rock(1, Ore.GOLD)),
KELDAGRIM_SOUTH_WEST_TOP(new WorldPoint(2864, 10170, 0), new Rock(5, Ore.TIN)),
LAVA_MAZE_DUNGEON(new WorldPoint(3045, 10263, 0), true, new Rock(1, Ore.RUNITE)),
LAVA_MAZE_NORTH(new WorldPoint(3059, 3884, 0), new Rock(2, Ore.RUNITE)),
LEGENDS_GUILD_EAST(new WorldPoint(2709, 3331, 0), new Rock(6, Ore.IRON), new Rock(8, Ore.COAL)),
LEGENDS_GUILD_WEST(new WorldPoint(2694, 3332, 0), new Rock(5, Ore.IRON), new Rock(5, Ore.COAL)),
LOVAKENGJ_SOUTH(new WorldPoint(1476, 3779, 0), new Rock(4, Ore.IRON), new Rock(6, Ore.COAL), new Rock(1, Ore.MITHRIL)),
LOVAKENGJ_SULPHUR_EAST(new WorldPoint(1445, 3870, 0), new Rock(3, Ore.VOLCANIC_SULPHUR)),
LOVAKENGJ_SULPHUR_WEST(new WorldPoint(1427, 3870, 0), new Rock(2, Ore.VOLCANIC_SULPHUR)),
LOVAKENGJ_WEST(new WorldPoint(1432, 3845, 0), true, new Rock(45, Ore.COAL), new Rock(80, Ore.LOVAKITE)),
LUMBRIDGE_SWAMP_EAST(new WorldPoint(3226, 3146, 0), new Rock(5, Ore.COPPER), new Rock(5, Ore.TIN)),
LUMBRIDGE_SWAMP_WEST(new WorldPoint(3148, 3149, 0),
new Rock(7, Ore.COAL), new Rock(5, Ore.MITHRIL), new Rock(2, Ore.ADAMANTITE)),
// Lunar Isle Dungeon: Starting north-east and going clockwise
LUNAR_ISLE_1(new WorldPoint(2163, 10347, 0),
new Rock(2, Ore.SILVER), new Rock(1, Ore.GOLD), new Rock(1, Ore.GEM_ROCK), new Rock(6, Ore.LUNAR)),
LUNAR_ISLE_2(new WorldPoint(2165, 10325, 0), new Rock(3, Ore.GEM_ROCK), new Rock(4, Ore.LUNAR)),
LUNAR_ISLE_3(new WorldPoint(2140, 10318, 0), new Rock(3, Ore.SILVER), new Rock(3, Ore.LUNAR)),
LUNAR_ISLE_4(new WorldPoint(2125, 10327, 0), new Rock(4, Ore.GOLD), new Rock(1, Ore.LUNAR)),
LUNAR_ISLE_5(new WorldPoint(2124, 10342, 0), new Rock(2, Ore.GOLD), new Rock(5, Ore.LUNAR)),
MINING_GUILD_AMETHYST(new WorldPoint(3022, 9704, 0), new Rock(26, Ore.AMETHYST)),
MINING_GUILD_NORTH(new WorldPoint(3040, 9740, 0),
new Rock(4, Ore.IRON), new Rock(37, Ore.COAL), new Rock(5, Ore.MITHRIL), new Rock(2, Ore.ADAMANTITE)),
MINING_GUILD_SOUTH(new WorldPoint(3032, 9720, 0),
new Rock(8, Ore.IRON), new Rock(20, Ore.COAL), new Rock(10, Ore.MITHRIL), new Rock(8, Ore.ADAMANTITE),
new Rock(2, Ore.RUNITE)),
MISCELLANIA(new WorldPoint(2526, 3891, 0), new Rock(9, Ore.COAL)),
MISCELLANIA_DUNGEON(new WorldPoint(2504, 10287, 0), new Rock(4, Ore.COAL)),
MOR_UL_REK_NORTH(new WorldPoint(2458, 5167, 0), new Rock(3, Ore.SILVER), new Rock(3, Ore.GOLD)),
MOR_UL_REK_SOUTH_EAST(new WorldPoint(2513, 5074, 0), new Rock(6, Ore.SILVER), new Rock(7, Ore.GOLD)),
MOR_UL_REK_SOUTH_WEST(new WorldPoint(2499, 5062, 0),
new Rock(3, Ore.IRON), new Rock(4, Ore.COAL), new Rock(2, Ore.ADAMANTITE), new Rock(3, Ore.RUNITE)),
MOUNT_KARUULM(new WorldPoint(1278, 3814, 0), new Rock(6, Ore.IRON), new Rock(5, Ore.COAL)),
// MOURNER_TUNNELS -- NOT AVAILABLE ON WORLD MAP
MYTHS_GUILD(new WorldPoint(1936, 9020, 0), new Rock(4, Ore.ADAMANTITE), new Rock(2, Ore.RUNITE)),
OGRESS_SETTLEMENT(new WorldPoint(1977, 9041, 0),
new Rock(5, Ore.COAL), new Rock(2, Ore.MITHRIL), new Rock(1, Ore.ADAMANTITE)),
PIRATES_HIDEOUT(new WorldPoint(3056, 3945, 0),
new Rock(1, Ore.IRON), new Rock(4, Ore.COAL), new Rock(4, Ore.MITHRIL), new Rock(1, Ore.ADAMANTITE)),
PISCARILLIUS(new WorldPoint(1759, 3718, 0),
new Rock(5, Ore.COPPER), new Rock(6, Ore.TIN), new Rock(5, Ore.IRON), new Rock(2, Ore.SILVER),
new Rock(1, Ore.MITHRIL)),
PISCATORIS(new WorldPoint(2337, 3640, 0),
new Rock(2, Ore.CLAY), new Rock(2, Ore.COPPER), new Rock(2, Ore.TIN), new Rock(3, Ore.IRON)),
PORT_KHAZARD(new WorldPoint(2651, 3172, 0),
new Rock(2, Ore.COPPER), new Rock(2, Ore.TIN), new Rock(2, Ore.MITHRIL)),
RELLEKKA(new WorldPoint(2682, 3704, 0), new Rock(4, Ore.CLAY), new Rock(3, Ore.SILVER), new Rock(7, Ore.COAL)),
RIMMINGTON(new WorldPoint(2977, 3240, 0),
new Rock(2, Ore.CLAY), new Rock(5, Ore.COPPER), new Rock(2, Ore.TIN), new Rock(6, Ore.IRON),
new Rock(2, Ore.GOLD)),
SALT_MINE(new WorldPoint(2835, 10334, 0),
new Rock(7, Ore.BASALT), new Rock(15, Ore.TE_SALT), new Rock(12, Ore.EFH_SALT), new Rock(12, Ore.URT_SALT)),
SHAYZIEN_EAST(new WorldPoint(1597, 3653, 0), new Rock(3, Ore.CLAY), new Rock(1, Ore.MITHRIL), new Rock(1, Ore.ADAMANTITE)),
SHAYZIEN_WEST(new WorldPoint(1586, 3650, 0),
new Rock(4, Ore.IRON), new Rock(4, Ore.COAL), new Rock(1, Ore.MITHRIL), new Rock(1, Ore.ADAMANTITE)),
SHILO_VILLAGE_SURFACE(new WorldPoint(2822, 3001, 0), new Rock(7, Ore.GEM_ROCK)),
SILVAREA(new WorldPoint(3371, 3498, 0), new Rock(7, Ore.LIMESTONE)),
SLEPE_UNDERGROUND(new WorldPoint(3888, 9749, 0), new Rock(6, Ore.IRON), new Rock(14, Ore.COAL)),
TRAHEARN(new WorldPoint(3295, 12387, 0),
new Rock(26, Ore.IRON), new Rock(8, Ore.SILVER), new Rock(19, Ore.COAL), new Rock(14, Ore.GOLD),
new Rock(7, Ore.MITHRIL), new Rock(10, Ore.SOFT_CLAY), new Rock(7, Ore.ADAMANTITE), new Rock(4, Ore.RUNITE)),
// TUTORIAL ISLAND -- NOT AVAILABLE ON WORLD MAP
UZER(new WorldPoint(3415, 3160, 0), new Rock(10, Ore.CLAY)),
VARROCK_SOUTH_EAST(new WorldPoint(3286, 3365, 0),
new Rock(9, Ore.COPPER), new Rock(6, Ore.TIN), new Rock(4, Ore.IRON)),
VARROCK_SOUTH_WEST(new WorldPoint(3176, 3370, 0),
new Rock(3, Ore.CLAY), new Rock(8, Ore.TIN), new Rock(3, Ore.IRON), new Rock(3, Ore.SILVER)),
VERDANT_VALLEY(new WorldPoint(3766, 3757, 0), true, new Rock(3, Ore.IRON)),
WILDERNESS_RESOURCE_AREA(new WorldPoint(3192, 3930, 0),
new Rock(6, Ore.IRON), new Rock(11, Ore.COAL), new Rock(4, Ore.GOLD), new Rock(1, Ore.MITHRIL), new Rock(6, Ore.ADAMANTITE)),
WILDERNESS_SOUTH(new WorldPoint(3104, 3569, 0), new Rock(2, Ore.IRON), new Rock(3, Ore.COAL)),
WILDERNESS_SOUTH_WEST(new WorldPoint(3013, 3589, 0), new Rock(34, Ore.COAL)),
;
private final WorldPoint location;
private final String tooltip;
private final boolean iconRequired;
MiningSiteLocation(WorldPoint location, Rock... rocks)
{
this(location, false, rocks);
}
MiningSiteLocation(WorldPoint location, boolean iconRequired, Rock... rocks)
{
this.location = location;
this.iconRequired = iconRequired;
this.tooltip = createTooltip(rocks);
}
private String createTooltip(Rock[] rocks)
{
return Joiner.on("<br>").join(rocks);
}
@RequiredArgsConstructor
private enum Ore
{
ROCK("Rock"),
CLAY("Clay"),
COPPER("Copper"),
TIN("Tin"),
LIMESTONE("Limestone"),
BLURITE("Blurite"),
IRON("Iron"),
ELEMENTAL("Elemental"),
SILVER("Silver"),
COAL("Coal"),
SANDSTONE("Sandstone"),
DENSE_ESSENCE("Dense essence"),
DAEYALT_ESSENCE("Daeyalt essence"),
GOLD("Gold"),
GEM_ROCK("Gem rock"),
HARD_ROCK("Hard rock"),
VOLCANIC_SULPHUR("Volcanic sulphur"),
GRANITE("Granite"),
MITHRIL("Mithril"),
LUNAR("Lunar"),
LOVAKITE("Lovakite"),
ADAMANTITE("Adamantite"),
SOFT_CLAY("Soft clay"),
BASALT("Basalt"),
TE_SALT("Te salt"),
EFH_SALT("Efh salt"),
URT_SALT("Urt salt"),
RUNITE("Runite"),
AMETHYST("Amethyst"),
;
private final String name;
@Override
public String toString()
{
return name;
}
}
@Value
private static class Rock
{
private final int count;
private final Ore ore;
@Override
public String toString()
{
return count + " " + ore;
}
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 2020, dekvall <https://github.com/dekvall>
* 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.worldmap;
import java.awt.image.BufferedImage;
import net.runelite.client.ui.overlay.worldmap.WorldMapPoint;
class MiningSitePoint extends WorldMapPoint
{
MiningSitePoint(MiningSiteLocation point, BufferedImage icon)
{
super(point.getLocation(), icon);
setTooltip(point.getTooltip());
}
}

View File

@@ -0,0 +1,190 @@
/*
* Copyright (c) 2018, John James Hamilton <https://github.com/johnhamilto>
* 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.worldmap;
import lombok.Getter;
import net.runelite.api.coords.WorldPoint;
import net.runelite.api.Quest;
// Some quests are in the same spot, but they are done in order. If multiple
// quests start in the same location, an array of quests is expected.
enum QuestStartLocation
{
//Free Quests
COOKS_ASSISTANT_RFD(Quest.COOKS_ASSISTANT, new WorldPoint(3211, 3216, 0)),
THE_CORSAIR_CURSE(Quest.THE_CORSAIR_CURSE, new WorldPoint(3029, 3273, 0)),
DEMON_SLAYER(Quest.DEMON_SLAYER, new WorldPoint(3204, 3424, 0)),
DORICS_QUEST(Quest.DORICS_QUEST, new WorldPoint(2952, 3450, 0)),
DRAGON_SLAYER(Quest.DRAGON_SLAYER, new WorldPoint(3190, 3362, 0)),
ERNEST_THE_CHICKEN(Quest.ERNEST_THE_CHICKEN, new WorldPoint(3109, 3330, 0)),
GOBLIN_DIPLOMACY(Quest.GOBLIN_DIPLOMACY, new WorldPoint(2957, 3509, 0)),
IMP_CATCHER(Quest.IMP_CATCHER, new WorldPoint(3108, 3160, 0)),
THE_KNIGHTS_SWORD(Quest.THE_KNIGHTS_SWORD, new WorldPoint(2976, 3342, 0)),
MISTHALIN_MYSTERY(Quest.MISTHALIN_MYSTERY, new WorldPoint(3235, 3155, 0)),
PIRATES_TREASURE(Quest.PIRATES_TREASURE, new WorldPoint(3051, 3252, 0)),
PRINCE_ALI_RESCUE(Quest.PRINCE_ALI_RESCUE, new WorldPoint(3301, 3163, 0)),
THE_RESTLESS_GHOST(Quest.THE_RESTLESS_GHOST, new WorldPoint(3240, 3210, 0)),
RUNE_MYSTERIES(Quest.RUNE_MYSTERIES, new WorldPoint(3210, 3220, 0)),
SHEEP_SHEARER(Quest.SHEEP_SHEARER, new WorldPoint(3190, 3272, 0)),
SHIELD_OF_ARRAV_PHOENIX_GANG(Quest.SHIELD_OF_ARRAV, new WorldPoint(3208, 3495, 0)),
SHIELD_OF_ARRAV_BLACK_ARM_GANG(Quest.SHIELD_OF_ARRAV, new WorldPoint(3208, 3392, 0)),
VAMPYRE_SLAYER(Quest.VAMPYRE_SLAYER, new WorldPoint(3096, 3266, 0)),
WITCHS_POTION(Quest.WITCHS_POTION, new WorldPoint(2967, 3203, 0)),
X_MARKS_THE_SPOT(Quest.X_MARKS_THE_SPOT, new WorldPoint(3227, 3242, 0)),
//Members' Quests
ANIMAL_MAGNETISM(Quest.ANIMAL_MAGNETISM, new WorldPoint(3094, 3360, 0)),
ANOTHER_SLICE_OF_HAM(Quest.ANOTHER_SLICE_OF_HAM, new WorldPoint(2799, 5428, 0)),
THE_ASCENT_OF_ARCEUUS(Quest.THE_ASCENT_OF_ARCEUUS, new WorldPoint(1699, 3742, 0)),
BETWEEN_A_ROCK(Quest.BETWEEN_A_ROCK, new WorldPoint(2823, 10168, 0)),
BIG_CHOMPY_BIRD_HUNTING(Quest.BIG_CHOMPY_BIRD_HUNTING, new WorldPoint(2629, 2981, 0)),
BIOHAZARD(Quest.BIOHAZARD, new WorldPoint(2591, 3335, 0)),
BONE_VOYAGE(Quest.BONE_VOYAGE, new WorldPoint(3259, 3450, 0)),
CABIN_FEVER(Quest.CABIN_FEVER, new WorldPoint(3674, 3496, 0)),
CLIENT_OF_KOUREND(Quest.CLIENT_OF_KOUREND, new WorldPoint(1823, 3690, 0)),
CLOCK_TOWER(Quest.CLOCK_TOWER, new WorldPoint(2568, 3249, 0)),
COLD_WAR(Quest.COLD_WAR, new WorldPoint(2593, 3265, 0)),
CONTACT(Quest.CONTACT, new WorldPoint(3280, 2770, 0)),
CREATURE_OF_FENKENSTRAIN(Quest.CREATURE_OF_FENKENSTRAIN, new WorldPoint(3487, 3485, 0)),
DARKNESS_OF_HALLOWVALE(Quest.DARKNESS_OF_HALLOWVALE, new WorldPoint(3494, 9628, 0)),
DEATH_PLATEAU_TROLL_STRONGHOLD(new Quest[]{Quest.DEATH_PLATEAU, Quest.TROLL_STRONGHOLD}, new WorldPoint(2895, 3528, 0)),
DEATH_TO_THE_DORGESHUUN(Quest.DEATH_TO_THE_DORGESHUUN, new WorldPoint(3316, 9613, 0)),
THE_DEPTHS_OF_DESPAIR(Quest.THE_DEPTHS_OF_DESPAIR, new WorldPoint(1781, 3570, 0)),
DESERT_TREASURE(Quest.DESERT_TREASURE, new WorldPoint(3177, 3043, 0)),
DEVIOUS_MINDS(Quest.DEVIOUS_MINDS, new WorldPoint(3405, 3492, 0)),
THE_DIG_SITE(Quest.THE_DIG_SITE, new WorldPoint(3363, 3337, 0)),
DRAGON_SLAYER_II(Quest.DRAGON_SLAYER_II, new WorldPoint(2456, 2868, 0)),
DREAM_MENTOR(Quest.DREAM_MENTOR, new WorldPoint(2144, 10346, 0)),
DRUIDIC_RITUAL(Quest.DRUIDIC_RITUAL, new WorldPoint(2916, 3484, 0)),
DWARF_CANNON(Quest.DWARF_CANNON, new WorldPoint(2566, 3461, 0)),
EADGARS_RUSE(Quest.EADGARS_RUSE, new WorldPoint(2896, 3426, 0)),
EAGLES_PEAK(Quest.EAGLES_PEAK, new WorldPoint(2605, 3264, 0)),
ELEMENTAL_WORKSHOP(new Quest[]{Quest.ELEMENTAL_WORKSHOP_I, Quest.ELEMENTAL_WORKSHOP_II}, new WorldPoint(2714, 3482, 0)),
ENAKHRAS_LAMENT(Quest.ENAKHRAS_LAMENT, new WorldPoint(3190, 2926, 0)),
ENLIGHTENED_JOURNEY(Quest.ENLIGHTENED_JOURNEY, new WorldPoint(2809, 3356, 0)),
THE_EYES_OF_GLOUPHRIE(Quest.THE_EYES_OF_GLOUPHRIE, new WorldPoint(2400, 3419, 0)),
FAIRYTALE(new Quest[]{Quest.FAIRYTALE_I__GROWING_PAINS, Quest.FAIRYTALE_II__CURE_A_QUEEN}, new WorldPoint(3077, 3258, 0)),
FAMILY_CREST(Quest.FAMILY_CREST, new WorldPoint(3278, 3404, 0)),
THE_FEUD(Quest.THE_FEUD, new WorldPoint(3301, 3211, 0)),
FIGHT_ARENA(Quest.FIGHT_ARENA, new WorldPoint(2565, 3199, 0)),
FISHING_CONTEST_1(Quest.FISHING_CONTEST, new WorldPoint(2875, 3483, 0)),
FISHING_CONTEST_2(Quest.FISHING_CONTEST, new WorldPoint(2820, 3487, 0)),
FORGETTABLE_TALE(Quest.FORGETTABLE_TALE, new WorldPoint(2826, 10215, 0)),
THE_FORSAKEN_TOWER(Quest.THE_FORSAKEN_TOWER, new WorldPoint(1482, 3748, 0)),
THE_FREMENNIK_ISLES(Quest.THE_FREMENNIK_ISLES, new WorldPoint(2645, 3711, 0)),
THE_FREMENNIK_TRIALS(Quest.THE_FREMENNIK_TRIALS, new WorldPoint(2657, 3669, 0)),
THE_FREMENNIK_EXILES(Quest.THE_FREMENNIK_EXILES, new WorldPoint(2658, 3669, 0)),
GARDEN_OF_TRANQUILLITY(Quest.GARDEN_OF_TRANQUILLITY, new WorldPoint(3227, 3477, 0)),
GERTRUDES_CAT_RATCATCHERS(Quest.GERTRUDES_CAT, new WorldPoint(3150, 3411, 0)),
GETTING_AHEAD(Quest.GETTING_AHEAD, new WorldPoint(1247, 3686, 0)),
GHOSTS_AHOY(Quest.GHOSTS_AHOY, new WorldPoint(3677, 3510, 0)),
THE_GIANT_DWARF(Quest.THE_GIANT_DWARF, new WorldPoint(2841, 10129, 0)),
THE_GOLEM(Quest.THE_GOLEM, new WorldPoint(3487, 3089, 0)),
THE_GRAND_TREE_MONKEY_MADNESS(new Quest[]{Quest.THE_GRAND_TREE, Quest.MONKEY_MADNESS_I, Quest.MONKEY_MADNESS_II}, new WorldPoint(2466, 3497, 0)),
THE_GREAT_BRAIN_ROBBERY(Quest.THE_GREAT_BRAIN_ROBBERY, new WorldPoint(3681, 2963, 0)),
GRIM_TALES(Quest.GRIM_TALES, new WorldPoint(2890, 3454, 0)),
THE_HAND_IN_THE_SAND(Quest.THE_HAND_IN_THE_SAND, new WorldPoint(2552, 3101, 0)),
HAUNTED_MINE(Quest.HAUNTED_MINE, new WorldPoint(3443, 3258, 0)),
HAZEEL_CULT(Quest.HAZEEL_CULT, new WorldPoint(2565, 3271, 0)),
HEROES_QUEST(Quest.HEROES_QUEST, new WorldPoint(2903, 3511, 0)),
HOLY_GRAIL(new Quest[]{Quest.MERLINS_CRYSTAL, Quest.HOLY_GRAIL}, new WorldPoint(2763, 3515, 0)),
HORROR_FROM_THE_DEEP(Quest.HORROR_FROM_THE_DEEP, new WorldPoint(2507, 3635, 0)),
ICTHLARINS_LITTLE_HELPER(Quest.ICTHLARINS_LITTLE_HELPER, new WorldPoint(3314, 2849, 0)),
IN_SEARCH_OF_THE_MYREQUE(Quest.IN_SEARCH_OF_THE_MYREQUE, new WorldPoint(3502, 3477, 0)),
JUNGLE_POTION(Quest.JUNGLE_POTION, new WorldPoint(2809, 3086, 0)),
KINGS_RANSOM(Quest.KINGS_RANSOM, new WorldPoint(2741, 3554, 0)),
LEGENDS_QUEST(Quest.LEGENDS_QUEST, new WorldPoint(2725, 3367, 0)),
LOST_CITY(Quest.LOST_CITY, new WorldPoint(3149, 3205, 0)),
THE_LOST_TRIBE(Quest.THE_LOST_TRIBE, new WorldPoint(3211, 3224, 0)),
LUNAR_DIPLOMACY(Quest.LUNAR_DIPLOMACY, new WorldPoint(2618, 3691, 0)),
MAKING_FRIENDS_WITH_MY_ARM(Quest.MAKING_FRIENDS_WITH_MY_ARM, new WorldPoint(2904, 10092, 0)),
MAKING_HISTORY(Quest.MAKING_HISTORY, new WorldPoint(2435, 3346, 0)),
MONKS_FRIEND(Quest.MONKS_FRIEND, new WorldPoint(2605, 3209, 0)),
MOUNTAIN_DAUGHTER(Quest.MOUNTAIN_DAUGHTER, new WorldPoint(2810, 3672, 0)),
MOURNINGS_ENDS_PART_I(Quest.MOURNINGS_END_PART_I, new WorldPoint(2289, 3149, 0)),
MOURNINGS_ENDS_PART_II(Quest.MOURNINGS_END_PART_II, new WorldPoint(2352, 3172, 0)),
MURDER_MYSTERY(Quest.MURDER_MYSTERY, new WorldPoint(2740, 3562, 0)),
MY_ARMS_BIG_ADVENTURE(Quest.MY_ARMS_BIG_ADVENTURE, new WorldPoint(2908, 10088, 0)),
NATURE_SPIRIT(Quest.NATURE_SPIRIT, new WorldPoint(3440, 9894, 0)),
OBSERVATORY_QUEST(Quest.OBSERVATORY_QUEST, new WorldPoint(2438, 3185, 0)),
OLAFS_QUEST(Quest.OLAFS_QUEST, new WorldPoint(2723, 3729, 0)),
ONE_SMALL_FAVOUR(Quest.ONE_SMALL_FAVOUR, new WorldPoint(2834, 2985, 0)),
PLAGUE_CITY_SONG_OF_THE_ELVES(new Quest[]{Quest.PLAGUE_CITY, Quest.SONG_OF_THE_ELVES}, new WorldPoint(2567, 3334, 0)),
A_PORCINE_OF_INTEREST(Quest.A_PORCINE_OF_INTEREST, new WorldPoint(3085, 3251, 0)),
PRIEST_IN_PERIL(Quest.PRIEST_IN_PERIL, new WorldPoint(3219, 3473, 0)),
THE_QUEEN_OF_THIEVES(Quest.THE_QUEEN_OF_THIEVES, new WorldPoint(1795, 3782, 0)),
RAG_AND_BONE_MAN(new Quest[]{Quest.RAG_AND_BONE_MAN, Quest.RAG_AND_BONE_MAN_II}, new WorldPoint(3359, 3504, 0)),
RECRUITMENT_DRIVE_BLACK_KNIGHTS_FORTRESS(new Quest[]{Quest.BLACK_KNIGHTS_FORTRESS, Quest.RECRUITMENT_DRIVE}, new WorldPoint(2959, 3336, 0)),
ROVING_ELVES(Quest.ROVING_ELVES, new WorldPoint(2288, 3146, 0)),
RUM_DEAL(Quest.RUM_DEAL, new WorldPoint(3679, 3535, 0)),
SCORPION_CATCHER(Quest.SCORPION_CATCHER, new WorldPoint(2701, 3399, 0)),
SEA_SLUG(Quest.SEA_SLUG, new WorldPoint(2715, 3302, 0)),
SHADES_OF_MORTTON(Quest.SHADES_OF_MORTTON, new WorldPoint(3463, 3308, 0)),
SHADOW_OF_THE_STORM(Quest.SHADOW_OF_THE_STORM, new WorldPoint(3270, 3159, 0)),
SHEEP_HERDER(Quest.SHEEP_HERDER, new WorldPoint(2616, 3299, 0)),
SHILO_VILLAGE(Quest.SHILO_VILLAGE, new WorldPoint(2882, 2951, 0)),
SINS_OF_THE_FATHER(Quest.SINS_OF_THE_FATHER, new WorldPoint(3728, 3319, 0)),
A_SOULS_BANE(Quest.A_SOULS_BANE, new WorldPoint(3307, 3454, 0)),
SPIRITS_OF_THE_ELID(Quest.SPIRITS_OF_THE_ELID, new WorldPoint(3441, 2911, 0)),
SWAN_SONG(Quest.SWAN_SONG, new WorldPoint(2345, 3652, 0)),
TAI_BWO_WANNAI_TRIO(Quest.TAI_BWO_WANNAI_TRIO, new WorldPoint(2779, 3087, 0)),
A_TAIL_OF_TWO_CATS(Quest.A_TAIL_OF_TWO_CATS, new WorldPoint(2917, 3557, 0)),
TALE_OF_THE_RIGHTEOUS(Quest.TALE_OF_THE_RIGHTEOUS, new WorldPoint(1511, 3631, 0)),
A_TASTE_OF_HOPE(Quest.A_TASTE_OF_HOPE, new WorldPoint(3668, 3216, 0)),
TEARS_OF_GUTHIX(Quest.TEARS_OF_GUTHIX, new WorldPoint(3251, 9517, 0)),
TEMPLE_OF_IKOV(Quest.TEMPLE_OF_IKOV, new WorldPoint(2574, 3320, 0)),
THRONE_OF_MISCELLANIA_ROYAL_TROUBLE(new Quest[]{Quest.THRONE_OF_MISCELLANIA, Quest.ROYAL_TROUBLE}, new WorldPoint(2497, 3859, 0)),
THE_TOURIST_TRAP(Quest.THE_TOURIST_TRAP, new WorldPoint(3302, 3113, 0)),
TOWER_OF_LIFE(Quest.TOWER_OF_LIFE, new WorldPoint(2640, 3218, 0)),
TREE_GNOME_VILLAGE(Quest.TREE_GNOME_VILLAGE, new WorldPoint(2541, 3169, 0)),
TRIBAL_TOTEM(Quest.TRIBAL_TOTEM, new WorldPoint(2790, 3182, 0)),
TROLL_ROMANCE(Quest.TROLL_ROMANCE, new WorldPoint(2890, 10097, 0)),
UNDERGROUND_PASS_REGICIDE(new Quest[]{Quest.REGICIDE, Quest.UNDERGROUND_PASS}, new WorldPoint(2575, 3293, 0)),
WANTED_SLUG_MENACE(new Quest[]{Quest.WANTED, Quest.THE_SLUG_MENACE}, new WorldPoint(2996, 3373, 0)),
WATCHTOWER(Quest.WATCHTOWER, new WorldPoint(2545, 3112, 0)),
WATERFALL_QUEST(Quest.WATERFALL_QUEST, new WorldPoint(2521, 3498, 0)),
WHAT_LIES_BELOW(Quest.WHAT_LIES_BELOW, new WorldPoint(3265, 3333, 0)),
WITCHS_HOUSE(Quest.WITCHS_HOUSE, new WorldPoint(2927, 3456, 0)),
ZOGRE_FLESH_EATERS(Quest.ZOGRE_FLESH_EATERS, new WorldPoint(2442, 3051, 0));
@Getter
private final WorldPoint location;
@Getter
private final Quest[] quests;
QuestStartLocation(Quest[] quests, WorldPoint location)
{
this.location = location;
this.quests = quests;
}
QuestStartLocation(Quest quest, WorldPoint location)
{
this.location = location;
this.quests = new Quest[]{quest};
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (c) 2018, John James Hamilton <https://github.com/johnhamilto>
* 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.worldmap;
import net.runelite.api.coords.WorldPoint;
import net.runelite.client.ui.overlay.worldmap.WorldMapPoint;
import java.awt.image.BufferedImage;
class QuestStartPoint extends WorldMapPoint
{
QuestStartPoint(WorldPoint location, BufferedImage icon, String tooltip)
{
super(location, icon);
setTooltip(tooltip);
}
}

View File

@@ -0,0 +1,250 @@
/*
* Copyright (c) 2018, Spedwards <https://github.com/Spedwards>
* 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.worldmap;
import lombok.Getter;
import net.runelite.api.coords.WorldPoint;
@Getter
enum RareTreeLocation
{
WILLOW("Willow tree", 30,
// Kandarin
new WorldPoint(2710, 3510, 0)),
TEAK("Teak tree", 35,
// Ape Atoll
new WorldPoint(2774, 2697, 0),
// Desert
new WorldPoint(3510, 3073, 0),
// Mos Le'Harmless
new WorldPoint(3832, 3067, 0),
// Karamja
new WorldPoint(2837, 2907, 0),
new WorldPoint(2899, 2897, 0),
// Feldip Hills
new WorldPoint(2333, 3049, 0),
// Prifddinas
new WorldPoint(3309, 6123, 0)),
SWAYING("Swaying tree", 40,
// The Fremennik Trials
new WorldPoint(2738, 3639, 0)),
MATURE_JUNIPER("Mature juniper tree", 42,
// Zeah
new WorldPoint(1690, 3524, 0)),
MAPLE("Maple tree", 45,
// Zeah
new WorldPoint(1231, 3704, 0),
new WorldPoint(1293, 3756, 0),
new WorldPoint(1640, 3496, 0),
new WorldPoint(1613, 3494, 0),
new WorldPoint(1560, 3636, 0),
new WorldPoint(1646, 3590, 0),
// Miscellania
new WorldPoint(2550, 3869, 0),
// Kandarin
new WorldPoint(2712, 3382, 0),
new WorldPoint(2720, 3465, 0),
new WorldPoint(2726, 3501, 0),
new WorldPoint(2728, 3481, 0),
new WorldPoint(2748, 3466, 0),
new WorldPoint(2710, 3570, 0),
// Prifddinas
new WorldPoint(2209, 3427, 0),
new WorldPoint(3233, 6179, 0)),
MAHOGANY("Mahogany tree", 50,
// Zeah
new WorldPoint(1237, 3770, 0),
// Ape Atoll
new WorldPoint(2716, 2710, 0),
new WorldPoint(2725, 2735, 0),
// Mos Le'Harmless
new WorldPoint(3824, 3053, 0),
// Karamja
new WorldPoint(2946, 2908, 0),
// Prifddinas
new WorldPoint(3301, 6129, 0)),
TEAK_MAHOGANY("Teak/Mahogany trees", 50,
// Miscellania
new WorldPoint(2602, 3895, 0),
// Mos Le'Harmless
new WorldPoint(3810, 3058, 0),
// Karamja
new WorldPoint(2821, 3084, 0)),
YEW("Yew tree", 60,
// Zeah
new WorldPoint(1217, 3688, 0),
new WorldPoint(1353, 3731, 0),
new WorldPoint(1529, 3452, 0),
new WorldPoint(1591, 3421, 0),
new WorldPoint(1647, 3508, 0),
new WorldPoint(1621, 3512, 0),
new WorldPoint(1593, 3491, 0),
new WorldPoint(1583, 3499, 0),
new WorldPoint(1696, 3554, 0),
new WorldPoint(1625, 3677, 0),
new WorldPoint(1625, 3669, 0),
new WorldPoint(1642, 3683, 0),
new WorldPoint(1642, 3663, 0),
new WorldPoint(1642, 3533, 0),
new WorldPoint(1671, 3657, 0),
new WorldPoint(1680, 3657, 0),
// Tirannwn
new WorldPoint(2217, 3141, 0),
// Prifddinas
new WorldPoint(3288, 6066, 0),
new WorldPoint(3305, 6032, 0),
// Kandarin
new WorldPoint(2315, 3610, 0),
new WorldPoint(2331, 3514, 0),
new WorldPoint(2358, 3510, 0),
new WorldPoint(2360, 3471, 0),
new WorldPoint(2434, 3432, 0),
new WorldPoint(2493, 3396, 0),
new WorldPoint(2495, 3490, 0),
new WorldPoint(2733, 3334, 0),
new WorldPoint(2757, 3431, 0),
new WorldPoint(2714, 3460, 0),
// Asgarnia
new WorldPoint(2995, 3312, 0),
new WorldPoint(3018, 3316, 0),
new WorldPoint(3041, 3320, 0),
new WorldPoint(3052, 3272, 0),
new WorldPoint(2931, 3231, 0),
// Misthalin
new WorldPoint(3085, 3481, 0),
new WorldPoint(3085, 3469, 0),
new WorldPoint(3146, 3255, 0),
new WorldPoint(3151, 3231, 0),
new WorldPoint(3165, 3220, 0),
new WorldPoint(3184, 3227, 0),
new WorldPoint(3251, 3364, 0),
new WorldPoint(3204, 3504, 0),
new WorldPoint(3208, 3500, 0),
new WorldPoint(3221, 3503, 0),
new WorldPoint(3248, 3473, 0),
new WorldPoint(3266, 3494, 0),
new WorldPoint(3270, 3471, 0),
new WorldPoint(3304, 3470, 0),
new WorldPoint(3249, 3202, 0),
// Morytania
new WorldPoint(3674, 3447, 0),
new WorldPoint(3684, 3385, 0),
// Zanaris
new WorldPoint(2412, 4464, 0),
new WorldPoint(2465, 4427, 0),
new WorldPoint(2491, 4426, 0)),
MAPLE_YEW("Maple/Yew trees", 60,
// Feldip Hills
new WorldPoint(2476, 2893, 0)),
SULLIUSCEP("Sulliuscep", 65,
// Fossil Island
new WorldPoint(3662, 3802, 0),
new WorldPoint(3662, 3781, 0),
new WorldPoint(3677, 3806, 0),
new WorldPoint(3677, 3733, 0),
new WorldPoint(3682, 3775, 0),
new WorldPoint(3682, 3758, 0)),
MAGIC("Magic tree", 75,
// Zeah
new WorldPoint(1373, 3821, 0),
new WorldPoint(1389, 3821, 0),
new WorldPoint(1610, 3443, 0),
new WorldPoint(1578, 3488, 0),
new WorldPoint(1685, 3740, 0),
new WorldPoint(1681, 3689, 0),
new WorldPoint(1751, 3564, 0),
new WorldPoint(1796, 3600, 0),
// Misthalin
new WorldPoint(3355, 3312, 0),
new WorldPoint(3368, 3312, 0),
// Tirannwn
new WorldPoint(2284, 3141, 0),
// Prifddinas
new WorldPoint(3229, 6101, 0),
// Kandarin
new WorldPoint(2371, 3427, 0),
new WorldPoint(2432, 3411, 0),
new WorldPoint(2490, 3414, 0),
new WorldPoint(2704, 3397, 0),
new WorldPoint(2695, 3423, 0),
// Feldip Hills
new WorldPoint(2443, 2845, 0),
// Wilderness
new WorldPoint(3175, 3931, 0)),
REDWOOD("Redwood tree", 90,
// Zeah
new WorldPoint(1569, 3493, 0),
new WorldPoint(1569, 3483, 0));
private final String tooltip;
private final WorldPoint[] locations;
private final int levelReq;
RareTreeLocation(String description, int level, WorldPoint... locations)
{
this.tooltip = description + " - Level " + level;
this.locations = locations;
this.levelReq = level;
}
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) 2018, Spedwards <https://github.com/Spedwards>
* 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.worldmap;
import net.runelite.api.coords.WorldPoint;
import net.runelite.client.ui.overlay.worldmap.WorldMapPoint;
import java.awt.image.BufferedImage;
class RareTreePoint extends WorldMapPoint
{
RareTreePoint(WorldPoint point, String tooltip, BufferedImage icon, boolean showTooltip)
{
super(point, icon);
if (showTooltip)
{
setTooltip(tooltip);
}
}
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright (c) 2019, Dava96 <https://github.com/Dava96>
* 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.worldmap;
import lombok.Getter;
import net.runelite.api.coords.WorldPoint;
@Getter
enum RunecraftingAltarLocation
{
AIR_ALTAR("Air Altar", 1, new WorldPoint(2985, 3293, 0), "air_altar_icon.png"),
MIND_ALTAR("Mind Altar", 2, new WorldPoint(2982, 3514, 0), "mind_altar_icon.png"),
WATER_ALTAR("Water Altar", 5, new WorldPoint(3185, 3165, 0), "water_altar_icon.png"),
EARTH_ALTAR("Earth Altar", 9, new WorldPoint(3306, 3474, 0), "earth_altar_icon.png"),
FIRE_ALTAR("Fire Altar", 14, new WorldPoint(3313, 3255, 0), "fire_altar_icon.png"),
BODY_ALTAR("Body Altar", 20, new WorldPoint(3053, 3445, 0), "body_altar_icon.png"),
COSMIC_ALTAR("Cosmic Altar", 27, new WorldPoint(2408, 4377, 0), "cosmic_altar_icon.png"),
CHAOS_ALTAR("Chaos Altar", 35, new WorldPoint(3060, 3591, 0), "chaos_altar_icon.png"),
ASTRAL_ALTAR("Astral Altar", 40, new WorldPoint(2158, 3864, 0), "astral_altar_icon.png"),
NATURE_ALTAR("Nature Altar", 44, new WorldPoint(2869, 3019, 0), "nature_altar_icon.png"),
LAW_ALTAR("Law Altar", 54, new WorldPoint(2858, 3381, 0), "law_altar_icon.png"),
DEATH_ALTAR("Death Altar", 65, new WorldPoint(1860, 4639, 0), "death_altar_icon.png"),
BLOOD_ALTAR("Blood Altar", 77, new WorldPoint(1716, 3827, 0), "blood_altar_icon.png"),
SOUL_ALTAR("Soul Altar", 90, new WorldPoint(1814, 3856, 0), "soul_altar_icon.png"),
WRATH_ALTAR("Wrath Altar", 95, new WorldPoint(2446, 2825, 0), "wrath_altar_icon.png");
private final String tooltip;
private final WorldPoint location;
private final int levelReq;
private final String iconPath;
RunecraftingAltarLocation(String description, int level, WorldPoint location, String iconPath)
{
this.tooltip = description + " - Level " + level;
this.location = location;
this.levelReq = level;
this.iconPath = iconPath;
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (c) 2019, Dava96 <https://github.com/Dava96>
* 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.worldmap;
import net.runelite.client.ui.overlay.worldmap.WorldMapPoint;
import net.runelite.client.util.ImageUtil;
class RunecraftingAltarPoint extends WorldMapPoint
{
RunecraftingAltarPoint(RunecraftingAltarLocation point)
{
super(point.getLocation(), WorldMapPlugin.BLANK_ICON);
setImage(ImageUtil.getResourceStreamFromClass(WorldMapPlugin.class, point.getIconPath()));
setTooltip(point.getTooltip());
}
}

View File

@@ -0,0 +1,220 @@
/*
* 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 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.worldmap;
import lombok.Getter;
import net.runelite.api.coords.WorldPoint;
@Getter
enum TeleportLocationData
{
VARROCK(TeleportType.NORMAL_MAGIC, "Varrock", 25, new WorldPoint(3213, 3424, 0), "varrock_teleport_icon.png"),
VARROCK_GE(TeleportType.NORMAL_MAGIC, "Varrock GE", 25, new WorldPoint(3164, 3478, 0), "varrock_teleport_icon.png"),
LUMBRIDGE(TeleportType.NORMAL_MAGIC, "Lumbridge", 31, new WorldPoint(3222, 3218, 0), "lumbridge_teleport_icon.png"),
FALADOR(TeleportType.NORMAL_MAGIC, "Falador", 37, new WorldPoint(2965, 3381, 0), "falador_teleport_icon.png"),
CAMELOT(TeleportType.NORMAL_MAGIC, "Camelot", 45, new WorldPoint(2757, 3477, 0), "camelot_teleport_icon.png"),
CAMELOT_BANK(TeleportType.NORMAL_MAGIC, "Camelot Bank", 45, new WorldPoint(2726, 3485, 0), "camelot_teleport_icon.png"),
ARDOUGNE(TeleportType.NORMAL_MAGIC, "Ardougne", 51, new WorldPoint(2664, 3306, 0), "ardougne_teleport_icon.png"),
WATCHTOWER(TeleportType.NORMAL_MAGIC, "Watchtower", 58, new WorldPoint(2547, 3114, 0), "watchtower_teleport_icon.png"),
WATCHTOWER_YANILLE(TeleportType.NORMAL_MAGIC, "Watchtower Yanille", 58, new WorldPoint(2584, 3097, 0), "watchtower_teleport_icon.png"),
TROLLHEIM(TeleportType.NORMAL_MAGIC, "Trollheim", 61, new WorldPoint(2891, 3678, 0), "trollheim_teleport_icon.png"),
APE_ATOLL(TeleportType.NORMAL_MAGIC, "Ape Atoll", 64, new WorldPoint(2796, 2791, 0), "ape_atoll_teleport_icon.png"),
KOUREND(TeleportType.NORMAL_MAGIC, "Kourend", 69, new WorldPoint(1643, 3672, 0), "kourend_teleport_icon.png"),
PADDEWWA(TeleportType.ANCIENT_MAGICKS, "Paddewwa", 54, new WorldPoint(3097, 9880, 0), "paddewwa_teleport_icon.png"),
SENNTISTEN(TeleportType.ANCIENT_MAGICKS, "Senntisten", 60, new WorldPoint(3319, 3336, 0), "senntisten_teleport_icon.png"),
KHARYRLL(TeleportType.ANCIENT_MAGICKS, "Kharyrll", 66, new WorldPoint(3494, 3473, 0), "kharyrll_teleport_icon.png"),
LASSAR(TeleportType.ANCIENT_MAGICKS, "Lassar", 72, new WorldPoint(3002, 3472, 0), "lassar_teleport_icon.png"),
DAREEYAK(TeleportType.ANCIENT_MAGICKS, "Dareeyak", 78, new WorldPoint(2969, 3695, 0), "dareeyak_teleport_icon.png"),
CARRALLANGAR(TeleportType.ANCIENT_MAGICKS, "Carrallangar", 84, new WorldPoint(3157, 3667, 0), "carrallangar_teleport_icon.png"),
ANNAKARL(TeleportType.ANCIENT_MAGICKS, "Annakarl", 90, new WorldPoint(3288, 3888, 0), "annakarl_teleport_icon.png"),
GHORROCK(TeleportType.ANCIENT_MAGICKS, "Ghorrock", 96, new WorldPoint(2977, 3872, 0), "ghorrock_teleport_icon.png"),
MOONCLAN(TeleportType.LUNAR_MAGIC, "Moonclan", 69, new WorldPoint(2113, 3915, 0), "moonclan_teleport_icon.png"),
OURANIA(TeleportType.LUNAR_MAGIC, "Ourania", 71, new WorldPoint(2468, 3246, 0), "ourania_teleport_icon.png"),
WATERBIRTH(TeleportType.LUNAR_MAGIC, "Waterbirth", 72, new WorldPoint(2546, 3755, 0), "waterbirth_teleport_icon.png"),
BARBARIAN(TeleportType.LUNAR_MAGIC, "Barbarian", 75, new WorldPoint(2543, 3568, 0), "barbarian_teleport_icon.png"),
KHAZARD(TeleportType.LUNAR_MAGIC, "Khazard", 78, new WorldPoint(2636, 3167, 0), "khazard_teleport_icon.png"),
FISHING_GUILD(TeleportType.LUNAR_MAGIC, "Fishing Guild", 85, new WorldPoint(2612, 3391, 0), "fishing_guild_teleport_icon.png"),
CATHERBY(TeleportType.LUNAR_MAGIC, "Catherby", 87, new WorldPoint(2802, 3449, 0), "catherby_teleport_icon.png"),
ICE_PLATEAU(TeleportType.LUNAR_MAGIC, "Ice Plateau", 89, new WorldPoint(2973, 3939, 0), "ice_plateau_teleport_icon.png"),
LUMBRIDGE_GRAVEYARD(TeleportType.ARCEUUS_MAGIC, "Lumbridge Graveyard", 6, new WorldPoint(3241, 3194, 0), "lumbridge_graveyard_teleport_icon.png"),
DRAYNOR_MANOR(TeleportType.ARCEUUS_MAGIC, "Draynor Manor", 17, new WorldPoint(3108, 3352, 0), "draynor_manor_teleport_icon.png"),
BATTLEFRONT(TeleportType.ARCEUUS_MAGIC, "Battlefront", 23, new WorldPoint(1349, 3739, 0), "battlefront_teleport_icon.png"),
MIND_ALTAR(TeleportType.ARCEUUS_MAGIC, "Mind Altar", 28, new WorldPoint(2979, 3509, 0), "mind_altar_teleport_icon.png"),
SALVE_GRAVEYARD(TeleportType.ARCEUUS_MAGIC, "Salve Graveyard", 40, new WorldPoint(3433, 3461, 0), "salve_graveyard_teleport_icon.png"),
FENKENSTRAINS_CASTLE(TeleportType.ARCEUUS_MAGIC, "Fenkenstrain's Castle", 48, new WorldPoint(3548, 3528, 0), "fenkenstrains_castle_teleport_icon.png"),
WEST_ARDOUGNE(TeleportType.ARCEUUS_MAGIC, "West Ardougne", 61, new WorldPoint(2500, 3291, 0), "west_ardougne_teleport_icon.png"),
HARMONY_ISLAND(TeleportType.ARCEUUS_MAGIC, "Harmony Island", 65, new WorldPoint(3797, 2866, 0), "harmony_island_teleport_icon.png"),
CEMETERY(TeleportType.ARCEUUS_MAGIC, "Cemetery", 71, new WorldPoint(2978, 3763, 0), "cemetery_teleport_icon.png"),
BARROWS(TeleportType.ARCEUUS_MAGIC, "Barrows", 83, new WorldPoint(3565, 3315, 0), "barrows_teleport_icon.png"),
APE_ATOLL_ARCEUUS(TeleportType.ARCEUUS_MAGIC, "Ape Atoll", 90, new WorldPoint(2770, 2703, 0), "ape_atoll_teleport_icon_arceuus.png"),
// Jewellery
BARBARIAN_ASSAULT(TeleportType.JEWELLERY, "Games Necklace" , "Barbarian Assault", new WorldPoint(2520, 3571, 0), "games_necklace_teleport_icon.png"),
BURTHORPE_GAMES_ROOM(TeleportType.JEWELLERY, "Games Necklace" , "Burthorpe Games Room", new WorldPoint(2898, 3554, 0), "games_necklace_teleport_icon.png"),
TEARS_OF_GUTHIX(TeleportType.JEWELLERY, "Games Necklace" , "Tears of Guthix", new WorldPoint(3245, 9500, 0), "games_necklace_teleport_icon.png"),
CORPOREAL_BEAST(TeleportType.JEWELLERY, "Games Necklace" , "Corporeal Beast", new WorldPoint(2967, 4384, 0), "games_necklace_teleport_icon.png"),
WINTERTODT_CAMP(TeleportType.JEWELLERY, "Games Necklace" , "Wintertodt Camp", new WorldPoint(1624, 3938, 0), "games_necklace_teleport_icon.png"),
DUEL_ARENA(TeleportType.JEWELLERY, "Ring of Dueling" , "Duel Arena", new WorldPoint(3315, 3235, 0), "ring_of_dueling_teleport_icon.png"),
FEROX_ENCLAVE(TeleportType.JEWELLERY, "Ring of Dueling" , "Ferox Enclave", new WorldPoint(3151, 3636, 0), "ring_of_dueling_teleport_icon.png"),
CASTLE_WARS(TeleportType.JEWELLERY, "Ring of Dueling" , "Castle Wars", new WorldPoint(2441, 3091, 0), "ring_of_dueling_teleport_icon.png"),
WARRIORS_GUILD(TeleportType.JEWELLERY, "Combat Bracelet" , "Warriors' Guild", new WorldPoint(2883, 3549, 0), "combat_bracelet_teleport_icon.png"),
CHAMPIONS_GUILD(TeleportType.JEWELLERY, "Combat Bracelet" , "Champions' Guild", new WorldPoint(3189, 3368, 0), "combat_bracelet_teleport_icon.png"),
EDGEVILLE_MONASTERY(TeleportType.JEWELLERY, "Combat Bracelet" , "Edgeville Monastery", new WorldPoint(3053, 3487, 0), "combat_bracelet_teleport_icon.png"),
RANGING_GUILD(TeleportType.JEWELLERY, "Combat Bracelet" , "Ranging Guild", new WorldPoint(2654, 3441, 0), "combat_bracelet_teleport_icon.png"),
FISHING_GUILD_NECK(TeleportType.JEWELLERY, "Skills Necklace" , "Fishing Guild", new WorldPoint(2613, 3390, 0), "skills_necklace_teleport_icon.png"),
MINING_GUILD(TeleportType.JEWELLERY, "Skills Necklace" , "Mining Guild", new WorldPoint(3049, 9762, 0), "skills_necklace_teleport_icon.png"),
CRAFTING_GUILD(TeleportType.JEWELLERY, "Skills Necklace" , "Crafting Guild", new WorldPoint(2934, 3294, 0), "skills_necklace_teleport_icon.png"),
COOKING_GUILD(TeleportType.JEWELLERY, "Skills Necklace" , "Cooking Guild", new WorldPoint(3145, 3438, 0), "skills_necklace_teleport_icon.png"),
WOODCUTTING_GUILD(TeleportType.JEWELLERY, "Skills Necklace" , "Woodcutting Guild", new WorldPoint(1662, 3505, 0), "skills_necklace_teleport_icon.png"),
FARMING_GUILD(TeleportType.JEWELLERY, "Skills Necklace" , "Farming Guild", new WorldPoint(1249, 3717, 0), "skills_necklace_teleport_icon.png"),
EDGEVILLE(TeleportType.JEWELLERY, "Amulet of Glory" , "Edgeville", new WorldPoint(3087, 3496, 0), "amulet_of_glory_teleport_icon.png"),
KARAMJA(TeleportType.JEWELLERY, "Amulet of Glory" , "Karamja", new WorldPoint(2918, 3176, 0), "amulet_of_glory_teleport_icon.png"),
DRAYNOR_VILLAGE(TeleportType.JEWELLERY, "Amulet of Glory" , "Draynor Village", new WorldPoint(3105, 3251, 0), "amulet_of_glory_teleport_icon.png"),
AL_KHARID(TeleportType.JEWELLERY, "Amulet of Glory" , "Al-Kharid", new WorldPoint(3293, 3163, 0), "amulet_of_glory_teleport_icon.png"),
MISCELLANIA(TeleportType.JEWELLERY, "Ring of Wealth" , "Miscellania", new WorldPoint(2535, 3862, 0), "ring_of_wealth_teleport_icon.png"),
GRAND_EXCHANGE(TeleportType.JEWELLERY, "Ring of Wealth" , "Grand Exchange", new WorldPoint(3162, 3480, 0), "ring_of_wealth_teleport_icon.png"),
FALADOR_PARK(TeleportType.JEWELLERY, "Ring of Wealth" , "Falador Park", new WorldPoint(2995, 3375, 0), "ring_of_wealth_teleport_icon.png"),
DONDAKAN(TeleportType.JEWELLERY, "Ring of Wealth" , "Dondakan", new WorldPoint(2831, 10165, 0), "ring_of_wealth_teleport_icon.png"),
SLAYER_TOWER(TeleportType.JEWELLERY, "Slayer Ring" , "Slayer Tower", new WorldPoint(3423, 3536, 0), "slayer_ring_teleport_icon.png"),
FREMENNIK_SLAYER_DUNGEON(TeleportType.JEWELLERY, "Slayer Ring" , "Fremennik Slayer Dungeon", new WorldPoint(2800, 9998, 0), "slayer_ring_teleport_icon.png"),
FREMENNIK_SLAYER_DUNGEON_OUTSIDE(TeleportType.JEWELLERY, "Slayer Ring" , "Fremennik Slayer Dungeon (inside)", new WorldPoint(2800, 3615, 0), "slayer_ring_teleport_icon.png"),
TARNS_LAIR(TeleportType.JEWELLERY, "Slayer Ring" , "Tarn's Lair", new WorldPoint(3187, 4601, 0), "slayer_ring_teleport_icon.png"),
STRONGHOLD_SLAYER_CAVE(TeleportType.JEWELLERY, "Slayer Ring" , "Stronghold Slayer Cave", new WorldPoint(2433, 3421, 0), "slayer_ring_teleport_icon.png"),
DARK_BEASTS(TeleportType.JEWELLERY, "Slayer Ring" , "Dark Beasts", new WorldPoint(2028, 4638, 0), "slayer_ring_teleport_icon.png"),
DIGSITE(TeleportType.JEWELLERY, "Digsite Pendant" , "Digsite", new WorldPoint(3339, 3445, 0), "digsite_pendant_teleport_icon.png"),
HOUSE_ON_THE_HILL(TeleportType.JEWELLERY, "Digsite Pendant" , "House on the Hill", new WorldPoint(3763, 3869, 0), "digsite_pendant_teleport_icon.png"),
LITHKREN(TeleportType.JEWELLERY, "Digsite Pendant" , "Lithkren", new WorldPoint(3547, 10456, 0), "digsite_pendant_teleport_icon.png"),
WIZARDS_TOWER(TeleportType.JEWELLERY, "Necklace of Passage" , "Wizards' Tower", new WorldPoint(3114, 3181, 0), "necklace_of_passage_teleport_icon.png"),
JORRALS_OUTPOST(TeleportType.JEWELLERY, "Necklace of Passage" , "Jorral's Outpost", new WorldPoint(2431, 3348, 0), "necklace_of_passage_teleport_icon.png"),
DESERT_EAGLE_STATION(TeleportType.JEWELLERY, "Necklace of Passage" , "Desert eagle station of the eagle transport system", new WorldPoint(3406, 3157, 0), "necklace_of_passage_teleport_icon.png"),
CHAOS_TEMPLE(TeleportType.JEWELLERY, "Burning Amulet" , "Chaos Temple (lvl 15)", new WorldPoint(3234, 3637, 0), "burning_amulet_teleport_icon.png"),
BANDIT_CAMP(TeleportType.JEWELLERY, "Burning Amulet" , "Bandit Camp (lvl 17)", new WorldPoint(3038, 3651, 0), "burning_amulet_teleport_icon.png"),
LAVA_MAZE(TeleportType.JEWELLERY, "Burning Amulet" , "Lava Maze (lvl 41)", new WorldPoint(3028, 3840, 0), "burning_amulet_teleport_icon.png"),
// Misc
XERICS_LOOKOUT(TeleportType.OTHER, "Xeric's Talisman", "Xeric's Lookout", new WorldPoint(1576, 3528, 0), "xerics_talisman_teleport_icon.png"),
XERICS_GLADE(TeleportType.OTHER, "Xeric's Talisman", "Xeric's Glade", new WorldPoint(1754, 3564, 0), "xerics_talisman_teleport_icon.png"),
XERICS_INFERNO(TeleportType.OTHER, "Xeric's Talisman", "Xeric's Inferno", new WorldPoint(1504, 3819, 0), "xerics_talisman_teleport_icon.png"),
XERICS_HEART(TeleportType.OTHER, "Xeric's Talisman", "Xeric's Heart", new WorldPoint(1641, 3670, 0), "xerics_talisman_teleport_icon.png"),
XERICS_HONOUR(TeleportType.OTHER, "Xeric's Talisman", "Xeric's Honour", new WorldPoint(1254, 3559, 0), "xerics_talisman_teleport_icon.png"),
STRONGHOLD_OF_SECURITY(TeleportType.OTHER, "Skull Sceptre", "Stronghold of Security", new WorldPoint(3081, 3421, 0), "skull_sceptre_teleport_icon.png"),
MYTHS_GUILD(TeleportType.OTHER, "Mythical Cape", "Myth's Guild", new WorldPoint(2458, 2851, 0), "mythical_cape_teleport_icon.png"),
ECTOFUNTUS(TeleportType.OTHER, "Ectophial", "Ectofuntus", new WorldPoint(3660, 3522, 0), "ectophial_teleport_icon.png"),
CHAMPIONS_GUILD_CHRONICLE(TeleportType.OTHER, "Chronicle", "Champions' Guild", new WorldPoint(3202, 3357, 0), "chronicle_teleport_icon.png"),
GRAND_TREE(TeleportType.OTHER, "Royal Seed Pod", "Grand Tree", new WorldPoint(2465, 3495, 0), "royal_seed_pod_teleport_icon.png"),
RELLEKKKA_LYRE(TeleportType.OTHER, "Enchanted Lyre", "Rellekka", new WorldPoint(2664, 3643, 0), "enchanted_lyre_teleport_icon.png"),
WATERBIRTH_ISLAND_LYRE(TeleportType.OTHER, "Enchanted Lyre", "Waterbirth Island", new WorldPoint(2550, 3756, 0), "enchanted_lyre_teleport_icon.png"),
NEITIZNOT_LYRE(TeleportType.OTHER, "Enchanted Lyre", "Neitiznot", new WorldPoint(2336, 3801, 0), "enchanted_lyre_teleport_icon.png"),
JATIZSO_LYRE(TeleportType.OTHER, "Enchanted Lyre", "Jatizso", new WorldPoint(2409, 3809, 0), "enchanted_lyre_teleport_icon.png"),
WEISS_ICY_BASALT(TeleportType.OTHER, "Icy Basalt", "Weiss", new WorldPoint(2846, 3940, 0), "icy_basalt_teleport_icon.png"),
TROLL_STRONGHOLD_STONY_BASALT(TeleportType.OTHER, "Stony Basalt", "Troll Stronghold (with 73 Agility)", new WorldPoint(2838, 3693, 0), "stony_basalt_teleport_icon.png"),
TROLL_STRONGHOLD_STONY_BASALT_OUTSIDE(TeleportType.OTHER, "Stony Basalt", "Troll Stronghold", new WorldPoint(2844, 3693, 0), "stony_basalt_teleport_icon.png"),
KHAREDSTS_MEMOIRS_HOSIDIUS(TeleportType.OTHER, "Kharedst's Memoirs", "Lunch by the Lancalliums (Hosidius)", new WorldPoint(1713, 3612, 0), "kharedsts_memoirs_teleport_icon.png"),
KHAREDSTS_MEMOIRS_PISCARILIUS(TeleportType.OTHER, "Kharedst's Memoirs", "The Fisher's Flute (Piscarilius)", new WorldPoint(1802, 3748, 0), "kharedsts_memoirs_teleport_icon.png"),
KHAREDSTS_MEMOIRS_SHAYZIEN(TeleportType.OTHER, "Kharedst's Memoirs", "History and Hearsay (Shayzien)", new WorldPoint(1476, 3580, 0), "kharedsts_memoirs_teleport_icon.png"),
KHAREDSTS_MEMOIRS_LOVAKENGJ(TeleportType.OTHER, "Kharedst's Memoirs", "Jewelry of Jubilation (Lovakengj)", new WorldPoint(1544, 3762, 0), "kharedsts_memoirs_teleport_icon.png"),
KHAREDSTS_MEMOIRS_ARCEUUS(TeleportType.OTHER, "Kharedst's Memoirs", "A Dark Disposition (Arceuus)", new WorldPoint(1680, 3746, 0), "kharedsts_memoirs_teleport_icon.png"),
PHARAOHS_SCEPTRE_JALSAVRAH(TeleportType.OTHER, "Pharaoh's Sceptre", "Jalsavrah (Pyramid Plunder)", new WorldPoint(3288, 2795, 0), "pharaohs_sceptre_teleport_icon.png"),
PHARAOHS_SCEPTRE_JALEUSTROPHOS(TeleportType.OTHER, "Pharaoh's Sceptre", "Jaleustrophos (Agility Pyramid)", new WorldPoint(3341, 2827, 0), "pharaohs_sceptre_teleport_icon.png"),
PHARAOHS_SCEPTRE_JALDRAOCHT(TeleportType.OTHER, "Pharaoh's Sceptre", "Jaldraocht (Desert Treasure Pyramid)", new WorldPoint(3232, 2897, 0), "pharaohs_sceptre_teleport_icon.png"),
CAMULET_TEMPLE(TeleportType.OTHER, "Camulet", "Enakhra's Temple", new WorldPoint(3190, 2923, 0), "camulet_teleport_icon.png"),
TELEPORT_CRYSTAL_LLETYA(TeleportType.OTHER, "Teleport crystal", "Lletya", new WorldPoint(2330, 3172, 0), "teleport_crystal_icon.png"),
TELEPORT_CRYSTAL_PRIFDDINAS(TeleportType.OTHER, "Teleport crystal", "Prifddinas", new WorldPoint(3264, 6065, 0), "teleport_crystal_icon.png"),
DRAKANS_MEDALLION_VER_SINHAZA(TeleportType.OTHER, "Drakan's medallion", "Ver Sinhaza", new WorldPoint(3649, 3230, 0), "drakans_medallion_teleport_icon.png"),
DRAKANS_MEDALLION_DARKMEYER(TeleportType.OTHER, "Drakan's medallion", "Darkmeyer", new WorldPoint(3592, 3337, 0), "drakans_medallion_teleport_icon.png"),
// Wilderness
OBELISK_13(TeleportType.OTHER, "Obelisk", "13", new WorldPoint(3156, 3620, 0), "obelisk_icon.png"),
OBELISK_19(TeleportType.OTHER, "Obelisk", "19", new WorldPoint(3227, 3667, 0), "obelisk_icon.png"),
OBELISK_27(TeleportType.OTHER, "Obelisk", "27", new WorldPoint(3035, 3732, 0), "obelisk_icon.png"),
OBELISK_35(TeleportType.OTHER, "Obelisk", "35", new WorldPoint(3106, 3794, 0), "obelisk_icon.png"),
OBELISK_44(TeleportType.OTHER, "Obelisk", "44", new WorldPoint(2980, 3866, 0), "obelisk_icon.png"),
OBELISK_50(TeleportType.OTHER, "Obelisk", "50", new WorldPoint(3307, 3916, 0), "obelisk_icon.png"),
WILDERNESS_CRABS_TELEPORT(TeleportType.OTHER, "Wilderness crabs teleport", new WorldPoint(3348, 3783, 0), "wilderness_crabs_teleport_icon.png"),
CANOE_WILDERNESS(TeleportType.OTHER, "Canoe (No departure)", "35", new WorldPoint(3141, 3796, 0), "transportation_icon.png"),
// Achievement Diary
ARDOUGNE_CLOAK_MONASTERY(TeleportType.OTHER, "Ardougne Cloak", "Monastery", new WorldPoint(2606, 3222, 0), "ardougne_cloak_icon.png"),
ARDOUGNE_CLOAK_FARM(TeleportType.OTHER, "Ardougne Cloak", "Farm", new WorldPoint(2673, 3375, 0), "ardougne_cloak_icon.png"),
EXPLORERS_RING(TeleportType.OTHER, "Explorer's Ring", new WorldPoint(3052, 3292, 0), "explorers_ring_icon.png"),
KARAMJA_GLOVES_GEM_MINE(TeleportType.OTHER, "Karamja Gloves", "Gem Mine (Underground)", new WorldPoint(2827, 2997, 0), "karamja_gloves_icon.png"),
KARAMJA_GLOVES_DURADEL(TeleportType.OTHER, "Karamja Gloves", "Duradel", new WorldPoint(2870, 2981, 0), "karamja_gloves_icon.png"),
DESERT_AMULET_NARDAH(TeleportType.OTHER, "Desert Amulet", "Nardah", new WorldPoint(3425, 2928, 0), "desert_amulet_icon.png"),
DESERT_AMULKT_KALPHITE_CAVE(TeleportType.OTHER, "Desert Amulet", "Kalphite Cave", new WorldPoint(3322, 3122, 0), "desert_amulet_icon.png"),
MORYTANIA_LEGS_SLIME_PIT(TeleportType.OTHER, "Morytania Legs", "Slime Pit (Underground)", new WorldPoint(3654, 3516, 0), "morytania_legs_icon.png"),
MORYTANIA_LEGS_BURGH_DE_ROTT(TeleportType.OTHER, "Morytania Legs", "Burgh de Rott", new WorldPoint(3482, 3231, 0), "morytania_legs_icon.png"),
FREMENNIK_SEA_BOOTS(TeleportType.OTHER, "Fremennik Sea Boots", new WorldPoint(2640, 3675, 0), "fremennik_boots_icon.png"),
KANDARIN_HEADGEAR(TeleportType.OTHER, "Kandarin Headgear", new WorldPoint(2729, 3411, 0), "kandarin_headgear_icon.png"),
WILDERNESS_SWORD(TeleportType.OTHER, "Wilderness Sword", new WorldPoint(3377, 3891, 0), "wilderness_sword_icon.png"),
WESTERN_BANNER(TeleportType.OTHER, "Western Banner", new WorldPoint(2329, 3685, 0), "western_banner_icon.png"),
RADAS_BLESSING_MOUNT_KARUULM(TeleportType.OTHER, "Rada's Blessing", new WorldPoint(1311, 3795, 0), "radas_blessing_icon.png"),
RADAS_BLESSING_WOODLANG(TeleportType.OTHER, "Rada's Blessing", new WorldPoint(1553, 3454, 0), "radas_blessing_icon.png"),
// Scrolls
DIGSITE_SCROLL(TeleportType.SCROLL, "Digsite Teleport", new WorldPoint(3324, 3412, 0), "scroll_teleport_icon.png"),
IORWERTH_CAMP_SCROLL(TeleportType.SCROLL, "Iorwerth Camp Teleport", new WorldPoint(2193, 3257, 0), "scroll_teleport_icon.png"),
FELDIP_HILLS_SCROLL(TeleportType.SCROLL, "Feldip Hills Teleport", new WorldPoint(2542, 2925, 0), "scroll_teleport_icon.png"),
LUMBERYARD_SCROLL(TeleportType.SCROLL, "Lumberyard Teleport", new WorldPoint(3303, 3487, 0), "scroll_teleport_icon.png"),
LUNAR_ISLE_SCROLL(TeleportType.SCROLL, "Lunar Isle Teleport", new WorldPoint(2093, 3912, 0), "scroll_teleport_icon.png"),
MORTTON_SCROLL(TeleportType.SCROLL, "Mort'ton", new WorldPoint(3489, 3288, 0), "scroll_teleport_icon.png"),
MOS_LEHARMLESS_SCROLL(TeleportType.SCROLL, "Mos Le'Harmless Teleport", new WorldPoint(3701, 2996, 0), "scroll_teleport_icon.png"),
NARDAH_SCROLL(TeleportType.SCROLL, "Nardah Teleport", new WorldPoint(3421, 2917, 0), "scroll_teleport_icon.png"),
PEST_CONTROL_SCROLL(TeleportType.SCROLL, "Pest Control Teleport", new WorldPoint(2657, 2660, 0), "scroll_teleport_icon.png"),
PISCATORIS_SCROLL(TeleportType.SCROLL, "Piscatoris Teleport", new WorldPoint(2339, 3648, 0), "scroll_teleport_icon.png"),
TAI_BWO_WANNAI_SCROLL(TeleportType.SCROLL, "Tai Bwo Wannai Teleport", new WorldPoint(2788, 3066, 0), "scroll_teleport_icon.png"),
ZULANDRA_SCROLL(TeleportType.SCROLL, "Zul-Andra Teleport", new WorldPoint(2197, 3056, 0), "scroll_teleport_icon.png"),
KEY_MASTER_SCROLL(TeleportType.SCROLL, "Key Master Teleport", new WorldPoint(2686, 9882, 0), "scroll_teleport_icon.png"),
REVENANT_CAVE_SCROLL(TeleportType.SCROLL, "Revenant Cave Teleport", new WorldPoint(3127, 3833, 0), "scroll_teleport_icon.png");
private final TeleportType type;
private final String tooltip;
private final WorldPoint location;
private final String iconPath;
TeleportLocationData(TeleportType type, String destination, int magicLevel, WorldPoint location, String iconPath)
{
this.type = type;
this.tooltip = type.getPrefix() + " " + destination + " - lvl " + magicLevel;
this.location = location;
this.iconPath = iconPath;
}
TeleportLocationData(TeleportType type, String item, String destination, WorldPoint location, String iconPath)
{
this.type = type;
this.tooltip = item + " - " + destination;
this.location = location;
this.iconPath = iconPath;
}
TeleportLocationData(TeleportType type, String item, WorldPoint location, String iconPath)
{
this.type = type;
this.tooltip = item;
this.location = location;
this.iconPath = iconPath;
}
}

View File

@@ -0,0 +1,39 @@
/*
* 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 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.worldmap;
import net.runelite.client.ui.overlay.worldmap.WorldMapPoint;
import net.runelite.client.util.ImageUtil;
class TeleportPoint extends WorldMapPoint
{
TeleportPoint(TeleportLocationData data)
{
super(data.getLocation(), WorldMapPlugin.BLANK_ICON);
setTooltip(data.getTooltip());
setImage(ImageUtil.getResourceStreamFromClass(WorldMapPlugin.class, data.getIconPath()));
}
}

View File

@@ -0,0 +1,47 @@
/*
* 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 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.worldmap;
import lombok.Getter;
@Getter
public enum TeleportType
{
NORMAL_MAGIC(""),
ANCIENT_MAGICKS("Ancient - "),
LUNAR_MAGIC("Lunar - "),
ARCEUUS_MAGIC("Arceuus - "),
JEWELLERY("Jewellery - "),
SCROLL(""),
OTHER("");
private String prefix;
TeleportType(String prefix)
{
this.prefix = prefix;
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright (c) 2019, Kyle Sergio <https://github.com/ksergio39>
* Copyright (c) 2019, Bryce Altomare <https://github.com/Twinkiel0ver>
* Copyright (c) 2019, Kyle Stead <http://github.com/kyle1elyk>
* 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.worldmap;
import net.runelite.api.coords.WorldPoint;
import net.runelite.client.ui.overlay.worldmap.WorldMapPoint;
import java.awt.image.BufferedImage;
class TransportationPoint extends WorldMapPoint
{
TransportationPoint(TransportationPointLocation data, BufferedImage icon)
{
super(data.getLocation(), icon);
final WorldPoint target = data.getTarget();
if (target != null)
{
setTarget(target);
setJumpOnClick(true);
}
setTooltip(data.getTooltip());
}
}

View File

@@ -0,0 +1,209 @@
/*
* Copyright (c) 2019, Kyle Sergio <https://github.com/ksergio39>
* Copyright (c) 2019, Bryce Altomare <https://github.com/Twinkiel0ver>
* Copyright (c) 2019, Kyle Stead <http://github.com/kyle1elyk>
* 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.worldmap;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.runelite.api.coords.WorldPoint;
import javax.annotation.Nullable;
@Getter
@AllArgsConstructor
enum TransportationPointLocation
{
//Ships
ARDOUGNE_TO_BRIMHAVEN("Ship to Brimhaven / Rimmington", new WorldPoint(2675, 3275, 0)),
ARDOUGNE_TO_FISHINGPLAT("Ship to Fishing Platform", new WorldPoint(2722, 3304, 0), new WorldPoint(2779, 3271, 0)),
BRIMHAVEN_TO_ARDOUGNE("Ship to Ardougne / Rimmington", new WorldPoint(2772, 3234, 0)),
RIMMINGTON_TO_ARDOUGNE("Ship to Ardougne / Brimhaven", new WorldPoint(2915, 3224, 0)),
CATHERBY_TO_KEEP_LE_FAYE("Ship to Keep Le Faye", new WorldPoint(2804, 3421, 0), new WorldPoint(2769, 3402, 0)),
CORSAIR_TO_RIMMINGTON("Ship to Rimmington", new WorldPoint(2577, 2839, 0), new WorldPoint(2909, 3227, 0 )),
DRAGONTOOTH_TO_PHASMATYS("Ship to Port Phasmatys", new WorldPoint(3791, 3561, 0), new WorldPoint(3703, 3487, 0)),
DIGSITE_TO_FOSSIL("Ship to Fossil Island", new WorldPoint(3361, 3448, 0), new WorldPoint(3723, 3807, 0)),
ENTRANA_TO_PORTSARIM("Ship to Port Sarim", new WorldPoint(2833, 3334, 0), new WorldPoint(3046, 3233, 0)),
FISHINGPLAT_TO_ARDOUGNE("Ship to Ardougne", new WorldPoint(2779, 3271, 0), new WorldPoint(2722, 3304, 0)),
HARMLESS_TO_PORT_PHASMATYS("Ship to Port Phasmatys", new WorldPoint(3682, 2951, 0), new WorldPoint(3709, 3497, 0)),
ICEBERG_TO_RELLEKKA("Ship to Rellekka", new WorldPoint(2657, 3988, 0), new WorldPoint(2707, 3735, 0)),
ISLAND_OF_STONE_TO_RELLEKKA("Ship to Rellekka", new WorldPoint(2470, 3994, 0), new WorldPoint(2621, 3692, 0)),
ISLAND_TO_APE_ATOLL("Ship to Ape Atoll", new WorldPoint(2891, 2726, 0), new WorldPoint(2802, 2706, 0)),
JATIZSO_TO_RELLEKKA("Ship to Rellekka", new WorldPoint(2420, 3780, 0), new WorldPoint(2639, 3710, 0)),
KARAMJA_TO_PORT_SARIM("Ship to Port Sarim", new WorldPoint(2955, 3145, 0), new WorldPoint(3029, 3218, 0)),
KARAMJA_TO_PORT_KHAZARD("Ship to Port Khazard", new WorldPoint(2763, 2957, 0), new WorldPoint(2653, 3166, 0)),
LANDSEND_TO_PORTSARIM_PORTPISCARILIUS("Ship to Port Sarim/Port Piscarilius", new WorldPoint(1503, 3398, 0)),
LUNAR_ISLE_TO_PIRATES_COVE("Ship to Pirates' Cove", new WorldPoint(2137, 3899, 0), new WorldPoint(2223, 3796, 0)),
MISCELLANIA_TO_RELLEKKA("Ship to Rellekka", new WorldPoint(2579, 3846, 0), new WorldPoint(2627, 3692, 0)),
NEITIZNOT_TO_RELLEKKA("Ship to Rellekka", new WorldPoint(2310, 3779, 0), new WorldPoint(2639, 3710, 0)),
PESTCONTROL_TO_PORTSARIM("Ship to Port Sarim", new WorldPoint(2659, 2675, 0), new WorldPoint(3039, 3201, 0)),
PIRATES_COVE_TO_LUNAR_ISLE("Ship to Lunar Isle", new WorldPoint(2223, 3796, 0), new WorldPoint(2137, 3899, 0)),
PIRATES_COVE_TO_RELLEKKA("Ship to Rellekka", new WorldPoint(2212, 3794, 0), new WorldPoint(2620, 3695, 0)),
PORT_PHASMATYS_TO_DRAGONTOOTH("Ship to Dragontooth Island", new WorldPoint(3703, 3487, 0), new WorldPoint(3791, 3561, 0)),
PORT_PHASMATYS_TO_HARMLESS("Ship to Mos Le'Harmless", new WorldPoint(3709, 3497, 0), new WorldPoint(3682, 2951, 0)),
PORT_PISCARILIUS_TO_PORTSARIM_LANDSEND("Ship to Port Sarim/Land's End", new WorldPoint(1823, 3692, 0)),
PORTSARIM_TO_GREAT_KOUREND("Ship to Great Kourend", new WorldPoint(3054, 3244, 0), new WorldPoint(1823, 3692, 0)),
PORTSARIM_TO_ENTRANA("Ship to Entrana", new WorldPoint(3046, 3233, 0), new WorldPoint(2833, 3334, 0)),
PORTSARIM_TO_KARAMJA("Ship to Karamja", new WorldPoint(3029, 3218, 0), new WorldPoint(2955, 3144, 0)),
PORTSARIM_TO_CRANDOR("Ship to Crandor", new WorldPoint(3045, 3205, 0), new WorldPoint(2839, 3261, 0)),
PORTSARIM_TO_PEST_CONTROL("Ship to Pest Control", new WorldPoint(3039, 3201, 0), new WorldPoint(2659, 2675, 0)),
RELLEKKA_TO_JATIZSO_NEITIZNOT("Ship to Jatizso/Neitiznot", new WorldPoint(2639, 3710, 0)),
RELLEKKA_TO_MISCELLANIA("Ship to Miscellania", new WorldPoint(2627, 3692, 0), new WorldPoint(2579, 3846, 0)),
RELLEKKA_TO_PIRATES_COVE("Ship to Pirates' Cove", new WorldPoint(2620, 3695, 0), new WorldPoint(2212, 3794, 0)),
RELLEKKA_TO_WATERBIRTH("Ship to Waterbirth", new WorldPoint(2618, 3685, 0), new WorldPoint(2549, 3758, 0)),
RELLEKKA_TO_WEISS_ICEBERG("Ship to Weiss/Iceberg", new WorldPoint(2707, 3735, 0)),
RELLEKKA_TO_UNGAEL("Ship to Ungael", new WorldPoint(2638, 3698, 0), new WorldPoint(2276, 4034, 0)),
RIMMINGTON_TO_CORSAIR_COVE("Ship to Corsair Cove", new WorldPoint(2909, 3227, 0 ), new WorldPoint(2577, 2839, 0)),
WATERBIRTH_TO_RELLEKKA("Ship to Rellekka", new WorldPoint(2549, 3758, 0), new WorldPoint(2618, 3685, 0)),
WEISS_TO_RELLEKKA("Ship to Rellekka", new WorldPoint(2847, 3967, 0), new WorldPoint(2707, 3735, 0)),
UNGAEL_TO_RELLEKKA("Ship to Rellekka", new WorldPoint(2276, 4034, 0), new WorldPoint(2638, 3698, 0)),
//Row Boats
ROW_BOAT_BATTLEFRONT("Rowboat to Molch/Molch Island/Shayzien", new WorldPoint(1383, 3663, 0)),
ROW_BOAT_BRAIN_DEATH("Rowboat to Port Phasmatys", new WorldPoint(2161, 5117, 0), new WorldPoint(3680, 3538, 0)),
ROW_BOAT_BURGH_DE_ROTT("Rowboat to Meiyerditch", new WorldPoint(3522, 3168, 0), new WorldPoint(3589, 3172, 0)),
ROW_BOAT_CRABCLAW("Rowboat to Hosidius", new WorldPoint(1780, 3417, 0), new WorldPoint(1779, 3457, 0)),
ROW_BOAT_DIVING_ISLAND("Rowboat to Barge/Camp/North of Island", new WorldPoint(3764, 3901, 0)),
ROW_BOAT_FISHING_GUILD("Rowboat to Hemenster", new WorldPoint(2598, 3426, 0), new WorldPoint(2613, 3439, 0)),
ROW_BOAT_GNOME_STRONGHOLD("Rowboat to Fishing Colony", new WorldPoint(2368, 3487, 0), new WorldPoint(2356, 3641, 0)),
ROW_BOAT_FISHING_COLONY("Rowboat to Gnome Stronghold", new WorldPoint(2356, 3641, 0), new WorldPoint(2368, 3487, 0)),
ROW_BOAT_HEMENSTER("Rowboat to Fishing Guild", new WorldPoint(2613, 3439, 0), new WorldPoint(2598, 3426, 0)),
ROW_BOAT_HOSIDIUS("Rowboat to Crabclaw Isle", new WorldPoint(1779, 3457, 0), new WorldPoint(1780, 3417, 0)),
ROW_BOAT_LITHKREN("Rowboat to Mushroom Forest", new WorldPoint(3582, 3973, 0), new WorldPoint(3659, 3849, 0)),
ROW_BOAT_LUMBRIDGE("Rowboat to Misthalin Mystery", new WorldPoint(3238, 3141, 0)),
ROW_BOAT_MOLCH("Rowboat to Molch Island/Shayzien/Battlefront", new WorldPoint(1343, 3646, 0)),
ROW_BOAT_MOLCH_ISLAND("Rowboat to Molch/Shayzien/Battlefront", new WorldPoint(1368, 3641, 0)),
ROW_BOAT_MORT("Rowboat to Mort Myre", new WorldPoint(3518, 3284, 0), new WorldPoint(3498, 3380, 0)),
ROW_BOAT_MORT_SWAMP("Rowboat to Mort'ton", new WorldPoint(3498, 3380, 0), new WorldPoint(3518, 3284, 0)),
ROW_BOAT_MUSEUM_CAMP("Rowboat to Barge/Digsite/North of Island", new WorldPoint(3723, 3807, 0)),
ROW_BOAT_MUSHROOM_FOREST_WEST("Rowboat to Lithkren", new WorldPoint(3659, 3849, 0), new WorldPoint(3582, 3973, 0)),
ROW_BOAT_MUSHROOM_FOREST_NE("Rowboat to Barge/Camp/Sea", new WorldPoint(3733, 3894, 0)),
ROW_BOAT_PORT_PHASMATYS_NORTH("Rowboat to Slepe", new WorldPoint(3670, 3545, 0), new WorldPoint(3661, 3279, 0)),
ROW_BOAT_PORT_PHASMATYS_EAST("Rowboat to Braindeath Island", new WorldPoint(3680, 3538, 0), new WorldPoint(2161, 5117, 0)),
ROW_BOAT_SHAYZIEN("Rowboat to Molch/Molch Island/Battlefront", new WorldPoint(1405, 3612, 0)),
ROW_BOAT_SLEPE("Rowboat to Port Phasmatys", new WorldPoint(3661, 3279, 0), new WorldPoint(3670, 3545, 0)),
OGRE_BOAT_FELDIP("Ogre Boat to Karamja", new WorldPoint(2653, 2964, 0), new WorldPoint(2757, 3085, 0)),
OGRE_BOAT_KARAMJA("Ogre Boat to Feldip", new WorldPoint(2757, 3085, 0), new WorldPoint(2653, 2964, 0)),
//Charter ships
CHARTER_BRIMHAVEN("Charter Ship", new WorldPoint(2760, 3238, 0)),
CHARTER_CATHERBY("Charter Ship", new WorldPoint(2791, 3415, 0)),
CHARTER_CORSAIR_("Charter Ship", new WorldPoint(2589, 2851, 0)),
CHARTER_KARAMJA_NORTH("Charter Ship", new WorldPoint(2954, 3158, 0)),
CHARTER_KARAMJA_EAST("Charter Ship", new WorldPoint(2999, 3032, 0)),
CHARTER_KHAZARD("Charter Ship", new WorldPoint(2673, 3143, 0)),
CHARTER_MOSLE_HARMLESS("Charter Ship", new WorldPoint(3669, 2931, 0)),
CHARTER_PORT_PHASMATYS("Charter Ship", new WorldPoint(3702, 3503, 0)),
CHARTER_PORTSARIM("Charter Ship", new WorldPoint(3037, 3191, 0)),
CHARTER_TYRAS("Charter Ship", new WorldPoint(2141, 3123, 0)),
CHARTER_PRIFDDINAS("Charter Ship", new WorldPoint(2156, 3331, 0)),
CHARTER_PRIFDDINAS_INSTANCE("Charter Ship", new WorldPoint(3180, 6083, 0)),
//Minecarts/Carts
MINE_CART_ARCEUUS("Minecart", new WorldPoint(1673, 3832, 0)),
MINE_CART_GRANDEXCHANGE("Minecart to Keldagrim", new WorldPoint(3139, 3504, 0)),
MINE_CART_HOSIDIUS("Minecart", new WorldPoint(1656, 3542, 0)),
MINE_CART_KELDAGRIM("Minecart", new WorldPoint(2908, 10170, 0)),
MINE_CART_LOVAKENGJ("Minecart", new WorldPoint(1524, 3721, 0)),
MINE_CART_PORT_PISCARILIUS("Minecart", new WorldPoint(1760, 3708, 0)),
MINE_CART_QUIDAMORTEM("Minecart", new WorldPoint(1253, 3550, 0)),
MINE_CART_SHAYZIEN("Minecart", new WorldPoint(1586, 3622, 0)),
MINE_CART_TAVERLEY_UNDERGROUND("Minecart", new WorldPoint(2874, 9870, 0)),
CART_TO_BRIMHAVEN("Cart to Brimhaven", new WorldPoint(2833, 2958, 0), new WorldPoint(2780, 3214, 0)),
CART_TO_SHILO("Cart to Shilo", new WorldPoint(2780, 3214, 0), new WorldPoint(2833, 2958, 0)),
//Canoes
CANOE_BARBVILLAGE("Canoe", new WorldPoint(3111, 3409, 0)),
CANOE_CHAMPIONSGUILD("Canoe", new WorldPoint(3202, 3344, 0)),
CANOE_EDGEVILLE("Canoe", new WorldPoint(3130, 3509, 0)),
CANOE_LUMBRIDGE("Canoe", new WorldPoint(3241, 3238, 0)),
CANOE_FEROXENCLAVE("Canoe", new WorldPoint(3155, 3630, 0)),
//Gnome Gliders
GNOME_GLIDER_KHARID("Gnome Glider", new WorldPoint(3278, 3213, 0)),
GNOME_GLIDER_APE_ATOLL("Gnome Glider", new WorldPoint(2712, 2804, 0)),
GNOME_GLIDER_KARAMJA("Gnome Glider", new WorldPoint(2971, 2974, 0)),
GNOME_GLIDER_FELDIP("Gnome Glider", new WorldPoint(2540, 2969, 0)),
GNOME_GLIDER_GNOMESTRONGHOLD("Gnome Glider", new WorldPoint(2460, 3502, 0)),
GNOME_GLIDER_WHITEWOLF("Gnome Glider", new WorldPoint(2845, 3501, 0)),
//Balloons
BALLOON_VARROCK("Hot Air Balloon", new WorldPoint(3298, 3480, 0)),
BALLOON_YANILLE("Hot Air Balloon", new WorldPoint(2458, 3108, 0)),
BALLOON_GNOMESTRONGHOLD("Hot Air Balloon", new WorldPoint(2478, 3459, 0)),
BALLOON_TAVERLEY("Hot Air Balloon", new WorldPoint(2936, 3422, 0)),
BALLOON_FALADOR("Hot Air Balloon", new WorldPoint(2921, 3301, 0)),
//Spirit Tree
SPIRITTREE_ARDOUGNE("Spirit Tree", new WorldPoint(2554, 3259, 0)),
SPIRITTREE_CORSAIR("Spirit Tree", new WorldPoint(2485, 2850, 0)),
SPIRITTREE_GNOMESTRONGHOLD("Spirit Tree", new WorldPoint(2459, 3446, 0)),
SPIRITTREE_GNOMEVILLAGE("Spirit Tree", new WorldPoint(2538, 3166, 0)),
SPIRITTREE_GRANDEXCHANGE("Spirit Tree", new WorldPoint(3184, 3510, 0)),
SPIRITTREE_PRIFDDINAS("Spirit Tree", new WorldPoint(3274, 6124, 0)),
//Carpets
CARPET_KHARID("Carpet to Bedabin/Pollnivneach/Uzer", new WorldPoint(3311, 3107, 0)),
CARPET_BEDABIN("Carpet to Shantay Pass", new WorldPoint(3183, 3042, 0), new WorldPoint(3311, 3107, 0)),
CARPET_POLLNIVNEACH_NORTH("Carpet to Shantay Pass", new WorldPoint(3351, 3001, 0), new WorldPoint(3311, 3107, 0)),
CARPET_POLLNIVNEACH_SOUTH("Carpet to Nardah/Sophanem/Menaphos", new WorldPoint(3345, 2943, 0)),
CARPET_NARDAH("Carpet to Pollnivneach", new WorldPoint(3399, 2916, 0), new WorldPoint(3345, 2943, 0)),
CARPET_SOPHANEM("Carpet to Pollnivneach", new WorldPoint(3288, 2814, 0), new WorldPoint(3345, 2943, 0)),
CARPET_MENAPHOS("Carpet to Pollnivneach", new WorldPoint(3244, 2812, 0), new WorldPoint(3345, 2943, 0)),
CARPET_UZER("Carpet to Shantay Pass", new WorldPoint(3468, 3111, 0), new WorldPoint(3311, 3107, 0)),
//Teleports
TELEPORT_ARCHIVE_FROM_ARCEUUS("Teleport to Library Archive", new WorldPoint(1623, 3808, 0)),
TELEPORT_HARMLESS_FROM_HARMONY("Teleport to Mos Le'Harmless", new WorldPoint(3784, 2828, 0)),
TELEPORT_RUNE_ARDOUGNE("Teleport to Rune Essence", new WorldPoint(2681, 3325, 0)),
TELEPORT_RUNE_YANILLE("Teleport to Rune Essence", new WorldPoint(2592, 3089, 0)),
TELEPORT_SORCERESS_GARDEN("Teleport to Sorceress's Garden", new WorldPoint(3320, 3141, 0)),
TELEPORT_PRIFDDINAS_LIBRARY("Teleport to Prifddinas Library", new WorldPoint(3254, 6082, 2)),
//Other
ALTER_KOUREND_UNDERGROUND("Altar to Skotizo", new WorldPoint(1662, 10047, 0)),
FAIRY_RING_ZANARIS_TO_KHARID("Fairy Ring to Al Kharid", new WorldPoint(2483, 4471, 0)),
FAIRY_RING_ZANARIS_TO_SHACK("Fairy Ring to Shack", new WorldPoint(2451, 4471, 0)),
MOUNTAIN_GUIDE_QUIDAMORTEM("Mountain Guide", new WorldPoint(1275, 3559, 0)),
MOUNTAIN_GUIDE_WALL("Mountain Guide", new WorldPoint(1400, 3538, 0)),
MUSHTREE_MUSHROOM_FOREST("Mushtree", new WorldPoint(3674, 3871, 0)),
MUSHTREE_TAR_SWAMP("Mushtree", new WorldPoint(3676, 3755, 0)),
MUSHTREE_VERDANT_VALLEY("Mushtree", new WorldPoint(3757, 3756, 0)),
MYTHS_GUILD_PORTAL("Portal to Guilds", new WorldPoint(2456, 2856, 0)),
TRAIN_KELDAGRIM("Railway Station", new WorldPoint(2941, 10179, 0)),
WILDERNESS_LEVER_ARDOUGNE("Wilderness Lever to Deserted Keep", new WorldPoint(2559, 3309, 0), new WorldPoint(3154, 3924, 0)),
WILDERNESS_LEVER_EDGEVILLE("Wilderness Lever to Deserted Keep", new WorldPoint(3088, 3474, 0), new WorldPoint(3154, 3924, 0)),
WILDERNESS_LEVER_WILDERNESS("Wilderness Lever to Ardougne/Edgeville", new WorldPoint(3154, 3924, 0));
private final String tooltip;
private final WorldPoint location;
@Nullable
private final WorldPoint target;
TransportationPointLocation(String tooltip, WorldPoint worldPoint)
{
this(tooltip, worldPoint, null);
}
}

View File

@@ -0,0 +1,309 @@
/*
* 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 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.worldmap;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
@ConfigGroup(WorldMapPlugin.CONFIG_KEY)
public interface WorldMapConfig extends Config
{
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_FAIRY_RING_TOOLTIPS,
name = "Show fairy ring codes in tooltip",
description = "Display the code for fairy rings in the icon tooltip",
position = 1
)
default boolean fairyRingTooltips()
{
return true;
}
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_FAIRY_RING_ICON,
name = "Show fairy ring travel icon",
description = "Override the travel icon for fairy rings",
position = 2
)
default boolean fairyRingIcon()
{
return true;
}
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_AGILITY_SHORTCUT_TOOLTIPS,
name = "Show agility level requirement",
description = "Display the required Agility level in the icon tooltip",
position = 3
)
default boolean agilityShortcutTooltips()
{
return true;
}
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_AGILITY_SHORTCUT_LEVEL_ICON,
name = "Indicate inaccessible shortcuts",
description = "Indicate shortcuts you do not have the level to use on the icon",
position = 4
)
default boolean agilityShortcutLevelIcon()
{
return true;
}
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_AGILITY_COURSE_TOOLTIPS,
name = "Show agility course in tooltip",
description = "Displays the name of the agility course in the tooltip",
position = 5
)
default boolean agilityCourseTooltip()
{
return true;
}
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_AGILITY_COURSE_ROOFTOP_ICON,
name = "Indicate rooftop courses",
description = "Replace the agility icon with a mark of grace for rooftop courses",
position = 6
)
default boolean agilityCourseRooftop()
{
return true;
}
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_NORMAL_TELEPORT_ICON,
name = "Show Standard Spellbook destinations",
description = "Show icons at the destinations for teleports in the Standard Spellbook",
position = 7
)
default boolean normalTeleportIcon()
{
return true;
}
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_MINIGAME_TOOLTIP,
name = "Show minigame name in tooltip",
description = "Display the name of the minigame in the icon tooltip",
position = 8
)
default boolean minigameTooltip()
{
return true;
}
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_ANCIENT_TELEPORT_ICON,
name = "Show Ancient Magicks destinations",
description = "Show icons at the destinations for teleports in the Ancient Spellbook",
position = 9
)
default boolean ancientTeleportIcon()
{
return true;
}
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_LUNAR_TELEPORT_ICON,
name = "Show Lunar Spellbook destinations",
description = "Show icons at the destinations for teleports in the Lunar Spellbook",
position = 10
)
default boolean lunarTeleportIcon()
{
return true;
}
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_ARCEUUS_TELEPORT_ICON,
name = "Show Arceuus Spellbook destinations",
description = "Show icons at the destinations for teleports in the Arceuus Spellbook",
position = 11
)
default boolean arceuusTeleportIcon()
{
return true;
}
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_JEWELLERY_TELEPORT_ICON,
name = "Show jewellery teleport locations",
description = "Show icons at the destinations for teleports from jewellery",
position = 12
)
default boolean jewelleryTeleportIcon()
{
return true;
}
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_SCROLL_TELEPORT_ICON,
name = "Show teleport scroll locations",
description = "Show icons at the destinations for teleports from scrolls",
position = 13
)
default boolean scrollTeleportIcon()
{
return true;
}
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_MISC_TELEPORT_ICON,
name = "Show misc teleport locations",
description = "Show icons at the destinations for miscellaneous teleport items",
position = 14
)
default boolean miscellaneousTeleportIcon()
{
return true;
}
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_QUEST_START_TOOLTIPS,
name = "Show quest names and status",
description = "Indicates the names of quests and shows completion status",
position = 15
)
default boolean questStartTooltips()
{
return true;
}
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_FARMING_PATCH_TOOLTIPS,
name = "Show farming patch type",
description = "Display the type of farming patches in the icon tooltip",
position = 16
)
default boolean farmingPatchTooltips()
{
return true;
}
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_RARE_TREE_TOOLTIPS,
name = "Show rare tree type",
description = "Display the type of rare tree in the icon tooltip",
position = 17
)
default boolean rareTreeTooltips()
{
return true;
}
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_RARE_TREE_LEVEL_ICON,
name = "Indicate unavailable trees",
description = "Indicate rare trees you do not have the level to cut on the icon",
position = 18
)
default boolean rareTreeLevelIcon()
{
return true;
}
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_TRANSPORTATION_TELEPORT_TOOLTIPS,
name = "Show transportation tooltips",
description = "Indicates types and destinations of Transportation",
position = 19
)
default boolean transportationTeleportTooltips()
{
return true;
}
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_RUNECRAFTING_ALTAR_ICON,
name = "Show runecrafting altar locations",
description = "Show the icons of runecrafting altars",
position = 20
)
default boolean runecraftingAltarIcon()
{
return true;
}
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_MINING_SITE_TOOLTIPS,
name = "Show mining site tooltips",
description = "Indicates the ore available at mining sites",
position = 21
)
default boolean miningSiteTooltips()
{
return true;
}
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_DUNGEON_TOOLTIPS,
name = "Show dungeon tooltips",
description = "Indicates the names of dungeons",
position = 22
)
default boolean dungeonTooltips()
{
return true;
}
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_HUNTER_AREA_TOOLTIPS,
name = "Show hunter area tooltips",
description = "Indicates the creatures inside a hunting area",
position = 23
)
default boolean hunterAreaTooltips()
{
return true;
}
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_FISHING_SPOT_TOOLTIPS,
name = "Show fishing spot tooltips",
description = "Indicates the type of fish fishable at the fishing spot",
position = 24
)
default boolean fishingSpotTooltips()
{
return true;
}
@ConfigItem(
keyName = WorldMapPlugin.CONFIG_KEY_KOUREND_TASK_TOOLTIPS,
name = "Show Kourend task tooltips",
description = "Indicates the task or unlock for Kourend Favour locations",
position = 25
)
default boolean kourendTaskTooltips()
{
return true;
}
}

View File

@@ -0,0 +1,464 @@
/*
* 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 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.worldmap;
import com.google.inject.Inject;
import com.google.inject.Provides;
import java.awt.image.BufferedImage;
import java.util.Arrays;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.Quest;
import net.runelite.api.QuestState;
import net.runelite.api.Skill;
import net.runelite.client.events.ConfigChanged;
import net.runelite.api.events.StatChanged;
import net.runelite.api.events.WidgetLoaded;
import net.runelite.api.widgets.WidgetID;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.game.AgilityShortcut;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.overlay.worldmap.WorldMapPointManager;
import net.runelite.client.util.ImageUtil;
@PluginDescriptor(
name = "World Map",
description = "Enhance the world map to display additional information",
tags = {"agility", "dungeon", "fairy", "farming", "rings", "teleports"}
)
public class WorldMapPlugin extends Plugin
{
static final BufferedImage BLANK_ICON;
private static final BufferedImage FAIRY_TRAVEL_ICON;
private static final BufferedImage NOPE_ICON;
private static final BufferedImage NOT_STARTED_ICON;
private static final BufferedImage STARTED_ICON;
private static final BufferedImage FINISHED_ICON;
private static final BufferedImage MINING_SITE_ICON;
private static final BufferedImage ROOFTOP_COURSE_ICON;
static final String CONFIG_KEY = "worldmap";
static final String CONFIG_KEY_FAIRY_RING_TOOLTIPS = "fairyRingTooltips";
static final String CONFIG_KEY_FAIRY_RING_ICON = "fairyRingIcon";
static final String CONFIG_KEY_AGILITY_SHORTCUT_TOOLTIPS = "agilityShortcutTooltips";
static final String CONFIG_KEY_AGILITY_SHORTCUT_LEVEL_ICON = "agilityShortcutIcon";
static final String CONFIG_KEY_AGILITY_COURSE_TOOLTIPS = "agilityCourseTooltips";
static final String CONFIG_KEY_AGILITY_COURSE_ROOFTOP_ICON = "agilityCourseRooftopIcon";
static final String CONFIG_KEY_NORMAL_TELEPORT_ICON = "standardSpellbookIcon";
static final String CONFIG_KEY_ANCIENT_TELEPORT_ICON = "ancientSpellbookIcon";
static final String CONFIG_KEY_LUNAR_TELEPORT_ICON = "lunarSpellbookIcon";
static final String CONFIG_KEY_ARCEUUS_TELEPORT_ICON = "arceuusSpellbookIcon";
static final String CONFIG_KEY_JEWELLERY_TELEPORT_ICON = "jewelleryIcon";
static final String CONFIG_KEY_SCROLL_TELEPORT_ICON = "scrollIcon";
static final String CONFIG_KEY_MISC_TELEPORT_ICON = "miscellaneousTeleportIcon";
static final String CONFIG_KEY_QUEST_START_TOOLTIPS = "questStartTooltips";
static final String CONFIG_KEY_MINIGAME_TOOLTIP = "minigameTooltip";
static final String CONFIG_KEY_FARMING_PATCH_TOOLTIPS = "farmingpatchTooltips";
static final String CONFIG_KEY_RARE_TREE_TOOLTIPS = "rareTreeTooltips";
static final String CONFIG_KEY_RARE_TREE_LEVEL_ICON = "rareTreeIcon";
static final String CONFIG_KEY_TRANSPORTATION_TELEPORT_TOOLTIPS = "transportationTooltips";
static final String CONFIG_KEY_RUNECRAFTING_ALTAR_ICON = "runecraftingAltarIcon";
static final String CONFIG_KEY_MINING_SITE_TOOLTIPS = "miningSiteTooltips";
static final String CONFIG_KEY_DUNGEON_TOOLTIPS = "dungeonTooltips";
static final String CONFIG_KEY_HUNTER_AREA_TOOLTIPS = "hunterAreaTooltips";
static final String CONFIG_KEY_FISHING_SPOT_TOOLTIPS = "fishingSpotTooltips";
static final String CONFIG_KEY_KOUREND_TASK_TOOLTIPS = "kourendTaskTooltips";
static
{
//A size of 17 gives us a buffer when triggering tooltips
final int iconBufferSize = 17;
//Quest icons are a bit bigger.
final int questIconBufferSize = 22;
BLANK_ICON = new BufferedImage(iconBufferSize, iconBufferSize, BufferedImage.TYPE_INT_ARGB);
FAIRY_TRAVEL_ICON = new BufferedImage(iconBufferSize, iconBufferSize, BufferedImage.TYPE_INT_ARGB);
final BufferedImage fairyTravelIcon = ImageUtil.getResourceStreamFromClass(WorldMapPlugin.class, "fairy_ring_travel.png");
FAIRY_TRAVEL_ICON.getGraphics().drawImage(fairyTravelIcon, 1, 1, null);
NOPE_ICON = new BufferedImage(iconBufferSize, iconBufferSize, BufferedImage.TYPE_INT_ARGB);
final BufferedImage nopeImage = ImageUtil.getResourceStreamFromClass(WorldMapPlugin.class, "nope_icon.png");
NOPE_ICON.getGraphics().drawImage(nopeImage, 1, 1, null);
NOT_STARTED_ICON = new BufferedImage(questIconBufferSize, questIconBufferSize, BufferedImage.TYPE_INT_ARGB);
final BufferedImage notStartedIcon = ImageUtil.getResourceStreamFromClass(WorldMapPlugin.class, "quest_not_started_icon.png");
NOT_STARTED_ICON.getGraphics().drawImage(notStartedIcon, 4, 4, null);
STARTED_ICON = new BufferedImage(questIconBufferSize, questIconBufferSize, BufferedImage.TYPE_INT_ARGB);
final BufferedImage startedIcon = ImageUtil.getResourceStreamFromClass(WorldMapPlugin.class, "quest_started_icon.png");
STARTED_ICON.getGraphics().drawImage(startedIcon, 4, 4, null);
FINISHED_ICON = new BufferedImage(questIconBufferSize, questIconBufferSize, BufferedImage.TYPE_INT_ARGB);
final BufferedImage finishedIcon = ImageUtil.getResourceStreamFromClass(WorldMapPlugin.class, "quest_completed_icon.png");
FINISHED_ICON.getGraphics().drawImage(finishedIcon, 4, 4, null);
MINING_SITE_ICON = new BufferedImage(iconBufferSize, iconBufferSize, BufferedImage.TYPE_INT_ARGB);
final BufferedImage miningSiteIcon = ImageUtil.getResourceStreamFromClass(WorldMapPlugin.class, "mining_site_icon.png");
MINING_SITE_ICON.getGraphics().drawImage(miningSiteIcon, 1, 1, null);
ROOFTOP_COURSE_ICON = new BufferedImage(iconBufferSize, iconBufferSize, BufferedImage.TYPE_INT_ARGB);
final BufferedImage rooftopCourseIcon = ImageUtil.getResourceStreamFromClass(WorldMapPlugin.class, "rooftop_course_icon.png");
ROOFTOP_COURSE_ICON.getGraphics().drawImage(rooftopCourseIcon, 1, 1, null);
}
@Inject
private Client client;
@Inject
private ClientThread clientThread;
@Inject
private WorldMapConfig config;
@Inject
private WorldMapPointManager worldMapPointManager;
private int agilityLevel = 0;
private int woodcuttingLevel = 0;
@Provides
WorldMapConfig provideConfig(ConfigManager configManager)
{
return configManager.getConfig(WorldMapConfig.class);
}
@Override
protected void startUp() throws Exception
{
agilityLevel = client.getRealSkillLevel(Skill.AGILITY);
woodcuttingLevel = client.getRealSkillLevel(Skill.WOODCUTTING);
updateShownIcons();
}
@Override
protected void shutDown() throws Exception
{
worldMapPointManager.removeIf(FairyRingPoint.class::isInstance);
worldMapPointManager.removeIf(AgilityShortcutPoint.class::isInstance);
worldMapPointManager.removeIf(QuestStartPoint.class::isInstance);
worldMapPointManager.removeIf(TeleportPoint.class::isInstance);
worldMapPointManager.removeIf(TransportationPoint.class::isInstance);
worldMapPointManager.removeIf(MinigamePoint.class::isInstance);
worldMapPointManager.removeIf(FarmingPatchPoint.class::isInstance);
worldMapPointManager.removeIf(RareTreePoint.class::isInstance);
worldMapPointManager.removeIf(RunecraftingAltarPoint.class::isInstance);
worldMapPointManager.removeIf(DungeonPoint.class::isInstance);
worldMapPointManager.removeIf(FishingSpotPoint.class::isInstance);
worldMapPointManager.removeIf(AgilityCoursePoint.class::isInstance);
agilityLevel = 0;
woodcuttingLevel = 0;
}
@Subscribe
public void onConfigChanged(ConfigChanged event)
{
if (!event.getGroup().equals(CONFIG_KEY))
{
return;
}
updateShownIcons();
}
@Subscribe
public void onStatChanged(StatChanged statChanged)
{
switch (statChanged.getSkill())
{
case AGILITY:
{
int newAgilityLevel = statChanged.getLevel();
if (newAgilityLevel != agilityLevel)
{
agilityLevel = newAgilityLevel;
updateAgilityIcons();
}
break;
}
case WOODCUTTING:
{
int newWoodcutLevel = statChanged.getLevel();
if (newWoodcutLevel != woodcuttingLevel)
{
woodcuttingLevel = newWoodcutLevel;
updateRareTreeIcons();
}
break;
}
}
}
@Subscribe
public void onWidgetLoaded(WidgetLoaded widgetLoaded)
{
if (widgetLoaded.getGroupId() == WidgetID.WORLD_MAP_GROUP_ID)
{
// Quest icons are per-account due to showing quest status,
// so we recreate them each time the map is loaded
updateQuestStartPointIcons();
}
}
private void updateAgilityIcons()
{
worldMapPointManager.removeIf(AgilityShortcutPoint.class::isInstance);
if (config.agilityShortcutLevelIcon() || config.agilityShortcutTooltips())
{
Arrays.stream(AgilityShortcut.values())
.filter(value -> value.getWorldMapLocation() != null)
.map(value -> new AgilityShortcutPoint(value,
agilityLevel > 0 && config.agilityShortcutLevelIcon() && value.getLevel() > agilityLevel ? NOPE_ICON : BLANK_ICON,
config.agilityShortcutTooltips()))
.forEach(worldMapPointManager::add);
}
}
private void updateAgilityCourseIcons()
{
worldMapPointManager.removeIf(AgilityCoursePoint.class::isInstance);
if (config.agilityCourseTooltip() || config.agilityCourseRooftop())
{
Arrays.stream(AgilityCourseLocation.values())
.filter(value -> value.getLocation() != null)
.map(value -> new AgilityCoursePoint(value,
config.agilityCourseRooftop() && value.isRooftopCourse() ? ROOFTOP_COURSE_ICON : BLANK_ICON,
config.agilityCourseTooltip()))
.forEach(worldMapPointManager::add);
}
}
private void updateRareTreeIcons()
{
worldMapPointManager.removeIf(RareTreePoint.class::isInstance);
if (config.rareTreeLevelIcon() || config.rareTreeTooltips())
{
Arrays.stream(RareTreeLocation.values()).forEach(rareTree ->
Arrays.stream(rareTree.getLocations())
.map(point -> new RareTreePoint(point,
rareTree.getTooltip(),
woodcuttingLevel > 0 && config.rareTreeLevelIcon() &&
rareTree.getLevelReq() > woodcuttingLevel ? NOPE_ICON : BLANK_ICON,
config.rareTreeTooltips()))
.forEach(worldMapPointManager::add));
}
}
private void updateShownIcons()
{
updateAgilityIcons();
updateAgilityCourseIcons();
updateRareTreeIcons();
updateQuestStartPointIcons();
worldMapPointManager.removeIf(FairyRingPoint.class::isInstance);
if (config.fairyRingIcon() || config.fairyRingTooltips())
{
Arrays.stream(FairyRingLocation.values())
.map(value -> new FairyRingPoint(value,
config.fairyRingIcon() ? FAIRY_TRAVEL_ICON : BLANK_ICON,
config.fairyRingTooltips()))
.forEach(worldMapPointManager::add);
}
worldMapPointManager.removeIf(MinigamePoint.class::isInstance);
if (config.minigameTooltip())
{
Arrays.stream(MinigameLocation.values())
.map(value -> new MinigamePoint(value, BLANK_ICON))
.forEach(worldMapPointManager::add);
}
worldMapPointManager.removeIf(TransportationPoint.class::isInstance);
if (config.transportationTeleportTooltips())
{
Arrays.stream(TransportationPointLocation.values())
.map(value -> new TransportationPoint(value, BLANK_ICON))
.forEach((worldMapPointManager::add));
}
worldMapPointManager.removeIf(FarmingPatchPoint.class::isInstance);
if (config.farmingPatchTooltips())
{
Arrays.stream(FarmingPatchLocation.values()).forEach(location ->
Arrays.stream(location.getLocations())
.map(point -> new FarmingPatchPoint(point, location.getTooltip(), BLANK_ICON))
.forEach(worldMapPointManager::add)
);
}
worldMapPointManager.removeIf(TeleportPoint.class::isInstance);
Arrays.stream(TeleportLocationData.values())
.filter(data ->
{
switch (data.getType())
{
case NORMAL_MAGIC:
return config.normalTeleportIcon();
case ANCIENT_MAGICKS:
return config.ancientTeleportIcon();
case LUNAR_MAGIC:
return config.lunarTeleportIcon();
case ARCEUUS_MAGIC:
return config.arceuusTeleportIcon();
case JEWELLERY:
return config.jewelleryTeleportIcon();
case SCROLL:
return config.scrollTeleportIcon();
case OTHER:
return config.miscellaneousTeleportIcon();
default:
return false;
}
}).map(TeleportPoint::new)
.forEach(worldMapPointManager::add);
worldMapPointManager.removeIf(RunecraftingAltarPoint.class::isInstance);
if (config.runecraftingAltarIcon())
{
Arrays.stream(RunecraftingAltarLocation.values())
.map(RunecraftingAltarPoint::new)
.forEach(worldMapPointManager::add);
}
worldMapPointManager.removeIf(MiningSitePoint.class::isInstance);
if (config.miningSiteTooltips())
{
Arrays.stream(MiningSiteLocation.values())
.map(value -> new MiningSitePoint(value, value.isIconRequired() ? MINING_SITE_ICON : BLANK_ICON))
.forEach(worldMapPointManager::add);
}
worldMapPointManager.removeIf(DungeonPoint.class::isInstance);
if (config.dungeonTooltips())
{
Arrays.stream(DungeonLocation.values())
.map(value -> new DungeonPoint(value, BLANK_ICON))
.forEach(worldMapPointManager::add);
}
worldMapPointManager.removeIf(HunterAreaPoint.class::isInstance);
if (config.hunterAreaTooltips())
{
Arrays.stream(HunterAreaLocation.values())
.map(value -> new HunterAreaPoint(value, BLANK_ICON))
.forEach(worldMapPointManager::add);
}
worldMapPointManager.removeIf(FishingSpotPoint.class::isInstance);
if (config.fishingSpotTooltips())
{
Arrays.stream(FishingSpotLocation.values()).forEach(location ->
Arrays.stream(location.getLocations())
.map(point -> new FishingSpotPoint(point, location.getTooltip(), BLANK_ICON))
.forEach(worldMapPointManager::add)
);
}
worldMapPointManager.removeIf(KourendTaskPoint.class::isInstance);
if (config.kourendTaskTooltips())
{
Arrays.stream(KourendTaskLocation.values())
.map(KourendTaskPoint::new)
.forEach(worldMapPointManager::add);
}
}
private void updateQuestStartPointIcons()
{
worldMapPointManager.removeIf(QuestStartPoint.class::isInstance);
if (!config.questStartTooltips())
{
return;
}
// Must setup the quest icons on the client thread, after the player has logged in.
clientThread.invokeLater(() ->
{
if (client.getGameState() != GameState.LOGGED_IN)
{
return false;
}
Arrays.stream(QuestStartLocation.values())
.map(this::createQuestStartPoint)
.forEach(worldMapPointManager::add);
return true;
});
}
private QuestStartPoint createQuestStartPoint(QuestStartLocation data)
{
Quest[] quests = data.getQuests();
// Get first uncompleted quest. Else, return the last quest.
Quest quest = null;
for (Quest q : quests)
{
if (q.getState(client) != QuestState.FINISHED)
{
quest = q;
break;
}
}
if (quest == null)
{
quest = quests[quests.length - 1];
}
BufferedImage icon = BLANK_ICON;
String tooltip = "";
if (quest != null)
{
tooltip = quest.getName();
switch (quest.getState(client))
{
case FINISHED:
icon = FINISHED_ICON;
tooltip += " - Finished";
break;
case IN_PROGRESS:
icon = STARTED_ICON;
tooltip += " - Started";
break;
case NOT_STARTED:
icon = NOT_STARTED_ICON;
tooltip += " - Not Started";
break;
}
}
return new QuestStartPoint(data.getLocation(), icon, tooltip);
}
}

View File

@@ -0,0 +1,92 @@
/*
* Copyright (c) 2019, Hexagon <hexagon@fking.work>
* 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.zalcano;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.util.List;
import javax.inject.Inject;
import net.runelite.api.Client;
import net.runelite.api.GraphicsObject;
import net.runelite.api.Perspective;
import net.runelite.api.Player;
import net.runelite.api.coords.LocalPoint;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer;
import net.runelite.client.ui.overlay.OverlayPosition;
import net.runelite.client.ui.overlay.OverlayPriority;
import net.runelite.client.ui.overlay.OverlayUtil;
class ZalcanoOverlay extends Overlay
{
private final Client client;
private final ZalcanoPlugin zalcanoPlugin;
@Inject
private ZalcanoOverlay(Client client, ZalcanoPlugin zalcanoPlugin)
{
this.client = client;
this.zalcanoPlugin = zalcanoPlugin;
setPosition(OverlayPosition.DYNAMIC);
setLayer(OverlayLayer.ABOVE_SCENE);
setPriority(OverlayPriority.MED);
}
@Override
public Dimension render(Graphics2D graphics)
{
List<GraphicsObject> rocks = zalcanoPlugin.getRocks();
if (!rocks.isEmpty())
{
rocks.removeIf(GraphicsObject::finished);
for (GraphicsObject graphicsObject : rocks)
{
final Player localPlayer = client.getLocalPlayer();
final LocalPoint graphicsObjectLocation = graphicsObject.getLocation();
final Polygon polygon = Perspective.getCanvasTilePoly(client, graphicsObjectLocation);
if (polygon != null)
{
OverlayUtil.renderPolygon(graphics, polygon, localPlayer.getLocalLocation().equals(graphicsObjectLocation) ? Color.RED : Color.ORANGE);
}
}
}
LocalPoint targetedGlowingRock = zalcanoPlugin.getTargetedGlowingRock();
if (targetedGlowingRock != null && client.getGameCycle() < zalcanoPlugin.getTargetedGlowingRockEndCycle())
{
final Polygon polygon = Perspective.getCanvasTileAreaPoly(client, targetedGlowingRock, 3);
if (polygon != null)
{
OverlayUtil.renderPolygon(graphics, polygon, Color.RED);
}
}
return null;
}
}

View File

@@ -0,0 +1,85 @@
/*
* Copyright (c) 2020, dekvall <https://github.com/dekvall>
* 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.zalcano;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import javax.inject.Inject;
import net.runelite.client.ui.overlay.OverlayPanel;
import net.runelite.client.ui.overlay.OverlayPosition;
import net.runelite.client.ui.overlay.components.LineComponent;
class ZalcanoPanel extends OverlayPanel
{
private final ZalcanoPlugin plugin;
@Inject
public ZalcanoPanel(ZalcanoPlugin plugin)
{
super(plugin);
setPosition(OverlayPosition.ABOVE_CHATBOX_RIGHT);
this.plugin = plugin;
}
@Override
public Dimension render(Graphics2D g)
{
if (!plugin.isInCavern())
{
return null;
}
panelComponent.getChildren().add(LineComponent.builder()
.left("Health damage:")
.leftColor(colorFromCount(plugin.getHealthDamage()))
.right(Integer.toString(plugin.getHealthDamage()))
.build());
panelComponent.getChildren().add(LineComponent.builder()
.left("Shield damage:")
.leftColor(colorFromCount(plugin.getShieldDamage()))
.right(Integer.toString(plugin.getShieldDamage()))
.build());
return super.render(g);
}
private static Color colorFromCount(int damage)
{
if (damage >= 50)
{
// Eligible for uniques/pet
return Color.GREEN;
}
if (damage >= 30)
{
// Eligible for drops
return Color.YELLOW;
}
return Color.RED;
}
}

View File

@@ -0,0 +1,270 @@
/*
* Copyright (c) 2019, Hexagon <hexagon@fking.work>
* 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.zalcano;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import lombok.Getter;
import net.runelite.api.Actor;
import net.runelite.api.Client;
import net.runelite.api.GameObject;
import net.runelite.api.GameState;
import static net.runelite.api.GraphicID.GRAPHICS_OBJECT_ROCKFALL;
import net.runelite.api.GraphicsObject;
import net.runelite.api.Hitsplat;
import net.runelite.api.NPC;
import net.runelite.api.NpcID;
import static net.runelite.api.NpcID.ZALCANO;
import net.runelite.api.ObjectID;
import net.runelite.api.Projectile;
import static net.runelite.api.ProjectileID.ZALCANO_PROJECTILE_FIREBALL;
import net.runelite.api.VarPlayer;
import net.runelite.api.coords.LocalPoint;
import net.runelite.api.coords.WorldPoint;
import net.runelite.api.events.GameObjectSpawned;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.GraphicsObjectCreated;
import net.runelite.api.events.HitsplatApplied;
import net.runelite.api.events.NpcChanged;
import net.runelite.api.events.NpcDespawned;
import net.runelite.api.events.NpcSpawned;
import net.runelite.api.events.ProjectileMoved;
import net.runelite.api.events.VarbitChanged;
import net.runelite.client.callback.ClientThread;
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;
@PluginDescriptor(
name = "Zalcano",
description = "Assistance for the Zalcano fight",
enabledByDefault = false
)
public class ZalcanoPlugin extends Plugin
{
private static final int ZALCANO_WEAKENED = NpcID.ZALCANO_9050;
private static final int GOLEM = NpcID.GOLEM_9051;
@Inject
private Client client;
@Inject
private OverlayManager overlayManager;
@Inject
private ZalcanoOverlay overlay;
@Inject
private ZalcanoPanel panel;
@Inject
private ClientThread clientThread;
@Getter
private LocalPoint targetedGlowingRock;
@Getter
private int targetedGlowingRockEndCycle;
private WorldPoint lastGlowingRock;
@Getter
private final List<GraphicsObject> rocks = new ArrayList<>();
@Getter
private int healthDamage;
@Getter
private int shieldDamage;
@Getter
private boolean inCavern;
@Override
protected void startUp()
{
overlayManager.add(overlay);
overlayManager.add(panel);
rocks.clear();
resetDamageCounter();
clientThread.invokeLater(() ->
{
if (client.getGameState() == GameState.LOGGED_IN)
{
inCavern = isHealthbarActive();
}
});
}
@Override
protected void shutDown()
{
overlayManager.remove(overlay);
overlayManager.remove(panel);
}
@Subscribe
public void onGraphicsObjectCreated(GraphicsObjectCreated graphicsObjectCreated)
{
GraphicsObject graphicsObject = graphicsObjectCreated.getGraphicsObject();
if (graphicsObject.getId() == GRAPHICS_OBJECT_ROCKFALL)
{
rocks.add(graphicsObject);
}
}
@Subscribe
public void onGameStateChanged(GameStateChanged event)
{
GameState gameState = event.getGameState();
if (gameState == GameState.LOADING)
{
rocks.clear();
}
}
@Subscribe
public void onVarbitChanged(VarbitChanged event)
{
boolean wasInCavern = inCavern;
inCavern = isHealthbarActive();
if (!inCavern && wasInCavern)
{
resetDamageCounter();
}
}
@Subscribe
public void onNpcSpawned(NpcSpawned event)
{
final NPC npc = event.getNpc();
if (npc.getId() == GOLEM)
{
client.setHintArrow(npc);
}
}
@Subscribe
public void onNpcDespawned(NpcDespawned event)
{
final NPC npc = event.getNpc();
if (npc.getId() == ZALCANO_WEAKENED)
{
client.clearHintArrow();
}
else if (npc.getId() == GOLEM)
{
if (lastGlowingRock != null)
{
client.setHintArrow(lastGlowingRock);
}
}
}
private void resetDamageCounter()
{
healthDamage = 0;
shieldDamage = 0;
}
@Subscribe
public void onGameObjectSpawned(GameObjectSpawned event)
{
final GameObject gameObject = event.getGameObject();
if (gameObject.getId() == ObjectID.ROCK_FORMATION_GLOWING)
{
WorldPoint worldLocation = lastGlowingRock = gameObject.getWorldLocation();
client.setHintArrow(worldLocation);
}
}
@Subscribe
public void onNpcChanged(NpcChanged event)
{
final NPC npc = event.getNpc();
if (npc.getId() == ZALCANO_WEAKENED)
{
client.setHintArrow(npc);
}
else if (npc.getId() == ZALCANO)
{
if (lastGlowingRock != null)
{
client.setHintArrow(lastGlowingRock);
}
}
}
@Subscribe
public void onProjectileMoved(ProjectileMoved event)
{
final Projectile projectile = event.getProjectile();
if (projectile.getId() == ZALCANO_PROJECTILE_FIREBALL)
{
targetedGlowingRock = event.getPosition();
targetedGlowingRockEndCycle = projectile.getEndCycle();
}
}
@Subscribe
public void onHitsplatApplied(HitsplatApplied event)
{
final Actor actor = event.getActor();
if (!(actor instanceof NPC))
{
return;
}
int npcId = ((NPC) actor).getId();
if (!(npcId == ZALCANO_WEAKENED || npcId == ZALCANO))
{
return;
}
Hitsplat hitsplat = event.getHitsplat();
int damage = hitsplat.getAmount();
switch (hitsplat.getHitsplatType())
{
case DAMAGE_ME:
healthDamage += damage;
break;
case DAMAGE_ME_ORANGE:
shieldDamage += damage;
break;
}
}
private boolean isHealthbarActive()
{
return client.getVar(VarPlayer.ZALCANO_FORM) != -1;
}
}