Merge remote-tracking branch 'runelite/master'

This commit is contained in:
Owain van Brakel
2021-07-21 19:15:43 +02:00
38 changed files with 2789 additions and 172 deletions

View File

@@ -25,7 +25,7 @@
object ProjectVersions {
const val launcherVersion = "2.2.0"
const val rlVersion = "1.7.15"
const val rlVersion = "1.7.16"
const val openosrsVersion = "4.9.5"

View File

@@ -81,6 +81,27 @@ public class Constants
public static final int MAX_Z = 4;
public static final int TILE_FLAG_BRIDGE = 2;
public static final int TILE_FLAG_UNDER_ROOF = 4;
/**
* Flag for roof removal to remove the roofs above the player's current position.
*/
public static final int ROOF_FLAG_POSITION = 1;
/**
* Flag for roof removal to remove the roofs above the currently hovered tile.
*/
public static final int ROOF_FLAG_HOVERED = 2;
/**
* Flag for roof removal to remove the roofs above the player's destination tile.
*/
public static final int ROOF_FLAG_DESTINATION = 4;
/**
* Flag for roof removal to remove the roofs that are above any tile between the camera and the player.
*/
public static final int ROOF_FLAG_BETWEEN = 8;
/**
* The height of the overworld, in tiles. Coordinates above this are in caves and other such zones.

View File

@@ -30,12 +30,13 @@ import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
public enum Quest
{
//Free Quests
BLACK_KNIGHTS_FORTRESS(299, "Black Knights' Fortress"),
COOKS_ASSISTANT(300, "Cook's Assistant"),
THE_CORSAIR_CURSE(301, "The Corsair Curse"),
DEMON_SLAYER(302, "Demon Slayer"),
DORICS_QUEST(303, "Doric's Quest"),
DRAGON_SLAYER_I(304, "Dragon Slayer I"),
DORICS_QUEST(3138, "Doric's Quest"),
DRAGON_SLAYER_I(3139, "Dragon Slayer I"),
ERNEST_THE_CHICKEN(305, "Ernest the Chicken"),
GOBLIN_DIPLOMACY(306, "Goblin Diplomacy"),
IMP_CATCHER(307, "Imp Catcher"),
@@ -50,7 +51,7 @@ public enum Quest
SHIELD_OF_ARRAV(316, "Shield of Arrav"),
VAMPYRE_SLAYER(1278, "Vampyre Slayer"),
WITCHS_POTION(318, "Witch's Potion"),
X_MARKS_THE_SPOT(550, "X Marks the Spot"),
X_MARKS_THE_SPOT(3155, "X Marks the Spot"),
BELOW_ICE_MOUNTAIN(2874, "Below Ice Mountain"),
//Members' Quests
@@ -89,7 +90,7 @@ public enum Quest
FIGHT_ARENA(363, "Fight Arena"),
FISHING_CONTEST(364, "Fishing Contest"),
FORGETTABLE_TALE(365, "Forgettable Tale..."),
BONE_VOYAGE(366, "Bone Voyage"),
BONE_VOYAGE(3135, "Bone Voyage"),
THE_FREMENNIK_ISLES(367, "The Fremennik Isles"),
THE_FREMENNIK_TRIALS(368, "The Fremennik Trials"),
GARDEN_OF_TRANQUILLITY(369, "Garden of Tranquillity"),
@@ -103,7 +104,7 @@ public enum Quest
THE_HAND_IN_THE_SAND(377, "The Hand in the Sand"),
HAUNTED_MINE(378, "Haunted Mine"),
HAZEEL_CULT(379, "Hazeel Cult"),
HEROES_QUEST(380, "Heroes' Quest"),
HEROES_QUEST(3142, "Heroes' Quest"),
HOLY_GRAIL(381, "Holy Grail"),
HORROR_FROM_THE_DEEP(382, "Horror from the Deep"),
ICTHLARINS_LITTLE_HELPER(383, "Icthlarin's Little Helper"),
@@ -111,7 +112,7 @@ public enum Quest
IN_SEARCH_OF_THE_MYREQUE(385, "In Search of the Myreque"),
JUNGLE_POTION(386, "Jungle Potion"),
KINGS_RANSOM(387, "King's Ransom"),
LEGENDS_QUEST(388, "Legends' Quest"),
LEGENDS_QUEST(3145, "Legends' Quest"),
LOST_CITY(389, "Lost City"),
THE_LOST_TRIBE(390, "The Lost Tribe"),
LUNAR_DIPLOMACY(391, "Lunar Diplomacy"),
@@ -122,18 +123,18 @@ public enum Quest
MONKEY_MADNESS_II(396, "Monkey Madness II"),
MONKS_FRIEND(397, "Monk's Friend"),
MOUNTAIN_DAUGHTER(398, "Mountain Daughter"),
MOURNINGS_END_PART_I(399, "Mourning's End Part I"),
MOURNINGS_END_PART_II(400, "Mourning's End Part II"),
MOURNINGS_END_PART_I(3147, "Mourning's End Part I"),
MOURNINGS_END_PART_II(3148, "Mourning's End Part II"),
MURDER_MYSTERY(401, "Murder Mystery"),
MY_ARMS_BIG_ADVENTURE(402, "My Arm's Big Adventure"),
NATURE_SPIRIT(403, "Nature Spirit"),
OBSERVATORY_QUEST(404, "Observatory Quest"),
OLAFS_QUEST(405, "Olaf's Quest"),
OBSERVATORY_QUEST(3149, "Observatory Quest"),
OLAFS_QUEST(3150, "Olaf's Quest"),
ONE_SMALL_FAVOUR(406, "One Small Favour"),
PLAGUE_CITY(407, "Plague City"),
PRIEST_IN_PERIL(408, "Priest in Peril"),
THE_QUEEN_OF_THIEVES(409, "The Queen of Thieves"),
RAG_AND_BONE_MAN_I(410, "Rag and Bone Man I"),
RAG_AND_BONE_MAN_I(3152, "Rag and Bone Man I"),
RAG_AND_BONE_MAN_II(411, "Rag and Bone Man II"),
RATCATCHERS(412, "Ratcatchers"),
RECIPE_FOR_DISASTER(413, "Recipe for Disaster"),
@@ -166,37 +167,37 @@ public enum Quest
TROLL_ROMANCE(440, "Troll Romance"),
TROLL_STRONGHOLD(441, "Troll Stronghold"),
UNDERGROUND_PASS(442, "Underground Pass"),
CLIENT_OF_KOUREND(443, "Client of Kourend"),
CLIENT_OF_KOUREND(3136, "Client of Kourend"),
WANTED(444, "Wanted!"),
WATCHTOWER(445, "Watchtower"),
WATERFALL_QUEST(446, "Waterfall Quest"),
WATERFALL_QUEST(3154, "Waterfall Quest"),
WHAT_LIES_BELOW(447, "What Lies Below"),
WITCHS_HOUSE(448, "Witch's House"),
ZOGRE_FLESH_EATERS(449, "Zogre Flesh Eaters"),
THE_ASCENT_OF_ARCEUUS(542, "The Ascent of Arceuus"),
THE_FORSAKEN_TOWER(543, "The Forsaken Tower"),
SONG_OF_THE_ELVES(603, "Song of the Elves"),
THE_FREMENNIK_EXILES(718, "The Fremennik Exiles"),
THE_FREMENNIK_EXILES(3141, "The Fremennik Exiles"),
SINS_OF_THE_FATHER(1276, "Sins of the Father"),
A_PORCINE_OF_INTEREST(1690, "A Porcine of Interest"),
A_PORCINE_OF_INTEREST(3151, "A Porcine of Interest"),
GETTING_AHEAD(752, "Getting Ahead"),
A_KINGDOM_DIVIDED(2971, "A Kingdom Divided"),
A_NIGHT_AT_THE_THEATRE(949, "A Night at the Theatre"),
//Miniquests
ENTER_THE_ABYSS(319, "Enter the Abyss"),
ENTER_THE_ABYSS(3140, "Enter the Abyss"),
ARCHITECTURAL_ALLIANCE(320, "Architectural Alliance"),
BEAR_YOUR_SOUL(321, "Bear Your Soul"),
BEAR_YOUR_SOUL(1275, "Bear Your Soul"),
ALFRED_GRIMHANDS_BARCRAWL(322, "Alfred Grimhand's Barcrawl"),
CURSE_OF_THE_EMPTY_LORD(323, "Curse of the Empty Lord"),
ENCHANTED_KEY(324, "Enchanted Key"),
CURSE_OF_THE_EMPTY_LORD(3137, "Curse of the Empty Lord"),
THE_ENCHANTED_KEY(324, "The Enchanted Key"),
THE_GENERALS_SHADOW(325, "The General's Shadow"),
SKIPPY_AND_THE_MOGRES(326, "Skippy and the Mogres"),
THE_MAGE_ARENA(327, "The Mage Arena"),
LAIR_OF_TARN_RAZORLOR(328, "Lair of Tarn Razorlor"),
SKIPPY_AND_THE_MOGRES(3153, "Skippy and the Mogres"),
MAGE_ARENA_I(3146, "Mage Arena I"),
LAIR_OF_TARN_RAZORLOR(3144, "Lair of Tarn Razorlor"),
FAMILY_PEST(329, "Family Pest"),
THE_MAGE_ARENA_II(330, "The Mage Arena II"),
IN_SEARCH_OF_KNOWLEDGE(602, "In Search of Knowledge"),
MAGE_ARENA_II(330, "Mage Arena II"),
IN_SEARCH_OF_KNOWLEDGE(3143, "In Search of Knowledge"),
DADDYS_HOME(1688, "Daddy's Home");
@Getter

View File

@@ -70,4 +70,8 @@ public interface Scene
* @param gameObject
*/
void removeGameObject(GameObject gameObject);
void generateHouses();
void setRoofRemovalMode(int flags);
}

