diff --git a/runelite-api/src/main/java/net/runelite/api/Varbits.java b/runelite-api/src/main/java/net/runelite/api/Varbits.java index 1115ad29f6..a9f1b92f8d 100644 --- a/runelite-api/src/main/java/net/runelite/api/Varbits.java +++ b/runelite-api/src/main/java/net/runelite/api/Varbits.java @@ -211,6 +211,12 @@ public enum Varbits */ IN_GAME_BA(3923), + /** + * 0 = Outside wilderness + * 1 = In wilderness + */ + IN_WILDERNESS(5963), + /** * Fishing Trawler * FISHING_TRAWLER_ACTIVITY Expected values: 0-255 diff --git a/runelite-api/src/main/java/net/runelite/api/WorldType.java b/runelite-api/src/main/java/net/runelite/api/WorldType.java index 88741753b3..81f2ae1d2d 100644 --- a/runelite-api/src/main/java/net/runelite/api/WorldType.java +++ b/runelite-api/src/main/java/net/runelite/api/WorldType.java @@ -24,6 +24,7 @@ */ package net.runelite.api; +import java.util.Collection; import java.util.EnumSet; /** @@ -75,6 +76,13 @@ public enum WorldType this.mask = mask; } + private static EnumSet PVP_WORLD_TYPES = EnumSet.of( + DEADMAN, + PVP, + PVP_HIGH_RISK, + SEASONAL_DEADMAN + ); + /** * Create enum set of world types from mask. * @@ -113,4 +121,16 @@ public enum WorldType return mask; } -} \ No newline at end of file + + /** + * Checks whether a world having a {@link Collection} of {@link WorldType}s is a PVP world. + * + * @param worldTypes A {@link Collection} of {@link WorldType}s describing the given world. + * @return True if the given worldtypes of the world are a PVP world, false otherwise. + * @see Client#getWorldType() + */ + public static boolean isPvpWorld(final Collection worldTypes) + { + return worldTypes.stream().anyMatch(PVP_WORLD_TYPES::contains); + } +} diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java index 4be0f223fe..8a4920b3d0 100644 --- a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java +++ b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java @@ -117,6 +117,7 @@ public class WidgetID public static final int FOSSIL_ISLAND_OXYGENBAR_ID = 609; public static final int MINIGAME_TAB_ID = 76; public static final int SPELLBOOK_GROUP_ID = 218; + public static final int PVP_GROUP_ID = 90; static class WorldMap { @@ -679,4 +680,15 @@ public class WidgetID { static final int ARCEUUS_HOME_TELEPORT = 145; } -} \ No newline at end of file + + static class Pvp + { + static final int PVP_WIDGET_CONTAINER = 50; + static final int SKULL_CONTAINER = 51; + static final int SKULL = 52; + static final int SAFE_ZONE = 53; + static final int ATTACK_RANGE = 55; + static final int WILDERNESS_LEVEL = 56; // this can also be the Deadman Mode "Protection" text + static final int DEADMAN_PROTECTION_TIME = 57; + } +} diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java index cd970d09e5..4a4333d139 100644 --- a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java +++ b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java @@ -414,7 +414,18 @@ public enum WidgetInfo SPELL_LUMBRIDGE_HOME_TELEPORT(WidgetID.SPELLBOOK_GROUP_ID, WidgetID.StandardSpellBook.LUMBRIDGE_HOME_TELEPORT), SPELL_EDGEVILLE_HOME_TELEPORT(WidgetID.SPELLBOOK_GROUP_ID, WidgetID.AncientSpellBook.EDGEVILLE_HOME_TELEPORT), SPELL_LUNAR_HOME_TELEPORT(WidgetID.SPELLBOOK_GROUP_ID, WidgetID.LunarSpellBook.LUNAR_HOME_TELEPORT), - SPELL_ARCEUUS_HOME_TELEPORT(WidgetID.SPELLBOOK_GROUP_ID, WidgetID.ArceuusSpellBook.ARCEUUS_HOME_TELEPORT); + SPELL_ARCEUUS_HOME_TELEPORT(WidgetID.SPELLBOOK_GROUP_ID, WidgetID.ArceuusSpellBook.ARCEUUS_HOME_TELEPORT), + + PVP_CONTAINER(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.PVP_WIDGET_CONTAINER), + PVP_SKULL_CONTAINER(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.SKULL_CONTAINER), + PVP_SKULL(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.SKULL), + PVP_WILDERNESS_LEVEL(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.ATTACK_RANGE), + + PVP_WORLD_SAFE_ZONE(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.SAFE_ZONE), + PVP_WORLD_ATTACK_RANGE(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.ATTACK_RANGE), + + DEADMAN_PROTECTION_TEXT(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.WILDERNESS_LEVEL), + DEADMAN_PROTECTION_TIME(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.DEADMAN_PROTECTION_TIME); private final int groupId; private final int childId; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/timers/TimersPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/timers/TimersPlugin.java index a56186ca88..6156d382a6 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/timers/TimersPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/timers/TimersPlugin.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2017, Seth + * Copyright (c) 2018, Jordan Atwood * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,6 +29,7 @@ import com.google.common.eventbus.Subscribe; import com.google.inject.Provides; import java.awt.image.BufferedImage; import javax.inject.Inject; +import lombok.extern.slf4j.Slf4j; import net.runelite.api.Actor; import net.runelite.api.AnimationID; import net.runelite.api.ChatMessageType; @@ -48,13 +50,17 @@ import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.AnimationChanged; import net.runelite.api.events.ChatMessage; import net.runelite.api.events.ConfigChanged; -import net.runelite.api.events.GameTick; import net.runelite.api.events.GameStateChanged; +import net.runelite.api.events.GameTick; import net.runelite.api.events.GraphicChanged; import net.runelite.api.events.ItemContainerChanged; import net.runelite.api.events.MenuOptionClicked; import net.runelite.api.events.NpcDespawned; import net.runelite.api.events.VarbitChanged; +import net.runelite.api.events.WidgetHiddenChanged; +import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetInfo; +import static net.runelite.api.widgets.WidgetInfo.PVP_WORLD_SAFE_ZONE; import net.runelite.client.config.ConfigManager; import net.runelite.client.game.ItemManager; import net.runelite.client.game.SpriteManager; @@ -68,6 +74,7 @@ import net.runelite.client.ui.overlay.infobox.InfoBoxManager; description = "Show various timers in an infobox", tags = {"combat", "items", "magic", "potions", "prayer", "overlay", "abyssal", "sire"} ) +@Slf4j public class TimersPlugin extends Plugin { private static final String ANTIFIRE_DRINK_MESSAGE = "You drink some of your antifire potion."; @@ -101,9 +108,12 @@ public class TimersPlugin extends Plugin private int freezeTime = -1; // time frozen, in game ticks private int lastRaidVarb; + private int lastWildernessVarb; private WorldPoint lastPoint; private TeleportWidget lastTeleportClicked; private int lastAnimation; + private boolean loggedInRace; + private boolean widgetHiddenChangedOnPvpWorld; @Inject private ItemManager itemManager; @@ -134,6 +144,8 @@ public class TimersPlugin extends Plugin lastPoint = null; lastTeleportClicked = null; lastAnimation = -1; + loggedInRace = false; + widgetHiddenChangedOnPvpWorld = false; } @Subscribe @@ -146,6 +158,33 @@ public class TimersPlugin extends Plugin removeGameTimer(PRAYER_ENHANCE); lastRaidVarb = raidVarb; } + + int inWilderness = client.getVar(Varbits.IN_WILDERNESS); + + if (lastWildernessVarb != inWilderness + && client.getGameState() == GameState.LOGGED_IN + && !loggedInRace) + { + if (!WorldType.isPvpWorld(client.getWorldType()) + && inWilderness == 0) + { + log.debug("Left wilderness in non-PVP world, clearing Teleblock timer."); + removeTbTimers(); + } + + lastWildernessVarb = inWilderness; + } + } + + @Subscribe + public void onWidgetHiddenChanged(WidgetHiddenChanged event) + { + Widget widget = event.getWidget(); + if (WorldType.isPvpWorld(client.getWorldType()) + && WidgetInfo.TO_GROUP(widget.getId()) == WidgetInfo.PVP_CONTAINER.getGroupId()) + { + widgetHiddenChangedOnPvpWorld = true; + } } @Subscribe @@ -250,10 +289,7 @@ public class TimersPlugin extends Plugin if (!config.showTeleblock()) { - removeGameTimer(FULLTB); - removeGameTimer(HALFTB); - removeGameTimer(DMM_FULLTB); - removeGameTimer(DMM_HALFTB); + removeTbTimers(); } if (!config.showFreezes()) @@ -503,34 +539,51 @@ public class TimersPlugin extends Plugin @Subscribe public void onGameTick(GameTick event) { + loggedInRace = false; + Player player = client.getLocalPlayer(); WorldPoint currentWorldPoint = player.getWorldLocation(); - if (freezeTimer == null) + if (freezeTimer != null) + { + // assume movement means unfrozen + if (!currentWorldPoint.equals(lastPoint)) + { + removeGameTimer(freezeTimer.getTimer()); + freezeTimer = null; + } + } + + lastPoint = currentWorldPoint; + + if (!widgetHiddenChangedOnPvpWorld) { - lastPoint = currentWorldPoint; return; } - // assume movement means unfrozen - if (!currentWorldPoint.equals(lastPoint)) + widgetHiddenChangedOnPvpWorld = false; + + Widget widget = client.getWidget(PVP_WORLD_SAFE_ZONE); + if (widget != null + && !widget.isSelfHidden()) { - removeGameTimer(freezeTimer.getTimer()); - freezeTimer = null; - lastPoint = currentWorldPoint; + log.debug("Entered safe zone in PVP world, clearing Teleblock timer."); + removeTbTimers(); } } @Subscribe public void onGameStateChanged(GameStateChanged gameStateChanged) { - // Check for game state changes which removes a teleblock (Hopping or Login screen) - if (gameStateChanged.getGameState() == GameState.HOPPING || gameStateChanged.getGameState() == GameState.LOGIN_SCREEN) + switch (gameStateChanged.getGameState()) { - removeGameTimer(HALFTB); - removeGameTimer(DMM_HALFTB); - removeGameTimer(FULLTB); - removeGameTimer(DMM_FULLTB); + case HOPPING: + case LOGIN_SCREEN: + removeTbTimers(); + break; + case LOGGED_IN: + loggedInRace = true; + break; } } @@ -755,4 +808,12 @@ public class TimersPlugin extends Plugin { infoBoxManager.removeIf(t -> t instanceof TimerTimer && ((TimerTimer) t).getTimer() == timer); } + + private void removeTbTimers() + { + removeGameTimer(FULLTB); + removeGameTimer(HALFTB); + removeGameTimer(DMM_FULLTB); + removeGameTimer(DMM_HALFTB); + } }