Merge remote-tracking branch 'runelite/master'

This commit is contained in:
Owain van Brakel
2019-06-05 19:51:04 +02:00
47 changed files with 2331 additions and 2658 deletions

View File

@@ -69,7 +69,7 @@ public class CacheUploader implements Runnable
archive.setHash(hash); archive.setHash(hash);
String path = new StringBuilder() String path = new StringBuilder()
.append(hashStr.substring(0, 2)) .append(hashStr, 0, 2)
.append('/') .append('/')
.append(hashStr.substring(2)) .append(hashStr.substring(2))
.toString(); .toString();

View File

@@ -116,7 +116,7 @@ public class FlatStorage implements Storage
{ {
int lidx = line.indexOf('='); int lidx = line.indexOf('=');
String key = line.substring(0, lidx); String key = line.substring(0, lidx);
String value = line.substring(lidx + 1, line.length()); String value = line.substring(lidx + 1);
if ("file".equals(key)) if ("file".equals(key))
{ {
@@ -128,7 +128,7 @@ public class FlatStorage implements Storage
int vidx = value.indexOf('='); int vidx = value.indexOf('=');
FileData fd = new FileData(); FileData fd = new FileData();
fd.setId(Integer.parseInt(value.substring(0, vidx))); fd.setId(Integer.parseInt(value.substring(0, vidx)));
fd.setNameHash(Integer.parseInt(value.substring(vidx + 1, value.length()))); fd.setNameHash(Integer.parseInt(value.substring(vidx + 1)));
fileData.add(fd); fileData.add(fd);
continue; continue;
} }

View File

@@ -104,7 +104,7 @@ public class CacheService
{ {
String hashStr = BaseEncoding.base16().encode(archiveEntry.getHash()); String hashStr = BaseEncoding.base16().encode(archiveEntry.getHash());
String path = new StringBuilder() String path = new StringBuilder()
.append(hashStr.substring(0, 2)) .append(hashStr, 0, 2)
.append('/') .append('/')
.append(hashStr.substring(2)) .append(hashStr.substring(2))
.toString(); .toString();

View File

@@ -151,6 +151,13 @@ public interface Client extends GameEngine
*/ */
void setPassword(String password); void setPassword(String password);
/**
* Sets the 6 digit pin used for authenticator on login screen.
*
* @param otp one time password
*/
void setOtp(String otp);
/** /**
* Gets currently selected login field. 0 is username, and 1 is password. * Gets currently selected login field. 0 is username, and 1 is password.
* *
@@ -158,6 +165,13 @@ public interface Client extends GameEngine
*/ */
int getCurrentLoginField(); int getCurrentLoginField();
/**
* Gets index of current login state. 2 is username/password form, 4 is authenticator form
*
* @return current login state index
*/
int getLoginIndex();
/** /**
* Gets the account type of the logged in player. * Gets the account type of the logged in player.
* *
@@ -1352,6 +1366,13 @@ public interface Client extends GameEngine
*/ */
boolean isInInstancedRegion(); boolean isInInstancedRegion();
/**
* Get the number of client ticks an item has been pressed
*
* @return the number of client ticks an item has been pressed
*/
int getItemPressedDuration();
/** /**
* Sets whether the client is hiding entities. * Sets whether the client is hiding entities.
* <p> * <p>
@@ -1598,6 +1619,19 @@ public interface Client extends GameEngine
void checkClickbox(Model model, int orientation, int pitchSin, int pitchCos, int yawSin, int yawCos, int x, int y, int z, long hash); void checkClickbox(Model model, int orientation, int pitchSin, int pitchCos, int yawSin, int yawCos, int x, int y, int z, long hash);
/**
* Get the if1 widget whose item is being dragged
*
* @return
*/
Widget getIf1DraggedWidget();
/**
* Get the item index of the item being dragged on an if1 widget
* @return
*/
int getIf1DraggedItemIndex();
/** /**
* Sets if a widget is in target mode * Sets if a widget is in target mode
*/ */

View File

@@ -41,6 +41,10 @@ public enum GameState
* The client is at the login screen. * The client is at the login screen.
*/ */
LOGIN_SCREEN(10), LOGIN_SCREEN(10),
/**
* The client is at the login screen entering authenticator code.
*/
LOGIN_SCREEN_AUTHENTICATOR(11),
/** /**
* There is a player logging in. * There is a player logging in.
*/ */

View File

@@ -27,6 +27,7 @@ package net.runelite.api;
public class GraphicID public class GraphicID
{ {
public static final int WINE_MAKE = 47;
public static final int SPLASH = 85; public static final int SPLASH = 85;
public static final int GREY_BUBBLE_TELEPORT = 86; public static final int GREY_BUBBLE_TELEPORT = 86;
public static final int TELEPORT = 111; public static final int TELEPORT = 111;

View File

@@ -79,6 +79,10 @@ public class ArdougneDiaryRequirement extends GenericDiaryRequirement
new QuestRequirement(Quest.FAIRYTALE_II__CURE_A_QUEEN, true)); new QuestRequirement(Quest.FAIRYTALE_II__CURE_A_QUEEN, true));
// HARD // HARD
// When the task is completed "the Totem" changes to "Totem" - so we add
// both variations.
add("Recharge some Jewellery at the Totem in the Legends Guild.",
new QuestRequirement(Quest.LEGENDS_QUEST));
add("Recharge some Jewellery at Totem in the Legends Guild.", add("Recharge some Jewellery at Totem in the Legends Guild.",
new QuestRequirement(Quest.LEGENDS_QUEST)); new QuestRequirement(Quest.LEGENDS_QUEST));
add("Enter the Magic Guild.", add("Enter the Magic Guild.",

View File

@@ -46,7 +46,7 @@ class Obstacles
// Draynor // Draynor
ROUGH_WALL, TIGHTROPE, TIGHTROPE_11406, NARROW_WALL, WALL_11630, GAP_11631, CRATE_11632, STILE_7527, ROUGH_WALL, TIGHTROPE, TIGHTROPE_11406, NARROW_WALL, WALL_11630, GAP_11631, CRATE_11632, STILE_7527,
// Al-Kharid // Al-Kharid
ROUGH_WALL_11633, TIGHTROPE_14398, CABLE, ZIP_LINE, TROPICAL_TREE_14404, ROOF_TOP_BEAMS, ROUGH_WALL_11633, TIGHTROPE_14398, CABLE, ZIP_LINE_14403, TROPICAL_TREE_14404, ROOF_TOP_BEAMS,
TIGHTROPE_14409, GAP_14399, TIGHTROPE_14409, GAP_14399,
// Pyramid // Pyramid
STAIRS_10857, LOW_WALL_10865, LEDGE_10860, PLANK_10868, GAP_10882, LEDGE_10886, STAIRS_10857, GAP_10884, STAIRS_10857, LOW_WALL_10865, LEDGE_10860, PLANK_10868, GAP_10882, LEDGE_10886, STAIRS_10857, GAP_10884,

View File

@@ -328,7 +328,10 @@ public class BarbarianAssaultPlugin extends Plugin
{ {
overlay.setCurrentRound(null); overlay.setCurrentRound(null);
if (config.waveTimes() && gameTime != null) // Use an instance check to determine if this is exiting a game or a tutorial
// After exiting tutorials there is a small delay before changing IN_GAME_BA back to
// 0 whereas when in a real wave it changes while still in the instance.
if (config.waveTimes() && gameTime != null && client.isInInstancedRegion())
{ {
announceTime("Wave " + currentWave + " duration: ", gameTime.getTime(true)); announceTime("Wave " + currentWave + " duration: ", gameTime.getTime(true));
} }

View File

@@ -33,8 +33,8 @@ import javax.annotation.Nonnull;
import lombok.Getter; import lombok.Getter;
import net.runelite.api.Client; import net.runelite.api.Client;
import net.runelite.api.EquipmentInventorySlot; import net.runelite.api.EquipmentInventorySlot;
import static net.runelite.api.EquipmentInventorySlot.LEGS;
import static net.runelite.api.EquipmentInventorySlot.*; import static net.runelite.api.EquipmentInventorySlot.*;
import static net.runelite.api.EquipmentInventorySlot.LEGS;
import net.runelite.api.Item; import net.runelite.api.Item;
import net.runelite.api.ItemID; import net.runelite.api.ItemID;
import static net.runelite.api.ItemID.*; import static net.runelite.api.ItemID.*;
@@ -47,13 +47,13 @@ import net.runelite.client.plugins.cluescrolls.ClueScrollPlugin;
import net.runelite.client.plugins.cluescrolls.clues.emote.AllRequirementsCollection; import net.runelite.client.plugins.cluescrolls.clues.emote.AllRequirementsCollection;
import net.runelite.client.plugins.cluescrolls.clues.emote.AnyRequirementCollection; import net.runelite.client.plugins.cluescrolls.clues.emote.AnyRequirementCollection;
import net.runelite.client.plugins.cluescrolls.clues.emote.Emote; import net.runelite.client.plugins.cluescrolls.clues.emote.Emote;
import static net.runelite.client.plugins.cluescrolls.clues.emote.Emote.BULL_ROARER;
import static net.runelite.client.plugins.cluescrolls.clues.emote.Emote.*; import static net.runelite.client.plugins.cluescrolls.clues.emote.Emote.*;
import static net.runelite.client.plugins.cluescrolls.clues.emote.Emote.BULL_ROARER;
import net.runelite.client.plugins.cluescrolls.clues.emote.ItemRequirement; import net.runelite.client.plugins.cluescrolls.clues.emote.ItemRequirement;
import net.runelite.client.plugins.cluescrolls.clues.emote.RangeItemRequirement; import net.runelite.client.plugins.cluescrolls.clues.emote.RangeItemRequirement;
import net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit; import net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit;
import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.SHANTAY_PASS;
import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.*; import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.*;
import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.SHANTAY_PASS;
import net.runelite.client.plugins.cluescrolls.clues.emote.SingleItemRequirement; import net.runelite.client.plugins.cluescrolls.clues.emote.SingleItemRequirement;
import net.runelite.client.plugins.cluescrolls.clues.emote.SlotLimitationRequirement; import net.runelite.client.plugins.cluescrolls.clues.emote.SlotLimitationRequirement;
import net.runelite.client.ui.overlay.OverlayUtil; import net.runelite.client.ui.overlay.OverlayUtil;
@@ -97,7 +97,7 @@ public class EmoteClue extends ClueScroll implements TextClueScroll, LocationClu
new EmoteClue("Cheer in the Ogre Pen in the Training Camp. Show you are angry before you talk to me. Equip a green dragonhide body and chaps and a steel square shield.", OGRE_CAGE_IN_KING_LATHAS_TRAINING_CAMP, new WorldPoint(2527, 3375, 0), CHEER, ANGRY, item(GREEN_DHIDE_BODY), item(GREEN_DHIDE_CHAPS), item(STEEL_SQ_SHIELD)), new EmoteClue("Cheer in the Ogre Pen in the Training Camp. Show you are angry before you talk to me. Equip a green dragonhide body and chaps and a steel square shield.", OGRE_CAGE_IN_KING_LATHAS_TRAINING_CAMP, new WorldPoint(2527, 3375, 0), CHEER, ANGRY, item(GREEN_DHIDE_BODY), item(GREEN_DHIDE_CHAPS), item(STEEL_SQ_SHIELD)),
new EmoteClue("Cheer in the Entrana church. Beware of double agents! Equip a full set of black dragonhide armour.", ENTRANA_CHAPEL, new WorldPoint(2852, 3349, 0), CHEER, item(BLACK_DHIDE_VAMB), item(BLACK_DHIDE_CHAPS), item(BLACK_DHIDE_BODY)), new EmoteClue("Cheer in the Entrana church. Beware of double agents! Equip a full set of black dragonhide armour.", ENTRANA_CHAPEL, new WorldPoint(2852, 3349, 0), CHEER, item(BLACK_DHIDE_VAMB), item(BLACK_DHIDE_CHAPS), item(BLACK_DHIDE_BODY)),
new EmoteClue("Cheer for the monks at Port Sarim. Equip a coif, steel plateskirt and a sapphire necklace.", NEAR_THE_ENTRANA_FERRY_IN_PORT_SARIM, new WorldPoint(3047, 3237, 0), CHEER, item(COIF), item(STEEL_PLATESKIRT), item(SAPPHIRE_NECKLACE)), new EmoteClue("Cheer for the monks at Port Sarim. Equip a coif, steel plateskirt and a sapphire necklace.", NEAR_THE_ENTRANA_FERRY_IN_PORT_SARIM, new WorldPoint(3047, 3237, 0), CHEER, item(COIF), item(STEEL_PLATESKIRT), item(SAPPHIRE_NECKLACE)),
new EmoteClue("Clap in the main exam room in the Exam Centre. Equip a white apron, green gnome boots and leather gloves.", INSIDE_THE_DIGSITE_EXAM_CENTRE, new WorldPoint(3361, 3339, 0), CLAP, item(WHITE_APRON), item(GREEN_BOOTS), item(LEATHER_GLOVES)), new EmoteClue("Clap in the main exam room in the Exam Centre. Equip a white apron, green gnome boots and leather gloves.", OUTSIDE_THE_DIGSITE_EXAM_CENTRE, new WorldPoint(3361, 3339, 0), CLAP, item(WHITE_APRON), item(GREEN_BOOTS), item(LEATHER_GLOVES)),
new EmoteClue("Clap on the causeway to the Wizards' Tower. Equip an iron medium helmet, emerald ring and a white apron.", ON_THE_BRIDGE_TO_THE_MISTHALIN_WIZARDS_TOWER, new WorldPoint(3113, 3196, 0), CLAP, item(IRON_MED_HELM), item(EMERALD_RING), item(WHITE_APRON)), new EmoteClue("Clap on the causeway to the Wizards' Tower. Equip an iron medium helmet, emerald ring and a white apron.", ON_THE_BRIDGE_TO_THE_MISTHALIN_WIZARDS_TOWER, new WorldPoint(3113, 3196, 0), CLAP, item(IRON_MED_HELM), item(EMERALD_RING), item(WHITE_APRON)),
new EmoteClue("Clap on the top level of the mill, north of East Ardougne. Equip a blue gnome robe top, HAM robe bottom and an unenchanted tiara.", UPSTAIRS_IN_THE_ARDOUGNE_WINDMILL, new WorldPoint(2635, 3385, 3), CLAP, item(BLUE_ROBE_TOP), item(HAM_ROBE), item(TIARA)), new EmoteClue("Clap on the top level of the mill, north of East Ardougne. Equip a blue gnome robe top, HAM robe bottom and an unenchanted tiara.", UPSTAIRS_IN_THE_ARDOUGNE_WINDMILL, new WorldPoint(2635, 3385, 3), CLAP, item(BLUE_ROBE_TOP), item(HAM_ROBE), item(TIARA)),
new EmoteClue("Clap in Seers court house. Spin before you talk to me. Equip an adamant halberd, blue mystic robe bottom and a diamond ring.", OUTSIDE_THE_SEERS_VILLAGE_COURTHOUSE, new WorldPoint(2735, 3469, 0), CLAP, SPIN, item(ADAMANT_HALBERD), item(MYSTIC_ROBE_BOTTOM), item(DIAMOND_RING)), new EmoteClue("Clap in Seers court house. Spin before you talk to me. Equip an adamant halberd, blue mystic robe bottom and a diamond ring.", OUTSIDE_THE_SEERS_VILLAGE_COURTHOUSE, new WorldPoint(2735, 3469, 0), CLAP, SPIN, item(ADAMANT_HALBERD), item(MYSTIC_ROBE_BOTTOM), item(DIAMOND_RING)),
@@ -118,7 +118,7 @@ public class EmoteClue extends ClueScroll implements TextClueScroll, LocationClu
new EmoteClue("Dance at the entrance to the Grand Exchange. Equip a pink skirt, pink robe top and a body tiara.", SOUTH_OF_THE_GRAND_EXCHANGE, new WorldPoint(3165, 3467, 0), DANCE, item(PINK_SKIRT), item(PINK_ROBE_TOP), item(BODY_TIARA)), new EmoteClue("Dance at the entrance to the Grand Exchange. Equip a pink skirt, pink robe top and a body tiara.", SOUTH_OF_THE_GRAND_EXCHANGE, new WorldPoint(3165, 3467, 0), DANCE, item(PINK_SKIRT), item(PINK_ROBE_TOP), item(BODY_TIARA)),
new EmoteClue("Goblin Salute in the Goblin Village. Beware of double agents! Equip a bandos godsword, a bandos cloak and a bandos platebody.", OUTSIDE_MUDKNUCKLES_HUT, new WorldPoint(2956, 3505, 0), GOBLIN_SALUTE, item(BANDOS_PLATEBODY), item(BANDOS_CLOAK), item(BANDOS_GODSWORD)), new EmoteClue("Goblin Salute in the Goblin Village. Beware of double agents! Equip a bandos godsword, a bandos cloak and a bandos platebody.", OUTSIDE_MUDKNUCKLES_HUT, new WorldPoint(2956, 3505, 0), GOBLIN_SALUTE, item(BANDOS_PLATEBODY), item(BANDOS_CLOAK), item(BANDOS_GODSWORD)),
new EmoteClue("Headbang in the mine north of Al Kharid. Equip a desert shirt, leather gloves and leather boots.", AL_KHARID_SCORPION_MINE, new WorldPoint(3299, 3289, 0), HEADBANG, item(DESERT_SHIRT), item(LEATHER_GLOVES), item(LEATHER_BOOTS)), new EmoteClue("Headbang in the mine north of Al Kharid. Equip a desert shirt, leather gloves and leather boots.", AL_KHARID_SCORPION_MINE, new WorldPoint(3299, 3289, 0), HEADBANG, item(DESERT_SHIRT), item(LEATHER_GLOVES), item(LEATHER_BOOTS)),
new EmoteClue("Headbang at the exam center. Beware of double agents! Equip a mystic fire staff, a diamond bracelet and rune boots.", OUTSIDE_THE_DIGSITE_EXAM_CENTRE, new WorldPoint(3362, 3340, 0), HEADBANG, item(MYSTIC_FIRE_STAFF), item(DIAMOND_BRACELET), item(RUNE_BOOTS)), new EmoteClue("Headbang at the exam center. Beware of double agents! Equip a mystic fire staff, a diamond bracelet and rune boots.", INSIDE_THE_DIGSITE_EXAM_CENTRE, new WorldPoint(3362, 3340, 0), HEADBANG, item(MYSTIC_FIRE_STAFF), item(DIAMOND_BRACELET), item(RUNE_BOOTS)),
new EmoteClue("Headbang at the top of Slayer Tower. Equip a seercull, a combat bracelet and helm of Neitiznot.", OUTSIDE_THE_SLAYER_TOWER_GARGOYLE_ROOM, new WorldPoint(3421, 3537, 2), HEADBANG, item(SEERCULL), range("Combat bracelet", COMBAT_BRACELET4, COMBAT_BRACELET), item(HELM_OF_NEITIZNOT)), new EmoteClue("Headbang at the top of Slayer Tower. Equip a seercull, a combat bracelet and helm of Neitiznot.", OUTSIDE_THE_SLAYER_TOWER_GARGOYLE_ROOM, new WorldPoint(3421, 3537, 2), HEADBANG, item(SEERCULL), range("Combat bracelet", COMBAT_BRACELET4, COMBAT_BRACELET), item(HELM_OF_NEITIZNOT)),
new EmoteClue("Dance a jig by the entrance to the Fishing Guild. Equip an emerald ring, a sapphire amulet, and a bronze chain body.", OUTSIDE_THE_FISHING_GUILD, new WorldPoint(2610, 3391, 0), JIG, item(EMERALD_RING), item(SAPPHIRE_AMULET), item(BRONZE_CHAINBODY)), new EmoteClue("Dance a jig by the entrance to the Fishing Guild. Equip an emerald ring, a sapphire amulet, and a bronze chain body.", OUTSIDE_THE_FISHING_GUILD, new WorldPoint(2610, 3391, 0), JIG, item(EMERALD_RING), item(SAPPHIRE_AMULET), item(BRONZE_CHAINBODY)),
new EmoteClue("Dance a jig under Shantay's Awning. Bow before you talk to me. Equip a pointed blue snail helmet, an air staff and a bronze square shield.", SHANTAY_PASS, new WorldPoint(3304, 3124, 0), JIG, BOW, any("Bruise blue snelm (pointed)", item(BRUISE_BLUE_SNELM_3343)), item(STAFF_OF_AIR), item(BRONZE_SQ_SHIELD)), new EmoteClue("Dance a jig under Shantay's Awning. Bow before you talk to me. Equip a pointed blue snail helmet, an air staff and a bronze square shield.", SHANTAY_PASS, new WorldPoint(3304, 3124, 0), JIG, BOW, any("Bruise blue snelm (pointed)", item(BRUISE_BLUE_SNELM_3343)), item(STAFF_OF_AIR), item(BRONZE_SQ_SHIELD)),

View File

@@ -51,127 +51,127 @@ import static net.runelite.client.plugins.cluescrolls.clues.hotcold.HotColdArea.
@Getter @Getter
public enum HotColdLocation public enum HotColdLocation
{ {
ASGARNIA_WARRIORS(new WorldPoint(2860, 3562, 0), ASGARNIA, "North of the Warriors' Guild in Burthorpe."), ASGARNIA_WARRIORS(new WorldPoint(2860, 3562, 0), ASGARNIA, "North of the Warriors' Guild in Burthorpe."),
ASGARNIA_JATIX(new WorldPoint(2914, 3429, 0), ASGARNIA, "East of Jatix's Herblore Shop in Taverley."), ASGARNIA_JATIX(new WorldPoint(2914, 3429, 0), ASGARNIA, "East of Jatix's Herblore Shop in Taverley."),
ASGARNIA_BARB(new WorldPoint(3036, 3439, 0), ASGARNIA, "West of Barbarian Village."), ASGARNIA_BARB(new WorldPoint(3036, 3439, 0), ASGARNIA, "West of Barbarian Village."),
ASGARNIA_MIAZRQA(new WorldPoint(2973, 3489, 0), ASGARNIA, "North of Miazrqa's tower, outside Goblin Village."), ASGARNIA_MIAZRQA(new WorldPoint(2973, 3489, 0), ASGARNIA, "North of Miazrqa's tower, outside Goblin Village."),
ASGARNIA_COW(new WorldPoint(3033, 3308, 0), ASGARNIA, "In the cow pen north of Sarah's Farming Shop."), ASGARNIA_COW(new WorldPoint(3033, 3308, 0), ASGARNIA, "In the cow pen north of Sarah's Farming Shop."),
ASGARNIA_PARTY_ROOM(new WorldPoint(3026, 3363, 0), ASGARNIA, "Outside the Falador Party Room."), ASGARNIA_PARTY_ROOM(new WorldPoint(3026, 3363, 0), ASGARNIA, "Outside the Falador Party Room."),
ASGARNIA_CRAFT_GUILD(new WorldPoint(2917, 3295, 0), ASGARNIA, "Outside the Crafting Guild cow pen."), ASGARNIA_CRAFT_GUILD(new WorldPoint(2917, 3295, 0), ASGARNIA, "Outside the Crafting Guild cow pen."),
ASGARNIA_RIMMINGTON(new WorldPoint(2978, 3241, 0), ASGARNIA, "In the centre of the Rimmington mine."), ASGARNIA_RIMMINGTON(new WorldPoint(2978, 3241, 0), ASGARNIA, "In the centre of the Rimmington mine."),
ASGARNIA_MUDSKIPPER(new WorldPoint(2984, 3109, 0), ASGARNIA, "Mudskipper Point, on the starfish in the south-west corner."), ASGARNIA_MUDSKIPPER(new WorldPoint(2984, 3109, 0), ASGARNIA, "Mudskipper Point, on the starfish in the south-west corner."),
ASGARNIA_TROLL(new WorldPoint(2910, 3616, 0), ASGARNIA, "The Troll arena, where the player fights Dad during the Troll Stronghold quest. Bring climbing boots if travelling from Burthorpe."), ASGARNIA_TROLL(new WorldPoint(2910, 3616, 0), ASGARNIA, "The Troll arena, where the player fights Dad during the Troll Stronghold quest. Bring climbing boots if travelling from Burthorpe."),
DESERT_GENIE(new WorldPoint(3364, 2910, 0), DESERT, "West of Nardah genie cave."), DESERT_GENIE(new WorldPoint(3364, 2910, 0), DESERT, "West of Nardah genie cave."),
DESERT_ALKHARID_MINE(new WorldPoint(3282, 3270, 0), DESERT, "West of Al Kharid mine."), DESERT_ALKHARID_MINE(new WorldPoint(3282, 3270, 0), DESERT, "West of Al Kharid mine."),
DESERT_MENAPHOS_GATE(new WorldPoint(3224, 2816, 0), DESERT, "North of Menaphos gate."), DESERT_MENAPHOS_GATE(new WorldPoint(3224, 2816, 0), DESERT, "North of Menaphos gate."),
DESERT_BEDABIN_CAMP(new WorldPoint(3164, 3050, 0), DESERT, "Bedabin Camp, dig around the north tent."), DESERT_BEDABIN_CAMP(new WorldPoint(3164, 3050, 0), DESERT, "Bedabin Camp, dig around the north tent."),
DESERT_UZER(new WorldPoint(3431, 3106, 0), DESERT, "West of Uzer."), DESERT_UZER(new WorldPoint(3431, 3106, 0), DESERT, "West of Uzer."),
DESERT_POLLNIVNEACH(new WorldPoint(3287, 2975, 0), DESERT, "West of Pollnivneach."), DESERT_POLLNIVNEACH(new WorldPoint(3287, 2975, 0), DESERT, "West of Pollnivneach."),
DESERT_MTA(new WorldPoint(3350, 3293, 0), DESERT, "Next to Mage Training Arena."), DESERT_MTA(new WorldPoint(3350, 3293, 0), DESERT, "Next to Mage Training Arena."),
DESERT_SHANTY(new WorldPoint(3294, 3106, 0), DESERT, "South-west of Shantay Pass."), DESERT_SHANTY(new WorldPoint(3294, 3106, 0), DESERT, "South-west of Shantay Pass."),
FELDIP_HILLS_JIGGIG(new WorldPoint(2413, 3055, 0), FELDIP_HILLS, "West of Jiggig, east of the fairy ring bkp."), FELDIP_HILLS_JIGGIG(new WorldPoint(2413, 3055, 0), FELDIP_HILLS, "West of Jiggig, east of the fairy ring bkp."),
FELDIP_HILLS_SW(new WorldPoint(2582, 2895, 0), FELDIP_HILLS, "West of the southeasternmost lake in Feldip Hills."), FELDIP_HILLS_SW(new WorldPoint(2582, 2895, 0), FELDIP_HILLS, "West of the southeasternmost lake in Feldip Hills."),
FELDIP_HILLS_GNOME_GLITER(new WorldPoint(2553, 2972, 0), FELDIP_HILLS, "East of the gnome glider (Lemantolly Undri)."), FELDIP_HILLS_GNOME_GLITER(new WorldPoint(2553, 2972, 0), FELDIP_HILLS, "East of the gnome glider (Lemantolly Undri)."),
FELDIP_HILLS_RANTZ(new WorldPoint(2611, 2946, 0), FELDIP_HILLS, "South of Rantz, six steps west of the empty glass bottles."), FELDIP_HILLS_RANTZ(new WorldPoint(2611, 2946, 0), FELDIP_HILLS, "South of Rantz, six steps west of the empty glass bottles."),
FELDIP_HILLS_SOUTH(new WorldPoint(2487, 3005, 0), FELDIP_HILLS, "South of Jiggig."), FELDIP_HILLS_SOUTH(new WorldPoint(2487, 3005, 0), FELDIP_HILLS, "South of Jiggig."),
FELDIP_HILLS_RED_CHIN(new WorldPoint(2532, 2900, 0), FELDIP_HILLS, "Outside the red chinchompa hunting ground entrance, south of the Hunting expert's hut."), FELDIP_HILLS_RED_CHIN(new WorldPoint(2532, 2900, 0), FELDIP_HILLS, "Outside the red chinchompa hunting ground entrance, south of the Hunting expert's hut."),
FELDIP_HILLS_SE(new WorldPoint(2567, 2916, 0), FELDIP_HILLS, "South-east of the ∩-shaped lake, near the icon."), FELDIP_HILLS_SE(new WorldPoint(2567, 2916, 0), FELDIP_HILLS, "South-east of the ∩-shaped lake, near the icon."),
FELDIP_HILLS_CW_BALLOON(new WorldPoint(2452, 3108, 0), FELDIP_HILLS, "Directly west of the Castle Wars balloon."), FELDIP_HILLS_CW_BALLOON(new WorldPoint(2452, 3108, 0), FELDIP_HILLS, "Directly west of the Castle Wars balloon."),
FREMENNIK_PROVINCE_MTN_CAMP(new WorldPoint(2804, 3672, 0), FREMENNIK_PROVINCE, "At the Mountain Camp."), FREMENNIK_PROVINCE_MTN_CAMP(new WorldPoint(2804, 3672, 0), FREMENNIK_PROVINCE, "At the Mountain Camp."),
FREMENNIK_PROVINCE_RELLEKKA_HUNTER(new WorldPoint(2724, 3783, 0), FREMENNIK_PROVINCE, "At the Rellekka Hunter area, near the icon."), FREMENNIK_PROVINCE_RELLEKKA_HUNTER(new WorldPoint(2724, 3783, 0), FREMENNIK_PROVINCE, "At the Rellekka Hunter area, near the icon."),
FREMENNIK_PROVINCE_KELGADRIM_ENTRANCE(new WorldPoint(2715, 3689, 0), FREMENNIK_PROVINCE, "West of the Keldagrim entrance mine."), FREMENNIK_PROVINCE_KELGADRIM_ENTRANCE(new WorldPoint(2715, 3689, 0), FREMENNIK_PROVINCE, "West of the Keldagrim entrance mine."),
FREMENNIK_PROVINCE_SW(new WorldPoint(2605, 3648, 0), FREMENNIK_PROVINCE, "Outside the fence in the south-western corner of Rellekka."), FREMENNIK_PROVINCE_SW(new WorldPoint(2605, 3648, 0), FREMENNIK_PROVINCE, "Outside the fence in the south-western corner of Rellekka."),
FREMENNIK_PROVINCE_LIGHTHOUSE(new WorldPoint(2589, 3598, 0), FREMENNIK_PROVINCE, "South-east of the Lighthouse."), FREMENNIK_PROVINCE_LIGHTHOUSE(new WorldPoint(2589, 3598, 0), FREMENNIK_PROVINCE, "South-east of the Lighthouse."),
FREMENNIK_PROVINCE_ETCETERIA_CASTLE(new WorldPoint(2614, 3867, 0), FREMENNIK_PROVINCE, "Inside Etceteria's castle, in the southern staircase."), FREMENNIK_PROVINCE_ETCETERIA_CASTLE(new WorldPoint(2614, 3867, 0), FREMENNIK_PROVINCE, "Inside Etceteria's castle, in the southern staircase."),
FREMENNIK_PROVINCE_MISC_COURTYARD(new WorldPoint(2529, 3867, 0), FREMENNIK_PROVINCE, "Outside Miscellania's courtyard."), FREMENNIK_PROVINCE_MISC_COURTYARD(new WorldPoint(2529, 3867, 0), FREMENNIK_PROVINCE, "Outside Miscellania's courtyard."),
FREMENNIK_PROVINCE_FREMMY_ISLES_MINE(new WorldPoint(2378, 3849, 0), FREMENNIK_PROVINCE, "Central Fremennik Isles mine."), FREMENNIK_PROVINCE_FREMMY_ISLES_MINE(new WorldPoint(2378, 3849, 0), FREMENNIK_PROVINCE, "Central Fremennik Isles mine."),
FREMENNIK_PROVINCE_WEST_ISLES_MINE(new WorldPoint(2313, 3854, 0), FREMENNIK_PROVINCE, "West Fremennik Isles mine."), FREMENNIK_PROVINCE_WEST_ISLES_MINE(new WorldPoint(2313, 3854, 0), FREMENNIK_PROVINCE, "West Fremennik Isles mine."),
FREMENNIK_PROVINCE_WEST_JATIZSO_ENTRANCE(new WorldPoint(2391, 3813, 0), FREMENNIK_PROVINCE, "West of the Jatizso mine entrance."), FREMENNIK_PROVINCE_WEST_JATIZSO_ENTRANCE(new WorldPoint(2391, 3813, 0), FREMENNIK_PROVINCE, "West of the Jatizso mine entrance."),
FREMENNIK_PROVINCE_PIRATES_COVE(new WorldPoint(2210, 3814, 0), FREMENNIK_PROVINCE, "Pirates' Cove"), FREMENNIK_PROVINCE_PIRATES_COVE(new WorldPoint(2210, 3814, 0), FREMENNIK_PROVINCE, "Pirates' Cove"),
FREMENNIK_PROVINCE_ASTRAL_ALTER(new WorldPoint(2147, 3862, 0), FREMENNIK_PROVINCE, "Astral altar"), FREMENNIK_PROVINCE_ASTRAL_ALTER(new WorldPoint(2147, 3862, 0), FREMENNIK_PROVINCE, "Astral altar"),
FREMENNIK_PROVINCE_LUNAR_VILLAGE(new WorldPoint(2087, 3915, 0), FREMENNIK_PROVINCE, "Lunar Isle, inside the village."), FREMENNIK_PROVINCE_LUNAR_VILLAGE(new WorldPoint(2087, 3915, 0), FREMENNIK_PROVINCE, "Lunar Isle, inside the village."),
FREMENNIK_PROVINCE_LUNAR_NORTH(new WorldPoint(2106, 3949, 0), FREMENNIK_PROVINCE, "Lunar Isle, north of the village."), FREMENNIK_PROVINCE_LUNAR_NORTH(new WorldPoint(2106, 3949, 0), FREMENNIK_PROVINCE, "Lunar Isle, north of the village."),
KANDARIN_SINCLAR_MANSION(new WorldPoint(2726, 3588, 0), KANDARIN, "North-west of the Sinclair Mansion, near the log balance shortcut."), KANDARIN_SINCLAR_MANSION(new WorldPoint(2726, 3588, 0), KANDARIN, "North-west of the Sinclair Mansion, near the log balance shortcut."),
KANDARIN_CATHERBY(new WorldPoint(2774, 3433, 0), KANDARIN, "Catherby, between the bank and the beehives, near small rock formation."), KANDARIN_CATHERBY(new WorldPoint(2774, 3433, 0), KANDARIN, "Catherby, between the bank and the beehives, near small rock formation."),
KANDARIN_GRAND_TREE(new WorldPoint(2444, 3503, 0), KANDARIN, "Grand Tree, just east of the terrorchick gnome enclosure."), KANDARIN_GRAND_TREE(new WorldPoint(2444, 3503, 0), KANDARIN, "Grand Tree, just east of the terrorchick gnome enclosure."),
KANDARIN_SEERS(new WorldPoint(2735, 3486, 0), KANDARIN, "Between the Seers' Village bank and Camelot."), KANDARIN_SEERS(new WorldPoint(2735, 3486, 0), KANDARIN, "Between the Seers' Village bank and Camelot."),
KANDARIN_MCGRUBORS_WOOD(new WorldPoint(2653, 3485, 0), KANDARIN, "McGrubor's Wood"), KANDARIN_MCGRUBORS_WOOD(new WorldPoint(2653, 3485, 0), KANDARIN, "McGrubor's Wood"),
KANDARIN_FISHING_BUILD(new WorldPoint(2586, 3372, 0), KANDARIN, "South of Fishing Guild"), KANDARIN_FISHING_BUILD(new WorldPoint(2586, 3372, 0), KANDARIN, "South of Fishing Guild"),
KANDARIN_WITCHHAVEN(new WorldPoint(2708, 3304, 0), KANDARIN, "Outside Witchaven, west of Jeb, Holgart, and Caroline."), KANDARIN_WITCHHAVEN(new WorldPoint(2708, 3304, 0), KANDARIN, "Outside Witchaven, west of Jeb, Holgart, and Caroline."),
KANDARIN_NECRO_TOWER(new WorldPoint(2669, 3242, 0), KANDARIN, "Ground floor inside the Necromancer Tower. Easily accessed by using fairy ring code djp."), KANDARIN_NECRO_TOWER(new WorldPoint(2669, 3242, 0), KANDARIN, "Ground floor inside the Necromancer Tower. Easily accessed by using fairy ring code djp."),
KANDARIN_FIGHT_ARENA(new WorldPoint(2587, 3134, 0), KANDARIN, "South of the Fight Arena, north-west of the Nightmare Zone."), KANDARIN_FIGHT_ARENA(new WorldPoint(2587, 3134, 0), KANDARIN, "South of the Fight Arena, north-west of the Nightmare Zone."),
KANDARIN_TREE_GNOME_VILLAGE(new WorldPoint(2526, 3160, 0), KANDARIN, "Tree Gnome Village, near the general store icon."), KANDARIN_TREE_GNOME_VILLAGE(new WorldPoint(2526, 3160, 0), KANDARIN, "Tree Gnome Village, near the general store icon."),
KANDARIN_GRAVE_OF_SCORPIUS(new WorldPoint(2464, 3228, 0), KANDARIN, "Grave of Scorpius"), KANDARIN_GRAVE_OF_SCORPIUS(new WorldPoint(2464, 3228, 0), KANDARIN, "Grave of Scorpius"),
KANDARIN_KHAZARD_BATTLEFIELD(new WorldPoint(2518, 3249, 0), KANDARIN, "Khazard Battlefield, in the small ruins south of tracker gnome 2."), KANDARIN_KHAZARD_BATTLEFIELD(new WorldPoint(2518, 3249, 0), KANDARIN, "Khazard Battlefield, in the small ruins south of tracker gnome 2."),
KANDARIN_WEST_ARDY(new WorldPoint(2533, 3320, 0), KANDARIN, "West Ardougne, near the staircase outside the Civic Office."), KANDARIN_WEST_ARDY(new WorldPoint(2533, 3320, 0), KANDARIN, "West Ardougne, near the staircase outside the Civic Office."),
KANDARIN_SW_TREE_GNOME_STRONGHOLD(new WorldPoint(2411, 3431, 0), KANDARIN, "South-west Tree Gnome Stronghold"), KANDARIN_SW_TREE_GNOME_STRONGHOLD(new WorldPoint(2411, 3431, 0), KANDARIN, "South-west Tree Gnome Stronghold"),
KANDARIN_OUTPOST(new WorldPoint(2458, 3364, 0), KANDARIN, "South of the Tree Gnome Stronghold, north-east of the Outpost."), KANDARIN_OUTPOST(new WorldPoint(2458, 3364, 0), KANDARIN, "South of the Tree Gnome Stronghold, north-east of the Outpost."),
KANDARIN_BAXTORIAN_FALLS(new WorldPoint(2534, 3479, 0), KANDARIN, "South-east of Almera's house on Baxtorian Falls."), KANDARIN_BAXTORIAN_FALLS(new WorldPoint(2534, 3479, 0), KANDARIN, "South-east of Almera's house on Baxtorian Falls."),
KANDARIN_BA_AGILITY_COURSE(new WorldPoint(2536, 3546, 0), KANDARIN, "Inside the Barbarian Agility Course. Completion of Alfred Grimhand's Barcrawl is required."), KANDARIN_BA_AGILITY_COURSE(new WorldPoint(2536, 3546, 0), KANDARIN, "Inside the Barbarian Agility Course. Completion of Alfred Grimhand's Barcrawl is required."),
KARAMJA_MUSA_POINT(new WorldPoint(2914, 3168, 0), KARAMJA, "Musa Point, banana plantation."), KARAMJA_MUSA_POINT(new WorldPoint(2914, 3168, 0), KARAMJA, "Musa Point, banana plantation."),
KARAMJA_BRIMHAVEN_FRUIT_TREE(new WorldPoint(2783, 3214, 0), KARAMJA, "Brimhaven, east of the fruit tree patch."), KARAMJA_BRIMHAVEN_FRUIT_TREE(new WorldPoint(2783, 3214, 0), KARAMJA, "Brimhaven, east of the fruit tree patch."),
KARAMJA_WEST_BRIMHAVEN(new WorldPoint(2721, 3169, 0), KARAMJA, "West of Brimhaven."), KARAMJA_WEST_BRIMHAVEN(new WorldPoint(2721, 3169, 0), KARAMJA, "West of Brimhaven."),
KARAMJA_GLIDER(new WorldPoint(2966, 2975, 0), KARAMJA, "West of the gnome glider."), KARAMJA_GLIDER(new WorldPoint(2966, 2975, 0), KARAMJA, "West of the gnome glider."),
KARAMJA_KHARAZI_NE(new WorldPoint(2908, 2922, 0), KARAMJA, "North-eastern part of Kharazi Jungle."), KARAMJA_KHARAZI_NE(new WorldPoint(2908, 2922, 0), KARAMJA, "North-eastern part of Kharazi Jungle."),
KARAMJA_KHARAZI_SW(new WorldPoint(2783, 2898, 0), KARAMJA, "South-western part of Kharazi Jungle."), KARAMJA_KHARAZI_SW(new WorldPoint(2783, 2898, 0), KARAMJA, "South-western part of Kharazi Jungle."),
KARAMJA_CRASH_ISLAND(new WorldPoint(2910, 2737, 0), KARAMJA, "Northern part of Crash Island."), KARAMJA_CRASH_ISLAND(new WorldPoint(2910, 2737, 0), KARAMJA, "Northern part of Crash Island."),
MISTHALIN_VARROCK_STONE_CIRCLE(new WorldPoint(3225, 3355, 0), MISTHALIN, "South of the stone circle near Varrock's entrance."), MISTHALIN_VARROCK_STONE_CIRCLE(new WorldPoint(3225, 3355, 0), MISTHALIN, "South of the stone circle near Varrock's entrance."),
MISTHALIN_LUMBRIDGE(new WorldPoint(3238, 3169, 0), MISTHALIN, "Just north-west of the Lumbridge Fishing tutor."), MISTHALIN_LUMBRIDGE(new WorldPoint(3238, 3169, 0), MISTHALIN, "Just north-west of the Lumbridge Fishing tutor."),
MISTHALIN_LUMBRIDGE_2(new WorldPoint(3170, 3278, 0), MISTHALIN, "North of the pond between Lumbridge and Draynor Village."), MISTHALIN_LUMBRIDGE_2(new WorldPoint(3170, 3278, 0), MISTHALIN, "North of the pond between Lumbridge and Draynor Village."),
MISTHALIN_GERTUDES(new WorldPoint(3158, 3421, 0), MISTHALIN, "North-east of Gertrude's house west of Varrock."), MISTHALIN_GERTUDES(new WorldPoint(3158, 3421, 0), MISTHALIN, "North-east of Gertrude's house west of Varrock."),
MISTHALIN_DRAYNOR_BANK(new WorldPoint(3096, 3235, 0), MISTHALIN, "South of Draynor Village bank."), MISTHALIN_DRAYNOR_BANK(new WorldPoint(3096, 3235, 0), MISTHALIN, "South of Draynor Village bank."),
MISTHALIN_LUMBER_YARD(new WorldPoint(3303, 3483, 0), MISTHALIN, "South of Lumber Yard, east of Assistant Serf."), MISTHALIN_LUMBER_YARD(new WorldPoint(3303, 3483, 0), MISTHALIN, "South of Lumber Yard, east of Assistant Serf."),
MORYTANIA_BURGH_DE_ROTT(new WorldPoint(3545, 3253, 0), MORYTANIA, "In the north-east area of Burgh de Rott, by the reverse-L-shaped ruins."), MORYTANIA_BURGH_DE_ROTT(new WorldPoint(3545, 3253, 0), MORYTANIA, "In the north-east area of Burgh de Rott, by the reverse-L-shaped ruins."),
MORYTANIA_PORT_PHASMATYS(new WorldPoint(3613, 3485, 0), MORYTANIA, "West of Port Phasmatys, south-east of fairy ring."), MORYTANIA_PORT_PHASMATYS(new WorldPoint(3613, 3485, 0), MORYTANIA, "West of Port Phasmatys, south-east of fairy ring."),
MORYTANIA_HOLLOWS(new WorldPoint(3500, 3423, 0), MORYTANIA, "Inside The Hollows, south of the bridge which was repaired in a quest."), MORYTANIA_HOLLOWS(new WorldPoint(3500, 3423, 0), MORYTANIA, "Inside The Hollows, south of the bridge which was repaired in a quest."),
MORYTANIA_SWAMP(new WorldPoint(3422, 3374, 0), MORYTANIA, "Inside the Mort Myre Swamp, north-west of the Nature Grotto."), MORYTANIA_SWAMP(new WorldPoint(3422, 3374, 0), MORYTANIA, "Inside the Mort Myre Swamp, north-west of the Nature Grotto."),
MORYTANIA_HAUNTED_MINE(new WorldPoint(3441, 3259, 0), MORYTANIA, "At Haunted Mine quest start."), MORYTANIA_HAUNTED_MINE(new WorldPoint(3441, 3259, 0), MORYTANIA, "At Haunted Mine quest start."),
MORYTANIA_MAUSOLEUM(new WorldPoint(3499, 3539, 0), MORYTANIA, "South of the Mausoleum."), MORYTANIA_MAUSOLEUM(new WorldPoint(3499, 3539, 0), MORYTANIA, "South of the Mausoleum."),
MORYTANIA_MOS_LES_HARMLESS(new WorldPoint(3744, 3041, 0), MORYTANIA, "Northern area of Mos Le'Harmless, between the lakes."), MORYTANIA_MOS_LES_HARMLESS(new WorldPoint(3744, 3041, 0), MORYTANIA, "Northern area of Mos Le'Harmless, between the lakes."),
MORYTANIA_MOS_LES_HARMLESS_BAR(new WorldPoint(3670, 2974, 0), MORYTANIA, "Near Mos Le'Harmless southern bar."), MORYTANIA_MOS_LES_HARMLESS_BAR(new WorldPoint(3670, 2974, 0), MORYTANIA, "Near Mos Le'Harmless southern bar."),
MORYTANIA_DRAGONTOOTH_NORTH(new WorldPoint(3813, 3567, 0), MORYTANIA, "Northern part of Dragontooth Island."), MORYTANIA_DRAGONTOOTH_NORTH(new WorldPoint(3813, 3567, 0), MORYTANIA, "Northern part of Dragontooth Island."),
MORYTANIA_DRAGONTOOTH_SOUTH(new WorldPoint(3803, 3532, 0), MORYTANIA, "Southern part of Dragontooth Island."), MORYTANIA_DRAGONTOOTH_SOUTH(new WorldPoint(3803, 3532, 0), MORYTANIA, "Southern part of Dragontooth Island."),
WESTERN_PROVINCE_EAGLES_PEAK(new WorldPoint(2297, 3530, 0), WESTERN_PROVINCE, "North-west of Eagles' Peak."), WESTERN_PROVINCE_EAGLES_PEAK(new WorldPoint(2297, 3530, 0), WESTERN_PROVINCE, "North-west of Eagles' Peak."),
WESTERN_PROVINCE_PISCATORIS(new WorldPoint(2337, 3689, 0), WESTERN_PROVINCE, "Piscatoris Fishing Colony"), WESTERN_PROVINCE_PISCATORIS(new WorldPoint(2337, 3689, 0), WESTERN_PROVINCE, "Piscatoris Fishing Colony"),
WESTERN_PROVINCE_PISCATORIS_HUNTER_AREA(new WorldPoint(2361, 3566, 0), WESTERN_PROVINCE, "Eastern part of Piscatoris Hunter area, south-west of the Falconry."), WESTERN_PROVINCE_PISCATORIS_HUNTER_AREA(new WorldPoint(2361, 3566, 0), WESTERN_PROVINCE, "Eastern part of Piscatoris Hunter area, south-west of the Falconry."),
WESTERN_PROVINCE_ARANDAR(new WorldPoint(2366, 3318, 0), WESTERN_PROVINCE, "South-west of the crystal gate to Arandar."), WESTERN_PROVINCE_ARANDAR(new WorldPoint(2366, 3318, 0), WESTERN_PROVINCE, "South-west of the crystal gate to Arandar."),
WESTERN_PROVINCE_ELF_CAMP_EAST(new WorldPoint(2270, 3244, 0), WESTERN_PROVINCE, "East of Elf Camp."), WESTERN_PROVINCE_ELF_CAMP_EAST(new WorldPoint(2270, 3244, 0), WESTERN_PROVINCE, "East of Elf Camp."),
WESTERN_PROVINCE_ELF_CAMP_NW(new WorldPoint(2174, 3280, 0), WESTERN_PROVINCE, "North-west of Elf Camp."), WESTERN_PROVINCE_ELF_CAMP_NW(new WorldPoint(2174, 3280, 0), WESTERN_PROVINCE, "North-west of Elf Camp."),
WESTERN_PROVINCE_LLETYA(new WorldPoint(2335, 3166, 0), WESTERN_PROVINCE, "In Lletya."), WESTERN_PROVINCE_LLETYA(new WorldPoint(2335, 3166, 0), WESTERN_PROVINCE, "In Lletya."),
WESTERN_PROVINCE_TYRAS(new WorldPoint(2204, 3157, 0), WESTERN_PROVINCE, "Near Tyras Camp."), WESTERN_PROVINCE_TYRAS(new WorldPoint(2204, 3157, 0), WESTERN_PROVINCE, "Near Tyras Camp."),
WESTERN_PROVINCE_ZULANDRA(new WorldPoint(2196, 3057, 0), WESTERN_PROVINCE, "The northern house at Zul-Andra."), WESTERN_PROVINCE_ZULANDRA(new WorldPoint(2196, 3057, 0), WESTERN_PROVINCE, "The northern house at Zul-Andra."),
WILDERNESS_5(new WorldPoint(3169, 3558, 0), WILDERNESS, "North of the Grand Exchange, level 5 Wilderness."), WILDERNESS_5(new WorldPoint(3169, 3558, 0), WILDERNESS, "North of the Grand Exchange, level 5 Wilderness."),
WILDERNESS_12(new WorldPoint(3038, 3612, 0), WILDERNESS, "South-east of the Dark Warriors' Fortress, level 12 Wilderness."), WILDERNESS_12(new WorldPoint(3038, 3612, 0), WILDERNESS, "South-east of the Dark Warriors' Fortress, level 12 Wilderness."),
WILDERNESS_20(new WorldPoint(3225, 3676, 0), WILDERNESS, "East of the Corporeal Beast's lair, level 20 Wilderness."), WILDERNESS_20(new WorldPoint(3225, 3676, 0), WILDERNESS, "East of the Corporeal Beast's lair, level 20 Wilderness."),
WILDERNESS_27(new WorldPoint(3174, 3735, 0), WILDERNESS, "Inside the Ruins north of the Graveyard of Shadows, level 27 Wilderness."), WILDERNESS_27(new WorldPoint(3174, 3735, 0), WILDERNESS, "Inside the Ruins north of the Graveyard of Shadows, level 27 Wilderness."),
WILDERNESS_28(new WorldPoint(3374, 3734, 0), WILDERNESS, "East of Venenatis' nest, level 28 Wilderness."), WILDERNESS_28(new WorldPoint(3374, 3734, 0), WILDERNESS, "East of Venenatis' nest, level 28 Wilderness."),
WILDERNESS_32(new WorldPoint(3311, 3773, 0), WILDERNESS, "North of Venenatis' nest, level 32 Wilderness."), WILDERNESS_32(new WorldPoint(3311, 3773, 0), WILDERNESS, "North of Venenatis' nest, level 32 Wilderness."),
WILDERNESS_35(new WorldPoint(3153, 3795, 0), WILDERNESS, "East of the Wilderness canoe exit, level 35 Wilderness."), WILDERNESS_35(new WorldPoint(3153, 3795, 0), WILDERNESS, "East of the Wilderness canoe exit, level 35 Wilderness."),
WILDERNESS_37(new WorldPoint(2975, 3811, 0), WILDERNESS, "South-east of the Chaos Temple, level 37 Wilderness."), WILDERNESS_37(new WorldPoint(2975, 3811, 0), WILDERNESS, "South-east of the Chaos Temple, level 37 Wilderness."),
WILDERNESS_38(new WorldPoint(3294, 3817, 0), WILDERNESS, "South of Callisto, level 38 Wilderness."), WILDERNESS_38(new WorldPoint(3294, 3817, 0), WILDERNESS, "South of Callisto, level 38 Wilderness."),
WILDERNESS_49(new WorldPoint(3140, 3910, 0), WILDERNESS, "South-west of the Deserted Keep, level 49 Wilderness."), WILDERNESS_49(new WorldPoint(3140, 3910, 0), WILDERNESS, "South-west of the Deserted Keep, level 49 Wilderness."),
WILDERNESS_54(new WorldPoint(2983, 3946, 0), WILDERNESS, "West of the Wilderness Agility Course, level 54 Wilderness."), WILDERNESS_54(new WorldPoint(2983, 3946, 0), WILDERNESS, "West of the Wilderness Agility Course, level 54 Wilderness."),
ZEAH_BLASTMINE_BANK(new WorldPoint(1507, 3856, 0), ZEAH, "Next to the bank in the Lovakengj blast mine."), ZEAH_BLASTMINE_BANK(new WorldPoint(1507, 3856, 0), ZEAH, "Next to the bank in the Lovakengj blast mine."),
ZEAH_BLASTMINE_NORTH(new WorldPoint(1490, 3883, 0), ZEAH, "Northern part of the Lovakengj blast mine."), ZEAH_BLASTMINE_NORTH(new WorldPoint(1490, 3883, 0), ZEAH, "Northern part of the Lovakengj blast mine."),
ZEAH_LOVAKITE_FURNACE(new WorldPoint(1505, 3814, 0), ZEAH, "Next to the lovakite furnace in Lovakengj."), ZEAH_LOVAKITE_FURNACE(new WorldPoint(1505, 3814, 0), ZEAH, "Next to the lovakite furnace in Lovakengj."),
ZEAH_LOVAKENGJ_MINE(new WorldPoint(1477, 3779, 0), ZEAH, "Next to mithril rock in the Lovakengj mine."), ZEAH_LOVAKENGJ_MINE(new WorldPoint(1477, 3779, 0), ZEAH, "Next to mithril rock in the Lovakengj mine."),
ZEAH_SULPHR_MINE(new WorldPoint(1428, 3866, 0), ZEAH, "Western entrance in the Lovakengj sulphur mine."), ZEAH_SULPHR_MINE(new WorldPoint(1428, 3866, 0), ZEAH, "Western entrance in the Lovakengj sulphur mine."),
ZEAH_SHAYZIEN_BANK(new WorldPoint(1517, 3603, 0), ZEAH, "South-east of the bank in Shayzien."), ZEAH_SHAYZIEN_BANK(new WorldPoint(1517, 3603, 0), ZEAH, "South-east of the bank in Shayzien."),
ZEAH_OVERPASS(new WorldPoint(1467, 3714, 0), ZEAH, "Overpass between Lovakengj and Shayzien."), ZEAH_OVERPASS(new WorldPoint(1467, 3714, 0), ZEAH, "Overpass between Lovakengj and Shayzien."),
ZEAH_LIZARDMAN(new WorldPoint(1493, 3694, 0), ZEAH, "Within Lizardman Canyon, east of the ladder. Requires 5% favour with Shayzien."), ZEAH_LIZARDMAN(new WorldPoint(1493, 3694, 0), ZEAH, "Within Lizardman Canyon, east of the ladder. Requires 5% favour with Shayzien."),
ZEAH_COMBAT_RING(new WorldPoint(1557, 3580, 0), ZEAH, "Shayzien, south-east of the Combat Ring."), ZEAH_COMBAT_RING(new WorldPoint(1557, 3580, 0), ZEAH, "Shayzien, south-east of the Combat Ring."),
ZEAH_SHAYZIEN_BANK_2(new WorldPoint(1494, 3622, 0), ZEAH, "North-west of the bank in Shayzien."), ZEAH_SHAYZIEN_BANK_2(new WorldPoint(1494, 3622, 0), ZEAH, "North-west of the bank in Shayzien."),
ZEAH_LIBRARY(new WorldPoint(1601, 3842, 0), ZEAH, "North-west of the Arceuus Library."), ZEAH_LIBRARY(new WorldPoint(1601, 3842, 0), ZEAH, "North-west of the Arceuus Library."),
ZEAH_HOUSECHURCH(new WorldPoint(1682, 3792, 0), ZEAH, "By the entrance to the Arceuus church."), ZEAH_HOUSECHURCH(new WorldPoint(1682, 3792, 0), ZEAH, "By the entrance to the Arceuus church."),
ZEAH_DARK_ALTAR(new WorldPoint(1699, 3879, 0), ZEAH, "West of the Dark Altar."), ZEAH_DARK_ALTAR(new WorldPoint(1699, 3879, 0), ZEAH, "West of the Dark Altar."),
ZEAH_ARCEUUS_HOUSE(new WorldPoint(1708, 3701, 0), ZEAH, "By the southern entrance to Arceuus."), ZEAH_ARCEUUS_HOUSE(new WorldPoint(1708, 3701, 0), ZEAH, "By the southern entrance to Arceuus."),
ZEAH_ESSENCE_MINE(new WorldPoint(1762, 3852, 0), ZEAH, "By the Arceuus essence mine."), ZEAH_ESSENCE_MINE(new WorldPoint(1762, 3852, 0), ZEAH, "By the Arceuus essence mine."),
ZEAH_ESSENCE_MINE_NE(new WorldPoint(1772, 3866, 0), ZEAH, "North-east of the Arceuus essence mine."), ZEAH_ESSENCE_MINE_NE(new WorldPoint(1772, 3866, 0), ZEAH, "North-east of the Arceuus essence mine."),
ZEAH_PISCARILUS_MINE(new WorldPoint(1768, 3705, 0), ZEAH, "South of the Piscarilius mine."), ZEAH_PISCARILUS_MINE(new WorldPoint(1768, 3705, 0), ZEAH, "South of the Piscarilius mine."),
ZEAH_GOLDEN_FIELD_TAVERN(new WorldPoint(1718, 3647, 0), ZEAH, "South of The Golden Field tavern in the northern area of Hosidius."), ZEAH_GOLDEN_FIELD_TAVERN(new WorldPoint(1718, 3647, 0), ZEAH, "South of The Golden Field tavern in the northern area of Hosidius."),
ZEAH_MESS_HALL(new WorldPoint(1658, 3621, 0), ZEAH, "East of the Mess hall."), ZEAH_MESS_HALL(new WorldPoint(1658, 3621, 0), ZEAH, "East of the Mess hall."),
ZEAH_WATSONS_HOUSE(new WorldPoint(1653, 3573, 0), ZEAH, "East of Watson's house."), ZEAH_WATSONS_HOUSE(new WorldPoint(1653, 3573, 0), ZEAH, "East of Watson's house."),
ZEAH_VANNAHS_FARM_STORE(new WorldPoint(1806, 3521, 0), ZEAH, "North of Vannah's Farm Store, between the chicken coop and willow trees."), ZEAH_VANNAHS_FARM_STORE(new WorldPoint(1806, 3521, 0), ZEAH, "North of Vannah's Farm Store, between the chicken coop and willow trees."),
ZEAH_FARMING_GUILD_W(new WorldPoint(1209, 3737, 0), ZEAH, "West of the Farming Guild."), ZEAH_FARMING_GUILD_W(new WorldPoint(1209, 3737, 0), ZEAH, "West of the Farming Guild."),
ZEAH_DAIRY_COW(new WorldPoint(1320, 3718, 0), ZEAH, "North-east of the Kebos Lowlands, east of the dairy cow."), ZEAH_DAIRY_COW(new WorldPoint(1320, 3718, 0), ZEAH, "North-east of the Kebos Lowlands, east of the dairy cow."),
ZEAH_CRIMSON_SWIFTS(new WorldPoint(1186, 3583, 0), ZEAH, "South-west of the Kebos Swamp, below the crimson swifts."); ZEAH_CRIMSON_SWIFTS(new WorldPoint(1186, 3583, 0), ZEAH, "South-west of the Kebos Swamp, below the crimson swifts.");

View File

@@ -46,8 +46,8 @@ public interface CookingConfig extends Config
@ConfigItem( @ConfigItem(
position = 2, position = 2,
keyName = "fermentTimer", keyName = "fermentTimer",
name = "Show wine fermenting timer", name = "Show wine ferment timer",
description = "Conifgures if the timer before wines are fermented is shown." description = "Configures if the timer before wines are fermented is shown"
) )
default boolean fermentTimer() default boolean fermentTimer()
{ {

View File

@@ -29,8 +29,8 @@ import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.time.Duration;
import java.time.Instant; import java.time.Instant;
import java.time.Duration;
import javax.inject.Inject; import javax.inject.Inject;
import static net.runelite.api.AnimationID.COOKING_FIRE; import static net.runelite.api.AnimationID.COOKING_FIRE;
import static net.runelite.api.AnimationID.COOKING_RANGE; import static net.runelite.api.AnimationID.COOKING_RANGE;
@@ -71,7 +71,7 @@ class CookingOverlay extends Overlay
@Override @Override
public Dimension render(Graphics2D graphics) public Dimension render(Graphics2D graphics)
{ {
CookingSession session = plugin.getCookingSession(); CookingSession session = plugin.getSession();
if (session == null) if (session == null)
{ {
return null; return null;

View File

@@ -28,23 +28,27 @@ package net.runelite.client.plugins.cooking;
import com.google.inject.Provides; import com.google.inject.Provides;
import java.time.Duration; import java.time.Duration;
import java.time.Instant; import java.time.Instant;
import java.util.Optional;
import javax.inject.Inject; import javax.inject.Inject;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import static net.runelite.api.AnimationID.COOKING_WINE;
import net.runelite.api.ChatMessageType; import net.runelite.api.ChatMessageType;
import net.runelite.api.Client; import net.runelite.api.Client;
import net.runelite.api.GraphicID;
import net.runelite.api.ItemID;
import net.runelite.api.Player; import net.runelite.api.Player;
import net.runelite.api.events.AnimationChanged;
import net.runelite.api.events.ChatMessage; import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.GameTick; import net.runelite.api.events.GameTick;
import net.runelite.api.events.GraphicChanged;
import net.runelite.client.config.ConfigManager; import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe; import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.game.ItemManager;
import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDependency; import net.runelite.client.plugins.PluginDependency;
import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.plugins.xptracker.XpTrackerPlugin; import net.runelite.client.plugins.xptracker.XpTrackerPlugin;
import net.runelite.client.ui.overlay.OverlayManager; import net.runelite.client.ui.overlay.OverlayManager;
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
@PluginDescriptor( @PluginDescriptor(
name = "Cooking", name = "Cooking",
@@ -61,19 +65,19 @@ public class CookingPlugin extends Plugin
private CookingConfig config; private CookingConfig config;
@Inject @Inject
private CookingOverlay cookingOverlay; private CookingOverlay overlay;
@Inject
private FermentTimerOverlay fermentTimerOverlay;
@Inject @Inject
private OverlayManager overlayManager; private OverlayManager overlayManager;
@Getter(AccessLevel.PACKAGE) @Inject
private CookingSession cookingSession; private InfoBoxManager infoBoxManager;
@Inject
private ItemManager itemManager;
@Getter(AccessLevel.PACKAGE) @Getter(AccessLevel.PACKAGE)
private FermentTimerSession fermentTimerSession; private CookingSession session;
@Provides @Provides
CookingConfig getConfig(ConfigManager configManager) CookingConfig getConfig(ConfigManager configManager)
@@ -84,69 +88,62 @@ public class CookingPlugin extends Plugin
@Override @Override
protected void startUp() throws Exception protected void startUp() throws Exception
{ {
cookingSession = null; session = null;
fermentTimerSession = null; overlayManager.add(overlay);
overlayManager.add(cookingOverlay);
overlayManager.add(fermentTimerOverlay);
} }
@Override @Override
protected void shutDown() throws Exception protected void shutDown() throws Exception
{ {
overlayManager.remove(fermentTimerOverlay); infoBoxManager.removeIf(FermentTimer.class::isInstance);
overlayManager.remove(cookingOverlay); overlayManager.remove(overlay);
fermentTimerSession = null; session = null;
cookingSession = null;
} }
@Subscribe @Subscribe
public void onGameTick(GameTick gameTick) public void onGameTick(GameTick gameTick)
{ {
if (config.statTimeout() == 0) if (session == null || config.statTimeout() == 0)
{ {
return; return;
} }
if (cookingSession != null)
{
Duration statTimeout = Duration.ofMinutes(config.statTimeout()); Duration statTimeout = Duration.ofMinutes(config.statTimeout());
Duration sinceCut = Duration.between(cookingSession.getLastCookingAction(), Instant.now()); Duration sinceCut = Duration.between(session.getLastCookingAction(), Instant.now());
if (sinceCut.compareTo(statTimeout) >= 0) if (sinceCut.compareTo(statTimeout) >= 0)
{ {
cookingSession = null; session = null;
}
}
if (fermentTimerSession != null)
{
Duration statTimeout = Duration.ofMinutes(config.statTimeout());
Duration sinceCut = Duration.between(fermentTimerSession.getLastWineMakingAction(), Instant.now());
if (sinceCut.compareTo(statTimeout) >= 0)
{
fermentTimerSession = null;
}
} }
} }
@Subscribe @Subscribe
public void onAnimationChanged(AnimationChanged animationChanged) public void onGraphicChanged(GraphicChanged graphicChanged)
{ {
Player localPlayer = client.getLocalPlayer(); Player player = client.getLocalPlayer();
if (localPlayer != animationChanged.getActor()) if (graphicChanged.getActor() != player)
{ {
return; return;
} }
if (localPlayer.getAnimation() == COOKING_WINE && config.fermentTimer()) if (player.getGraphic() == GraphicID.WINE_MAKE && config.fermentTimer())
{ {
if (fermentTimerSession == null) Optional<FermentTimer> fermentTimerOpt = infoBoxManager.getInfoBoxes().stream()
{ .filter(FermentTimer.class::isInstance)
fermentTimerSession = new FermentTimerSession(); .map(FermentTimer.class::cast)
} .findAny();
fermentTimerSession.updateLastWineMakingAction(); if (fermentTimerOpt.isPresent())
{
FermentTimer fermentTimer = fermentTimerOpt.get();
fermentTimer.reset();
}
else
{
FermentTimer fermentTimer = new FermentTimer(itemManager.getImage(ItemID.JUG_OF_WINE), this);
infoBoxManager.addInfoBox(fermentTimer);
}
} }
} }
@@ -166,24 +163,24 @@ public class CookingPlugin extends Plugin
|| message.startsWith("You roast a") || message.startsWith("You roast a")
|| message.startsWith("You cook")) || message.startsWith("You cook"))
{ {
if (cookingSession == null) if (session == null)
{ {
cookingSession = new CookingSession(); session = new CookingSession();
} }
cookingSession.updateLastCookingAction(); session.updateLastCookingAction();
cookingSession.increaseCookAmount(); session.increaseCookAmount();
} }
else if (message.startsWith("You accidentally burn")) else if (message.startsWith("You accidentally burn"))
{ {
if (cookingSession == null) if (session == null)
{ {
cookingSession = new CookingSession(); session = new CookingSession();
} }
cookingSession.updateLastCookingAction(); session.updateLastCookingAction();
cookingSession.increaseBurnAmount(); session.increaseBurnAmount();
} }
} }
} }

View File

@@ -0,0 +1,76 @@
/*
* Copyright (c) 2019, 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.cooking;
import java.awt.Color;
import java.awt.Image;
import java.time.Duration;
import java.time.Instant;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.ui.overlay.infobox.InfoBox;
final class FermentTimer extends InfoBox
{
private static final Duration FERMENT_TIME = Duration.ofMillis(13_800);
private Instant fermentTime;
FermentTimer(Image image, Plugin plugin)
{
super(image, plugin);
reset();
}
@Override
public String getText()
{
int seconds = timeUntilFerment();
return Integer.toString(seconds);
}
@Override
public Color getTextColor()
{
int seconds = timeUntilFerment();
return seconds <= 3 ? Color.RED : Color.WHITE;
}
@Override
public boolean cull()
{
int seconds = timeUntilFerment();
return seconds <= 0;
}
void reset()
{
fermentTime = Instant.now().plus(FERMENT_TIME);
}
private int timeUntilFerment()
{
return (int) Duration.between(Instant.now(), fermentTime).getSeconds();
}
}

View File

@@ -1,104 +0,0 @@
/*
* Copyright (c) 2019, Lucas C <lucas1757@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.cooking;
import com.google.inject.Inject;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.time.Duration;
import java.time.Instant;
import lombok.extern.slf4j.Slf4j;
import static net.runelite.api.AnimationID.COOKING_WINE;
import net.runelite.api.Client;
import static net.runelite.api.MenuAction.RUNELITE_OVERLAY_CONFIG;
import net.runelite.client.ui.overlay.Overlay;
import static net.runelite.client.ui.overlay.OverlayManager.OPTION_CONFIGURE;
import net.runelite.client.ui.overlay.OverlayMenuEntry;
import net.runelite.client.ui.overlay.OverlayPosition;
import net.runelite.client.ui.overlay.components.PanelComponent;
import net.runelite.client.ui.overlay.components.TitleComponent;
import net.runelite.client.ui.overlay.components.table.TableAlignment;
import net.runelite.client.ui.overlay.components.table.TableComponent;
@Slf4j
class FermentTimerOverlay extends Overlay
{
private static final int INITIAL_TIME = 12;
private final Client client;
private final CookingPlugin plugin;
private final PanelComponent panelComponent = new PanelComponent();
@Inject
private FermentTimerOverlay(final Client client, final CookingPlugin plugin)
{
super(plugin);
setPosition(OverlayPosition.TOP_LEFT);
this.client = client;
this.plugin = plugin;
getMenuEntries().add(new OverlayMenuEntry(RUNELITE_OVERLAY_CONFIG, OPTION_CONFIGURE, "Fermenting Timer overlay"));
}
@Override
public Dimension render(Graphics2D graphics)
{
FermentTimerSession session = plugin.getFermentTimerSession();
if (session == null)
{
return null;
}
panelComponent.getChildren().clear();
if (isMakingWine() || Duration.between(session.getLastWineMakingAction(), Instant.now()).getSeconds() < INITIAL_TIME)
{
panelComponent.getChildren().add(TitleComponent.builder()
.text("Making Wine")
.color(Color.GREEN)
.build());
TableComponent tableComponent = new TableComponent();
tableComponent.setColumnAlignments(TableAlignment.LEFT, TableAlignment.RIGHT);
tableComponent.addRow("Ferments in:", String.valueOf(INITIAL_TIME - Duration.between(session.getLastWineMakingAction(), Instant.now()).getSeconds()));
panelComponent.getChildren().add(tableComponent);
}
else
{
panelComponent.getChildren().add(TitleComponent.builder()
.text("Wine Fermented")
.color(Color.ORANGE)
.build());
}
return panelComponent.render(graphics);
}
private boolean isMakingWine()
{
return (client.getLocalPlayer().getAnimation() == COOKING_WINE);
}
}

View File

@@ -489,6 +489,7 @@ class DevToolsOverlay extends Overlay
WidgetItem widgetItem = widget.getWidgetItem(itemIndex); WidgetItem widgetItem = widget.getWidgetItem(itemIndex);
if (widgetItem == null if (widgetItem == null
|| widgetItem.getId() < 0
|| widgetItem.getId() == ITEM_EMPTY || widgetItem.getId() == ITEM_EMPTY
|| widgetItem.getId() == ITEM_FILLED) || widgetItem.getId() == ITEM_FILLED)
{ {

View File

@@ -123,7 +123,7 @@ public class ExaminePlugin extends Plugin
int widgetChild = TO_CHILD(widgetId); int widgetChild = TO_CHILD(widgetId);
Widget widget = client.getWidget(widgetGroup, widgetChild); Widget widget = client.getWidget(widgetGroup, widgetChild);
WidgetItem widgetItem = widget.getWidgetItem(event.getActionParam()); WidgetItem widgetItem = widget.getWidgetItem(event.getActionParam());
quantity = widgetItem != null ? widgetItem.getQuantity() : 1; quantity = widgetItem != null && widgetItem.getId() >= 0 ? widgetItem.getQuantity() : 1;
break; break;
} }
case EXAMINE_ITEM_BANK_EQ: case EXAMINE_ITEM_BANK_EQ:

View File

@@ -1,6 +1,5 @@
/* /*
* Copyright (c) 2018, Seth <Sethtroll3@gmail.com> * Copyright (c) 2018, Jeremy Plsek <https://github.com/jplsek>
* Copyright (c) 2018, Lars <lars.oernlo@gmail.com>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -23,53 +22,41 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package net.runelite.client.plugins.mining; package net.runelite.client.plugins.inventorygrid;
import net.runelite.client.config.Config; import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem; import net.runelite.client.config.ConfigItem;
@ConfigGroup("mining") @ConfigGroup("inventorygrid")
public interface MiningConfig extends Config public interface InventoryGridConfig extends Config
{ {
@ConfigItem( @ConfigItem(
keyName = "showMiningRocks", keyName = "showItem",
name = "Show rock mining spots", name = "Show item",
description = "Configures whether or not the mining spots are displayed." description = "Show a preview of the item in the new slot"
) )
default boolean showMiningRocks() default boolean showItem()
{ {
return true; return true;
} }
@ConfigItem( @ConfigItem(
keyName = "statTimeout", keyName = "showGrid",
name = "Reset stats (minutes)", name = "Show grid",
description = "Configures the time until statistics are reset" description = "Show a grid on the inventory while dragging"
) )
default int statTimeout() default boolean showGrid()
{
return 5;
}
@ConfigItem(
keyName = "showMiningStats",
name = "Show mining session stats",
description = "Configures whether to display mining session stats"
)
default boolean showMiningStats()
{ {
return true; return true;
} }
@ConfigItem( @ConfigItem(
keyName = "showMiningState", keyName = "showHighlight",
name = "Show current mining state", name = "Highlight background",
description = "Shows current mining state. 'You are currently mining' / 'You are currently NOT mining'" description = "Show a green background highlight on the new slot"
) )
default boolean showMiningState() default boolean showHighlight()
{ {
return true; return true;
} }

View File

@@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2018, Jeremy Plsek <https://github.com/jplsek> * Copyright (c) 2018, Jeremy Plsek <https://github.com/jplsek>
* Copyright (c) 2019, Adam <Adam@sigterm.info>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -22,7 +23,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package net.runelite.client.plugins.inventoryhighlight; package net.runelite.client.plugins.inventorygrid;
import com.google.inject.Inject; import com.google.inject.Inject;
import java.awt.AlphaComposite; import java.awt.AlphaComposite;
@@ -35,105 +36,80 @@ import java.awt.image.BufferedImage;
import net.runelite.api.Client; import net.runelite.api.Client;
import net.runelite.api.widgets.Widget; import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo; import net.runelite.api.widgets.WidgetInfo;
import net.runelite.api.widgets.WidgetItem;
import net.runelite.client.game.ItemManager; import net.runelite.client.game.ItemManager;
import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer; import net.runelite.client.ui.overlay.OverlayLayer;
import net.runelite.client.ui.overlay.OverlayPosition;
public class InventoryHighlightOverlay extends Overlay class InventoryGridOverlay extends Overlay
{ {
private final InventoryHighlightPlugin plugin; private static final int INVENTORY_SIZE = 28;
private final InventoryHighlightConfig config; private static final int DRAG_DELAY = 5;
private final Client client;
private final ItemManager itemManager;
// the inventory widget location is slightly off
private static final int FIXED_MARGIN_X = -10;
private static final int FIXED_MARGIN_Y = -25;
private static final int RESIZEABLE_MARGIN_X = -6;
private static final int RESIZEABLE_MARGIN_Y = -21;
private static final int ITEM_WIDTH = 32;
private static final int ITEM_HEIGHT = 32;
private static final int ITEM_MARGIN_X = 10;
private static final int ITEM_MARGIN_Y = 4;
private static final Color HIGHLIGHT = new Color(0, 255, 0, 45); private static final Color HIGHLIGHT = new Color(0, 255, 0, 45);
private static final Color GRID = new Color(255, 255, 255, 45); private static final Color GRID = new Color(255, 255, 255, 45);
private final InventoryGridConfig config;
private final Client client;
private final ItemManager itemManager;
@Inject @Inject
public InventoryHighlightOverlay(InventoryHighlightPlugin plugin, InventoryHighlightConfig config, Client client, ItemManager itemManager) private InventoryGridOverlay(InventoryGridConfig config, Client client, ItemManager itemManager)
{ {
this.plugin = plugin;
this.itemManager = itemManager; this.itemManager = itemManager;
this.client = client; this.client = client;
this.config = config; this.config = config;
setPosition(OverlayPosition.DYNAMIC);
setLayer(OverlayLayer.ABOVE_WIDGETS); setLayer(OverlayLayer.ABOVE_WIDGETS);
} }
@Override @Override
public Dimension render(Graphics2D graphics) public Dimension render(Graphics2D graphics)
{ {
if (plugin.getDraggingItem() == -1 || !plugin.isDragging()) final Widget if1DraggingWidget = client.getIf1DraggedWidget();
final Widget inventoryWidget = client.getWidget(WidgetInfo.INVENTORY);
if (if1DraggingWidget == null || if1DraggingWidget != inventoryWidget
|| client.getItemPressedDuration() < DRAG_DELAY)
{ {
return null; return null;
} }
int marginX, marginY;
if (client.isResized())
{
marginX = RESIZEABLE_MARGIN_X;
marginY = RESIZEABLE_MARGIN_Y;
}
else
{
marginX = FIXED_MARGIN_X;
marginY = FIXED_MARGIN_Y;
}
final net.runelite.api.Point mouse = client.getMouseCanvasPosition(); final net.runelite.api.Point mouse = client.getMouseCanvasPosition();
final Point updatedMouse = new Point(mouse.getX() + marginX, mouse.getY() + marginY); final Point mousePoint = new Point(mouse.getX(), mouse.getY());
// null checks for inventory are checked during dragging events for (int i = 0; i < INVENTORY_SIZE; ++i)
final Widget inventoryWidget = client.getWidget(WidgetInfo.INVENTORY);
final int inventoryX = inventoryWidget.getCanvasLocation().getX() + marginX;
final int inventoryY = inventoryWidget.getCanvasLocation().getY() + marginY;
final BufferedImage draggedItemImage = itemManager.getImage(plugin.getDraggingItem());
for (int i = 0; i < 4; i++)
{ {
for (int j = 0; j < 7; j++) WidgetItem widgetItem = inventoryWidget.getWidgetItem(i);
{
final int x = (ITEM_WIDTH + ITEM_MARGIN_X) * i + inventoryX;
final int y = (ITEM_HEIGHT + ITEM_MARGIN_Y) * j + inventoryY;
final Rectangle bounds = new Rectangle(x, y, ITEM_WIDTH, ITEM_HEIGHT);
if (config.showItem() && bounds.contains(updatedMouse)) final Rectangle bounds = widgetItem.getCanvasBounds();
boolean inBounds = bounds.contains(mousePoint);
if (config.showItem() && inBounds)
{ {
final WidgetItem draggedItem = inventoryWidget.getWidgetItem(client.getIf1DraggedItemIndex());
final BufferedImage draggedItemImage = itemManager.getImage(draggedItem.getId());
final int x = (int) bounds.getX();
final int y = (int) bounds.getY();
graphics.setComposite(AlphaComposite.SrcOver.derive(0.3f)); graphics.setComposite(AlphaComposite.SrcOver.derive(0.3f));
graphics.drawImage(draggedItemImage, x, y, null); graphics.drawImage(draggedItemImage, x, y, null);
graphics.setComposite(AlphaComposite.SrcOver); graphics.setComposite(AlphaComposite.SrcOver);
} }
if (config.showHighlight() && bounds.contains(updatedMouse)) if (config.showHighlight() && inBounds)
{ {
graphics.setColor(HIGHLIGHT); graphics.setColor(HIGHLIGHT);
graphics.fill(bounds); graphics.fill(bounds);
} }
else if (config.showGrid())
if (config.showGrid())
{
// don't set color on highlighted slot
if (!config.showHighlight() || !(config.showHighlight() && bounds.contains(updatedMouse)))
{ {
graphics.setColor(GRID); graphics.setColor(GRID);
graphics.fill(bounds); graphics.fill(bounds);
} }
} }
}
}
return null; return null;
} }

View File

@@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2018, Jeremy Plsek <https://github.com/jplsek> * Copyright (c) 2018, Jeremy Plsek <https://github.com/jplsek>
* Copyright (c) 2019, Adam <Adam@sigterm.info>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -22,79 +23,44 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package net.runelite.client.plugins.inventoryhighlight; package net.runelite.client.plugins.inventorygrid;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provides; import com.google.inject.Provides;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import net.runelite.api.events.FocusChanged;
import net.runelite.client.config.ConfigManager; import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.input.MouseManager;
import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.plugins.PluginType;
import net.runelite.client.ui.overlay.OverlayManager; import net.runelite.client.ui.overlay.OverlayManager;
@PluginDescriptor( @PluginDescriptor(
name = "Inventory Highlight", name = "Inventory Grid",
description = "Shows a preview of where items will be dragged", description = "Shows a grid over the inventory and a preview of where items will be dragged",
tags = {"items", "overlay"}, tags = {"items", "overlay"},
type = PluginType.UTILITY,
enabledByDefault = false enabledByDefault = false
) )
public class InventoryGridPlugin extends Plugin
public class InventoryHighlightPlugin extends Plugin
{ {
@Inject @Inject
private InventoryHighlightOverlay overlay; private InventoryGridOverlay overlay;
@Inject
private InventoryHighlightInputListener inputListener;
@Inject
private MouseManager mouseManager;
@Inject @Inject
private OverlayManager overlayManager; private OverlayManager overlayManager;
@Getter(AccessLevel.PACKAGE)
@Setter(AccessLevel.PACKAGE)
private int draggingItem = -1;
@Getter(AccessLevel.PACKAGE)
@Setter(AccessLevel.PACKAGE)
private boolean dragging = false;
@Override @Override
public void startUp() public void startUp()
{ {
overlayManager.add(overlay); overlayManager.add(overlay);
mouseManager.registerMouseListener(inputListener);
} }
@Override @Override
public void shutDown() public void shutDown()
{ {
mouseManager.unregisterMouseListener(inputListener);
overlayManager.remove(overlay); overlayManager.remove(overlay);
} }
@Provides @Provides
InventoryHighlightConfig getConfig(ConfigManager configManager) InventoryGridConfig getConfig(ConfigManager configManager)
{ {
return configManager.getConfig(InventoryHighlightConfig.class); return configManager.getConfig(InventoryGridConfig.class);
}
@Subscribe
public void onFocusChanged(FocusChanged focusChanged)
{
if (!focusChanged.isFocused())
{
dragging = false;
draggingItem = -1;
}
} }
} }

View File

@@ -1,53 +0,0 @@
package net.runelite.client.plugins.inventoryhighlight;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
import net.runelite.client.config.Stub;
@ConfigGroup("inventoryHighlight")
public interface InventoryHighlightConfig extends Config
{
@ConfigItem(
keyName = "showItem",
name = "Show the item",
description = "Show a preview of the item in the new slot"
)
default boolean showItem()
{
return true;
}
@ConfigItem(
keyName = "gridStub",
name = "Grid",
description = "",
position = 1
)
default Stub gridStub()
{
return new Stub();
}
@ConfigItem(
keyName = "showGrid",
name = "Show a grid",
description = "Show a grid on the inventory while dragging",
parent = "gridStub"
)
default boolean showGrid()
{
return false;
}
@ConfigItem(
keyName = "showHighlight",
name = "Show background highlight",
description = "Show a green background highlight in the new slot",
parent = "gridStub"
)
default boolean showHighlight()
{
return false;
}
}

View File

@@ -1,119 +0,0 @@
/*
* Copyright (c) 2018, Jeremy Plsek <https://github.com/jplsek>
* 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.inventoryhighlight;
import com.google.inject.Inject;
import java.awt.event.MouseEvent;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.Point;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.api.widgets.WidgetItem;
import net.runelite.client.input.MouseListener;
public class InventoryHighlightInputListener implements MouseListener
{
private final InventoryHighlightPlugin plugin;
private final Client client;
@Inject
public InventoryHighlightInputListener(InventoryHighlightPlugin plugin, Client client)
{
this.plugin = plugin;
this.client = client;
}
@Override
public MouseEvent mouseDragged(MouseEvent mouseEvent)
{
plugin.setDragging(true);
return mouseEvent;
}
@Override
public MouseEvent mouseMoved(MouseEvent mouseEvent)
{
return mouseEvent;
}
@Override
public MouseEvent mouseClicked(MouseEvent mouseEvent)
{
return mouseEvent;
}
@Override
public MouseEvent mousePressed(MouseEvent mouseEvent)
{
if (client.getGameState() != GameState.LOGGED_IN)
{
return mouseEvent;
}
final Widget inventoryWidget = client.getWidget(WidgetInfo.INVENTORY);
final Widget bankInventoryWidget = client.getWidget(WidgetInfo.BANK_INVENTORY_ITEMS_CONTAINER);
if ((inventoryWidget == null || inventoryWidget.isSelfHidden()) &&
(inventoryWidget == null || bankInventoryWidget == null || bankInventoryWidget.isSelfHidden()))
{
return mouseEvent;
}
final Point mouse = client.getMouseCanvasPosition();
for (WidgetItem item : inventoryWidget.getWidgetItems())
{
if (item.getCanvasBounds().contains(mouse.getX(), mouse.getY()))
{
plugin.setDraggingItem(item.getId());
break;
}
}
return mouseEvent;
}
@Override
public MouseEvent mouseReleased(MouseEvent mouseEvent)
{
plugin.setDragging(false);
plugin.setDraggingItem(-1);
return mouseEvent;
}
@Override
public MouseEvent mouseEntered(MouseEvent mouseEvent)
{
return mouseEvent;
}
@Override
public MouseEvent mouseExited(MouseEvent mouseEvent)
{
return mouseEvent;
}
}

View File

@@ -58,7 +58,7 @@ public class InventoryTagsOverlay extends WidgetItemOverlay
{ {
Rectangle bounds = itemWidget.getCanvasBounds(); Rectangle bounds = itemWidget.getCanvasBounds();
final BufferedImage outline = itemManager.getItemOutline(itemId, itemWidget.getQuantity(), color); final BufferedImage outline = itemManager.getItemOutline(itemId, itemWidget.getQuantity(), color);
graphics.drawImage(outline, (int) bounds.getX() + 1, (int) bounds.getY() + 1, null); graphics.drawImage(outline, (int) bounds.getX(), (int) bounds.getY(), null);
} }
} }
} }

View File

@@ -162,9 +162,7 @@ class ItemChargeOverlay extends WidgetItemOverlay
final Rectangle bounds = itemWidget.getCanvasBounds(); final Rectangle bounds = itemWidget.getCanvasBounds();
final TextComponent textComponent = new TextComponent(); final TextComponent textComponent = new TextComponent();
textComponent.setPosition(new textComponent.setPosition(new Point(bounds.x - 1, bounds.y + 15));
Point(bounds.x, bounds.y + 16));
textComponent.setText(charges < 0 ? "?" : String.valueOf(charges)); textComponent.setText(charges < 0 ? "?" : String.valueOf(charges));
textComponent.setColor(itemChargePlugin.getColor(charges)); textComponent.setColor(itemChargePlugin.getColor(charges));
textComponent.render(graphics); textComponent.render(graphics);

View File

@@ -87,7 +87,7 @@ class ItemIdentificationOverlay extends WidgetItemOverlay
private void renderText(Graphics2D graphics, Rectangle bounds, ItemIdentification iden) private void renderText(Graphics2D graphics, Rectangle bounds, ItemIdentification iden)
{ {
final TextComponent textComponent = new TextComponent(); final TextComponent textComponent = new TextComponent();
textComponent.setPosition(new Point(bounds.x, bounds.y + bounds.height)); textComponent.setPosition(new Point(bounds.x - 1, bounds.y + bounds.height - 1));
textComponent.setColor(config.textColor()); textComponent.setColor(config.textColor());
switch (config.identificationType()) switch (config.identificationType())
{ {

View File

@@ -22,7 +22,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package net.runelite.client.plugins.wasdcamera; package net.runelite.client.plugins.keyremapping;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
import net.runelite.client.config.Config; import net.runelite.client.config.Config;
@@ -30,13 +30,24 @@ import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem; import net.runelite.client.config.ConfigItem;
import net.runelite.client.config.ModifierlessKeybind; import net.runelite.client.config.ModifierlessKeybind;
@ConfigGroup("wasdcamera") @ConfigGroup("keyremapping")
public interface WASDCameraConfig extends Config public interface KeyRemappingConfig extends Config
{ {
@ConfigItem( @ConfigItem(
position = 1, position = 1,
keyName = "cameraRemap",
name = "Remap Camera",
description = "Configures whether the camera movement uses remapped keys"
)
default boolean cameraRemap()
{
return true;
}
@ConfigItem(
position = 2,
keyName = "up", keyName = "up",
name = "Up key", name = "Camera Up key",
description = "The key which will replace up." description = "The key which will replace up."
) )
default ModifierlessKeybind up() default ModifierlessKeybind up()
@@ -45,9 +56,9 @@ public interface WASDCameraConfig extends Config
} }
@ConfigItem( @ConfigItem(
position = 2, position = 3,
keyName = "down", keyName = "down",
name = "Down key", name = "Camera Down key",
description = "The key which will replace down." description = "The key which will replace down."
) )
default ModifierlessKeybind down() default ModifierlessKeybind down()
@@ -56,9 +67,9 @@ public interface WASDCameraConfig extends Config
} }
@ConfigItem( @ConfigItem(
position = 3, position = 4,
keyName = "left", keyName = "left",
name = "Left key", name = "Camera Left key",
description = "The key which will replace left." description = "The key which will replace left."
) )
default ModifierlessKeybind left() default ModifierlessKeybind left()
@@ -67,13 +78,24 @@ public interface WASDCameraConfig extends Config
} }
@ConfigItem( @ConfigItem(
position = 4, position = 5,
keyName = "right", keyName = "right",
name = "Right key", name = "Camera Right key",
description = "The key which will replace right." description = "The key which will replace right."
) )
default ModifierlessKeybind right() default ModifierlessKeybind right()
{ {
return new ModifierlessKeybind(KeyEvent.VK_D, 0); return new ModifierlessKeybind(KeyEvent.VK_D, 0);
} }
@ConfigItem(
position = 6,
keyName = "fkeyRemap",
name = "Remap F Keys",
description = "Configures whether F-Keys are Remapped to 1 (F1) through 0 (F10), '-' (F11), and '=' (F12)"
)
default boolean fkeyRemap()
{
return false;
}
} }

View File

@@ -0,0 +1,307 @@
/*
* Copyright (c) 2018, Adam <Adam@sigterm.info>
* Copyright (c) 2018, Abexlry <abexlry@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.keyremapping;
import com.google.common.base.Strings;
import java.awt.event.KeyEvent;
import java.util.HashMap;
import java.util.Map;
import javax.inject.Inject;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.VarClientStr;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.config.Keybind;
import net.runelite.client.config.ModifierlessKeybind;
import net.runelite.client.input.KeyListener;
import net.runelite.client.input.MouseAdapter;
class KeyRemappingListener extends MouseAdapter implements KeyListener
{
private static final Keybind ONE = new ModifierlessKeybind(KeyEvent.VK_1, 0);
private static final Keybind TWO = new ModifierlessKeybind(KeyEvent.VK_2, 0);
private static final Keybind THREE = new ModifierlessKeybind(KeyEvent.VK_3, 0);
private static final Keybind FOUR = new ModifierlessKeybind(KeyEvent.VK_4, 0);
private static final Keybind FIVE = new ModifierlessKeybind(KeyEvent.VK_5, 0);
private static final Keybind SIX = new ModifierlessKeybind(KeyEvent.VK_6, 0);
private static final Keybind SEVEN = new ModifierlessKeybind(KeyEvent.VK_7, 0);
private static final Keybind EIGHT = new ModifierlessKeybind(KeyEvent.VK_8, 0);
private static final Keybind NINE = new ModifierlessKeybind(KeyEvent.VK_9, 0);
private static final Keybind ZERO = new ModifierlessKeybind(KeyEvent.VK_0, 0);
private static final Keybind MINUS = new ModifierlessKeybind(KeyEvent.VK_MINUS, 0);
private static final Keybind EQUALS = new ModifierlessKeybind(KeyEvent.VK_EQUALS, 0);
@Inject
private KeyRemappingPlugin plugin;
@Inject
private KeyRemappingConfig config;
@Inject
private Client client;
@Inject
private ClientThread clientThread;
private final Map<Integer, Integer> modified = new HashMap<>();
@Override
public void keyTyped(KeyEvent e)
{
}
@Override
public void keyPressed(KeyEvent e)
{
if (client.getGameState() == GameState.LOGIN_SCREEN || !plugin.chatboxFocused())
{
return;
}
if (!plugin.isTyping())
{
if (config.cameraRemap())
{
if (config.up().matches(e))
{
modified.put(e.getKeyCode(), KeyEvent.VK_UP);
e.setKeyCode(KeyEvent.VK_UP);
}
else if (config.down().matches(e))
{
modified.put(e.getKeyCode(), KeyEvent.VK_DOWN);
e.setKeyCode(KeyEvent.VK_DOWN);
}
else if (config.left().matches(e))
{
modified.put(e.getKeyCode(), KeyEvent.VK_LEFT);
e.setKeyCode(KeyEvent.VK_LEFT);
}
else if (config.right().matches(e))
{
modified.put(e.getKeyCode(), KeyEvent.VK_RIGHT);
e.setKeyCode(KeyEvent.VK_RIGHT);
}
}
if (config.fkeyRemap())
{
if (ONE.matches(e))
{
modified.put(e.getKeyCode(), KeyEvent.VK_F1);
e.setKeyCode(KeyEvent.VK_F1);
}
else if (TWO.matches(e))
{
modified.put(e.getKeyCode(), KeyEvent.VK_F2);
e.setKeyCode(KeyEvent.VK_F2);
}
else if (THREE.matches(e))
{
modified.put(e.getKeyCode(), KeyEvent.VK_F3);
e.setKeyCode(KeyEvent.VK_F3);
}
else if (FOUR.matches(e))
{
modified.put(e.getKeyCode(), KeyEvent.VK_F4);
e.setKeyCode(KeyEvent.VK_F4);
}
else if (FIVE.matches(e))
{
modified.put(e.getKeyCode(), KeyEvent.VK_F5);
e.setKeyCode(KeyEvent.VK_F5);
}
else if (SIX.matches(e))
{
modified.put(e.getKeyCode(), KeyEvent.VK_F6);
e.setKeyCode(KeyEvent.VK_F6);
}
else if (SEVEN.matches(e))
{
modified.put(e.getKeyCode(), KeyEvent.VK_F7);
e.setKeyCode(KeyEvent.VK_F7);
}
else if (EIGHT.matches(e))
{
modified.put(e.getKeyCode(), KeyEvent.VK_F8);
e.setKeyCode(KeyEvent.VK_F8);
}
else if (NINE.matches(e))
{
modified.put(e.getKeyCode(), KeyEvent.VK_F9);
e.setKeyCode(KeyEvent.VK_F9);
}
else if (ZERO.matches(e))
{
modified.put(e.getKeyCode(), KeyEvent.VK_F10);
e.setKeyCode(KeyEvent.VK_F10);
}
else if (MINUS.matches(e))
{
modified.put(e.getKeyCode(), KeyEvent.VK_F11);
e.setKeyCode(KeyEvent.VK_F11);
}
else if (EQUALS.matches(e))
{
modified.put(e.getKeyCode(), KeyEvent.VK_F12);
e.setKeyCode(KeyEvent.VK_F12);
}
}
switch (e.getKeyCode())
{
case KeyEvent.VK_ENTER:
case KeyEvent.VK_SLASH:
case KeyEvent.VK_COLON:
// refocus chatbox
plugin.setTyping(true);
clientThread.invoke(plugin::unlockChat);
break;
}
}
else
{
switch (e.getKeyCode())
{
case KeyEvent.VK_ENTER:
plugin.setTyping(false);
clientThread.invoke(plugin::lockChat);
break;
case KeyEvent.VK_ESCAPE:
plugin.setTyping(false);
clientThread.invoke(() ->
{
client.setVar(VarClientStr.CHATBOX_TYPED_TEXT, "");
plugin.lockChat();
});
break;
case KeyEvent.VK_BACK_SPACE:
if (Strings.isNullOrEmpty(client.getVar(VarClientStr.CHATBOX_TYPED_TEXT)))
{
plugin.setTyping(false);
clientThread.invoke(plugin::lockChat);
}
}
}
}
@Override
public void keyReleased(KeyEvent e)
{
if (client.getGameState() == GameState.LOGIN_SCREEN)
{
return;
}
if (plugin.chatboxFocused() && !plugin.isTyping())
{
modified.remove(e.getKeyCode());
if (config.cameraRemap())
{
if (config.up().matches(e))
{
e.setKeyCode(KeyEvent.VK_UP);
}
else if (config.down().matches(e))
{
e.setKeyCode(KeyEvent.VK_DOWN);
}
else if (config.left().matches(e))
{
e.setKeyCode(KeyEvent.VK_LEFT);
}
else if (config.right().matches(e))
{
e.setKeyCode(KeyEvent.VK_RIGHT);
}
}
if (config.fkeyRemap())
{
if (ONE.matches(e))
{
e.setKeyCode(KeyEvent.VK_F1);
}
else if (TWO.matches(e))
{
e.setKeyCode(KeyEvent.VK_F2);
}
else if (THREE.matches(e))
{
e.setKeyCode(KeyEvent.VK_F3);
}
else if (FOUR.matches(e))
{
e.setKeyCode(KeyEvent.VK_F4);
}
else if (FIVE.matches(e))
{
e.setKeyCode(KeyEvent.VK_F5);
}
else if (SIX.matches(e))
{
e.setKeyCode(KeyEvent.VK_F6);
}
else if (SEVEN.matches(e))
{
e.setKeyCode(KeyEvent.VK_F7);
}
else if (EIGHT.matches(e))
{
e.setKeyCode(KeyEvent.VK_F8);
}
else if (NINE.matches(e))
{
e.setKeyCode(KeyEvent.VK_F9);
}
else if (ZERO.matches(e))
{
e.setKeyCode(KeyEvent.VK_F10);
}
else if (MINUS.matches(e))
{
e.setKeyCode(KeyEvent.VK_F11);
}
else if (EQUALS.matches(e))
{
e.setKeyCode(KeyEvent.VK_F12);
}
}
}
else
{
// press d + enter + release d - causes the right arrow to never be released
Integer m = modified.get(e.getKeyCode());
if (m != null)
{
modified.remove(e.getKeyCode());
e.setKeyCode(m);
}
}
}
}

View File

@@ -23,7 +23,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package net.runelite.client.plugins.wasdcamera; package net.runelite.client.plugins.keyremapping;
import com.google.inject.Provides; import com.google.inject.Provides;
import java.awt.Color; import java.awt.Color;
@@ -50,12 +50,12 @@ import net.runelite.client.ui.JagexColors;
import net.runelite.client.util.ColorUtil; import net.runelite.client.util.ColorUtil;
@PluginDescriptor( @PluginDescriptor(
name = "WASD Camera", name = "Key Remapping",
description = "Allows use of WASD keys for camera movement with 'Press Enter to Chat'", description = "Allows use of WASD keys for camera movement with 'Press Enter to Chat', and remapping number keys to F-keys",
tags = {"enter", "chat"}, tags = {"enter", "chat", "wasd", "camera"},
enabledByDefault = false enabledByDefault = false
) )
public class WASDCameraPlugin extends Plugin public class KeyRemappingPlugin extends Plugin
{ {
private static final String PRESS_ENTER_TO_CHAT = "Press Enter to Chat..."; private static final String PRESS_ENTER_TO_CHAT = "Press Enter to Chat...";
private static final String SCRIPT_EVENT_SET_CHATBOX_INPUT = "setChatboxInput"; private static final String SCRIPT_EVENT_SET_CHATBOX_INPUT = "setChatboxInput";
@@ -74,7 +74,7 @@ public class WASDCameraPlugin extends Plugin
private KeyManager keyManager; private KeyManager keyManager;
@Inject @Inject
private WASDCameraListener inputListener; private KeyRemappingListener inputListener;
@Getter(AccessLevel.PACKAGE) @Getter(AccessLevel.PACKAGE)
@Setter(AccessLevel.PACKAGE) @Setter(AccessLevel.PACKAGE)
@@ -111,9 +111,9 @@ public class WASDCameraPlugin extends Plugin
} }
@Provides @Provides
WASDCameraConfig getConfig(ConfigManager configManager) KeyRemappingConfig getConfig(ConfigManager configManager)
{ {
return configManager.getConfig(WASDCameraConfig.class); return configManager.getConfig(KeyRemappingConfig.class);
} }
boolean chatboxFocused() boolean chatboxFocused()
@@ -127,8 +127,12 @@ public class WASDCameraPlugin extends Plugin
// the search box on the world map can be focused, and chat input goes there, even // the search box on the world map can be focused, and chat input goes there, even
// though the chatbox still has its key listener. // though the chatbox still has its key listener.
Widget worldMapSearch = client.getWidget(WidgetInfo.WORLD_MAP_SEARCH); Widget worldMapSearch = client.getWidget(WidgetInfo.WORLD_MAP_SEARCH);
return worldMapSearch == null || client.getVar(VarClientInt.WORLD_MAP_SEARCH_FOCUSED) != 1; if (worldMapSearch != null && client.getVar(VarClientInt.WORLD_MAP_SEARCH_FOCUSED) == 1)
{
return false;
}
return true;
} }
@Subscribe @Subscribe

View File

@@ -36,9 +36,9 @@ import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client; import net.runelite.api.Client;
import net.runelite.api.GameState; import net.runelite.api.GameState;
import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.GameStateChanged;
import net.runelite.client.events.SessionOpen;
import net.runelite.client.config.ConfigManager; import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe; import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.events.SessionOpen;
import net.runelite.client.input.KeyListener; import net.runelite.client.input.KeyListener;
import net.runelite.client.input.KeyManager; import net.runelite.client.input.KeyManager;
import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.Plugin;
@@ -54,6 +54,7 @@ public class LoginScreenPlugin extends Plugin implements KeyListener
{ {
private static final int MAX_USERNAME_LENGTH = 254; private static final int MAX_USERNAME_LENGTH = 254;
private static final int MAX_PASSWORD_LENGTH = 20; private static final int MAX_PASSWORD_LENGTH = 20;
private static final int MAX_PIN_LENGTH = 6;
@Inject @Inject
private Client client; private Client client;
@@ -163,7 +164,9 @@ public class LoginScreenPlugin extends Plugin implements KeyListener
@Override @Override
public void keyPressed(KeyEvent e) public void keyPressed(KeyEvent e)
{ {
if (!config.pasteEnabled() || client.getGameState() != GameState.LOGIN_SCREEN) if (!config.pasteEnabled() || (
client.getGameState() != GameState.LOGIN_SCREEN &&
client.getGameState() != GameState.LOGIN_SCREEN_AUTHENTICATOR))
{ {
return; return;
} }
@@ -182,7 +185,10 @@ public class LoginScreenPlugin extends Plugin implements KeyListener
.toString() .toString()
.trim(); .trim();
// 0 is username, 1 is password switch (client.getLoginIndex())
{
// Username/password form
case 2:
if (client.getCurrentLoginField() == 0) if (client.getCurrentLoginField() == 0)
{ {
// Truncate data to maximum username length if necessary // Truncate data to maximum username length if necessary
@@ -193,6 +199,14 @@ public class LoginScreenPlugin extends Plugin implements KeyListener
// Truncate data to maximum password length if necessary // Truncate data to maximum password length if necessary
client.setPassword(data.substring(0, Math.min(data.length(), MAX_PASSWORD_LENGTH))); client.setPassword(data.substring(0, Math.min(data.length(), MAX_PASSWORD_LENGTH)));
} }
break;
// Authenticator form
case 4:
// Truncate data to maximum OTP code length if necessary
client.setOtp(data.substring(0, Math.min(data.length(), MAX_PIN_LENGTH)));
break;
}
} }
catch (UnsupportedFlavorException | IOException ex) catch (UnsupportedFlavorException | IOException ex)
{ {

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018, Seth <Sethtroll3@gmail.com> * Copyright (c) 2019, Adam <Adam@sigterm.info>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -24,97 +24,73 @@
*/ */
package net.runelite.client.plugins.mining; package net.runelite.client.plugins.mining;
import com.google.common.collect.ImmutableSet;
import java.awt.Color; import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.time.Duration;
import java.time.Instant; import java.time.Instant;
import java.util.Set; import java.util.Iterator;
import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
import static net.runelite.api.AnimationID.*;
import net.runelite.api.Client; import net.runelite.api.Client;
import net.runelite.api.Perspective;
import net.runelite.api.Point;
import net.runelite.api.coords.LocalPoint;
import net.runelite.api.coords.WorldPoint;
import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer;
import net.runelite.client.ui.overlay.OverlayPosition; import net.runelite.client.ui.overlay.OverlayPosition;
import net.runelite.client.ui.overlay.components.PanelComponent; import net.runelite.client.ui.overlay.components.ProgressPieComponent;
import net.runelite.client.ui.overlay.components.TitleComponent;
import net.runelite.client.ui.overlay.components.table.TableAlignment;
import net.runelite.client.ui.overlay.components.table.TableComponent;
class MiningOverlay extends Overlay class MiningOverlay extends Overlay
{ {
private static final Set<Integer> MINING_ANIMATION_IDS = ImmutableSet.of(
MINING_MOTHERLODE_BRONZE, MINING_MOTHERLODE_IRON, MINING_MOTHERLODE_STEEL,
MINING_MOTHERLODE_BLACK, MINING_MOTHERLODE_MITHRIL, MINING_MOTHERLODE_ADAMANT,
MINING_MOTHERLODE_RUNE, MINING_MOTHERLODE_DRAGON, MINING_MOTHERLODE_DRAGON_ORN,
MINING_MOTHERLODE_INFERNAL
);
private final Client client; private final Client client;
private final MiningPlugin plugin; private final MiningPlugin plugin;
private final MiningConfig config;
private final PanelComponent panelComponent = new PanelComponent();
@Inject @Inject
MiningOverlay(Client client, MiningPlugin plugin, MiningConfig config) private MiningOverlay(Client client, MiningPlugin plugin)
{ {
setPosition(OverlayPosition.TOP_LEFT); setPosition(OverlayPosition.DYNAMIC);
this.client = client; setLayer(OverlayLayer.ABOVE_SCENE);
this.plugin = plugin; this.plugin = plugin;
this.config = config; this.client = client;
} }
@Override @Override
public Dimension render(Graphics2D graphics) public Dimension render(Graphics2D graphics)
{ {
if (!plugin.isInMlm() || !config.showMiningStats()) List<RockRespawn> respawns = plugin.getRespawns();
if (respawns.isEmpty())
{ {
return null; return null;
} }
MiningSession session = plugin.getSession(); Instant now = Instant.now();
for (Iterator<RockRespawn> it = respawns.iterator(); it.hasNext();)
if (session.getLastPayDirtMined() == null)
{ {
RockRespawn rockRespawn = it.next();
float percent = (now.toEpochMilli() - rockRespawn.getStartTime().toEpochMilli()) / (float) rockRespawn.getRespawnTime();
WorldPoint worldPoint = rockRespawn.getWorldPoint();
LocalPoint loc = LocalPoint.fromWorld(client, worldPoint);
if (loc == null || percent > 1.0f)
{
it.remove();
continue;
}
Point point = Perspective.localToCanvas(client, loc, client.getPlane());
if (point == null)
{
it.remove();
continue;
}
ProgressPieComponent ppc = new ProgressPieComponent();
ppc.setBorderColor(Color.ORANGE);
ppc.setFill(Color.YELLOW);
ppc.setPosition(point);
ppc.setProgress(percent);
ppc.render(graphics);
}
return null; return null;
} }
Duration statTimeout = Duration.ofMinutes(config.statTimeout());
Duration sinceCut = Duration.between(session.getLastPayDirtMined(), Instant.now());
if (sinceCut.compareTo(statTimeout) >= 0)
{
return null;
}
panelComponent.getChildren().clear();
if (config.showMiningState())
{
if (MINING_ANIMATION_IDS.contains(client.getLocalPlayer().getAnimation()))
{
panelComponent.getChildren().add(TitleComponent.builder()
.text("Mining")
.color(Color.GREEN)
.build());
}
else
{
panelComponent.getChildren().add(TitleComponent.builder()
.text("NOT mining")
.color(Color.RED)
.build());
}
}
TableComponent tableComponent = new TableComponent();
tableComponent.setColumnAlignments(TableAlignment.LEFT, TableAlignment.RIGHT);
tableComponent.addRow("Pay-dirt mined:", Integer.toString(session.getTotalMined()));
tableComponent.addRow("Pay-dirt/hr:", session.getRecentMined() > 2 ? Integer.toString(session.getPerHour()) : "");
panelComponent.getChildren().add(tableComponent);
return panelComponent.render(graphics);
}
} }

View File

@@ -1,7 +1,5 @@
/* /*
* Copyright (c) 2018, Seth <Sethtroll3@gmail.com> * Copyright (c) 2019, Adam <Adam@sigterm.info>
* Copyright (c) 2018, Adam <Adam@sigterm.info>
* Copyright (c) 2018, Lars <lars.oernlo@gmail.com>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -26,63 +24,45 @@
*/ */
package net.runelite.client.plugins.mining; package net.runelite.client.plugins.mining;
import com.google.common.collect.ImmutableSet; import java.time.Instant;
import com.google.inject.Provides; import java.util.ArrayList;
import java.time.temporal.ChronoUnit; import java.util.List;
import java.util.HashSet;
import java.util.Set;
import javax.inject.Inject; import javax.inject.Inject;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client; import net.runelite.api.Client;
import net.runelite.api.GameObject; import net.runelite.api.GameObject;
import net.runelite.api.GameState; import net.runelite.api.GameState;
import net.runelite.api.ItemID; import static net.runelite.api.ObjectID.DEPLETED_VEIN_26665;
import static net.runelite.api.ObjectID.ORE_VEIN_26661; import static net.runelite.api.ObjectID.DEPLETED_VEIN_26666;
import static net.runelite.api.ObjectID.ORE_VEIN_26662; import static net.runelite.api.ObjectID.DEPLETED_VEIN_26667;
import static net.runelite.api.ObjectID.ORE_VEIN_26663; import static net.runelite.api.ObjectID.DEPLETED_VEIN_26668;
import static net.runelite.api.ObjectID.ORE_VEIN_26664; import static net.runelite.api.ObjectID.EMPTY_WALL;
import net.runelite.api.WallObject; import net.runelite.api.WallObject;
import net.runelite.api.events.GameObjectChanged;
import net.runelite.api.events.GameObjectDespawned; import net.runelite.api.events.GameObjectDespawned;
import net.runelite.api.events.GameObjectSpawned;
import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.GameStateChanged;
import net.runelite.client.callback.ClientThread; import net.runelite.api.events.GameTick;
import net.runelite.client.config.ConfigManager; import net.runelite.api.events.WallObjectSpawned;
import net.runelite.client.eventbus.Subscribe; import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.plugins.PluginType;
import net.runelite.client.task.Schedule;
import net.runelite.client.ui.overlay.OverlayManager; import net.runelite.client.ui.overlay.OverlayManager;
@Slf4j
@PluginDescriptor( @PluginDescriptor(
name = "Mining", name = "Mining",
description = "Show helpful information about Mining", description = "Show ore respawn timers",
tags = {"mining", "skilling", "overlay"}, tags = {"overlay", "skilling", "timers"},
type = PluginType.SKILLING,
enabledByDefault = false enabledByDefault = false
) )
public class MiningPlugin extends Plugin public class MiningPlugin extends Plugin
{ {
private static final Set<Integer> MOTHERLODE_MAP_REGIONS = ImmutableSet.of(14679, 14680, 14681, 14935, 14936, 14937, 15191, 15192, 15193); private static final int ROCK_DISTANCE = 14;
private static final Set<Integer> MINE_SPOTS = ImmutableSet.of(ORE_VEIN_26661, ORE_VEIN_26662, ORE_VEIN_26663, ORE_VEIN_26664); private static final int MINING_GUILD_REGION = 12183;
private static final Set<Integer> MLM_ORE_TYPES = ImmutableSet.of(ItemID.RUNITE_ORE, ItemID.ADAMANTITE_ORE,
ItemID.MITHRIL_ORE, ItemID.GOLD_ORE, ItemID.COAL, ItemID.GOLDEN_NUGGET);
private static final Set<Integer> MINING_ROCKS = ImmutableSet.of(
// another website says depleted rocks are 7468, 7469
// website says stoney 2902, 2962, 2963, 2964,
2231, 2257, 2584, 2704, 3722, 3723, 3748, 3790, 3791, 3803, 3804, 3805, 3806, 3807, 3808, 4437, 4438, 4676, 6669, 6670, 6671, 6672, 6673, 7453, 7454, 7455, 7456, 7457, 7458, 7459, 7460, 7461, 7462, 7463, 7464, 7467, 7470, 7484, 7485, 7486, 7487, 7488, 7489, 7490, 7491, 7492, 7493, 7494, 7495, 8727, 8828, 8829, 8830, 10079, 10080, 10081, 11441, 11924, 12590, 15127, 15128, 15213, 16464, 16514, 16515, 16521, 16522, 16523, 16524, 16534, 16535, 16545, 16549, 16550, 16998, 16999, 17042, 17043, 17064, 17065, 18817, 18840, 18952, 18953, 18954, 18961, 19849, 19969, 19970, 19971, 19972, 19973, 22665, 22667, 23280, 23281, 23640, 24146, 24147, 24148, 24557, 26873, 26874, 27984, 27985, 27987, 27988, 28596, 28597, 28752, 28753, 28890
//2090, 2091, 2092, 2093, 2094, 2095, 2096, 2097, 2098, 2099, 2100, 2101, 2102, 2103, 2104, 2105, 2106, 2107, 2108, 2109, 2110, 2111, 2119, 2120, 2121, 2122, 2123, 2124, 2125, 2126, 2127, 2128, 2129, 2130, 2131, 2132, 2133, 2134, 2135, 2136, 2137, 2138, 2139, 2140, 2231, 2257, 2328, 3042, 3043, 3722, 3723, 3748, 3790, 3791, 3803, 3804, 4676, 6943, 6944, 6945, 6946, 6947, 6948, 9296, 9297, 9303, 9304, 9305, 9306, 9316, 9317, 9331, 9332, 9335, 9336, 9708, 9709, 9710, 9711, 9712, 9713, 9714, 9715, 9716, 9717, 9718, 9719, 9720, 9721, 9722, 9723, 9724, 9725, 9726, 9727, 9728, 9729, 9730, 9731, 9732, 9733, 9734, 9735, 9736, 9737, 10583, 10584, 10585, 10586, 10587, 10944, 10945, 10946, 10947, 10948, 10949, 11165, 11166, 11167, 11168, 11169, 11170, 11171, 11172, 11173, 11174, 11175, 11176, 11177, 11178, 11179, 11180, 11181, 11182, 11183, 11184, 11185, 11186, 11187, 11188, 11189, 11190, 11191, 11192, 11193, 11194, 11195, 11424, 11425, 11426, 11427, 11428, 11429, 11430, 11431, 11432, 11433, 11434, 11435, 11436, 11437, 11438, 11439, 11440, 11441, 11442, 11443, 11444, 11552, 11553, 11554, 11555, 11556, 11557, 11915, 11916, 11917, 11918, 11919, 11920, 11921, 11922, 11923, 11924, 11925, 11926, 11927, 11928, 11929, 11930, 11931, 11932, 11933, 11934, 11935, 11936, 11937, 11938, 11939, 11940, 11941, 11942, 11943, 11944, 11945, 11946, 11947, 11948, 11949, 11950, 11951, 11952, 11953, 11954, 11955, 11956, 11957, 11958, 11959, 11960, 11961, 11962, 11963, 11964, 11965
//968, 1480, 1855, 4043, 4487, 7533, 9716, 21250, 1997, 2581, 2582, 2694, 2695, 2696, 2697, 2835, 2836, 2837, 2901, 2965, 3339, 3364, 4526, 4552, 4553, 4554, 4555, 4556, 4557, 4558, 4887, 5604, 5605, 5606, 5844, 5845, 5896, 5985, 5987, 6622, 6623, 6707, 6708, 6709, 7466, 8725, 8726, 8950, 8951, 8952, 9031, 9032, 10036, 10782, 10783, 10784, 10785, 10786, 10787, 10788, 11097, 11098, 11182, 11183, 11424, 11425, 12564, 12565, 12566, 12567, 12588, 12589, 12774, 14814, 14815, 14816, 14817, 15198, 15199, 15217, 15218, 15219, 15410, 15536, 15537, 16077, 16078, 16079, 16080, 16115, 16136, 16284, 16303, 17350, 17351, 17352, 17353, 17354, 17355, 17356, 17357, 17358, 17364, 17365, 17366, 17679, 17958, 17959, 17960, 17970, 17971, 17972, 18871, 18872, 18873, 19131, 21571, 21572, 21573, 22549, 22550, 22551, 23124, 23125, 23126, 23127, 23165, 23976, 23977, 23978, 23979, 23980, 23981, 24693, 24694, 24695, 24696, 24697, 24698, 24699, 24700, 24701, 24781, 25158, 25159, 25160, 25422, 25423, 26372, 26373, 26376, 26377, 26850, 26856, 28580, 29102, 29883, 29884, 29885, 30344, 30519, 30521, 30522, 30857, 30858, 31045, 31781, 31782, 31783, 31784, 31785, 31786, 31787, 31788, 31789
);
private static final int MAX_INVENTORY_SIZE = 28;
// private static final int SACK_LARGE_SIZE = 162; @Inject
// private static final int SACK_SIZE = 81; private Client client;
//
// private static final int UPPER_FLOOR_HEIGHT = -500;
@Inject @Inject
private OverlayManager overlayManager; private OverlayManager overlayManager;
@@ -90,278 +70,99 @@ public class MiningPlugin extends Plugin
@Inject @Inject
private MiningOverlay overlay; private MiningOverlay overlay;
@Inject
private MiningRocksOverlay rocksOverlay;
@Inject
private MiningConfig config;
@Inject
private Client client;
@Inject
private ClientThread clientThread;
@Getter(AccessLevel.PACKAGE) @Getter(AccessLevel.PACKAGE)
private boolean inMlm; private final List<RockRespawn> respawns = new ArrayList<>();
private boolean recentlyLoggedIn;
@Getter(AccessLevel.PACKAGE)
private int curSackSize;
@Getter(AccessLevel.PACKAGE)
private int maxSackSize;
@Getter(AccessLevel.PACKAGE)
private Integer depositsLeft;
private MiningSession session;
@Getter(AccessLevel.PACKAGE)
private final Set<WallObject> veins = new HashSet<>();
@Getter(AccessLevel.PACKAGE)
private final Set<GameObject> rocks = new HashSet<>();
@Provides
MiningConfig getConfig(ConfigManager configManager)
{
return configManager.getConfig(MiningConfig.class);
}
@Override @Override
protected void startUp() protected void startUp()
{ {
overlayManager.add(overlay); overlayManager.add(overlay);
overlayManager.add(rocksOverlay);
// overlayManager.add(motherlodeGemOverlay);
// overlayManager.add(motherlodeSackOverlay);
session = new MiningSession();
//inMlm = checkInMlm();
// if (inMlm)
// {
// clientThread.invokeLater(this::refreshSackValues);
// }
} }
@Override @Override
protected void shutDown() throws Exception protected void shutDown() throws Exception
{ {
overlayManager.remove(overlay); overlayManager.remove(overlay);
overlayManager.remove(rocksOverlay); respawns.clear();
// overlayManager.remove(motherlodeGemOverlay);
// overlayManager.remove(motherlodeSackOverlay);
session = null;
// veins.clear();
rocks.clear();
// Widget sack = client.getWidget(WidgetInfo.MOTHERLODE_MINE);
// clientThread.invokeLater(() ->
// {
// if (sack != null && sack.isHidden())
// {
// sack.setHidden(false);
// }
// });
}
public MiningSession getSession()
{
return session;
}
// @Subscribe
// public void onVarbitChanged(VarbitChanged event)
// {
// if (inMlm)
// {
// refreshSackValues();
// }
// }
// @Subscribe
// public void onChatMessage(ChatMessage event)
// {
// if (!inMlm || event.getType() != ChatMessageType.FILTERED)
// {
// return;
// }
//
// String chatMessage = event.getMessage();
//
// switch (chatMessage)
// {
// case "You manage to mine some pay-dirt.":
// session.incrementPayDirtMined();
// break;
//
// case "You just found a Diamond!":
// session.incrementGemFound(ItemID.UNCUT_DIAMOND);
// break;
//
// case "You just found a Ruby!":
// session.incrementGemFound(ItemID.UNCUT_RUBY);
// break;
//
// case "You just found an Emerald!":
// session.incrementGemFound(ItemID.UNCUT_EMERALD);
// break;
//
// case "You just found a Sapphire!":
// session.incrementGemFound(ItemID.UNCUT_SAPPHIRE);
// break;
// }
// }
@Schedule(
period = 1,
unit = ChronoUnit.SECONDS
)
// public void checkMining()
// {
// if (!inMlm)
// {
// return;
// }
//
// depositsLeft = calculateDepositsLeft();
//
// Instant lastPayDirtMined = session.getLastPayDirtMined();
// if (lastPayDirtMined == null)
// {
// return;
// }
//
// // reset recentPayDirtMined if you haven't mined anything recently
// Duration statTimeout = Duration.ofMinutes(config.statTimeout());
// Duration sinceMined = Duration.between(lastPayDirtMined, Instant.now());
//
// if (sinceMined.compareTo(statTimeout) >= 0)
// {
// session.resetRecent();
// }
// }
@Subscribe
public void onGameObjectSpawned(GameObjectSpawned event)
{
GameObject gameObject = event.getGameObject();
if (MINING_ROCKS.contains(gameObject.getId()))
{
rocks.add(gameObject);
}
}
@Subscribe
public void onGameObjectChanged(GameObjectChanged event)
{
GameObject previous = event.getPrevious();
GameObject gameObject = event.getGameObject();
rocks.remove(previous);
if (MINING_ROCKS.contains(gameObject.getId()))
{
rocks.add(gameObject);
}
}
@Subscribe
public void onGameObjectDespawned(GameObjectDespawned event)
{
GameObject gameObject = event.getGameObject();
rocks.remove(gameObject);
} }
@Subscribe @Subscribe
public void onGameStateChanged(GameStateChanged event) public void onGameStateChanged(GameStateChanged event)
{ {
if (event.getGameState() == GameState.LOADING) switch (event.getGameState())
{ {
// on region changes the tiles get set to null case LOADING:
rocks.clear(); case HOPPING:
respawns.clear();
break;
case LOGGED_IN:
// After login rocks that are depleted will be changed,
// so wait for the next game tick before watching for
// rocks to deplete
recentlyLoggedIn = true;
break;
} }
} }
// private Integer calculateDepositsLeft() @Subscribe
// { public void onGameTick(GameTick gameTick)
// if (maxSackSize == 0) // check if maxSackSize has been initialized {
// { recentlyLoggedIn = false;
// refreshSackValues(); }
// }
// @Subscribe
// double depositsLeft = 0; public void onGameObjectDespawned(GameObjectDespawned event)
// int nonPayDirtItems = 0; {
// if (client.getGameState() != GameState.LOGGED_IN || recentlyLoggedIn)
// ItemContainer inventory = client.getItemContainer(InventoryID.INVENTORY); {
// if (inventory == null) return;
// { }
// return null;
// } final GameObject object = event.getGameObject();
//
// Item[] result = inventory.getItems(); Rock rock = Rock.getRock(object.getId());
// assert result != null; if (rock != null)
// {
// for (Item item : result) RockRespawn rockRespawn = new RockRespawn(rock, object.getWorldLocation(), Instant.now(), (int) rock.getRespawnTime(inMiningGuild()).toMillis());
// { respawns.add(rockRespawn);
// // Assume that MLM ores are being banked and exclude them from the check, }
// // so the user doesn't see the Overlay switch between deposits left and N/A. }
// //
// // Count other items at nonPayDirtItems so depositsLeft is calculated accordingly. @Subscribe
// if (item.getId() != ItemID.PAYDIRT && item.getId() != -1 && !MLM_ORE_TYPES.contains(item.getId())) public void onWallObjectSpawned(WallObjectSpawned event)
// { {
// nonPayDirtItems += 1; if (client.getGameState() != GameState.LOGGED_IN)
// } {
// } return;
// }
// double inventorySpace = MAX_INVENTORY_SIZE - nonPayDirtItems;
// double sackSizeRemaining = maxSackSize - curSackSize; final WallObject object = event.getWallObject();
//
// if (inventorySpace > 0 && sackSizeRemaining > 0) switch (object.getId())
// { {
// depositsLeft = Math.ceil(sackSizeRemaining / inventorySpace); case EMPTY_WALL:
// } {
// else if (inventorySpace == 0) Rock rock = Rock.AMETHYST;
// { RockRespawn rockRespawn = new RockRespawn(rock, object.getWorldLocation(), Instant.now(), (int) rock.getRespawnTime(inMiningGuild()).toMillis());
// return null; respawns.add(rockRespawn);
// } break;
// }
// return (int) depositsLeft; case DEPLETED_VEIN_26665: // Depleted motherlode vein
// } case DEPLETED_VEIN_26666: // Depleted motherlode vein
// case DEPLETED_VEIN_26667: // Depleted motherlode vein
// private boolean checkInMlm() case DEPLETED_VEIN_26668: // Depleted motherlode vein
// { {
// if (client.getGameState() != GameState.LOGGED_IN) Rock rock = Rock.ORE_VEIN;
// { RockRespawn rockRespawn = new RockRespawn(rock, object.getWorldLocation(), Instant.now(), (int) rock.getRespawnTime(inMiningGuild()).toMillis());
// return false; respawns.add(rockRespawn);
// } break;
// }
// int[] currentMapRegions = client.getMapRegions(); }
// }
// // Verify that all regions exist in MOTHERLODE_MAP_REGIONS
// for (int region : currentMapRegions) private boolean inMiningGuild()
// { {
// if (!MOTHERLODE_MAP_REGIONS.contains(region)) return client.getLocalPlayer().getWorldLocation().getRegionID() == MINING_GUILD_REGION;
// { }
// return false;
// }
// }
//
// return true;
// }
//
// private void refreshSackValues()
// {
// curSackSize = client.getVar(Varbits.SACK_NUMBER);
// boolean sackUpgraded = client.getVar(Varbits.SACK_UPGRADED) == 1;
// maxSackSize = sackUpgraded ? SACK_LARGE_SIZE : SACK_SIZE;
// }
//
// /**
// * Checks if the given point is "upstairs" in the mlm.
// * The upper floor is actually on z=0.
// * @param localPoint
// * @return
// */
// boolean isUpstairs(LocalPoint localPoint)
// {
// return Perspective.getTileHeight(client, localPoint, 0) < UPPER_FLOOR_HEIGHT;
// }
} }

View File

@@ -1,115 +0,0 @@
/*
* Copyright (c) 2018, Seth <Sethtroll3@gmail.com>
* Copyright (c) 2018, Adam <Adam@sigterm.info>
* Copyright (c) 2018, Lars <lars.oernlo@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.mining;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.inject.Inject;
import net.runelite.api.Client;
import net.runelite.api.GameObject;
import net.runelite.api.Perspective;
import net.runelite.api.Player;
import net.runelite.api.Point;
import net.runelite.api.Skill;
import net.runelite.api.coords.LocalPoint;
import net.runelite.client.game.SkillIconManager;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer;
import net.runelite.client.ui.overlay.OverlayPosition;
class MiningRocksOverlay extends Overlay
{
private static final int MAX_DISTANCE = 2350;
private final Client client;
private final MiningPlugin plugin;
private final MiningConfig config;
private final BufferedImage miningIcon;
@Inject
MiningRocksOverlay(Client client, MiningPlugin plugin, MiningConfig config, SkillIconManager iconManager)
{
setPosition(OverlayPosition.DYNAMIC);
setLayer(OverlayLayer.ABOVE_SCENE);
this.client = client;
this.plugin = plugin;
this.config = config;
miningIcon = iconManager.getSkillImage(Skill.MINING);
}
@Override
public Dimension render(Graphics2D graphics)
{
Player local = client.getLocalPlayer();
renderTiles(graphics, local);
return null;
}
private void renderTiles(Graphics2D graphics, Player local)
{
LocalPoint localLocation = local.getLocalLocation();
if (config.showMiningRocks())
{
for (GameObject rock : plugin.getRocks())
{
LocalPoint location = rock.getLocalLocation();
if (localLocation.distanceTo(location) <= MAX_DISTANCE)
{
renderMiningRock(graphics, rock);
}
}
}
}
private void renderMiningRock(Graphics2D graphics, GameObject rock)
{
Point canvasLoc = Perspective.getCanvasImageLocation(client, rock.getLocalLocation(), miningIcon, 0);
if (canvasLoc != null)
{
graphics.drawImage(miningIcon, canvasLoc.getX(), canvasLoc.getY(), null);
}
}
// private void renderMiningRockSquare(Graphics2D graphics, GameObject rock)
// {
// Polygon poly = Perspective.getCanvasTilePoly(client, rock.getLocalLocation());
//
// if (poly != null)
// {
// OverlayUtil.renderPolygon(graphics, poly, Color.red);
// }
// }
}

View File

@@ -1,139 +0,0 @@
/*
* 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.mining;
import java.time.Duration;
import java.time.Instant;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.ItemID;
@Slf4j
public class MiningSession
{
private static final Duration HOUR = Duration.ofHours(1);
private int perHour;
private Instant lastPayDirtMined;
private int totalMined;
private Instant recentPayDirtMined;
private int recentMined;
@Getter(AccessLevel.PACKAGE)
private Instant lastGemFound;
@Getter(AccessLevel.PACKAGE)
private int diamondsFound;
@Getter(AccessLevel.PACKAGE)
private int rubiesFound;
@Getter(AccessLevel.PACKAGE)
private int emeraldsFound;
@Getter(AccessLevel.PACKAGE)
private int sapphiresFound;
public void incrementGemFound(int gemID)
{
lastGemFound = Instant.now();
switch (gemID)
{
case ItemID.UNCUT_DIAMOND:
diamondsFound++;
break;
case ItemID.UNCUT_RUBY:
rubiesFound++;
break;
case ItemID.UNCUT_EMERALD:
emeraldsFound++;
break;
case ItemID.UNCUT_SAPPHIRE:
sapphiresFound++;
break;
default:
log.error("Invalid gem type specified. The gem count will not be incremented.");
}
}
public void incrementPayDirtMined()
{
Instant now = Instant.now();
lastPayDirtMined = now;
++totalMined;
if (recentMined == 0)
{
recentPayDirtMined = now;
}
++recentMined;
Duration timeSinceStart = Duration.between(recentPayDirtMined, now);
if (!timeSinceStart.isZero())
{
perHour = (int) ((double) recentMined * (double) HOUR.toMillis() / (double) timeSinceStart.toMillis());
}
}
public void resetRecent()
{
recentPayDirtMined = null;
recentMined = 0;
}
public int getPerHour()
{
return perHour;
}
public Instant getLastPayDirtMined()
{
return lastPayDirtMined;
}
public int getTotalMined()
{
return totalMined;
}
public Instant getRecentPayDirtMined()
{
return recentPayDirtMined;
}
public int getRecentMined()
{
return recentMined;
}
}

View File

@@ -0,0 +1,129 @@
/*
* Copyright (c) 2019, 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.mining;
import com.google.common.collect.ImmutableMap;
import java.time.Duration;
import java.util.Map;
import static net.runelite.api.ObjectID.ROCKS_11161;
import static net.runelite.api.ObjectID.ROCKS_11360;
import static net.runelite.api.ObjectID.ROCKS_11361;
import static net.runelite.api.ObjectID.ROCKS_11364;
import static net.runelite.api.ObjectID.ROCKS_11365;
import static net.runelite.api.ObjectID.ROCKS_11366;
import static net.runelite.api.ObjectID.ROCKS_11367;
import static net.runelite.api.ObjectID.ROCKS_11369;
import static net.runelite.api.ObjectID.ROCKS_11370;
import static net.runelite.api.ObjectID.ROCKS_11371;
import static net.runelite.api.ObjectID.ROCKS_11372;
import static net.runelite.api.ObjectID.ROCKS_11373;
import static net.runelite.api.ObjectID.ROCKS_11374;
import static net.runelite.api.ObjectID.ROCKS_11375;
import static net.runelite.api.ObjectID.ROCKS_11376;
import static net.runelite.api.ObjectID.ROCKS_11377;
enum Rock
{
TIN(Duration.ofMillis(2300), ROCKS_11360, ROCKS_11361),
COPPER(Duration.ofMillis(2200), ROCKS_11161),
IRON(Duration.ofMillis(5300), ROCKS_11364, ROCKS_11365)
{
@Override
Duration getRespawnTime(boolean inMiningGuild)
{
return inMiningGuild ? Duration.ofMillis(2200) : super.respawnTime;
}
},
COAL(Duration.ofSeconds(40), ROCKS_11366, ROCKS_11367)
{
@Override
Duration getRespawnTime(boolean inMiningGuild)
{
return inMiningGuild ? Duration.ofMillis(14_500) : super.respawnTime;
}
},
SILVER(Duration.ofMinutes(1), ROCKS_11369),
GOLD(Duration.ofMinutes(1), ROCKS_11370, ROCKS_11371),
MITHRIL(Duration.ofMinutes(2), ROCKS_11372, ROCKS_11373)
{
@Override
Duration getRespawnTime(boolean inMiningGuild)
{
return inMiningGuild ? Duration.ofMinutes(1) : super.respawnTime;
}
},
ADAMANTITE(Duration.ofMinutes(4), ROCKS_11374, ROCKS_11375)
{
@Override
Duration getRespawnTime(boolean inMiningGuild)
{
return inMiningGuild ? Duration.ofMinutes(2) : super.respawnTime;
}
},
RUNITE(Duration.ofMinutes(12), ROCKS_11376, ROCKS_11377)
{
@Override
Duration getRespawnTime(boolean inMiningGuild)
{
return inMiningGuild ? Duration.ofMinutes(6) : super.respawnTime;
}
},
ORE_VEIN(Duration.ofSeconds(108)),
AMETHYST(Duration.ofSeconds(75));
private static final Map<Integer, Rock> ROCKS;
static
{
ImmutableMap.Builder<Integer, Rock> builder = new ImmutableMap.Builder<>();
for (Rock rock : values())
{
for (int id : rock.ids)
{
builder.put(id, rock);
}
}
ROCKS = builder.build();
}
private final Duration respawnTime;
private final int[] ids;
Rock(Duration respawnTime, int... ids)
{
this.respawnTime = respawnTime;
this.ids = ids;
}
Duration getRespawnTime(boolean inMiningGuild)
{
return respawnTime;
}
static Rock getRock(int id)
{
return ROCKS.get(id);
}
}

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019, Lucas C <lucas1757@gmail.com> * Copyright (c) 2019, Adam <Adam@sigterm.info>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -22,19 +22,19 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package net.runelite.client.plugins.cooking; package net.runelite.client.plugins.mining;
import java.time.Instant; import java.time.Instant;
import lombok.AccessLevel; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import net.runelite.api.coords.WorldPoint;
class FermentTimerSession @AllArgsConstructor
@Getter
class RockRespawn
{ {
@Getter(AccessLevel.PACKAGE) private final Rock rock;
private Instant lastWineMakingAction; private final WorldPoint worldPoint;
private final Instant startTime;
void updateLastWineMakingAction() private final int respawnTime;
{
this.lastWineMakingAction = Instant.now();
}
} }

View File

@@ -123,6 +123,8 @@ public class MusicListPlugin extends Plugin
return; return;
} }
header.deleteAllChildren();
//Creation of the search and toggle status buttons //Creation of the search and toggle status buttons
musicSearchButton = header.createChild(-1, WidgetType.GRAPHIC); musicSearchButton = header.createChild(-1, WidgetType.GRAPHIC);
musicSearchButton.setSpriteId(SpriteID.GE_SEARCH); musicSearchButton.setSpriteId(SpriteID.GE_SEARCH);

View File

@@ -134,6 +134,8 @@ public class QuestListPlugin extends Plugin
Widget header = client.getWidget(WidgetInfo.QUESTLIST_BOX); Widget header = client.getWidget(WidgetInfo.QUESTLIST_BOX);
if (header != null) if (header != null)
{ {
header.deleteAllChildren();
questSearchButton = header.createChild(-1, WidgetType.GRAPHIC); questSearchButton = header.createChild(-1, WidgetType.GRAPHIC);
questSearchButton.setSpriteId(SpriteID.GE_SEARCH); questSearchButton.setSpriteId(SpriteID.GE_SEARCH);
questSearchButton.setOriginalWidth(18); questSearchButton.setOriginalWidth(18);

View File

@@ -118,13 +118,13 @@ public class RunepouchOverlay extends WidgetItemOverlay
} }
graphics.setColor(Color.black); graphics.setColor(Color.black);
graphics.drawString("" + formatNumber(amount), location.getX() + (config.showIcons() ? 13 : 6),
location.getY() + 14 + (graphics.getFontMetrics().getHeight() - 1) * i);
graphics.setColor(config.fontColor());
graphics.drawString("" + formatNumber(amount), location.getX() + (config.showIcons() ? 12 : 5), graphics.drawString("" + formatNumber(amount), location.getX() + (config.showIcons() ? 12 : 5),
location.getY() + 13 + (graphics.getFontMetrics().getHeight() - 1) * i); location.getY() + 13 + (graphics.getFontMetrics().getHeight() - 1) * i);
graphics.setColor(config.fontColor());
graphics.drawString("" + formatNumber(amount), location.getX() + (config.showIcons() ? 11 : 4),
location.getY() + 12 + (graphics.getFontMetrics().getHeight() - 1) * i);
if (!config.showIcons()) if (!config.showIcons())
{ {
continue; continue;
@@ -134,7 +134,7 @@ public class RunepouchOverlay extends WidgetItemOverlay
if (image != null) if (image != null)
{ {
OverlayUtil.renderImageLocation(graphics, OverlayUtil.renderImageLocation(graphics,
new Point(location.getX(), location.getY() + graphics.getFontMetrics().getHeight() * i), new Point(location.getX() - 1, location.getY() + graphics.getFontMetrics().getHeight() * i - 1),
image); image);
} }
} }

View File

@@ -124,8 +124,8 @@ class SlayerOverlay extends WidgetItemOverlay
textComponent.setText(String.valueOf(amount)); textComponent.setText(String.valueOf(amount));
// Draw the counter in the top left for equipment, and bottom left for jewelry // Draw the counter in the bottom left for equipment, and top left for jewelry
textComponent.setPosition(new Point(bounds.x, bounds.y + (SLAYER_JEWELRY.contains(itemId) textComponent.setPosition(new Point(bounds.x - 1, bounds.y - 1 + (SLAYER_JEWELRY.contains(itemId)
? bounds.height ? bounds.height
: graphics.getFontMetrics().getHeight()))); : graphics.getFontMetrics().getHeight())));
textComponent.render(graphics); textComponent.render(graphics);

View File

@@ -1,177 +0,0 @@
/*
* Copyright (c) 2018, Adam <Adam@sigterm.info>
* Copyright (c) 2018, Abexlry <abexlry@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.wasdcamera;
import com.google.common.base.Strings;
import java.awt.event.KeyEvent;
import java.util.HashMap;
import java.util.Map;
import javax.inject.Inject;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.VarClientStr;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.input.KeyListener;
import net.runelite.client.input.MouseAdapter;
class WASDCameraListener extends MouseAdapter implements KeyListener
{
@Inject
private WASDCameraPlugin plugin;
@Inject
private WASDCameraConfig config;
@Inject
private Client client;
@Inject
private ClientThread clientThread;
private final Map<Integer, Integer> modified = new HashMap<>();
@Override
public void keyTyped(KeyEvent e)
{
}
@Override
public void keyPressed(KeyEvent e)
{
if (client.getGameState() != GameState.LOGGED_IN || !plugin.chatboxFocused())
{
return;
}
if (!plugin.isTyping())
{
if (config.up().matches(e))
{
modified.put(e.getKeyCode(), KeyEvent.VK_UP);
e.setKeyCode(KeyEvent.VK_UP);
}
else if (config.down().matches(e))
{
modified.put(e.getKeyCode(), KeyEvent.VK_DOWN);
e.setKeyCode(KeyEvent.VK_DOWN);
}
else if (config.left().matches(e))
{
modified.put(e.getKeyCode(), KeyEvent.VK_LEFT);
e.setKeyCode(KeyEvent.VK_LEFT);
}
else if (config.right().matches(e))
{
modified.put(e.getKeyCode(), KeyEvent.VK_RIGHT);
e.setKeyCode(KeyEvent.VK_RIGHT);
}
else
{
switch (e.getKeyCode())
{
case KeyEvent.VK_ENTER:
case KeyEvent.VK_SLASH:
case KeyEvent.VK_COLON:
// refocus chatbox
plugin.setTyping(true);
clientThread.invoke(() ->
{
plugin.unlockChat();
});
break;
}
}
}
else
{
switch (e.getKeyCode())
{
case KeyEvent.VK_ENTER:
plugin.setTyping(false);
clientThread.invoke(() ->
{
plugin.lockChat();
});
break;
case KeyEvent.VK_ESCAPE:
plugin.setTyping(false);
clientThread.invoke(() ->
{
client.setVar(VarClientStr.CHATBOX_TYPED_TEXT, "");
plugin.lockChat();
});
break;
case KeyEvent.VK_BACK_SPACE:
if (Strings.isNullOrEmpty(client.getVar(VarClientStr.CHATBOX_TYPED_TEXT)))
{
plugin.setTyping(false);
clientThread.invoke(() -> plugin.lockChat());
}
}
}
}
@Override
public void keyReleased(KeyEvent e)
{
if (client.getGameState() != GameState.LOGGED_IN)
{
return;
}
if (plugin.chatboxFocused() && !plugin.isTyping())
{
modified.remove(e.getKeyCode());
if (config.up().matches(e))
{
e.setKeyCode(KeyEvent.VK_UP);
}
else if (config.down().matches(e))
{
e.setKeyCode(KeyEvent.VK_DOWN);
}
else if (config.left().matches(e))
{
e.setKeyCode(KeyEvent.VK_LEFT);
}
else if (config.right().matches(e))
{
e.setKeyCode(KeyEvent.VK_RIGHT);
}
}
else
{
// press d + enter + release d - causes the right arrow to never be released
Integer m = modified.get(e.getKeyCode());
if (m != null)
{
modified.remove(e.getKeyCode());
e.setKeyCode(m);
}
}
}
}

View File

@@ -3314,7 +3314,7 @@
"21521": 250, "21521": 250,
"21543": 13000, "21543": 13000,
"21545": 13000, "21545": 13000,
"21555": 18000, "21555": 30000,
"21622": 13000, "21622": 13000,
"21634": 8, "21634": 8,
"21637": 5, "21637": 5,

View File

@@ -30,14 +30,23 @@ import com.google.inject.testing.fieldbinder.BoundFieldModule;
import javax.inject.Inject; import javax.inject.Inject;
import net.runelite.api.ChatMessageType; import net.runelite.api.ChatMessageType;
import net.runelite.api.Client; import net.runelite.api.Client;
import net.runelite.api.GraphicID;
import net.runelite.api.Player;
import net.runelite.api.events.ChatMessage; import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.GraphicChanged;
import net.runelite.client.game.ItemManager;
import net.runelite.client.ui.overlay.OverlayManager; import net.runelite.client.ui.overlay.OverlayManager;
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import static org.mockito.Matchers.any;
import org.mockito.Mock; import org.mockito.Mock;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.mockito.runners.MockitoJUnitRunner; import org.mockito.runners.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class) @RunWith(MockitoJUnitRunner.class)
@@ -60,6 +69,14 @@ public class CookingPluginTest
@Bind @Bind
Client client; Client client;
@Mock
@Bind
InfoBoxManager infoBoxManager;
@Mock
@Bind
ItemManager itemManager;
@Mock @Mock
@Bind @Bind
CookingConfig config; CookingConfig config;
@@ -68,10 +85,6 @@ public class CookingPluginTest
@Bind @Bind
CookingOverlay cookingOverlay; CookingOverlay cookingOverlay;
@Mock
@Bind
FermentTimerOverlay fermentTimerOverlay;
@Mock @Mock
@Bind @Bind
OverlayManager overlayManager; OverlayManager overlayManager;
@@ -91,8 +104,24 @@ public class CookingPluginTest
cookingPlugin.onChatMessage(chatMessage); cookingPlugin.onChatMessage(chatMessage);
} }
CookingSession cookingSession = cookingPlugin.getCookingSession(); CookingSession cookingSession = cookingPlugin.getSession();
assertNotNull(cookingSession); assertNotNull(cookingSession);
assertEquals(COOKING_MESSAGES.length, cookingSession.getCookAmount()); assertEquals(COOKING_MESSAGES.length, cookingSession.getCookAmount());
} }
@Test
public void testOnGraphicChanged()
{
Player player = mock(Player.class);
when(player.getGraphic()).thenReturn(GraphicID.WINE_MAKE);
when(config.fermentTimer()).thenReturn(true);
when(client.getLocalPlayer()).thenReturn(player);
GraphicChanged graphicChanged = new GraphicChanged();
graphicChanged.setActor(player);
cookingPlugin.onGraphicChanged(graphicChanged);
verify(infoBoxManager).addInfoBox(any(FermentTimer.class));
}
} }

View File

@@ -26,12 +26,10 @@ package net.runelite.mixins;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import net.runelite.api.Actor;
import net.runelite.api.CollisionData; import net.runelite.api.CollisionData;
import net.runelite.api.CollisionDataFlag; import net.runelite.api.CollisionDataFlag;
import net.runelite.api.Constants; import net.runelite.api.Constants;
import net.runelite.api.DecorativeObject; import net.runelite.api.DecorativeObject;
import net.runelite.api.GameObject;
import net.runelite.api.GroundObject; import net.runelite.api.GroundObject;
import net.runelite.api.Item; import net.runelite.api.Item;
import net.runelite.api.ItemLayer; import net.runelite.api.ItemLayer;
@@ -59,13 +57,18 @@ import net.runelite.api.mixins.FieldHook;
import net.runelite.api.mixins.Inject; import net.runelite.api.mixins.Inject;
import net.runelite.api.mixins.Mixin; import net.runelite.api.mixins.Mixin;
import net.runelite.api.mixins.Shadow; import net.runelite.api.mixins.Shadow;
import net.runelite.rs.api.RSActor;
import net.runelite.rs.api.RSClient; import net.runelite.rs.api.RSClient;
import net.runelite.rs.api.RSDeque; import net.runelite.rs.api.RSDeque;
import net.runelite.rs.api.RSGameObject; import net.runelite.rs.api.RSGameObject;
import net.runelite.rs.api.RSGraphicsObject;
import net.runelite.rs.api.RSItem; import net.runelite.rs.api.RSItem;
import net.runelite.rs.api.RSItemLayer; import net.runelite.rs.api.RSItemLayer;
import net.runelite.rs.api.RSNode; import net.runelite.rs.api.RSNode;
import net.runelite.rs.api.RSProjectile;
import net.runelite.rs.api.RSRenderable;
import net.runelite.rs.api.RSTile; import net.runelite.rs.api.RSTile;
import org.slf4j.Logger;
@Mixin(RSTile.class) @Mixin(RSTile.class)
public abstract class RSTileMixin implements RSTile public abstract class RSTileMixin implements RSTile
@@ -73,9 +76,6 @@ public abstract class RSTileMixin implements RSTile
@Shadow("clientInstance") @Shadow("clientInstance")
private static RSClient client; private static RSClient client;
@Inject
private static GameObject lastGameObject;
@Inject @Inject
private static RSDeque[][][] lastGroundItems = new RSDeque[Constants.MAX_Z][Constants.SCENE_SIZE][Constants.SCENE_SIZE]; private static RSDeque[][][] lastGroundItems = new RSDeque[Constants.MAX_Z][Constants.SCENE_SIZE][Constants.SCENE_SIZE];
@@ -89,7 +89,7 @@ public abstract class RSTileMixin implements RSTile
private GroundObject previousGroundObject; private GroundObject previousGroundObject;
@Inject @Inject
private GameObject[] previousGameObjects; private RSGameObject[] previousGameObjects;
@Inject @Inject
@Override @Override
@@ -222,49 +222,77 @@ public abstract class RSTileMixin implements RSTile
if (previousGameObjects == null) if (previousGameObjects == null)
{ {
previousGameObjects = new GameObject[5]; previousGameObjects = new RSGameObject[5];
} }
// Previous game object // Previous game object
GameObject previous = previousGameObjects[idx]; RSGameObject previous = previousGameObjects[idx];
// GameObject that was changed. // GameObject that was changed.
RSGameObject current = (RSGameObject) getGameObjects()[idx]; RSGameObject current = (RSGameObject) getGameObjects()[idx];
// Last game object
GameObject last = lastGameObject;
// Update last game object
lastGameObject = current;
// Update previous object to current // Update previous object to current
previousGameObjects[idx] = current; previousGameObjects[idx] = current;
// Duplicate event, return // Duplicate event, return
if (current != null && current.equals(last)) if (current == previous)
{ {
return; return;
} }
// Characters seem to generate a constant stream of new GameObjects // actors, projectiles, and graphics objects are added and removed from the scene each frame as GameObjects,
if (current == null || !(current.getRenderable() instanceof Actor)) // so ignore them.
boolean currentInvalid = false, prevInvalid = false;
if (current != null)
{ {
if (current == null && previous != null) RSRenderable renderable = current.getRenderable();
currentInvalid = renderable instanceof RSActor || renderable instanceof RSProjectile || renderable instanceof RSGraphicsObject;
}
if (previous != null)
{ {
RSRenderable renderable = previous.getRenderable();
prevInvalid = renderable instanceof RSActor || renderable instanceof RSProjectile || renderable instanceof RSGraphicsObject;
}
Logger logger = client.getLogger();
if (current == null)
{
if (prevInvalid)
{
return;
}
logger.trace("Game object despawn: {}", previous.getId());
GameObjectDespawned gameObjectDespawned = new GameObjectDespawned(); GameObjectDespawned gameObjectDespawned = new GameObjectDespawned();
gameObjectDespawned.setTile(this); gameObjectDespawned.setTile(this);
gameObjectDespawned.setGameObject(previous); gameObjectDespawned.setGameObject(previous);
client.getCallbacks().post(gameObjectDespawned); client.getCallbacks().post(gameObjectDespawned);
} }
else if (current != null && previous == null) else if (previous == null)
{ {
if (currentInvalid)
{
return;
}
logger.trace("Game object spawn: {}", current.getId());
GameObjectSpawned gameObjectSpawned = new GameObjectSpawned(); GameObjectSpawned gameObjectSpawned = new GameObjectSpawned();
gameObjectSpawned.setTile(this); gameObjectSpawned.setTile(this);
gameObjectSpawned.setGameObject(current); gameObjectSpawned.setGameObject(current);
client.getCallbacks().post(gameObjectSpawned); client.getCallbacks().post(gameObjectSpawned);
} }
else if (current != null && previous != null) else
{ {
if (currentInvalid && prevInvalid)
{
return;
}
logger.trace("Game object change: {} -> {}", previous.getId(), current.getId());
GameObjectChanged gameObjectsChanged = new GameObjectChanged(); GameObjectChanged gameObjectsChanged = new GameObjectChanged();
gameObjectsChanged.setTile(this); gameObjectsChanged.setTile(this);
gameObjectsChanged.setPrevious(previous); gameObjectsChanged.setPrevious(previous);
@@ -272,7 +300,6 @@ public abstract class RSTileMixin implements RSTile
client.getCallbacks().post(gameObjectsChanged); client.getCallbacks().post(gameObjectsChanged);
} }
} }
}
@FieldHook("itemLayer") @FieldHook("itemLayer")
@Inject @Inject

View File

@@ -258,6 +258,11 @@ public abstract class RSWidgetMixin implements RSWidget
for (int i = 0; i < itemIds.length; ++i) for (int i = 0; i < itemIds.length; ++i)
{ {
if (itemIds[i] <= 0)
{
continue;
}
WidgetItem item = getWidgetItem(i); WidgetItem item = getWidgetItem(i);
if (item != null) if (item != null)
@@ -287,19 +292,17 @@ public abstract class RSWidgetMixin implements RSWidget
int itemId = itemIds[index]; int itemId = itemIds[index];
int itemQuantity = itemQuantities[index]; int itemQuantity = itemQuantities[index];
Point widgetCanvasLocation = getCanvasLocation(); if (columns <= 0)
if (itemId <= 0 || itemQuantity <= 0 || columns <= 0)
{ {
return null; return null;
} }
int row = index / columns; int row = index / columns;
int col = index % columns; int col = index % columns;
int itemX = widgetCanvasLocation.getX() + ((ITEM_SLOT_SIZE + xPitch) * col); int itemX = rl$x + ((ITEM_SLOT_SIZE + xPitch) * col);
int itemY = widgetCanvasLocation.getY() + ((ITEM_SLOT_SIZE + yPitch) * row); int itemY = rl$y + ((ITEM_SLOT_SIZE + yPitch) * row);
Rectangle bounds = new Rectangle(itemX - 1, itemY - 1, ITEM_SLOT_SIZE, ITEM_SLOT_SIZE); Rectangle bounds = new Rectangle(itemX, itemY, ITEM_SLOT_SIZE, ITEM_SLOT_SIZE);
return new WidgetItem(itemId - 1, itemQuantity, index, bounds, this); return new WidgetItem(itemId - 1, itemQuantity, index, bounds, this);
} }

View File

@@ -248,10 +248,18 @@ public interface RSClient extends RSGameEngine, Client
@Override @Override
void setPassword(String password); void setPassword(String password);
@Import("otp")
@Override
void setOtp(String otp);
@Import("currentLoginField") @Import("currentLoginField")
@Override @Override
int getCurrentLoginField(); int getCurrentLoginField();
@Import("loginIndex")
@Override
int getLoginIndex();
@Import("playerOptions") @Import("playerOptions")
@Override @Override
String[] getPlayerOptions(); String[] getPlayerOptions();
@@ -772,6 +780,7 @@ public interface RSClient extends RSGameEngine, Client
boolean isInInstancedRegion(); boolean isInInstancedRegion();
@Import("itemPressedDuration") @Import("itemPressedDuration")
@Override
int getItemPressedDuration(); int getItemPressedDuration();
@Import("itemPressedDuration") @Import("itemPressedDuration")
@@ -927,6 +936,14 @@ public interface RSClient extends RSGameEngine, Client
@Import("endY") @Import("endY")
int getEndY(); int getEndY();
@Import("if1DraggedWidget")
@Override
RSWidget getIf1DraggedWidget();
@Import("if1DraggedItemIndex")
@Override
int getIf1DraggedItemIndex();
@Import("spellSelected") @Import("spellSelected")
@Override @Override
void setSpellSelected(boolean selected); void setSpellSelected(boolean selected);