View File

@@ -82,6 +82,7 @@ public class WidgetID
public static final int BA_DEFENDER_GROUP_ID = 487;
public static final int BA_HEALER_GROUP_ID = 488;
public static final int BA_REWARD_GROUP_ID = 497;
public static final int BA_TEAM_GROUP_ID = 256;
public static final int LEVEL_UP_GROUP_ID = 233;
public static final int DIALOG_SPRITE_GROUP_ID = 193;
public static final int QUEST_COMPLETED_GROUP_ID = 153;
@@ -684,12 +685,15 @@ public class WidgetID
static class HLR
{
static final int TEAMMATES = 13;
static final int TEAMMATE1 = 18;
static final int TEAMMATE2 = 22;
static final int TEAMMATE3 = 26;
static final int TEAMMATE4 = 30;
}
static final int TEAM = 2;
static final int ROLE_SPRITE = 10;
static final int ROLE = 11;

View File

@@ -373,9 +373,12 @@ public enum WidgetInfo
CHATBOX_TAB_CLAN(WidgetID.CHATBOX_GROUP_ID, WidgetID.Chatbox.TAB_CLAN),
CHATBOX_TAB_TRADE(WidgetID.CHATBOX_GROUP_ID, WidgetID.Chatbox.TAB_TRADE),
BA_TEAM(WidgetID.BA_TEAM_GROUP_ID, WidgetID.BarbarianAssault.TEAM),
BA_HEAL_ROLE_TEXT(WidgetID.BA_HEALER_GROUP_ID, WidgetID.BarbarianAssault.ROLE),
BA_HEAL_ROLE_SPRITE(WidgetID.BA_HEALER_GROUP_ID, WidgetID.BarbarianAssault.ROLE_SPRITE),
BA_HEAL_TEAMMATES(WidgetID.BA_HEALER_GROUP_ID, WidgetID.BarbarianAssault.HLR.TEAMMATES),
BA_HEAL_TEAMMATE1(WidgetID.BA_HEALER_GROUP_ID, WidgetID.BarbarianAssault.HLR.TEAMMATE1),
BA_HEAL_TEAMMATE2(WidgetID.BA_HEALER_GROUP_ID, WidgetID.BarbarianAssault.HLR.TEAMMATE2),
BA_HEAL_TEAMMATE3(WidgetID.BA_HEALER_GROUP_ID, WidgetID.BarbarianAssault.HLR.TEAMMATE3),

View File

@@ -275,13 +275,14 @@ public enum ItemMapping
ITEM_CRYSTAL_AXE(DRAGON_AXE, CRYSTAL_AXE, CRYSTAL_AXE_INACTIVE),
ITEM_CRYSTAL_HARPOON(DRAGON_HARPOON, CRYSTAL_HARPOON, CRYSTAL_HARPOON_INACTIVE),
ITEM_CRYSTAL_PICKAXE(DRAGON_PICKAXE, CRYSTAL_PICKAXE, CRYSTAL_PICKAXE_INACTIVE),
ITEM_BLADE_OF_SAELDOR(BLADE_OF_SAELDOR_INACTIVE, BLADE_OF_SAELDOR, BLADE_OF_SAELDOR_C),
ITEM_BLADE_OF_SAELDOR(BLADE_OF_SAELDOR_INACTIVE, BLADE_OF_SAELDOR, BLADE_OF_SAELDOR_C, BLADE_OF_SAELDOR_C_25870, BLADE_OF_SAELDOR_C_25872, BLADE_OF_SAELDOR_C_25874, BLADE_OF_SAELDOR_C_25876, BLADE_OF_SAELDOR_C_25878, BLADE_OF_SAELDOR_C_25880, BLADE_OF_SAELDOR_C_25882),
ITEM_CRYSTAL_BOW(CRYSTAL_WEAPON_SEED, CRYSTAL_BOW, CRYSTAL_BOW_24123, CRYSTAL_BOW_INACTIVE),
ITEM_CRYSTAL_HALBERD(CRYSTAL_WEAPON_SEED, CRYSTAL_HALBERD, CRYSTAL_HALBERD_24125, CRYSTAL_HALBERD_INACTIVE),
ITEM_CRYSTAL_SHIELD(CRYSTAL_WEAPON_SEED, CRYSTAL_SHIELD, CRYSTAL_SHIELD_24127, CRYSTAL_SHIELD_INACTIVE),
ITEM_CRYSTAL_HELMET(CRYSTAL_ARMOUR_SEED, CRYSTAL_HELM, CRYSTAL_HELM_INACTIVE),
ITEM_CRYSTAL_LEGS(CRYSTAL_ARMOUR_SEED, 2L, CRYSTAL_LEGS, CRYSTAL_LEGS_INACTIVE),
ITEM_CRYSTAL_BODY(CRYSTAL_ARMOUR_SEED, 3L, CRYSTAL_BODY, CRYSTAL_BODY_INACTIVE),
ITEM_BOW_OF_FAERDHINEN(BOW_OF_FAERDHINEN_INACTIVE, BOW_OF_FAERDHINEN, BOW_OF_FAERDHINEN_C, BOW_OF_FAERDHINEN_C_25884, BOW_OF_FAERDHINEN_C_25886, BOW_OF_FAERDHINEN_C_25888, BOW_OF_FAERDHINEN_C_25890, BOW_OF_FAERDHINEN_C_25892, BOW_OF_FAERDHINEN_C_25894, BOW_OF_FAERDHINEN_C_25896),
// Bird nests
ITEM_BIRD_NEST(BIRD_NEST_5075, BIRD_NEST, BIRD_NEST_5071, BIRD_NEST_5072, BIRD_NEST_5073, BIRD_NEST_5074, BIRD_NEST_7413, BIRD_NEST_13653, BIRD_NEST_22798, BIRD_NEST_22800, CLUE_NEST_EASY, CLUE_NEST_MEDIUM, CLUE_NEST_HARD, CLUE_NEST_ELITE),

View File

@@ -81,7 +81,7 @@ public class DesertDiaryRequirement extends GenericDiaryRequirement
new QuestRequirement(Quest.DREAM_MENTOR));
add("Complete a lap of the Pollnivneach agility course.",
new SkillRequirement(Skill.AGILITY, 70));
add("Slay a Dust Devil with a Slayer helmet equipped.",
add("Slay a Dust Devil in the desert cave with a Slayer helmet equipped.",
new SkillRequirement(Skill.SLAYER, 65),
new SkillRequirement(Skill.DEFENCE, 10),
new SkillRequirement(Skill.CRAFTING, 55),

View File

@@ -70,7 +70,7 @@ public class WildernessDiaryRequirement extends GenericDiaryRequirement
// HARD
add("Cast one of the 3 God spells against another player in the Wilderness.",
new SkillRequirement(Skill.MAGIC, 60),
new QuestRequirement(Quest.THE_MAGE_ARENA));
new QuestRequirement(Quest.MAGE_ARENA_I));
add("Charge an Air Orb.",
new SkillRequirement(Skill.MAGIC, 66));
add("Catch a Black Salamander in the Wilderness.",

View File

@@ -237,7 +237,7 @@ public class CoordinateClue extends ClueScroll implements TextClueScroll, Locati
.put(new WorldPoint(3188, 3939, 0), new CoordinateClueInfo("Wilderness. Resource Area.", BRASSICAN_MAGE))
.put(new WorldPoint(3304, 3941, 0), new CoordinateClueInfo("Wilderness. East of Rogues' Castle.", ANCIENT_WIZARDS))
.put(new WorldPoint(2994, 3961, 0), new CoordinateClueInfo("Wilderness. Inside Agility Training Area.", BRASSICAN_MAGE))
.put(new WorldPoint(1770, 3417, 0), new CoordinateClueInfo("Crabclaw Isle", ANCIENT_WIZARDS))
.put(new WorldPoint(1769, 3418, 0), new CoordinateClueInfo("Crabclaw Isle", ANCIENT_WIZARDS))
.build();
private final String text;

View File

@@ -27,7 +27,6 @@ package net.runelite.client.plugins.crowdsourcing;
import java.time.temporal.ChronoUnit;
import javax.inject.Inject;
import lombok.extern.slf4j.Slf4j;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
@@ -40,7 +39,6 @@ import net.runelite.client.plugins.crowdsourcing.woodcutting.CrowdsourcingWoodcu
import net.runelite.client.plugins.crowdsourcing.zmi.CrowdsourcingZMI;
import net.runelite.client.task.Schedule;
@Slf4j
@PluginDescriptor(
name = "OSRS Wiki Crowdsourcing",
description = "Send data to the wiki to help figure out skilling success rates, burn rates, more. See osrs.wiki/RS:CROWD"

View File

@@ -56,6 +56,7 @@ import net.runelite.api.Tile;
import net.runelite.api.TileItem;
import net.runelite.api.TileObject;
import net.runelite.api.coords.LocalPoint;
import net.runelite.api.coords.WorldPoint;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.api.widgets.WidgetItem;
@@ -134,9 +135,50 @@ class DevToolsOverlay extends Overlay
renderGraphicsObjects(graphics);
}
if (plugin.getRoofs().isActive())
{
renderRoofs(graphics);
}
return null;
}
private void renderRoofs(Graphics2D graphics)
{
Scene scene = client.getScene();
Tile[][][] tiles = scene.getTiles();
byte[][][] settings = client.getTileSettings();
int z = client.getPlane();
String text = "R";
for (int x = 0; x < Constants.SCENE_SIZE; ++x)
{
for (int y = 0; y < Constants.SCENE_SIZE; ++y)
{
Tile tile = tiles[z][x][y];
if (tile == null)
{
continue;
}
int flag = settings[z][x][y];
if ((flag & Constants.TILE_FLAG_UNDER_ROOF) == 0)
{
continue;
}
Point loc = Perspective.getCanvasTextLocation(client, graphics, tile.getLocalLocation(), text, z);
if (loc == null)
{
continue;
}
OverlayUtil.renderTextLocation(graphics, loc, text, Color.RED);
}
}
}
private void renderPlayers(Graphics2D graphics)
{
List<Player> players = client.getPlayers();
@@ -248,7 +290,11 @@ class DevToolsOverlay extends Overlay
Polygon poly = Perspective.getCanvasTilePoly(client, tile.getLocalLocation());
if (poly != null && poly.contains(client.getMouseCanvasPosition().getX(), client.getMouseCanvasPosition().getY()))
{
toolTipManager.add(new Tooltip("World Location: " + tile.getWorldLocation().getX() + ", " + tile.getWorldLocation().getY() + ", " + client.getPlane()));
WorldPoint worldLocation = tile.getWorldLocation();
String tooltip = String.format("World location: %d, %d, %d</br>" +
"Region ID: %d location: %d, %d", worldLocation.getX(), worldLocation.getY(), worldLocation.getPlane(),
worldLocation.getRegionID(), worldLocation.getRegionX(), worldLocation.getRegionY());
toolTipManager.add(new Tooltip(tooltip));
OverlayUtil.renderPolygon(graphics, poly, GREEN);
}
}

View File

@@ -180,6 +180,8 @@ class DevToolsPanel extends PluginPanel
disconnectBtn.addActionListener(e -> clientThread.invoke(() -> client.setGameState(GameState.CONNECTION_LOST)));
container.add(disconnectBtn);
container.add(plugin.getRoofs());
try
{
ShellFrame sf = plugin.getInjector().getInstance(ShellFrame.class);

View File

@@ -145,6 +145,7 @@ public class DevToolsPlugin extends Plugin
private DevToolsButton soundEffects;
private DevToolsButton scriptInspector;
private DevToolsButton inventoryInspector;
private DevToolsButton roofs;
private DevToolsButton shell;
private NavigationButton navButton;
@@ -191,6 +192,7 @@ public class DevToolsPlugin extends Plugin
soundEffects = new DevToolsButton("Sound Effects");
scriptInspector = new DevToolsButton("Script Inspector");
inventoryInspector = new DevToolsButton("Inventory Inspector");
roofs = new DevToolsButton("Roofs");
shell = new DevToolsButton("Shell");
overlayManager.add(overlay);

View File

@@ -45,7 +45,6 @@ import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.border.CompoundBorder;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.IndexDataBase;
import net.runelite.api.VarClientInt;
@@ -63,7 +62,6 @@ import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.DynamicGridLayout;
import net.runelite.client.ui.FontManager;
@Slf4j
class VarInspector extends DevToolsFrame
{
@Getter

View File

@@ -289,7 +289,8 @@ enum DiscordGameEventType
MG_CLAN_WARS("Clan Wars", DiscordAreaType.MINIGAMES, 12621, 12622, 12623, 13130, 13131, 13133, 13134, 13135, 13386, 13387, 13390, 13641, 13642, 13643, 13644, 13645, 13646, 13647, 13899, 13900, 14155, 14156),
MG_DUEL_ARENA("Duel Arena", DiscordAreaType.MINIGAMES, 13362, 13363),
MG_FISHING_TRAWLER("Fishing Trawler", DiscordAreaType.MINIGAMES, 7499),
MG_GAUNTLET("The Gauntlet", DiscordAreaType.MINIGAMES, 12127, 7512, 7768),
MG_GAUNTLET("The Gauntlet", DiscordAreaType.MINIGAMES, 12127, 7512),
MG_CORRUPTED_GAUNTLET("Corrupted Gauntlet", DiscordAreaType.MINIGAMES, 7768),
MG_HALLOWED_SEPULCHRE("Hallowed Sepulchre", DiscordAreaType.MINIGAMES, 8797, 9051, 9052, 9053, 9054, 9309, 9563, 9565, 9821, 10074, 10075, 10077),
MG_INFERNO("The Inferno", DiscordAreaType.MINIGAMES, 9043),
MG_KELDAGRIM_RAT_PITS("Keldagrim Rat Pits", DiscordAreaType.MINIGAMES, 7753),

View File

@@ -26,6 +26,8 @@ package net.runelite.client.plugins.itemidentification;
import com.google.common.collect.ImmutableMap;
import java.util.Map;
import java.util.function.Predicate;
import lombok.AllArgsConstructor;
import net.runelite.api.ItemID;
enum ItemIdentification
@@ -364,7 +366,25 @@ enum ItemIdentification
TARGET_TELEPORT(Type.TABLET, "Target", "TRG", ItemID.TARGET_TELEPORT),
VOLCANIC_MINE_TELEPORT(Type.TABLET, "V.Mine", "VM", ItemID.VOLCANIC_MINE_TELEPORT),
WILDERNESS_CRABS_TELEPORT(Type.TABLET, "W.Crab", "CRAB", ItemID.WILDERNESS_CRABS_TELEPORT);
WILDERNESS_CRABS_TELEPORT(Type.TABLET, "W.Crab", "CRAB", ItemID.WILDERNESS_CRABS_TELEPORT),
// Scrolls
NARDAH_TELEPORT(Type.SCROLL, "Nardah", "NAR", ItemID.NARDAH_TELEPORT),
DIGSITE_TELEPORT(Type.SCROLL, "Digsite", "DIG", ItemID.DIGSITE_TELEPORT),
FELDIP_HILLS_TELEPORT(Type.SCROLL, "F.Hills", "F.H", ItemID.FELDIP_HILLS_TELEPORT),
LUNAR_ISLE_TELEPORT(Type.SCROLL, "L.Isle", "L.I", ItemID.LUNAR_ISLE_TELEPORT),
MORTTON_TELEPORT(Type.SCROLL, "Mort'ton", "MORT", ItemID.MORTTON_TELEPORT),
PEST_CONTROL_TELEPORT(Type.SCROLL, "P.Cont", "PEST", ItemID.PEST_CONTROL_TELEPORT),
PISCATORIS_TELEPORT(Type.SCROLL, "Pisca", "PISC", ItemID.PISCATORIS_TELEPORT),
TAI_BWO_WANNAI_TELEPORT(Type.SCROLL, "TaiBwo", "TAI", ItemID.TAI_BWO_WANNAI_TELEPORT),
IORWERTH_CAMP_TELEPORT(Type.SCROLL, "Iorwerth", "IOR", ItemID.IORWERTH_CAMP_TELEPORT),
MOS_LEHARMLESS_TELEPORT(Type.SCROLL, "M.LeHarm", "M.L", ItemID.MOS_LEHARMLESS_TELEPORT),
LUMBERYARD_TELEPORT(Type.SCROLL, "Lumber", "LUMB", ItemID.LUMBERYARD_TELEPORT),
ZUL_ANDRA_TELEPORT(Type.SCROLL, "Zul-andra", "ZUL", ItemID.ZULANDRA_TELEPORT),
KEY_MASTER_TELEPORT(Type.SCROLL, "Key master", "KEY", ItemID.KEY_MASTER_TELEPORT),
REVENANT_CAVE_TELEPORT(Type.SCROLL, "Rev cave", "REV", ItemID.REVENANT_CAVE_TELEPORT),
WATSON_TELEPORT(Type.SCROLL, "Watson", "WATS", ItemID.WATSON_TELEPORT);
final Type type;
final String medName;
@@ -401,20 +421,24 @@ enum ItemIdentification
return itemIdentifications.get(id);
}
@AllArgsConstructor
enum Type
{
SEED,
SACK,
HERB,
LOGS,
PLANK,
SAPLING,
COMPOST,
ORE,
BAR,
GEM,
POTION,
IMPLING_JAR,
TABLET
SEED(ItemIdentificationConfig::showSeeds),
SACK(ItemIdentificationConfig::showSacks),
HERB(ItemIdentificationConfig::showHerbs),
LOGS(ItemIdentificationConfig::showLogs),
PLANK(ItemIdentificationConfig::showPlanks),
SAPLING(ItemIdentificationConfig::showSaplings),
COMPOST(ItemIdentificationConfig::showComposts),
ORE(ItemIdentificationConfig::showOres),
BAR(ItemIdentificationConfig::showBars),
GEM(ItemIdentificationConfig::showGems),
POTION(ItemIdentificationConfig::showPotions),
IMPLING_JAR(ItemIdentificationConfig::showImplingJars),
TABLET(ItemIdentificationConfig::showTablets),
SCROLL(ItemIdentificationConfig::showTeleportScrolls);
final Predicate<ItemIdentificationConfig> enabled;
}
}

View File

@@ -203,4 +203,15 @@ public interface ItemIdentificationConfig extends Config
{
return false;
}
@ConfigItem(
keyName = "showTeleportScrolls",
name = "Teleport Scrolls",
description = "Show identification on teleport scrolls",
section = identificationSection
)
default boolean showTeleportScrolls()
{
return false;
}
}

View File

@@ -58,93 +58,11 @@ class ItemIdentificationOverlay extends WidgetItemOverlay
public void renderItemOverlay(Graphics2D graphics, int itemId, WidgetItem widgetItem)
{
ItemIdentification iden = findItemIdentification(itemId);
if (iden == null)
if (iden == null || !iden.type.enabled.test(config))
{
return;
}
switch (iden.type)
{
case SEED:
if (!config.showSeeds())
{
return;
}
break;
case SACK:
if (!config.showSacks())
{
return;
}
break;
case HERB:
if (!config.showHerbs())
{
return;
}
break;
case LOGS:
if (!config.showLogs())
{
return;
}
break;
case PLANK:
if (!config.showPlanks())
{
return;
}
break;
case SAPLING:
if (!config.showSaplings())
{
return;
}
break;
case COMPOST:
if (!config.showComposts())
{
return;
}
break;
case ORE:
if (!config.showOres())
{
return;
}
break;
case BAR:
if (!config.showBars())
{
return;
}
break;
case GEM:
if (!config.showGems())
{
return;
}
break;
case POTION:
if (!config.showPotions())
{
return;
}
break;
case IMPLING_JAR:
if (!config.showImplingJars())
{
return;
}
break;
case TABLET:
if (!config.showTablets())
{
return;
}
break;
}
graphics.setFont(FontManager.getRunescapeSmallFont());
renderText(graphics, widgetItem.getCanvasBounds(), iden);
}

View File

@@ -247,6 +247,8 @@ public class MenuEntrySwapperPlugin extends Plugin
swap("inspect", "trapdoor", "travel", config::swapTravel);
swap("board", "travel cart", "pay-fare", config::swapTravel);
swap("board", "sacrificial boat", "quick-board", config::swapQuick);
swap("cage", "harpoon", config::swapHarpoon);
swap("big net", "harpoon", config::swapHarpoon);
swap("net", "harpoon", config::swapHarpoon);

View File

@@ -25,7 +25,10 @@
package net.runelite.client.plugins.mining;
import com.google.common.collect.ImmutableMap;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.Getter;
import static net.runelite.api.AnimationID.MINING_3A_PICKAXE;
import static net.runelite.api.AnimationID.MINING_ADAMANT_PICKAXE;
@@ -135,4 +138,11 @@ enum Pickaxe
{
return PICKAXE_ANIM_IDS.get(animId);
}
public static Set<Integer> all()
{
return Arrays.stream(values())
.map(pickaxe -> pickaxe.itemId)
.collect(Collectors.toSet());
}
}

View File

@@ -42,7 +42,6 @@ import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Actor;
import net.runelite.api.Client;
import net.runelite.api.GameState;
@@ -86,7 +85,6 @@ import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.overlay.tooltip.Tooltip;
import net.runelite.client.ui.overlay.tooltip.TooltipManager;
@Slf4j
@PluginDescriptor(
name = "Music",
description = "Adds search and filter for the music list, and additional volume control",

View File

@@ -37,6 +37,7 @@ import java.time.temporal.ChronoUnit;
import java.util.Date;
import javax.inject.Inject;
import net.runelite.api.Client;
import net.runelite.api.Constants;
import net.runelite.api.GameState;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.GameTick;
@@ -49,6 +50,7 @@ import net.runelite.client.events.ConfigChanged;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.task.Schedule;
import org.apache.commons.lang3.time.DurationFormatUtils;
@PluginDescriptor(
name = "Report Button",
@@ -180,6 +182,9 @@ public class ReportButtonPlugin extends Plugin
case LOGIN_TIME:
reportButton.setText(getLoginTime());
break;
case IDLE_TIME:
reportButton.setText(getIdleTime());
break;
case DATE:
reportButton.setText(getDate());
break;
@@ -192,6 +197,12 @@ public class ReportButtonPlugin extends Plugin
}
}
private String getIdleTime()
{
long lastActivity = Long.min(client.getMouseIdleTicks(), client.getKeyboardIdleTicks());
return DurationFormatUtils.formatDuration(lastActivity * Constants.CLIENT_TICK_LENGTH, "mm:ss");
}
private String getLoginTime()
{
if (loginTime == null)

View File

@@ -32,7 +32,8 @@ public enum TimeStyle
UTC("UTC Time"),
JAGEX("Jagex HQ Time"),
LOCAL_TIME("Local Time"),
GAME_TICKS("Game Ticks");
GAME_TICKS("Game Ticks"),
IDLE_TIME("Idle Time");
private final String name;

View File

@@ -0,0 +1,75 @@
/*
* Copyright (c) 2021, Hydrox6 <ikada@protonmail.ch>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.roofremoval;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
@ConfigGroup(RoofRemovalConfig.CONFIG_GROUP)
public interface RoofRemovalConfig extends Config
{
String CONFIG_GROUP = "roofremoval";
@ConfigItem(
keyName = "removePosition",
name = "Player's position",
description = "Remove roofs above the player's position"
)
default boolean removePosition()
{
return true;
}
@ConfigItem(
keyName = "removeHovered",
name = "Hovered tile",
description = "Remove roofs above the hovered tile"
)
default boolean removeHovered()
{
return true;
}
@ConfigItem(
keyName = "removeDestination",
name = "Destination tile",
description = "Remove roofs above the destination tile"
)
default boolean removeDestination()
{
return true;
}
@ConfigItem(
keyName = "removeBetween",
name = "Between camera & player",
description = "Remove roofs between the camera and the player at low camera angles"
)
default boolean removeBetween()
{
return true;
}
}

View File

@@ -0,0 +1,267 @@
/*
* Copyright (c) 2021 Hydrox6 <ikada@protonmail.ch>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.roofremoval;
import com.google.common.base.Stopwatch;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.google.inject.Provides;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.Constants;
import static net.runelite.api.Constants.ROOF_FLAG_BETWEEN;
import static net.runelite.api.Constants.ROOF_FLAG_DESTINATION;
import static net.runelite.api.Constants.ROOF_FLAG_HOVERED;
import static net.runelite.api.Constants.ROOF_FLAG_POSITION;
import net.runelite.api.GameState;
import net.runelite.api.Tile;
import net.runelite.api.events.GameStateChanged;
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.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
@PluginDescriptor(
name = "Roof Removal",
description = "Remove only the needed roofs above your player, hovered tile, or destination",
enabledByDefault = false
)
@Slf4j
public class RoofRemovalPlugin extends Plugin
{
private static class FlaggedArea
{
int rx1;
int ry1;
int rx2;
int ry2;
int z1;
int z2;
}
@Inject
private Client client;
@Inject
private ClientThread clientThread;
@Inject
private Gson gson;
@Inject
private RoofRemovalConfig config;
private final Map<Integer, long[]> overrides = new HashMap<>();
@Provides
RoofRemovalConfig getConfig(ConfigManager configManager)
{
return configManager.getConfig(RoofRemovalConfig.class);
}
@Override
public void startUp() throws IOException
{
loadRoofOverrides();
clientThread.invoke(() ->
{
if (client.getGameState() == GameState.LOGGED_IN)
{
performRoofRemoval();
}
client.getScene().setRoofRemovalMode(buildRoofRemovalFlags());
});
}
@Override
public void shutDown()
{
overrides.clear();
clientThread.invoke(() ->
{
client.getScene().setRoofRemovalMode(0);
// Reload the scene to clear roof flag overrides
if (client.getGameState() == GameState.LOGGED_IN)
{
client.setGameState(GameState.LOADING);
}
});
}
@Subscribe
public void onGameStateChanged(GameStateChanged e)
{
if (e.getGameState() == GameState.LOGGED_IN)
{
performRoofRemoval();
}
}
@Subscribe
public void onConfigChanged(ConfigChanged e)
{
if (!e.getGroup().equals(RoofRemovalConfig.CONFIG_GROUP))
{
return;
}
client.getScene().setRoofRemovalMode(buildRoofRemovalFlags());
}
private int buildRoofRemovalFlags()
{
int roofRemovalMode = 0;
if (config.removePosition())
{
roofRemovalMode |= ROOF_FLAG_POSITION;
}
if (config.removeHovered())
{
roofRemovalMode |= ROOF_FLAG_HOVERED;
}
if (config.removeDestination())
{
roofRemovalMode |= ROOF_FLAG_DESTINATION;
}
if (config.removeBetween())
{
roofRemovalMode |= ROOF_FLAG_BETWEEN;
}
return roofRemovalMode;
}
private void performRoofRemoval()
{
assert client.isClientThread();
applyRoofOverrides();
Stopwatch sw = Stopwatch.createStarted();
client.getScene().generateHouses();
log.debug("House generation duration: {}", sw.stop());
}
private void loadRoofOverrides() throws IOException
{
try (InputStream in = getClass().getResourceAsStream("overrides.jsonc"))
{
final InputStreamReader data = new InputStreamReader(in, StandardCharsets.UTF_8);
//CHECKSTYLE:OFF
final Type type = new TypeToken<Map<Integer, List<FlaggedArea>>>() {}.getType();
//CHECKSTYLE:ON
Map<Integer, List<FlaggedArea>> parsed = gson.fromJson(data, type);
overrides.clear();
for (Map.Entry<Integer, List<FlaggedArea>> entry : parsed.entrySet())
{
for (FlaggedArea fla : entry.getValue())
{
for (int z = fla.z1; z <= fla.z2; z++)
{
// Given that each region is 64x64, and the override data is a boolean, one of the axis can be stored as
// bits in a long. This removes the need for a boolean[64][64] and an extra array lookup in favour of
// a bitwise &, and results in a consistently smaller amount of memory required to store the overrides.
int packedRegion = entry.getKey() << 2 | z;
long[] regionData = overrides.computeIfAbsent(packedRegion, k -> new long[Constants.REGION_SIZE]);
for (int y = fla.ry1; y <= fla.ry2; y++)
{
long row = regionData[y];
for (int x = fla.rx1; x <= fla.rx2; x++)
{
row |= (1L << x);
}
regionData[y] = row;
}
}
}
}
}
}
private void applyRoofOverrides()
{
Stopwatch sw = Stopwatch.createStarted();
boolean regionsHaveOverrides = false;
outer:
for (int regionID : client.getMapRegions())
{
for (int z = 0; z < Constants.MAX_Z; z++)
{
if (overrides.containsKey(regionID << 2 | z))
{
regionsHaveOverrides = true;
break outer;
}
}
}
if (!regionsHaveOverrides)
{
return;
}
Tile[][][] tiles = client.getScene().getTiles();
byte[][][] settings = client.getTileSettings();
for (int z = 0; z < Constants.MAX_Z; z++)
{
for (int x = 0; x < Constants.SCENE_SIZE; x++)
{
for (int y = 0; y < Constants.SCENE_SIZE; y++)
{
Tile tile = tiles[z][x][y];
if (tile == null)
{
continue;
}
int regionID = tile.getWorldLocation().getRegionID() << 2 | z;
if (!overrides.containsKey(regionID))
{
continue;
}
int rx = tile.getWorldLocation().getRegionX();
int ry = tile.getWorldLocation().getRegionY();
long[] region = overrides.get(regionID);
if ((region[ry] & (1L << rx)) != 0)
{
settings[z][x][y] |= Constants.TILE_FLAG_UNDER_ROOF;
}
}
}
}
log.debug("Roof override duration: {}", sw.stop());
}
}

View File

@@ -520,12 +520,12 @@ public class SlayerPlugin extends Plugin
log.debug("Slayer xp change delta: {}, killed npcs: {}", delta, taggedNpcsDiedPrevTick);
final Task task = Task.getTask(taskName);
if (task != null && task.getExpectedKillExp() > 0)
if (task != null && task.getMinimumKillXp() > 0)
{
// Only decrement a kill if the xp drop matches the expected drop. This is just for Tzhaar tasks.
if (task.getExpectedKillExp() == delta)
// Only decrement a kill if the xp drop is above the minimum threshold. This is for Tzhaar and Sire tasks.
if (delta >= task.getMinimumKillXp())
{
killed(1);
killed(max(taggedNpcsDiedPrevTick, 1));
}
}
else

View File

@@ -39,8 +39,12 @@ enum Task
{
//<editor-fold desc="Enums">
ABERRANT_SPECTRES("Aberrant spectres", ItemID.ABERRANT_SPECTRE, "Spectre"),
ABYSSAL_DEMONS("Abyssal demons", ItemID.ABYSSAL_DEMON),
ABYSSAL_SIRE("Abyssal Sire", ItemID.ABYSSAL_ORPHAN),
// Abyssal demon - 150 xp
// Greater abyssal demon - 4200 xp
// Abyssal sire - 450 xp
// Use 51 for minimum xp to avoid a kill triggering from killing the sire vents
ABYSSAL_DEMONS("Abyssal demons", ItemID.ABYSSAL_DEMON, 51),
ABYSSAL_SIRE("Abyssal Sire", ItemID.ABYSSAL_ORPHAN, 51),
ADAMANT_DRAGONS("Adamant dragons", ItemID.ADAMANT_DRAGON_MASK),
ALCHEMICAL_HYDRA("Alchemical Hydra", ItemID.IKKLE_HYDRA),
ANKOU("Ankou", ItemID.ANKOU_MASK),
@@ -238,7 +242,7 @@ enum Task
private final String[] targetNames;
private final int weaknessThreshold;
private final int weaknessItem;
private final int expectedKillExp;
private final int minimumKillXp;
static
{
@@ -260,7 +264,7 @@ enum Task
this.weaknessThreshold = -1;
this.weaknessItem = -1;
this.targetNames = targetNames;
this.expectedKillExp = 0;
this.minimumKillXp = 0;
}
Task(String name, int itemSpriteId, int weaknessThreshold, int weaknessItem, String... targetNames)
@@ -271,10 +275,10 @@ enum Task
this.weaknessThreshold = weaknessThreshold;
this.weaknessItem = weaknessItem;
this.targetNames = targetNames;
this.expectedKillExp = 0;
this.minimumKillXp = 0;
}
Task(String name, int itemSpriteId, int expectedKillExp)
Task(String name, int itemSpriteId, int minimumKillXp)
{
Preconditions.checkArgument(itemSpriteId >= 0);
this.name = name;
@@ -282,7 +286,7 @@ enum Task
this.weaknessThreshold = -1;
this.weaknessItem = -1;
this.targetNames = new String[0];
this.expectedKillExp = expectedKillExp;
this.minimumKillXp = minimumKillXp;
}
@Nullable

View File

@@ -45,6 +45,7 @@ enum GameTimer
EXANTIFIRE(ItemID.EXTENDED_ANTIFIRE4, GameTimerImageType.ITEM, "Extended antifire", 12, ChronoUnit.MINUTES),
OVERLOAD(ItemID.OVERLOAD_4, GameTimerImageType.ITEM, "Overload", 5, ChronoUnit.MINUTES, true),
CANNON(ItemID.CANNON_BARRELS, GameTimerImageType.ITEM, "Cannon", 25, ChronoUnit.MINUTES),
CANNON_REPAIR(ItemID.TOOLKIT, GameTimerImageType.ITEM, "Broken Cannon", 10, ChronoUnit.MINUTES),
MAGICIMBUE(SpriteID.SPELL_MAGIC_IMBUE, GameTimerImageType.SPRITE, "Magic imbue", 21, GAME_TICKS),
SUPERANTIFIRE(ItemID.SUPER_ANTIFIRE_POTION4, GameTimerImageType.ITEM, "Super antifire", 3, ChronoUnit.MINUTES),
BIND(SpriteID.SPELL_BIND, GameTimerImageType.SPRITE, "Bind", GraphicID.BIND, 8, GAME_TICKS, true),
@@ -85,7 +86,9 @@ enum GameTimer
RESURRECT_THRALL_COOLDOWN(SpriteID.SPELL_RESURRECT_SUPERIOR_SKELETON_DISABLED, GameTimerImageType.SPRITE, "Resurrect thrall cooldown", 12, GAME_TICKS),
WARD_OF_ARCEUUS_COOLDOWN(SpriteID.SPELL_WARD_OF_ARCEUUS_DISABLED, GameTimerImageType.SPRITE, "Ward of Arceuus cooldown", 30, ChronoUnit.SECONDS),
DEATH_CHARGE_COOLDOWN(SpriteID.SPELL_DEATH_CHARGE_DISABLED, GameTimerImageType.SPRITE, "Death charge cooldown", 60, ChronoUnit.SECONDS),
CORRUPTION_COOLDOWN(SpriteID.SPELL_GREATER_CORRUPTION_DISABLED, GameTimerImageType.SPRITE, "Corruption cooldown", 30, ChronoUnit.SECONDS);
CORRUPTION_COOLDOWN(SpriteID.SPELL_GREATER_CORRUPTION_DISABLED, GameTimerImageType.SPRITE, "Corruption cooldown", 30, ChronoUnit.SECONDS),
PICKPOCKET_STUN(SpriteID.SKILL_THIEVING, GameTimerImageType.SPRITE, "Stunned", true)
;
@Nullable
private final Duration duration;

View File

@@ -283,4 +283,14 @@ public interface TimersConfig extends Config
{
return false;
}
@ConfigItem(
keyName = "showPickpocketStun",
name = "Pickpocket stun timer",
description = "Configures whether pickpocket stun timer is displayed"
)
default boolean showPickpocketStun()
{
return true;
}
}

View File

@@ -55,7 +55,6 @@ import net.runelite.api.Varbits;
import net.runelite.api.coords.WorldPoint;
import net.runelite.api.events.ActorDeath;
import net.runelite.api.events.AnimationChanged;
import net.runelite.api.events.StatChanged;
import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.GameTick;
@@ -63,6 +62,7 @@ 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.StatChanged;
import net.runelite.api.events.VarbitChanged;
import net.runelite.api.widgets.Widget;
import static net.runelite.api.widgets.WidgetInfo.PVP_WORLD_SAFE_ZONE;
@@ -82,7 +82,7 @@ import org.apache.commons.lang3.ArrayUtils;
@PluginDescriptor(
name = "Timers",
description = "Show various timers in an infobox",
tags = {"combat", "items", "magic", "potions", "prayer", "overlay", "abyssal", "sire", "inferno", "fight", "caves", "cape", "timer", "tzhaar"}
tags = {"combat", "items", "magic", "potions", "prayer", "overlay", "abyssal", "sire", "inferno", "fight", "caves", "cape", "timer", "tzhaar", "thieving", "pickpocket"}
)
@Slf4j
public class TimersPlugin extends Plugin
@@ -90,10 +90,14 @@ public class TimersPlugin extends Plugin
private static final String ABYSSAL_SIRE_STUN_MESSAGE = "The Sire has been disorientated temporarily.";
private static final String ANTIFIRE_DRINK_MESSAGE = "You drink some of your antifire potion.";
private static final String ANTIFIRE_EXPIRED_MESSAGE = "<col=7f007f>Your antifire potion has expired.</col>";
private static final String CANNON_BASE_MESSAGE = "You place the cannon base on the ground.";
private static final String CANNON_STAND_MESSAGE = "You add the stand.";
private static final String CANNON_BARRELS_MESSAGE = "You add the barrels.";
private static final String CANNON_FURNACE_MESSAGE = "You add the furnace.";
private static final String CANNON_PICKUP_MESSAGE = "You pick up the cannon. It's really heavy.";
private static final String CANNON_REPAIR_MESSAGE = "You repair your cannon, restoring it to working order.";
private static final String CANNON_DESTROYED_MESSAGE = "Your cannon has been destroyed!";
private static final String CANNON_BROKEN_MESSAGE = "<col=ef1020>Your cannon has broken!";
private static final String CHARGE_EXPIRED_MESSAGE = "<col=ef1020>Your magical charge fades away.</col>";
private static final String CHARGE_MESSAGE = "<col=ef1020>You feel charged with magic power.</col>";
private static final String EXTENDED_ANTIFIRE_DRINK_MESSAGE = "You drink some of your extended antifire potion.";
@@ -122,6 +126,7 @@ public class TimersPlugin extends Plugin
private static final String RESURRECT_THRALL_DISAPPEAR_MESSAGE_START = ">Your ";
private static final String RESURRECT_THRALL_DISAPPEAR_MESSAGE_END = " thrall returns to the grave.</col>";
private static final String WARD_OF_ARCEUUS_MESSAGE = ">Your defence against Arceuus magic has been strengthened.</col>";
private static final String PICKPOCKET_FAILURE_MESSAGE = "You fail to pick the ";
private static final Pattern TELEBLOCK_PATTERN = Pattern.compile("A Tele Block spell has been cast on you(?: by .+)?\\. It will expire in (?<mins>\\d+) minutes?(?:, (?<secs>\\d+) seconds?)?\\.");
private static final Pattern DIVINE_POTION_PATTERN = Pattern.compile("You drink some of your divine (.+) potion\\.");
@@ -498,6 +503,18 @@ public class TimersPlugin extends Plugin
return;
}
if (message.contains(PICKPOCKET_FAILURE_MESSAGE) && config.showPickpocketStun() && message.contains("pocket"))
{
if (message.contains("hero") || message.contains("elf"))
{
createGameTimer(PICKPOCKET_STUN, Duration.ofSeconds(6));
}
else
{
createGameTimer(PICKPOCKET_STUN, Duration.ofSeconds(5));
}
}
if (message.equals(ABYSSAL_SIRE_STUN_MESSAGE) && config.showAbyssalSireStun())
{
createGameTimer(ABYSSAL_SIRE_STUN);
@@ -559,15 +576,27 @@ public class TimersPlugin extends Plugin
}
if (config.showCannon() && (message.equals(CANNON_FURNACE_MESSAGE) || message.contains(CANNON_REPAIR_MESSAGE)))
if (config.showCannon())
{
TimerTimer cannonTimer = createGameTimer(CANNON);
cannonTimer.setTooltip(cannonTimer.getTooltip() + " - World " + client.getWorld());
}
if (config.showCannon() && (message.equals(CANNON_PICKUP_MESSAGE) || message.equals(CANNON_DESTROYED_MESSAGE)))
{
removeGameTimer(CANNON);
if (message.equals(CANNON_BASE_MESSAGE) || message.equals(CANNON_STAND_MESSAGE)
|| message.equals(CANNON_BARRELS_MESSAGE) || message.equals(CANNON_FURNACE_MESSAGE)
|| message.contains(CANNON_REPAIR_MESSAGE))
{
removeGameTimer(CANNON_REPAIR);
TimerTimer cannonTimer = createGameTimer(CANNON);
cannonTimer.setTooltip(cannonTimer.getTooltip() + " - World " + client.getWorld());
}
else if (message.equals(CANNON_BROKEN_MESSAGE))
{
removeGameTimer(CANNON);
TimerTimer cannonTimer = createGameTimer(CANNON_REPAIR);
cannonTimer.setTooltip(cannonTimer.getTooltip() + " - World " + client.getWorld());
}
else if (message.equals(CANNON_PICKUP_MESSAGE) || message.equals(CANNON_DESTROYED_MESSAGE))
{
removeGameTimer(CANNON);
removeGameTimer(CANNON_REPAIR);
}
}
if (config.showMagicImbue() && message.equals(MAGIC_IMBUE_MESSAGE))

View File

@@ -35,7 +35,6 @@ import javax.swing.JPanel;
import javax.swing.JToggleButton;
import javax.swing.border.EmptyBorder;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Constants;
import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.FontManager;
@@ -44,7 +43,6 @@ import net.runelite.client.ui.components.shadowlabel.JShadowedLabel;
import net.runelite.client.util.ImageUtil;
import net.runelite.client.util.SwingUtil;
@Slf4j
@Getter
public class TimeablePanel<T> extends JPanel
{

View File

@@ -35,7 +35,6 @@ import java.util.Set;
import javax.swing.JLabel;
import javax.swing.JToggleButton;
import javax.swing.border.EmptyBorder;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.ItemID;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.game.ItemManager;
@@ -45,7 +44,6 @@ import net.runelite.client.plugins.timetracking.TimeablePanel;
import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.FontManager;
@Slf4j
public class FarmingTabPanel extends TabContentPanel
{
private final FarmingTracker farmingTracker;

View File

@@ -69,7 +69,9 @@ public class WidgetOverlay extends Overlay
new WidgetOverlay(client, WidgetInfo.MULTICOMBAT_FIXED, OverlayPosition.BOTTOM_RIGHT),
new WidgetOverlay(client, WidgetInfo.MULTICOMBAT_RESIZEABLE_MODERN, OverlayPosition.CANVAS_TOP_RIGHT),
new WidgetOverlay(client, WidgetInfo.MULTICOMBAT_RESIZEABLE_CLASSIC, OverlayPosition.CANVAS_TOP_RIGHT),
new WidgetOverlay(client, WidgetInfo.TEMPOROSS_STATUS_INDICATOR, OverlayPosition.TOP_LEFT)
new WidgetOverlay(client, WidgetInfo.TEMPOROSS_STATUS_INDICATOR, OverlayPosition.TOP_LEFT),
new WidgetOverlay(client, WidgetInfo.BA_HEAL_TEAMMATES, OverlayPosition.BOTTOM_LEFT),
new WidgetOverlay(client, WidgetInfo.BA_TEAM, OverlayPosition.TOP_RIGHT)
);
}

View File

@@ -450,7 +450,7 @@ public class ModelOutlineRenderer
{
y3 = clipY2;
}
if (y1 == y3 || y3 < 0)
if (y1 == y3 || y3 < clipY1)
{
return;
}
@@ -459,16 +459,16 @@ public class ModelOutlineRenderer
x2 <<= 14;
x3 = x1;
if (y1 < 0)
if (y1 < clipY1)
{
x3 -= y1 * slope3;
x1 -= y1 * slope1;
y1 = 0;
x3 -= (y1 - clipY1) * slope3;
x1 -= (y1 - clipY1) * slope1;
y1 = clipY1;
}
if (y2 < 0)
if (y2 < clipY1)
{
x2 -= slope2 * y2;
y2 = 0;
x2 -= (y2 - clipY1) * slope2;
y2 = clipY1;
}
int pixelY = y1;

View File

@@ -162,6 +162,12 @@
"name": "Silver Stall",
"xp": 54
},
{
"level": 50,
"icon": 5560,
"name": "Wall Safe",
"xp": 70
},
{
"level": 53,
"icon": 4625,

View File

@@ -32,13 +32,11 @@ import javax.swing.text.JTextComponent;
import jdk.jshell.JShell;
import jdk.jshell.SourceCodeAnalysis;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.fife.ui.autocomplete.BasicCompletion;
import org.fife.ui.autocomplete.Completion;
import org.fife.ui.autocomplete.CompletionProviderBase;
import org.fife.ui.autocomplete.ParameterizedCompletion;
@Slf4j
@RequiredArgsConstructor
public class JShellAutocompleteProvider extends CompletionProviderBase
{