update to latest and fix style

This commit is contained in:
Davis Cook
2019-02-25 18:51:20 -05:00
199 changed files with 4794 additions and 1310 deletions

View File

@@ -183,9 +183,9 @@ public class RuneLite
System.exit(0);
}
final boolean developerMode = options.has("developer-mode");
final boolean developerMode = options.has("developer-mode") && RuneLiteProperties.getLauncherVersion() == null;
if (developerMode && RuneLiteProperties.getLauncherVersion() == null)
if (developerMode)
{
boolean assertions = false;
assert assertions = true;

View File

@@ -43,8 +43,11 @@ import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.nio.channels.FileLock;
import java.nio.charset.Charset;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -70,6 +73,7 @@ import net.runelite.http.api.config.Configuration;
public class ConfigManager
{
private static final String SETTINGS_FILE_NAME = "settings.properties";
private static final DateFormat TIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
@Inject
EventBus eventBus;
@@ -111,12 +115,17 @@ public class ConfigManager
load(); // load profile specific config
}
private File getLocalPropertiesFile()
{
return new File(RuneLite.RUNELITE_DIR, SETTINGS_FILE_NAME);
}
private File getPropertiesFile()
{
// Sessions that aren't logged in have no username
if (session == null || session.getUsername() == null)
{
return new File(RuneLite.RUNELITE_DIR, SETTINGS_FILE_NAME);
return getLocalPropertiesFile();
}
else
{
@@ -158,7 +167,13 @@ public class ConfigManager
for (ConfigEntry entry : configuration.getConfig())
{
log.debug("Loading configuration value from client {}: {}", entry.getKey(), entry.getValue());
final String[] split = entry.getKey().split("\\.");
final String[] split = entry.getKey().split("\\.", 2);
if (split.length != 2)
{
continue;
}
final String groupName = split[0];
final String key = split[1];
final String value = entry.getValue();
@@ -174,7 +189,7 @@ public class ConfigManager
try
{
saveToFile();
saveToFile(propertiesFile);
log.debug("Updated configuration on disk with the latest version");
}
@@ -184,6 +199,75 @@ public class ConfigManager
}
}
private synchronized void syncPropertiesFromFile(File propertiesFile)
{
final Properties properties = new Properties();
try (FileInputStream in = new FileInputStream(propertiesFile))
{
properties.load(new InputStreamReader(in, Charset.forName("UTF-8")));
}
catch (Exception e)
{
log.debug("Malformed properties, skipping update");
return;
}
final Map<String, String> copy = (Map) ImmutableMap.copyOf(this.properties);
copy.forEach((groupAndKey, value) ->
{
if (!properties.containsKey(groupAndKey))
{
final String[] split = groupAndKey.split("\\.", 2);
if (split.length != 2)
{
return;
}
final String groupName = split[0];
final String key = split[1];
unsetConfiguration(groupName, key);
}
});
properties.forEach((objGroupAndKey, objValue) ->
{
final String groupAndKey = String.valueOf(objGroupAndKey);
final String[] split = groupAndKey.split("\\.", 2);
if (split.length != 2)
{
return;
}
final String groupName = split[0];
final String key = split[1];
final String value = String.valueOf(objValue);
setConfiguration(groupName, key, value);
});
}
public void importLocal()
{
if (session == null)
{
// No session, no import
return;
}
final File file = new File(propertiesFile.getParent(), propertiesFile.getName() + "." + TIME_FORMAT.format(new Date()));
try
{
saveToFile(file);
}
catch (IOException e)
{
log.warn("Backup failed, skipping import", e);
return;
}
syncPropertiesFromFile(getLocalPropertiesFile());
}
private synchronized void loadFromFile()
{
properties.clear();
@@ -231,7 +315,7 @@ public class ConfigManager
}
}
private synchronized void saveToFile() throws IOException
private synchronized void saveToFile(final File propertiesFile) throws IOException
{
propertiesFile.getParentFile().mkdirs();
@@ -294,8 +378,6 @@ public class ConfigManager
public void setConfiguration(String groupName, String key, String value)
{
log.debug("Setting configuration value for {}.{} to {}", groupName, key, value);
String oldValue = (String) properties.setProperty(groupName + "." + key, value);
if (Objects.equals(oldValue, value))
@@ -303,6 +385,8 @@ public class ConfigManager
return;
}
log.debug("Setting configuration value for {}.{} to {}", groupName, key, value);
synchronized (pendingChanges)
{
pendingChanges.put(groupName + "." + key, value);
@@ -312,7 +396,7 @@ public class ConfigManager
{
try
{
saveToFile();
saveToFile(propertiesFile);
}
catch (IOException ex)
{
@@ -337,8 +421,6 @@ public class ConfigManager
public void unsetConfiguration(String groupName, String key)
{
log.debug("Unsetting configuration value for {}.{}", groupName, key);
String oldValue = (String) properties.remove(groupName + "." + key);
if (oldValue == null)
@@ -346,6 +428,8 @@ public class ConfigManager
return;
}
log.debug("Unsetting configuration value for {}.{}", groupName, key);
synchronized (pendingChanges)
{
pendingChanges.put(groupName + "." + key, null);
@@ -355,7 +439,7 @@ public class ConfigManager
{
try
{
saveToFile();
saveToFile(propertiesFile);
}
catch (IOException ex)
{

View File

@@ -78,7 +78,7 @@ public class DiscordService implements AutoCloseable
discordRPC = DiscordRPC.INSTANCE;
discordEventHandlers = new DiscordEventHandlers();
}
catch (UnsatisfiedLinkError e)
catch (Error e)
{
log.warn("Failed to load Discord library, Discord support will be disabled.");
}
@@ -150,9 +150,12 @@ public class DiscordService implements AutoCloseable
? "default"
: discordPresence.getLargeImageKey();
discordRichPresence.largeImageText = discordPresence.getLargeImageText();
discordRichPresence.smallImageKey = Strings.isNullOrEmpty(discordPresence.getSmallImageKey())
? "default"
: discordPresence.getSmallImageKey();
if (!Strings.isNullOrEmpty(discordPresence.getSmallImageKey()))
{
discordRichPresence.smallImageKey = discordPresence.getSmallImageKey();
}
discordRichPresence.smallImageText = discordPresence.getSmallImageText();
discordRichPresence.partyId = discordPresence.getPartyId();
discordRichPresence.partySize = discordPresence.getPartySize();

View File

@@ -25,8 +25,10 @@
package net.runelite.client.events;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public abstract class ChatboxInput extends ChatInput
{
private final String value;

View File

@@ -25,8 +25,10 @@
package net.runelite.client.events;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public abstract class PrivateMessageInput extends ChatInput
{
private final String target;

View File

@@ -0,0 +1,242 @@
/*
* Copyright (c) 2018, SomeoneWithAnInternetConnection
* Copyright (c) 2019, MrGroggle
* 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.game;
import lombok.Getter;
import static net.runelite.api.NullObjectID.*;
import static net.runelite.api.ObjectID.*;
import net.runelite.api.coords.WorldPoint;
@Getter
public enum AgilityShortcut
{
GENERIC_SHORTCUT(1, "Shortcut", null,
// Trollheim
ROCKS_3790, ROCKS_3791,
// Fremennik Slayer Cave
STEPS_29993,
// Fossil Island
LADDER_30938, LADDER_30939, LADDER_30940, LADDER_30941, RUBBER_CAP_MUSHROOM,
// Brimhaven dungeon
CREVICE_30198,
// Lumbridge
STILE_12982,
// Gu'Tanoth Bridge
GAP, GAP_2831,
// Lumbridge Swamp Caves
STEPPING_STONE_5948, STEPPING_STONE_5949, ROCKS_6673,
// Morytania Pirate Ship
ROCK_16115,
// Lumber Yard
BROKEN_FENCE_2618,
// McGrubor's Wood
LOOSE_RAILING,
// Underwater Area Fossil Island
TUNNEL_30959, HOLE_30966, OBSTACLE, OBSTACLE_30767, OBSTACLE_30964, OBSTACLE_30962,
// Tree Gnome Village
LOOSE_RAILING_2186,
// Burgh de Rott
LOW_FENCE,
// Taverley
STILE,
// Asgarnian Ice Dungeon
STEPS,
// Fossil Island Wyvern Cave
STAIRS_31485),
BRIMHAVEN_DUNGEON_MEDIUM_PIPE_RETURN(1, "Pipe Squeeze", null, new WorldPoint(2698, 9491, 0), PIPE_21727),
BRIMHAVEN_DUNGEON_PIPE_RETURN(1, "Pipe Squeeze", null, new WorldPoint(2655, 9573, 0), PIPE_21728),
BRIMHAVEN_DUNGEON_STEPPING_STONES_RETURN(1, "Pipe Squeeze", null, STEPPING_STONE_21739),
BRIMHAVEN_DUNGEON_LOG_BALANCE_RETURN(1, "Log Balance", null, LOG_BALANCE_20884),
AGILITY_PYRAMID_ROCKS_WEST(1, "Rocks", null, CLIMBING_ROCKS_11948),
CAIRN_ISLE_CLIMBING_ROCKS(1, "Rocks", null, CLIMBING_ROCKS),
KARAMJA_GLIDER_LOG(1, "Log Balance", new WorldPoint(2906, 3050, 0), A_WOODEN_LOG ),
FALADOR_CRUMBLING_WALL(5, "Crumbling Wall", new WorldPoint(2936, 3357, 0), CRUMBLING_WALL_24222 ),
RIVER_LUM_GRAPPLE_WEST(8, "Grapple Broken Raft", new WorldPoint(3245, 3179, 0), BROKEN_RAFT),
RIVER_LUM_GRAPPLE_EAST(8, "Grapple Broken Raft", new WorldPoint(3258, 3179, 0), BROKEN_RAFT),
CORSAIR_COVE_ROCKS(10, "Rocks", new WorldPoint(2545, 2871, 0), ROCKS_31757),
KARAMJA_MOSS_GIANT_SWING(10, "Rope", null, ROPESWING_23568, ROPESWING_23569),
FALADOR_GRAPPLE_WALL(11, "Grapple Wall", new WorldPoint(3031, 3391, 0), WALL_17049, WALL_17050),
BRIMHAVEN_DUNGEON_STEPPING_STONES(12, "Stepping Stones", null, STEPPING_STONE_21738),
VARROCK_SOUTH_FENCE(13, "Fence", new WorldPoint(3239, 3334, 0), FENCE_16518),
GOBLIN_VILLAGE_WALL(14, "Wall", new WorldPoint(2925, 3523, 0), TIGHTGAP),
CORSAIR_COVE_DUNGEON_PILLAR(15, "Pillar Jump", new WorldPoint(1980, 8996, 0), PILLAR_31809),
EDGEVILLE_DUNGEON_MONKEYBARS(15, "Monkey Bars", null, MONKEYBARS_23566),
TROLLHEIM_ROCKS(15, "Rocks", null, new WorldPoint(2838, 3614, 0), ROCKS_3748), // No fixed world map location, but rocks near death plateau have a requirement of 15
YANILLE_UNDERWALL_TUNNEL(16, "Underwall Tunnel", new WorldPoint(2574, 3109, 0), HOLE_16520, WALL_17047),
YANILLE_WATCHTOWER_TRELLIS(18, "Trellis", null, TRELLIS_20056),
COAL_TRUCKS_LOG_BALANCE(20, "Log Balance", new WorldPoint(2598, 3475, 0), LOG_BALANCE_23274),
GRAND_EXCHANGE_UNDERWALL_TUNNEL(21, "Underwall Tunnel", new WorldPoint(3139, 3515, 0), UNDERWALL_TUNNEL_16529, UNDERWALL_TUNNEL_16530),
BRIMHAVEN_DUNGEON_PIPE(22, "Pipe Squeeze", new WorldPoint(2654, 9569, 0), PIPE_21728),
OBSERVATORY_SCALE_CLIFF(23, "Grapple Rocks", new WorldPoint(2447, 3155, 0), NULL_31849),
EAGLES_PEAK_ROCK_CLIMB(25, "Rock Climb", new WorldPoint(2320, 3499, 0), ROCKS_19849),
FALADOR_UNDERWALL_TUNNEL(26, "Underwall Tunnel", new WorldPoint(2947, 3313, 0), UNDERWALL_TUNNEL, UNDERWALL_TUNNEL_16528),
MOUNT_KARUULM_LOWER(29, "Rocks", new WorldPoint(1324, 3782, 0), ROCKS_34397),
CORSAIR_COVE_RESOURCE_ROCKS(30, "Rocks", new WorldPoint(2486, 2898, 0), ROCKS_31758, ROCKS_31759),
SOUTHEAST_KARAJMA_STEPPING_STONES(30, "Stepping Stones", new WorldPoint(2924, 2946, 0), STEPPING_STONES, STEPPING_STONES_23646, STEPPING_STONES_23647),
BRIMHAVEN_DUNGEON_LOG_BALANCE(30, "Log Balance", null, LOG_BALANCE_20882),
AGILITY_PYRAMID_ROCKS_EAST(30, "Rocks", null, CLIMBING_ROCKS_11949),
DRAYNOR_MANOR_STEPPING_STONES(31, "Stepping Stones", new WorldPoint(3150, 3362, 0), STEPPING_STONE_16533),
CATHERBY_CLIFFSIDE_GRAPPLE(32, "Grapple Rock", new WorldPoint(2868, 3429, 0), ROCKS_17042),
CAIRN_ISLE_ROCKS(32, "Rocks", null, ROCKS_2231),
ARDOUGNE_LOG_BALANCE(33, "Log Balance", new WorldPoint(2602, 3336, 0), LOG_BALANCE_16546, LOG_BALANCE_16547, LOG_BALANCE_16548),
BRIMHAVEN_DUNGEON_MEDIUM_PIPE(34, "Pipe Squeeze", null, new WorldPoint(2698, 9501, 0), PIPE_21727),
CATHERBY_OBELISK_GRAPPLE(36, "Grapple Rock", new WorldPoint(2841, 3434, 0), CROSSBOW_TREE_17062),
GNOME_STRONGHOLD_ROCKS(37, "Rocks", new WorldPoint(2485, 3515, 0), ROCKS_16534, ROCKS_16535),
AL_KHARID_MINING_PITCLIFF_SCRAMBLE(38, "Rocks", new WorldPoint(3305, 3315, 0), ROCKS_16549, ROCKS_16550),
YANILLE_WALL_GRAPPLE(39, "Grapple Wall", new WorldPoint(2552, 3072, 0), CASTLE_WALL),
NEITIZNOT_BRIDGE_REPAIR(40, "Bridge Repair - Quest", new WorldPoint(2315, 3828, 0), ROPE_BRIDGE_21306, ROPE_BRIDGE_21307),
KOUREND_LAKE_JUMP_EAST(40, "Stepping Stones", new WorldPoint(1612, 3570, 0), STEPPING_STONE_29729, STEPPING_STONE_29730),
KOUREND_LAKE_JUMP_WEST(40, "Stepping Stones", new WorldPoint(1604, 3572, 0), STEPPING_STONE_29729, STEPPING_STONE_29730),
YANILLE_DUNGEON_BALANCE(40, "Balancing Ledge", null, BALANCING_LEDGE_23548),
TROLLHEIM_EASY_CLIFF_SCRAMBLE(41, "Rocks", new WorldPoint(2869, 3670, 0), ROCKS_16521),
DWARVEN_MINE_NARROW_CREVICE(42, "Narrow Crevice", new WorldPoint(3034, 9806, 0), CREVICE_16543),
DRAYNOR_UNDERWALL_TUNNEL(42, "Underwall Tunnel", new WorldPoint(3068, 3261, 0), UNDERWALL_TUNNEL_19032, UNDERWALL_TUNNEL_19036),
TROLLHEIM_MEDIUM_CLIFF_SCRAMBLE_NORTH(43, "Rocks", new WorldPoint(2886, 3684, 0), ROCKS_3803, ROCKS_3804, ROCKS_16522),
TROLLHEIM_MEDIUM_CLIFF_SCRAMBLE_SOUTH(43, "Rocks", new WorldPoint(2876, 3666, 0), ROCKS_3803, ROCKS_3804, ROCKS_16522),
TROLLHEIM_ADVANCED_CLIFF_SCRAMBLE(44, "Rocks", new WorldPoint(2907, 3686, 0), ROCKS_16523, ROCKS_3748),
KOUREND_RIVER_STEPPING_STONES(45, "Stepping Stones", new WorldPoint(1721, 3509, 0), STEPPING_STONE_29728),
TIRANNWN_LOG_BALANCE(45, "Log Balance", null, LOG_BALANCE_3933, LOG_BALANCE_3931, LOG_BALANCE_3930, LOG_BALANCE_3929, LOG_BALANCE_3932),
COSMIC_ALTAR_MEDIUM_WALKWAY(46, "Narrow Walkway", new WorldPoint(2399, 4403, 0), JUTTING_WALL_17002),
DEEP_WILDERNESS_DUNGEON_CREVICE_NORTH(46, "Narrow Crevice", new WorldPoint(3047, 10335, 0), CREVICE_19043),
DEEP_WILDERNESS_DUNGEON_CREVICE_SOUTH(46, "Narrow Crevice", new WorldPoint(3045, 10327, 0), CREVICE_19043),
TROLLHEIM_HARD_CLIFF_SCRAMBLE(47, "Rocks", new WorldPoint(2902, 3680, 0), ROCKS_16524),
FREMENNIK_LOG_BALANCE(48, "Log Balance", new WorldPoint(2721, 3591, 0), LOG_BALANCE_16540, LOG_BALANCE_16541, LOG_BALANCE_16542),
YANILLE_DUNGEON_PIPE_SQUEEZE(49, "Pipe Squeeze", null, OBSTACLE_PIPE_23140),
ARCEUUS_ESSENCE_MINE_BOULDER(49, "Boulder", new WorldPoint(1774, 3888, 0), BOULDER_27990),
MORYTANIA_STEPPING_STONE(50, "Stepping Stone", new WorldPoint(3418, 3326, 0), STEPPING_STONE_13504),
VARROCK_SEWERS_PIPE_SQUEEZE(51, "Pipe Squeeze", new WorldPoint(3152, 9905, 0), OBSTACLE_PIPE_16511),
ARCEUUS_ESSENCE_MINE_EAST_SCRAMBLE(52, "Rock Climb", new WorldPoint(1770, 3851, 0), ROCKS_27987, ROCKS_27988),
KARAMJA_VOLCANO_GRAPPLE_NORTH(53, "Grapple Rock", new WorldPoint(2873, 3143, 0), STRONG_TREE_17074),
KARAMJA_VOLCANO_GRAPPLE_SOUTH(53, "Grapple Rock", new WorldPoint(2874, 3128, 0), STRONG_TREE_17074),
MOTHERLODE_MINE_WALL_EAST(54, "Wall", new WorldPoint(3124, 9703, 0), DARK_TUNNEL_10047),
MOTHERLODE_MINE_WALL_WEST(54, "Wall", new WorldPoint(3118, 9702, 0), DARK_TUNNEL_10047),
MISCELLANIA_DOCK_STEPPING_STONE(55, "Stepping Stone", new WorldPoint(2572, 3862, 0), STEPPING_STONE_11768),
ISAFDAR_FOREST_OBSTACLES(56, "Trap", null, DENSE_FOREST_3938, DENSE_FOREST_3939, DENSE_FOREST_3998, DENSE_FOREST_3999, DENSE_FOREST, LEAVES, LEAVES_3924, LEAVES_3925, STICKS, TRIPWIRE),
RELEKKA_EAST_FENCE(57, "Fence", new WorldPoint(2688, 3697, 0), BROKEN_FENCE),
YANILLE_DUNGEON_MONKEY_BARS(57, "Monkey Bars", null, MONKEYBARS_23567),
PHASMATYS_ECTOPOOL_SHORTCUT(58, "Weathered Wall", null , WEATHERED_WALL, WEATHERED_WALL_16526),
ELVEN_OVERPASS_CLIFF_SCRAMBLE(59, "Rocks", new WorldPoint(2345, 3300, 0), ROCKS_16514, ROCKS_16515),
WILDERNESS_GWD_CLIMB_EAST(60, "Rocks", new WorldPoint(2943, 3770, 0), ROCKY_HANDHOLDS_26400, ROCKY_HANDHOLDS_26401, ROCKY_HANDHOLDS_26402, ROCKY_HANDHOLDS_26404, ROCKY_HANDHOLDS_26405, ROCKY_HANDHOLDS_26406),
WILDERNESS_GWD_CLIMB_WEST(60, "Rocks", new WorldPoint(2928, 3760, 0), ROCKY_HANDHOLDS_26400, ROCKY_HANDHOLDS_26401, ROCKY_HANDHOLDS_26402, ROCKY_HANDHOLDS_26404, ROCKY_HANDHOLDS_26405, ROCKY_HANDHOLDS_26406),
MOS_LEHARMLESS_STEPPING_STONE(60, "Stepping Stone", new WorldPoint(3710, 2970, 0), STEPPING_STONE_19042),
WINTERTODT_GAP(60, "Gap", new WorldPoint(1629, 4023, 0), GAP_29326),
UNGAEL_ICE(60, "Ice Chunks", null, NULL_25337, NULL_29868, NULL_29869, NULL_29870, ICE_CHUNKS_31822, NULL_31823, ICE_CHUNKS_31990),
SLAYER_TOWER_MEDIUM_CHAIN_FIRST(61, "Spiked Chain (Floor 1)", new WorldPoint(3421, 3550, 0), SPIKEY_CHAIN),
SLAYER_TOWER_MEDIUM_CHAIN_SECOND(61, "Spiked Chain (Floor 2)", new WorldPoint(3420, 3551, 0), SPIKEY_CHAIN_16538),
SLAYER_DUNGEON_CREVICE(62, "Narrow Crevice", new WorldPoint(2729, 10008, 0), CREVICE_16539),
MOUNT_KARUULM_UPPER(62, "Rocks", new WorldPoint(1322, 3791, 0), ROCKS_34396),
TAVERLEY_DUNGEON_RAILING(63, "Loose Railing", new WorldPoint(2935, 9811, 0), LOOSE_RAILING_28849),
TROLLHEIM_WILDERNESS_ROCKS_EAST(64, "Rocks", new WorldPoint(2945, 3678, 0), ROCKS_16545),
TROLLHEIM_WILDERNESS_ROCKS_WEST(64, "Rocks", new WorldPoint(2917, 3672, 0), ROCKS_16545),
FOSSIL_ISLAND_VOLCANO(64, "Rope", new WorldPoint(3780, 3822, 0), ROPE_ANCHOR, ROPE_ANCHOR_30917),
MORYTANIA_TEMPLE(65, "Loose Railing", new WorldPoint(3422, 3476, 0), ROCKS_16998, ROCKS_16999, ORNATE_RAILING, ORNATE_RAILING_17000),
REVENANT_CAVES_GREEN_DRAGONS(65, "Jump", new WorldPoint(3220, 10086, 0), PILLAR_31561),
COSMIC_ALTAR_ADVANCED_WALKWAY(66, "Narrow Walkway", new WorldPoint(2408, 4401, 0), JUTTING_WALL_17002),
LUMBRIDGE_DESERT_STEPPING_STONE(66, "Stepping Stone", new WorldPoint(3210, 3135, 0), STEPPING_STONE_16513),
HEROES_GUILD_TUNNEL_EAST(67, "Crevice", new WorldPoint(2898, 9901, 0), CREVICE_9739, CREVICE_9740),
HEROES_GUILD_TUNNEL_WEST(67, "Crevice", new WorldPoint(2913, 9895, 0), CREVICE_9739, CREVICE_9740),
YANILLE_DUNGEON_RUBBLE_CLIMB(67, "Pile of Rubble", null, PILE_OF_RUBBLE_23563, PILE_OF_RUBBLE_23564),
ELVEN_OVERPASS_MEDIUM_CLIFF(68, "Rocks", new WorldPoint(2337, 3288, 0), ROCKS_16514, ROCKS_16515),
WEISS_OBSTACLES(68, "Shortcut", null, LITTLE_BOULDER, ROCKSLIDE_33184, ROCKSLIDE_33185, NULL_33327, NULL_33328, LEDGE_33190, ROCKSLIDE_33191, FALLEN_TREE_33192),
ARCEUUS_ESSENSE_NORTH(69, "Rock Climb", new WorldPoint(1759, 3873, 0), ROCKS_27984, ROCKS_27985),
TAVERLEY_DUNGEON_PIPE_BLUE_DRAGON(70, "Pipe Squeeze", new WorldPoint(2886, 9798, 0), OBSTACLE_PIPE_16509),
TAVERLEY_DUNGEON_ROCKS_NORTH(70, "Rocks", new WorldPoint(2887, 9823, 0), ROCKS, ROCKS_14106),
TAVERLEY_DUNGEON_ROCKS_SOUTH(70, "Rocks", new WorldPoint(2887, 9631, 0), ROCKS, ROCKS_14106),
FOSSIL_ISLAND_HARDWOOD_NORTH(70, "Hole" , new WorldPoint(3713, 3827, 0), HOLE_31481, HOLE_31482),
FOSSIL_ISLAND_HARDWOOD_SOUTH(70, "Hole" , new WorldPoint(3715, 3817, 0), HOLE_31481, HOLE_31482),
AL_KHARID_WINDOW(70, "Window", new WorldPoint(3293, 3158, 0), BROKEN_WALL_33344, BIG_WINDOW),
GWD_SARADOMIN_ROPE_NORTH(70, "Rope Descent", new WorldPoint(2912, 5300, 0), NULL_26371),
GWD_SARADOMIN_ROPE_SOUTH(70, "Rope Descent", new WorldPoint(2951, 5267, 0), NULL_26375),
SLAYER_TOWER_ADVANCED_CHAIN_FIRST(71, "Spiked Chain (Floor 2)", new WorldPoint(3447, 3578, 0), SPIKEY_CHAIN ),
SLAYER_TOWER_ADVANCED_CHAIN_SECOND(71, "Spiked Chain (Floor 3)", new WorldPoint(3446, 3576, 0), SPIKEY_CHAIN_16538),
STRONGHOLD_SLAYER_CAVE_TUNNEL(72, "Tunnel", new WorldPoint(2431, 9806, 0), TUNNEL_30174, TUNNEL_30175),
TROLL_STRONGHOLD_WALL_CLIMB(73, "Rocks", new WorldPoint(2841, 3694, 0), ROCKS_16464),
ARCEUUS_ESSENSE_MINE_WEST(73, "Rock Climb", new WorldPoint(1742, 3853, 0), ROCKS_27984, ROCKS_27985 ),
LAVA_DRAGON_ISLE_JUMP(74, "Stepping Stone", new WorldPoint(3200, 3807, 0), STEPPING_STONE_14918),
REVENANT_CAVES_DEMONS_JUMP(75, "Jump", new WorldPoint(3199, 10135, 0), PILLAR_31561),
REVENANT_CAVES_ANKOU_EAST(75, "Jump", new WorldPoint(3201, 10195, 0), PILLAR_31561),
REVENANT_CAVES_ANKOU_NORTH(75, "Jump", new WorldPoint(3180, 10209, 0), PILLAR_31561),
ZUL_ANDRA_ISLAND_CROSSING(76, "Stepping Stone", new WorldPoint(2156, 3073, 0), STEPPING_STONE_10663),
SHILO_VILLAGE_STEPPING_STONES( 77, "Stepping Stones", new WorldPoint(2863, 2974, 0), STEPPING_STONE_16466),
KHARAZI_JUNGLE_VINE_CLIMB(79, "Vine", new WorldPoint(2897, 2939, 0), NULL_26884, NULL_26886),
TAVERLEY_DUNGEON_SPIKED_BLADES(80, "Strange Floor", new WorldPoint(2877, 9813, 0), STRANGE_FLOOR),
SLAYER_DUNGEON_CHASM_JUMP(81, "Spiked Blades", new WorldPoint(2770, 10003, 0), STRANGE_FLOOR_16544),
LAVA_MAZE_NORTH_JUMP(82, "Stepping Stone", new WorldPoint(3092, 3880, 0), STEPPING_STONE_14917),
BRIMHAVEN_DUNGEON_EAST_STEPPING_STONES_NORTH(83, "Stepping Stones", new WorldPoint(2685, 9547, 0), STEPPING_STONE_19040),
BRIMHAVEN_DUNGEON_EAST_STEPPING_STONES_SOUTH(83, "Stepping Stones", new WorldPoint(2693, 9529, 0), STEPPING_STONE_19040),
ELVEN_ADVANCED_CLIFF_SCRAMBLE(85, "Rocks", new WorldPoint(2337, 3253, 0), ROCKS_16514, ROCKS_16514),
KALPHITE_WALL(86, "Crevice", new WorldPoint(3214, 9508, 0), CREVICE_16465),
BRIMHAVEN_DUNGEON_VINE_EAST(87, "Vine", new WorldPoint(2672, 9582, 0), VINE_26880, VINE_26882),
BRIMHAVEN_DUNGEON_VINE_WEST(87, "Vine", new WorldPoint(2606, 9584, 0), VINE_26880, VINE_26882),
REVENANT_CAVES_CHAMBER_JUMP(89, "Jump", new WorldPoint(3240, 10144, 0), PILLAR_31561);
/**
* The agility level required to pass the shortcut
*/
@Getter
private final int level;
/**
* Brief description of the shortcut (e.g. 'Rocks', 'Stepping Stones', 'Jump')
*/
@Getter
private final String description;
/**
* The location of the Shortcut icon on the world map (null if there is no icon)
*/
@Getter
private final WorldPoint worldMapLocation;
/**
* An optional location in case the location of the shortcut icon is either
* null or isn't close enough to the obstacle
*/
@Getter
private final WorldPoint worldLocation;
/**
* Array of obstacles, null objects, decorations etc. that this shortcut uses.
* Typically an ObjectID/NullObjectID
*/
@Getter
private final int[] obstacleIds;
AgilityShortcut(int level, String description, WorldPoint mapLocation, WorldPoint worldLocation, int... obstacleIds)
{
this.level = level;
this.description = description;
this.worldMapLocation = mapLocation;
this.worldLocation = worldLocation;
this.obstacleIds = obstacleIds;
}
AgilityShortcut(int level, String description, WorldPoint location, int... obstacleIds)
{
this(level, description, location, location, obstacleIds);
}
public String getTooltip()
{
return description + " - Level " + level;
}
}

View File

@@ -256,6 +256,15 @@ public class ItemManager
itemCompositions.put(event.getItemComposition().getId(), event.getItemComposition());
}
/**
* Invalidates internal item manager item composition cache (but not client item composition cache)
* @see Client#getItemCompositionCache()
*/
public void invalidateItemCompositionCache()
{
itemCompositions.invalidateAll();
}
/**
* Look up an item's price
*

View File

@@ -28,6 +28,7 @@ import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.inject.Inject;
import java.awt.image.BufferedImage;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import javax.annotation.Nullable;
@@ -36,11 +37,14 @@ import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.SpritePixels;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.util.ImageUtil;
@Slf4j
@Singleton
public class SpriteManager
{
@@ -127,4 +131,36 @@ public class SpriteManager
});
});
}
public void addSpriteOverrides(SpriteOverride[] add)
{
if (add.length <= 0)
{
return;
}
clientThread.invokeLater(() ->
{
Map<Integer, SpritePixels> overrides = client.getSpriteOverrides();
Class<?> owner = add[0].getClass();
for (SpriteOverride o : add)
{
BufferedImage image = ImageUtil.getResourceStreamFromClass(owner, o.getFileName());
SpritePixels sp = ImageUtil.getImageSpritePixels(image, client);
overrides.put(o.getSpriteId(), sp);
}
});
}
public void removeSpriteOverrides(SpriteOverride[] remove)
{
clientThread.invokeLater(() ->
{
Map<Integer, SpritePixels> overrides = client.getSpriteOverrides();
for (SpriteOverride o : remove)
{
overrides.remove(o.getSpriteId());
}
});
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (c) 2018 Abex
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.game;
import net.runelite.api.SpriteID;
public interface SpriteOverride
{
/**
* An ID for a sprite. Negative numbers are used by RuneLite specific sprites
*
* @see SpriteID
*/
int getSpriteId();
/**
* The file name for the resource to be loaded, relative to the implementing class
*/
String getFileName();
}

View File

@@ -24,7 +24,10 @@
*/
package net.runelite.client.game.chatbox;
import com.google.common.base.Strings;
import com.google.common.primitives.Ints;
import com.google.inject.Inject;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.datatransfer.DataFlavor;
@@ -33,21 +36,25 @@ import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.IntPredicate;
import java.util.function.Predicate;
import java.util.function.ToIntFunction;
import java.util.regex.Pattern;
import javax.swing.SwingUtilities;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.FontTypeFace;
import net.runelite.api.FontID;
import net.runelite.api.widgets.WidgetType;
import net.runelite.api.FontTypeFace;
import net.runelite.api.widgets.JavaScriptCallback;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetPositionMode;
import net.runelite.api.widgets.WidgetSizeMode;
import net.runelite.api.widgets.WidgetTextAlignment;
import net.runelite.api.widgets.WidgetType;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.input.KeyListener;
import net.runelite.client.input.MouseListener;
@@ -57,6 +64,7 @@ import net.runelite.client.util.Text;
public class ChatboxTextInput extends ChatboxInput implements KeyListener, MouseListener
{
private static final int CURSOR_FLASH_RATE_MILLIS = 1000;
private static final Pattern BREAK_MATCHER = Pattern.compile("[^a-zA-Z0-9']");
private final ChatboxPanelManager chatboxPanelManager;
private final ClientThread clientThread;
@@ -66,13 +74,24 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
return i -> i >= 32 && i < 127;
}
@AllArgsConstructor
private static class Line
{
private final int start;
private final int end;
private final String text;
}
@Getter
private String prompt;
@Getter
private int lines;
private StringBuffer value = new StringBuffer();
@Getter
private int cursor = 0;
private int cursorStart = 0;
@Getter
private int cursorEnd = 0;
@@ -95,12 +114,14 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
@Getter
private int fontID = FontID.QUILL_8;
// This is a lambda so I can have atomic updates for it's captures
private ToIntFunction<MouseEvent> getCharOffset = null;
private Predicate<MouseEvent> isInBounds = null;
@Getter
private boolean built = false;
// These are lambdas for atomic updates
private Predicate<MouseEvent> isInBounds = null;
private ToIntFunction<Integer> getLineOffset = null;
private ToIntFunction<Point> getPointCharOffset = null;
@Inject
protected ChatboxTextInput(ChatboxPanelManager chatboxPanelManager, ClientThread clientThread)
{
@@ -108,6 +129,16 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
this.clientThread = clientThread;
}
public ChatboxTextInput lines(int lines)
{
this.lines = lines;
if (built)
{
clientThread.invoke(this::update);
}
return this;
}
public ChatboxTextInput prompt(String prompt)
{
this.prompt = prompt;
@@ -157,7 +188,7 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
end = v;
}
this.cursor = start;
this.cursorStart = start;
this.cursorEnd = end;
if (built)
@@ -209,7 +240,6 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
protected void update()
{
this.built = true;
Widget container = chatboxPanelManager.getContainerWidget();
container.deleteAllChildren();
@@ -232,103 +262,209 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
protected void buildEdit(int x, int y, int w, int h)
{
final List<Line> editLines = new ArrayList<>();
Widget container = chatboxPanelManager.getContainerWidget();
String lt = Text.escapeJagex(value.substring(0, this.cursor));
String mt = Text.escapeJagex(value.substring(this.cursor, this.cursorEnd));
String rt = Text.escapeJagex(value.substring(this.cursorEnd));
Widget leftText = container.createChild(-1, WidgetType.TEXT);
Widget cursor = container.createChild(-1, WidgetType.RECTANGLE);
Widget middleText = container.createChild(-1, WidgetType.TEXT);
Widget rightText = container.createChild(-1, WidgetType.TEXT);
leftText.setFontId(fontID);
FontTypeFace font = leftText.getFont();
final Widget cursor = container.createChild(-1, WidgetType.RECTANGLE);
long start = System.currentTimeMillis();
cursor.setOnTimerListener((JavaScriptCallback) ev ->
{
boolean on = (System.currentTimeMillis() - start) % CURSOR_FLASH_RATE_MILLIS > (CURSOR_FLASH_RATE_MILLIS / 2);
cursor.setOpacity(on ? 255 : 0);
});
cursor.setTextColor(0xFFFFFF);
cursor.setHasListener(true);
cursor.setFilled(true);
cursor.setFontId(fontID);
FontTypeFace font = cursor.getFont();
if (h <= 0)
{
h = font.getBaseline();
}
int ltw = font.getTextWidth(lt);
int mtw = font.getTextWidth(mt);
int rtw = font.getTextWidth(rt);
final int oy = y;
final int ox = x;
final int oh = h;
int fullWidth = ltw + mtw + rtw;
int ox = x;
if (w > 0)
int breakIndex = -1;
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < value.length(); i++)
{
x += (w - fullWidth) / 2;
}
int ltx = x;
int mtx = ltx + ltw;
int rtx = mtx + mtw;
leftText.setText(lt);
leftText.setOriginalX(ltx);
leftText.setOriginalY(y);
leftText.setOriginalWidth(ltw);
leftText.setOriginalHeight(h);
leftText.revalidate();
if (!mt.isEmpty())
{
cursor.setTextColor(0x113399);
}
else
{
cursor.setTextColor(0xFFFFFF);
long start = System.currentTimeMillis();
cursor.setOnTimerListener((JavaScriptCallback) ev ->
int count = i - sb.length();
final String c = value.charAt(i) + "";
sb.append(c);
if (BREAK_MATCHER.matcher(c).matches())
{
boolean on = (System.currentTimeMillis() - start) % CURSOR_FLASH_RATE_MILLIS > (CURSOR_FLASH_RATE_MILLIS / 2);
cursor.setOpacity(on ? 255 : 0);
});
cursor.setHasListener(true);
breakIndex = sb.length();
}
if (i == value.length() - 1)
{
Line line = new Line(count, count + sb.length() - 1, sb.toString());
editLines.add(line);
break;
}
if (font.getTextWidth(sb.toString() + value.charAt(i + 1)) < w)
{
continue;
}
if (editLines.size() < this.lines - 1 || this.lines == 0)
{
if (breakIndex > 1)
{
String str = sb.substring(0, breakIndex);
Line line = new Line(count, count + str.length() - 1, str);
editLines.add(line);
sb.replace(0, breakIndex, "");
breakIndex = -1;
continue;
}
Line line = new Line(count, count + sb.length() - 1, sb.toString());
editLines.add(line);
sb.replace(0, sb.length(), "");
}
}
cursor.setFilled(true);
cursor.setOriginalX(mtx - 1);
cursor.setOriginalY(y);
cursor.setOriginalWidth(2 + mtw);
cursor.setOriginalHeight(h);
cursor.revalidate();
middleText.setText(mt);
middleText.setFontId(fontID);
middleText.setOriginalX(mtx);
middleText.setOriginalY(y);
middleText.setOriginalWidth(mtw);
middleText.setOriginalHeight(h);
middleText.setTextColor(0xFFFFFF);
middleText.revalidate();
Rectangle bounds = new Rectangle(container.getCanvasLocation().getX() + container.getWidth(), y, 0, editLines.size() * oh);
for (int i = 0; i < editLines.size() || i == 0; i++)
{
final Line line = editLines.size() > 0 ? editLines.get(i) : new Line(0, 0, "");
final String text = line.text;
final int len = text.length();
rightText.setText(rt);
rightText.setFontId(fontID);
rightText.setOriginalX(rtx);
rightText.setOriginalY(y);
rightText.setOriginalWidth(rtw);
rightText.setOriginalHeight(h);
rightText.revalidate();
String lt = Text.escapeJagex(text);
String mt = "";
String rt = "";
final boolean isStartLine = cursorOnLine(cursorStart, line.start, line.end)
|| (cursorOnLine(cursorStart, line.start, line.end + 1) && i == editLines.size() - 1);
final boolean isEndLine = cursorOnLine(cursorEnd, line.start, line.end);
if (isStartLine || isEndLine || (cursorEnd > line.end && cursorStart < line.start))
{
final int cIdx = Ints.constrainToRange(cursorStart - line.start, 0, len);
final int ceIdx = Ints.constrainToRange(cursorEnd - line.start, 0, len);
lt = Text.escapeJagex(text.substring(0, cIdx));
mt = Text.escapeJagex(text.substring(cIdx, ceIdx));
rt = Text.escapeJagex(text.substring(ceIdx));
}
final int ltw = font.getTextWidth(lt);
final int mtw = font.getTextWidth(mt);
final int rtw = font.getTextWidth(rt);
final int fullWidth = ltw + mtw + rtw;
int ltx = ox;
if (w > 0)
{
ltx += (w - fullWidth) / 2;
}
final int mtx = ltx + ltw;
final int rtx = mtx + mtw;
if (ltx < bounds.x)
{
bounds.setLocation(ltx, bounds.y);
}
if (fullWidth > bounds.width)
{
bounds.setSize(fullWidth, bounds.height);
}
if (editLines.size() == 0 || isStartLine)
{
cursor.setOriginalX(mtx - 1);
cursor.setOriginalY(y);
cursor.setOriginalWidth(2);
cursor.setOriginalHeight(h);
cursor.revalidate();
}
if (!Strings.isNullOrEmpty(lt))
{
final Widget leftText = container.createChild(-1, WidgetType.TEXT);
leftText.setFontId(fontID);
leftText.setText(lt);
leftText.setOriginalX(ltx);
leftText.setOriginalY(y);
leftText.setOriginalWidth(ltw);
leftText.setOriginalHeight(h);
leftText.revalidate();
}
if (!Strings.isNullOrEmpty(mt))
{
final Widget background = container.createChild(-1, WidgetType.RECTANGLE);
background.setTextColor(0x113399);
background.setFilled(true);
background.setOriginalX(mtx - 1);
background.setOriginalY(y);
background.setOriginalWidth(2 + mtw);
background.setOriginalHeight(h);
background.revalidate();
final Widget middleText = container.createChild(-1, WidgetType.TEXT);
middleText.setText(mt);
middleText.setFontId(fontID);
middleText.setOriginalX(mtx);
middleText.setOriginalY(y);
middleText.setOriginalWidth(mtw);
middleText.setOriginalHeight(h);
middleText.setTextColor(0xFFFFFF);
middleText.revalidate();
}
if (!Strings.isNullOrEmpty(rt))
{
final Widget rightText = container.createChild(-1, WidgetType.TEXT);
rightText.setText(rt);
rightText.setFontId(fontID);
rightText.setOriginalX(rtx);
rightText.setOriginalY(y);
rightText.setOriginalWidth(rtw);
rightText.setOriginalHeight(h);
rightText.revalidate();
}
y += h;
}
net.runelite.api.Point ccl = container.getCanvasLocation();
int canvasX = ltx + ccl.getX();
Rectangle bounds = new Rectangle(ccl.getX() + ox, ccl.getY() + y, w > 0 ? w : fullWidth, h);
String tsValue = value.toString();
isInBounds = ev -> bounds.contains(ev.getPoint());
getCharOffset = ev ->
isInBounds = ev -> bounds.contains(new Point(ev.getX() - ccl.getX(), ev.getY() - ccl.getY()));
getPointCharOffset = p ->
{
if (fullWidth <= 0)
if (bounds.width <= 0)
{
return 0;
}
int cx = ev.getX() - canvasX;
int cx = p.x - ccl.getX() - ox;
int cy = p.y - ccl.getY() - oy;
int charIndex = (tsValue.length() * cx) / fullWidth;
int currentLine = Ints.constrainToRange(cy / oh, 0, editLines.size() - 1);
final Line line = editLines.get(currentLine);
final String tsValue = line.text;
int charIndex = tsValue.length();
int fullWidth = font.getTextWidth(tsValue);
int tx = ox;
if (w > 0)
{
tx += (w - fullWidth) / 2;
}
cx -= tx;
// `i` is used to track max execution time incase there is a font with ligature width data that causes this to fail
for (int i = tsValue.length(); i >= 0 && charIndex >= 0 && charIndex <= tsValue.length(); i--)
@@ -353,22 +489,72 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
break;
}
if (charIndex < 0)
charIndex = Ints.constrainToRange(charIndex, 0, tsValue.length());
return line.start + charIndex;
};
getLineOffset = code ->
{
if (editLines.size() < 2)
{
charIndex = 0;
}
if (charIndex > tsValue.length())
{
charIndex = tsValue.length();
return cursorStart;
}
return charIndex;
int currentLine = -1;
for (int i = 0; i < editLines.size(); i++)
{
Line l = editLines.get(i);
if (cursorOnLine(cursorStart, l.start, l.end)
|| (cursorOnLine(cursorStart, l.start, l.end + 1) && i == editLines.size() - 1))
{
currentLine = i;
break;
}
}
if (currentLine == -1
|| (code == KeyEvent.VK_UP && currentLine == 0)
|| (code == KeyEvent.VK_DOWN && currentLine == editLines.size() - 1))
{
return cursorStart;
}
final Line line = editLines.get(currentLine);
final int direction = code == KeyEvent.VK_UP ? -1 : 1;
final Point dest = new Point(cursor.getCanvasLocation().getX(), cursor.getCanvasLocation().getY() + (direction * oh));
final int charOffset = getPointCharOffset.applyAsInt(dest);
// Place cursor on right line if whitespace keep it on the same line or skip a line
final Line nextLine = editLines.get(currentLine + direction);
if ((direction == -1 && charOffset >= line.start)
|| (direction == 1 && (charOffset > nextLine.end && (currentLine + direction != editLines.size() - 1))))
{
return nextLine.end;
}
return charOffset;
};
}
private boolean cursorOnLine(final int cursor, final int start, final int end)
{
return (cursor >= start) && (cursor <= end);
}
private int getCharOffset(MouseEvent ev)
{
if (getPointCharOffset == null)
{
return 0;
}
return getPointCharOffset.applyAsInt(ev.getPoint());
}
@Override
protected void open()
{
this.built = true;
update();
}
@@ -398,12 +584,12 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
char c = e.getKeyChar();
if (charValidator.test(c))
{
if (cursor != cursorEnd)
if (cursorStart != cursorEnd)
{
value.delete(cursor, cursorEnd);
value.delete(cursorStart, cursorEnd);
}
value.insert(cursor, c);
cursorAt(cursor + 1);
value.insert(cursorStart, c);
cursorAt(cursorStart + 1);
if (onChanged != null)
{
onChanged.accept(getValue());
@@ -421,13 +607,13 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
{
case KeyEvent.VK_X:
case KeyEvent.VK_C:
if (cursor != cursorEnd)
if (cursorStart != cursorEnd)
{
String s = value.substring(cursor, cursorEnd);
String s = value.substring(cursorStart, cursorEnd);
if (code == KeyEvent.VK_X)
{
value.delete(cursor, cursorEnd);
cursorAt(cursor);
value.delete(cursorStart, cursorEnd);
cursorAt(cursorStart);
}
Toolkit.getDefaultToolkit()
.getSystemClipboard()
@@ -441,20 +627,20 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
.getSystemClipboard()
.getData(DataFlavor.stringFlavor)
.toString();
if (cursor != cursorEnd)
if (cursorStart != cursorEnd)
{
value.delete(cursor, cursorEnd);
value.delete(cursorStart, cursorEnd);
}
for (int i = 0; i < s.length(); i++)
{
char ch = s.charAt(i);
if (charValidator.test(ch))
{
value.insert(cursor, ch);
cursor++;
value.insert(cursorStart, ch);
cursorStart++;
}
}
cursorAt(cursor);
cursorAt(cursorStart);
if (onChanged != null)
{
onChanged.accept(getValue());
@@ -468,13 +654,13 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
}
return;
}
int newPos = cursor;
int newPos = cursorStart;
if (ev.isShiftDown())
{
if (selectionEnd == -1 || selectionStart == -1)
{
selectionStart = cursor;
selectionEnd = cursor;
selectionStart = cursorStart;
selectionEnd = cursorStart;
}
newPos = selectionEnd;
}
@@ -486,20 +672,20 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
switch (code)
{
case KeyEvent.VK_DELETE:
if (cursor != cursorEnd)
if (cursorStart != cursorEnd)
{
value.delete(cursor, cursorEnd);
cursorAt(cursor);
value.delete(cursorStart, cursorEnd);
cursorAt(cursorStart);
if (onChanged != null)
{
onChanged.accept(getValue());
}
return;
}
if (cursor < value.length())
if (cursorStart < value.length())
{
value.deleteCharAt(cursor);
cursorAt(cursor);
value.deleteCharAt(cursorStart);
cursorAt(cursorStart);
if (onChanged != null)
{
onChanged.accept(getValue());
@@ -507,20 +693,20 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
}
return;
case KeyEvent.VK_BACK_SPACE:
if (cursor != cursorEnd)
if (cursorStart != cursorEnd)
{
value.delete(cursor, cursorEnd);
cursorAt(cursor);
value.delete(cursorStart, cursorEnd);
cursorAt(cursorStart);
if (onChanged != null)
{
onChanged.accept(getValue());
}
return;
}
if (cursor > 0)
if (cursorStart > 0)
{
value.deleteCharAt(cursor - 1);
cursorAt(cursor - 1);
value.deleteCharAt(cursorStart - 1);
cursorAt(cursorStart - 1);
if (onChanged != null)
{
onChanged.accept(getValue());
@@ -535,6 +721,14 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
ev.consume();
newPos++;
break;
case KeyEvent.VK_UP:
ev.consume();
newPos = getLineOffset.applyAsInt(code);
break;
case KeyEvent.VK_DOWN:
ev.consume();
newPos = getLineOffset.applyAsInt(code);
break;
case KeyEvent.VK_HOME:
ev.consume();
newPos = 0;
@@ -553,9 +747,9 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
return;
case KeyEvent.VK_ESCAPE:
ev.consume();
if (cursor != cursorEnd)
if (cursorStart != cursorEnd)
{
cursorAt(cursor);
cursorAt(cursorStart);
return;
}
chatboxPanelManager.close();
@@ -602,16 +796,16 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
}
if (isInBounds == null || !isInBounds.test(mouseEvent))
{
if (cursor != cursorEnd)
if (cursorStart != cursorEnd)
{
selectionStart = -1;
selectionEnd = -1;
cursorAt(getCharOffset.applyAsInt(mouseEvent));
cursorAt(getCharOffset(mouseEvent));
}
return mouseEvent;
}
int nco = getCharOffset.applyAsInt(mouseEvent);
int nco = getCharOffset(mouseEvent);
if (mouseEvent.isShiftDown() && selectionEnd != -1)
{
@@ -653,7 +847,7 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
return mouseEvent;
}
int nco = getCharOffset.applyAsInt(mouseEvent);
int nco = getCharOffset(mouseEvent);
if (selectionStart != -1)
{
selectionEnd = nco;

View File

@@ -36,6 +36,7 @@ import net.runelite.api.Client;
import net.runelite.api.Point;
import net.runelite.api.Tile;
import net.runelite.api.coords.LocalPoint;
import net.runelite.client.game.AgilityShortcut;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer;
import net.runelite.client.ui.overlay.OverlayPosition;
@@ -44,6 +45,7 @@ import net.runelite.client.ui.overlay.OverlayUtil;
class AgilityOverlay extends Overlay
{
private static final int MAX_DISTANCE = 2350;
private static final Color SHORTCUT_HIGH_LEVEL_COLOR = Color.ORANGE;
private final Client client;
private final AgilityPlugin plugin;
@@ -66,14 +68,15 @@ class AgilityOverlay extends Overlay
LocalPoint playerLocation = client.getLocalPlayer().getLocalLocation();
Point mousePosition = client.getMouseCanvasPosition();
final List<Tile> marksOfGrace = plugin.getMarksOfGrace();
plugin.getObstacles().forEach((object, tile) ->
plugin.getObstacles().forEach((object, obstacle) ->
{
if (Obstacles.SHORTCUT_OBSTACLE_IDS.contains(object.getId()) && !config.highlightShortcuts() ||
if (Obstacles.SHORTCUT_OBSTACLE_IDS.containsKey(object.getId()) && !config.highlightShortcuts() ||
Obstacles.TRAP_OBSTACLE_IDS.contains(object.getId()) && !config.showTrapOverlay())
{
return;
}
Tile tile = obstacle.getTile();
if (tile.getPlane() == client.getPlane()
&& object.getLocalLocation().distanceTo(playerLocation) < MAX_DISTANCE)
{
@@ -87,11 +90,11 @@ class AgilityOverlay extends Overlay
}
return;
}
Area objectClickbox = object.getClickbox();
if (objectClickbox != null)
{
Color configColor = config.getOverlayColor();
AgilityShortcut agilityShortcut = obstacle.getShortcut();
Color configColor = agilityShortcut == null || agilityShortcut.getLevel() <= plugin.getAgilityLevel() ? config.getOverlayColor() : SHORTCUT_HIGH_LEVEL_COLOR;
if (config.highlightMarks() && !marksOfGrace.isEmpty())
{
configColor = config.getMarkColor();

View File

@@ -38,10 +38,12 @@ import net.runelite.api.Item;
import net.runelite.api.ItemID;
import static net.runelite.api.ItemID.AGILITY_ARENA_TICKET;
import net.runelite.api.Player;
import net.runelite.api.Skill;
import static net.runelite.api.Skill.AGILITY;
import net.runelite.api.Tile;
import net.runelite.api.TileObject;
import net.runelite.api.coords.WorldPoint;
import net.runelite.api.events.BoostedLevelChanged;
import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.DecorativeObjectChanged;
import net.runelite.api.events.DecorativeObjectDespawned;
@@ -63,6 +65,7 @@ import net.runelite.api.events.WallObjectSpawned;
import net.runelite.client.Notifier;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.game.AgilityShortcut;
import net.runelite.client.game.ItemManager;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
@@ -80,7 +83,7 @@ public class AgilityPlugin extends Plugin
private static final int AGILITY_ARENA_REGION_ID = 11157;
@Getter
private final Map<TileObject, Tile> obstacles = new HashMap<>();
private final Map<TileObject, Obstacle> obstacles = new HashMap<>();
@Getter
private final List<Tile> marksOfGrace = new ArrayList<>();
@@ -115,6 +118,9 @@ public class AgilityPlugin extends Plugin
private int lastAgilityXp;
private WorldPoint lastArenaTicketPosition;
@Getter
private int agilityLevel;
@Provides
AgilityConfig getConfig(ConfigManager configManager)
{
@@ -126,6 +132,7 @@ public class AgilityPlugin extends Plugin
{
overlayManager.add(agilityOverlay);
overlayManager.add(lapCounterOverlay);
agilityLevel = client.getBoostedSkillLevel(Skill.AGILITY);
}
@Override
@@ -136,6 +143,7 @@ public class AgilityPlugin extends Plugin
marksOfGrace.clear();
obstacles.clear();
session = null;
agilityLevel = 0;
}
@Subscribe
@@ -208,6 +216,17 @@ public class AgilityPlugin extends Plugin
}
}
@Subscribe
public void onBoostedLevelChanged(BoostedLevelChanged boostedLevelChanged)
{
Skill skill = boostedLevelChanged.getSkill();
if (skill == AGILITY)
{
agilityLevel = client.getBoostedSkillLevel(skill);
}
}
@Subscribe
public void onItemSpawned(ItemSpawned itemSpawned)
{
@@ -366,11 +385,40 @@ public class AgilityPlugin extends Plugin
}
if (Obstacles.COURSE_OBSTACLE_IDS.contains(newObject.getId()) ||
Obstacles.SHORTCUT_OBSTACLE_IDS.contains(newObject.getId()) ||
(Obstacles.TRAP_OBSTACLE_IDS.contains(newObject.getId())
&& Obstacles.TRAP_OBSTACLE_REGIONS.contains(newObject.getWorldLocation().getRegionID())))
{
obstacles.put(newObject, tile);
obstacles.put(newObject, new Obstacle(tile, null));
}
if (Obstacles.SHORTCUT_OBSTACLE_IDS.containsKey(newObject.getId()))
{
AgilityShortcut closestShortcut = null;
int distance = -1;
// Find the closest shortcut to this object
for (AgilityShortcut shortcut : Obstacles.SHORTCUT_OBSTACLE_IDS.get(newObject.getId()))
{
if (shortcut.getWorldLocation() == null)
{
closestShortcut = shortcut;
break;
}
else
{
int newDistance = shortcut.getWorldLocation().distanceTo2D(newObject.getWorldLocation());
if (closestShortcut == null || newDistance < distance)
{
closestShortcut = shortcut;
distance = newDistance;
}
}
}
if (closestShortcut != null)
{
obstacles.put(newObject, new Obstacle(tile, closestShortcut));
}
}
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright (c) 2019, MrGroggle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.agility;
import javax.annotation.Nullable;
import lombok.AllArgsConstructor;
import lombok.Value;
import net.runelite.api.Tile;
import net.runelite.client.game.AgilityShortcut;
@Value
@AllArgsConstructor
class Obstacle
{
private final Tile tile;
@Nullable
private final AgilityShortcut shortcut;
}

View File

@@ -25,11 +25,27 @@
package net.runelite.client.plugins.agility;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import java.util.List;
import java.util.Set;
import static net.runelite.api.NullObjectID.*;
import static net.runelite.api.NullObjectID.NULL_10872;
import static net.runelite.api.NullObjectID.NULL_10873;
import static net.runelite.api.NullObjectID.NULL_12945;
import static net.runelite.api.NullObjectID.NULL_18083;
import static net.runelite.api.NullObjectID.NULL_18116;
import static net.runelite.api.NullObjectID.NULL_18122;
import static net.runelite.api.NullObjectID.NULL_18124;
import static net.runelite.api.NullObjectID.NULL_18129;
import static net.runelite.api.NullObjectID.NULL_18130;
import static net.runelite.api.NullObjectID.NULL_18132;
import static net.runelite.api.NullObjectID.NULL_18133;
import static net.runelite.api.NullObjectID.NULL_18135;
import static net.runelite.api.NullObjectID.NULL_18136;
import static net.runelite.api.NullObjectID.NULL_3550;
import static net.runelite.api.ObjectID.*;
import net.runelite.client.game.AgilityShortcut;
class Obstacles
{
@@ -62,7 +78,7 @@ class Obstacles
STEPPING_STONE_15412, TROPICAL_TREE_15414, MONKEYBARS_15417, SKULL_SLOPE_15483, ROPE_15487, TROPICAL_TREE_16062,
// Falador
ROUGH_WALL_10833, TIGHTROPE_10834, HAND_HOLDS_10836, GAP_11161, GAP_11360, TIGHTROPE_11361,
TIGHTROPE_11364, GAP_11365, LEDGE_11366, LEDGE_11367, LEDGE_11368, LEDGE_11370, EDGE_11371,
TIGHTROPE_11364, GAP_11365, LEDGE_11366, LEDGE_11367, LEDGE_11369, LEDGE_11370, EDGE_11371,
// Wilderness
OBSTACLE_PIPE_23137, ROPESWING_23132, STEPPING_STONE_23556, LOG_BALANCE_23542, ROCKS_23640,
// Seers
@@ -91,144 +107,7 @@ class Obstacles
ZIP_LINE_11645, ZIP_LINE_11646
);
static final Set<Integer> SHORTCUT_OBSTACLE_IDS = ImmutableSet.of(
// Grand Exchange
UNDERWALL_TUNNEL_16529, UNDERWALL_TUNNEL_16530,
// South Varrock
STEPPING_STONE_16533, FENCE_16518, ROCKS_16549, ROCKS_16550,
// Falador
WALL_17049, WALL_17050, CRUMBLING_WALL_24222, UNDERWALL_TUNNEL, UNDERWALL_TUNNEL_16528, CREVICE_16543,
// Draynor
UNDERWALL_TUNNEL_19032, UNDERWALL_TUNNEL_19036,
// South Lumbridge
BROKEN_RAFT, STEPPING_STONE_16513,
// Trollheim
ROCKS_3790, ROCKS_3791, ROCKS_3803, ROCKS_3804, ROCKS_16523, ROCKS_16524, ROCKS_3748, ROCKS_16545, ROCKS_16521,
ROCKS_16522, ROCKS_16464,
// North Camelot
LOG_BALANCE_16540, LOG_BALANCE_16541, LOG_BALANCE_16542,
// Rellekka
BROKEN_FENCE,
// Ardougne
LOG_BALANCE_16546, LOG_BALANCE_16547, LOG_BALANCE_16548,
// Yanille
CASTLE_WALL, HOLE_16520, WALL_17047,
// Observatory
NULL_31849,
// Gnome Stronghold
ROCKS_16534, ROCKS_16535,
// Karamja Volcano
STRONG_TREE_17074,
// Shilo Village
STEPPING_STONE_16466,
// Vine east of Shilo Village
NULL_26884, NULL_26886,
// Stepping stones east of Shilo Village
STEPPING_STONES, STEPPING_STONES_23646, STEPPING_STONES_23647,
// Middle of Karamja
A_WOODEN_LOG,
// Slayer Tower
SPIKEY_CHAIN, SPIKEY_CHAIN_16538,
// Fremennik Slayer Cave
STRANGE_FLOOR_16544, CREVICE_16539, STEPS_29993,
// Wilderness
STEPPING_STONE_14918, STEPPING_STONE_14917, ROCKY_HANDHOLDS_26404, ROCKY_HANDHOLDS_26405, ROCKY_HANDHOLDS_26406,
// Godwars
ROCKY_HANDHOLDS_26400, ROCKY_HANDHOLDS_26401, ROCKY_HANDHOLDS_26402,
// Seers' Village Coal Mine
LOG_BALANCE_23274,
// Arceuus Essence Mine
ROCKS_27984, ROCKS_27985, BOULDER_27990, ROCKS_27987, ROCKS_27988,
// Wintertodt
GAP_29326,
// Gnome Stronghold Slayer Underground
TUNNEL_30174, TUNNEL_30175,
// Taverley Underground
OBSTACLE_PIPE_16509, STRANGE_FLOOR, ROCKS, ROCKS_14106, LOOSE_RAILING_28849,
// Heroes Guild
CREVICE_9739, CREVICE_9740,
// Fossil Island
HOLE_31481, HOLE_31482, LADDER_30938, LADDER_30939, LADDER_30940, LADDER_30941, ROPE_ANCHOR, ROPE_ANCHOR_30917,
RUBBER_CAP_MUSHROOM,
ROCKS_31757, ROCKS_31758, ROCKS_31759, PILLAR_31809,
// West Brimhaven
ROPESWING_23568, ROPESWING_23569,
// Brimhaven Dungeon
VINE_26880, VINE_26882, PIPE_21728, STEPPING_STONE_19040, PIPE_21727, LOG_BALANCE_20882, LOG_BALANCE_20884,
STEPPING_STONE_21738, STEPPING_STONE_21739, TIGHTGAP,
// Lumbridge
STILE_12982,
// Edgeville Dungeon
MONKEYBARS_23566, OBSTACLE_PIPE_16511,
// Miscellania
STEPPING_STONE_11768,
// Kalphite
CREVICE_16465,
// Eagles' Peak
ROCKS_19849,
// Catherby
CROSSBOW_TREE_17062, ROCKS_17042,
// McGrubor's Woods
LOOSE_RAILING,
// Cairn Isle
ROCKS_2231,
// South Kourend
STEPPING_STONE_29728, STEPPING_STONE_29729, STEPPING_STONE_29730,
// Cosmic Temple
JUTTING_WALL_17002,
// Arandar
ROCKS_16514, ROCKS_16515, LOG_BALANCE_3933,
// South River Salve
STEPPING_STONE_13504,
DARK_TUNNEL_10047,
// Ectofuntus
WEATHERED_WALL, WEATHERED_WALL_16526,
// Mos Le'Harmless
STEPPING_STONE_19042,
// North River Salve
ROCKS_16998, ROCKS_16999, ORNATE_RAILING, ORNATE_RAILING_17000,
// West Zul-Andra
STEPPING_STONE_10663,
// Yanille Agility Dungeon
BALANCING_LEDGE_23548, OBSTACLE_PIPE_23140, MONKEYBARS_23567, PILE_OF_RUBBLE_23563, PILE_OF_RUBBLE_23564,
// High Level Wilderness Dungeon
CREVICE_19043,
// Revenant Caves
PILLAR_31561,
// Elf Camp Isafdar Tirranwn
LOG_BALANCE_3931, LOG_BALANCE_3930, LOG_BALANCE_3929, LOG_BALANCE_3932, DENSE_FOREST_3938, DENSE_FOREST_3939,
DENSE_FOREST_3998, DENSE_FOREST_3999, DENSE_FOREST, LEAVES, LEAVES_3924, LEAVES_3925, STICKS, TRIPWIRE,
// Gu'Tanoth bridge
GAP, GAP_2831,
// Lumbridge Swamp Caves
STEPPING_STONE_5948, STEPPING_STONE_5949, ROCKS_6673,
// Morytania Pirate Ship
ROCK_16115,
// Agility Pyramid Entrance
CLIMBING_ROCKS_11948, CLIMBING_ROCKS_11949,
// Lumber Yard
BROKEN_FENCE_2618,
// Ungael and Vorkath crater
NULL_25337, NULL_29868, NULL_29869, NULL_29870, ICE_CHUNKS_31822, NULL_31823, ICE_CHUNKS_31990,
// Underwater Area Fossil Island
TUNNEL_30959, HOLE_30966, OBSTACLE, OBSTACLE_30767, OBSTACLE_30964, OBSTACLE_30962,
// Tree Gnome Village
LOOSE_RAILING_2186,
// Weiss
LITTLE_BOULDER, ROCKSLIDE_33184, ROCKSLIDE_33185, NULL_33327, NULL_33328, LEDGE_33190, ROCKSLIDE_33191, FALLEN_TREE_33192,
// Al-Kharid
BROKEN_WALL_33344, BIG_WINDOW,
// Burgh de Rott
LOW_FENCE,
// Taverley
STILE,
// Asgarnian Ice Dungeon
STEPS,
// Fossil Island Wyvern Cave
STAIRS_31485,
// Mount Karuulm
ROCKS_34397, ROCKS_34396
);
static final Multimap<Integer, AgilityShortcut> SHORTCUT_OBSTACLE_IDS;
static final Set<Integer> TRAP_OBSTACLE_IDS = ImmutableSet.of(
// Agility pyramid
@@ -236,4 +115,17 @@ class Obstacles
);
static final List<Integer> TRAP_OBSTACLE_REGIONS = ImmutableList.of(12105, 13356);
static
{
final ImmutableMultimap.Builder<Integer, AgilityShortcut> builder = ImmutableMultimap.builder();
for (final AgilityShortcut item : AgilityShortcut.values())
{
for (int obstacle : item.getObstacleIds())
{
builder.put(obstacle, item);
}
}
SHORTCUT_OBSTACLE_IDS = builder.build();
}
}

View File

@@ -60,6 +60,7 @@ import net.runelite.client.callback.ClientThread;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.game.ItemManager;
import net.runelite.client.game.SpriteManager;
import net.runelite.client.game.chatbox.ChatboxPanelManager;
import net.runelite.client.input.KeyListener;
import net.runelite.client.input.KeyManager;
@@ -125,6 +126,9 @@ public class BankTagsPlugin extends Plugin implements MouseWheelListener, KeyLis
@Inject
private KeyManager keyManager;
@Inject
private SpriteManager spriteManager;
private boolean shiftPressed = false;
@Provides
@@ -139,7 +143,7 @@ public class BankTagsPlugin extends Plugin implements MouseWheelListener, KeyLis
keyManager.registerKeyListener(this);
mouseManager.registerMouseWheelListener(this);
clientThread.invokeLater(tabInterface::init);
client.getSpriteOverrides().putAll(TabSprites.toMap(client));
spriteManager.addSpriteOverrides(TabSprites.values());
}
@Override
@@ -148,11 +152,7 @@ public class BankTagsPlugin extends Plugin implements MouseWheelListener, KeyLis
keyManager.unregisterKeyListener(this);
mouseManager.unregisterMouseWheelListener(this);
clientThread.invokeLater(tabInterface::destroy);
for (TabSprites value : TabSprites.values())
{
client.getSpriteOverrides().remove(value.getSpriteId());
}
spriteManager.removeSpriteOverrides(TabSprites.values());
shiftPressed = false;
}

View File

@@ -167,6 +167,20 @@ public class TagManager
}
}
public void renameTag(String oldTag, String newTag)
{
List<Integer> items = getItemsForTag(Text.standardize(oldTag));
items.forEach(id ->
{
Collection<String> tags = getTags(id, id < 0);
tags.remove(Text.standardize(oldTag));
tags.add(Text.standardize(newTag));
setTags(id, tags, id < 0);
});
}
private int getItemId(int itemId, boolean variation)
{
itemId = Math.abs(itemId);

View File

@@ -39,5 +39,6 @@ class MenuIndexes
static final int CHANGE_ICON = 3;
static final int DELETE_TAB = 4;
static final int EXPORT_TAB = 5;
static final int RENAME_TAB = 6;
}
}

View File

@@ -64,7 +64,6 @@ import net.runelite.api.SpriteID;
import net.runelite.api.VarClientInt;
import net.runelite.api.VarClientStr;
import net.runelite.api.Varbits;
import net.runelite.api.widgets.WidgetType;
import net.runelite.api.events.MenuEntryAdded;
import net.runelite.api.events.MenuOptionClicked;
import net.runelite.api.vars.InputType;
@@ -73,15 +72,14 @@ import net.runelite.api.widgets.JavaScriptCallback;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetConfig;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.api.widgets.WidgetSizeMode;
import net.runelite.api.widgets.WidgetType;
import net.runelite.client.Notifier;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.game.ItemManager;
import net.runelite.client.game.chatbox.ChatboxPanelManager;
import net.runelite.client.plugins.banktags.BankTagsConfig;
import net.runelite.client.plugins.banktags.BankTagsPlugin;
import static net.runelite.client.plugins.banktags.BankTagsPlugin.CONFIG_GROUP;
import static net.runelite.client.plugins.banktags.BankTagsPlugin.ICON_SEARCH;
import static net.runelite.client.plugins.banktags.BankTagsPlugin.TAG_SEARCH;
import static net.runelite.client.plugins.banktags.BankTagsPlugin.VAR_TAG_SUFFIX;
import net.runelite.client.plugins.banktags.TagManager;
@@ -102,6 +100,7 @@ public class TabInterface
private static final String EXPORT_TAB = "Export tag tab";
private static final String IMPORT_TAB = "Import tag tab";
private static final String VIEW_TAB = "View tag tab";
private static final String RENAME_TAB = "Rename tag tab";
private static final String CHANGE_ICON = "Change icon";
private static final String REMOVE_TAG = "Remove-tag";
private static final String TAG_GEAR = "Tag-equipment";
@@ -111,11 +110,12 @@ public class TabInterface
private static final int BUTTON_HEIGHT = 20;
private static final int MARGIN = 1;
private static final int SCROLL_TICK = 500;
private static final int INCINERATOR_WIDTH = 48;
private static final int INCINERATOR_HEIGHT = 39;
private final Client client;
private final ClientThread clientThread;
private final ItemManager itemManager;
private final ConfigManager configManager;
private final TagManager tagManager;
private final TabManager tabManager;
private final ChatboxPanelManager chatboxPanelManager;
@@ -148,7 +148,6 @@ public class TabInterface
final Client client,
final ClientThread clientThread,
final ItemManager itemManager,
final ConfigManager configManager,
final TagManager tagManager,
final TabManager tabManager,
final ChatboxPanelManager chatboxPanelManager,
@@ -159,7 +158,6 @@ public class TabInterface
this.client = client;
this.clientThread = clientThread;
this.itemManager = itemManager;
this.configManager = configManager;
this.tagManager = tagManager;
this.tabManager = tabManager;
this.chatboxPanelManager = chatboxPanelManager;
@@ -211,7 +209,7 @@ public class TabInterface
if (config.rememberTab() && !Strings.isNullOrEmpty(config.tab()))
{
openTag(TAG_SEARCH + config.tab());
openTag(config.tab());
}
}
@@ -239,7 +237,7 @@ public class TabInterface
tagManager.addTag(item, activeTab.getTag(), false);
}
openTag(TAG_SEARCH + activeTab.getTag());
openTag(activeTab.getTag());
}
return;
@@ -292,7 +290,7 @@ public class TabInterface
final Iterator<String> dataIter = Text.fromCSV(dataString).iterator();
final String name = dataIter.next();
final String icon = dataIter.next();
configManager.setConfiguration(CONFIG_GROUP, ICON_SEARCH + name, icon);
tabManager.setIcon(name, icon);
while (dataIter.hasNext())
{
@@ -306,7 +304,7 @@ public class TabInterface
if (activeTab != null && name.equals(activeTab.getTag()))
{
openTag(TAG_SEARCH + activeTab.getTag());
openTag(activeTab.getTag());
}
notifier.notify("Tag tab " + name + " has been imported from your clipboard!");
@@ -336,7 +334,7 @@ public class TabInterface
}
else
{
openTag(TAG_SEARCH + Text.removeTags(clicked.getName()));
openTag(Text.removeTags(clicked.getName()));
}
client.playSoundEffect(SoundEffectID.UI_BOOP);
@@ -373,6 +371,10 @@ public class TabInterface
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(stringSelection, null);
notifier.notify("Tag tab " + tagTab.getTag() + " has been copied to your clipboard!");
break;
case Tab.RENAME_TAB:
String renameTarget = Text.standardize(event.getOpbase());
renameTab(renameTarget);
break;
}
}
@@ -550,7 +552,7 @@ public class TabInterface
int itemId = itemManager.canonicalize(item.getId());
iconToSet.setIconItemId(itemId);
iconToSet.getIcon().setItemId(itemId);
configManager.setConfiguration(CONFIG_GROUP, ICON_SEARCH + iconToSet.getTag(), itemId + "");
tabManager.setIcon(iconToSet.getTag(), itemId + "");
event.consume();
}
@@ -597,7 +599,7 @@ public class TabInterface
{
if (activeTab != null && tags.contains(activeTab.getTag()))
{
openTag(TAG_SEARCH + activeTab.getTag());
openTag(activeTab.getTag());
}
}
@@ -683,6 +685,7 @@ public class TabInterface
btn.setAction(2, CHANGE_ICON);
btn.setAction(3, REMOVE_TAB);
btn.setAction(4, EXPORT_TAB);
btn.setAction(5, RENAME_TAB);
btn.setOnOpListener((JavaScriptCallback) this::handleTagTab);
tagTab.setBackground(btn);
}
@@ -712,13 +715,66 @@ public class TabInterface
}
tabManager.remove(tag);
configManager.unsetConfiguration(CONFIG_GROUP, ICON_SEARCH + tag);
tabManager.save();
updateBounds();
scrollTab(0);
}
private void renameTab(String oldTag)
{
chatboxPanelManager.openTextInput("Enter new tag name for tag \"" + oldTag + "\":")
.onDone((newTag) -> clientThread.invoke(() ->
{
if (!Strings.isNullOrEmpty(newTag) && !newTag.equalsIgnoreCase(oldTag))
{
if (tabManager.find(newTag) == null)
{
TagTab tagTab = tabManager.find(oldTag);
tagTab.setTag(newTag);
final String coloredName = ColorUtil.wrapWithColorTag(newTag, HILIGHT_COLOR);
tagTab.getIcon().setName(coloredName);
tagTab.getBackground().setName(coloredName);
tabManager.removeIcon(oldTag);
tabManager.setIcon(newTag, tagTab.getIconItemId() + "");
tabManager.save();
tagManager.renameTag(oldTag, newTag);
if (activeTab != null && activeTab.equals(tagTab))
{
openTag(newTag);
}
}
else
{
chatboxPanelManager.openTextMenuInput("The specified bank tag already exists.")
.option("1. Merge into existing tag \"" + newTag + "\".", () ->
clientThread.invoke(() ->
{
tagManager.renameTag(oldTag, newTag);
final String activeTag = activeTab != null ? activeTab.getTag() : "";
deleteTab(oldTag);
if (activeTag.equals(oldTag))
{
openTag(newTag);
}
})
)
.option("2. Choose a different name.", () ->
clientThread.invoke(() ->
renameTab(oldTag))
)
.build();
}
}
}))
.build();
}
private void scrollTick(int direction)
{
// This ensures that dragging on scroll buttons do not scrolls too fast
@@ -805,17 +861,18 @@ public class TabInterface
if (incinerator != null && !incinerator.isHidden())
{
// This is the required way to move incinerator, don't change it!
incinerator.setOriginalHeight(39);
incinerator.setOriginalWidth(48);
incinerator.setRelativeY(itemContainer.getHeight());
incinerator.revalidate();
incinerator.setOriginalHeight(INCINERATOR_HEIGHT);
incinerator.setOriginalWidth(INCINERATOR_WIDTH);
incinerator.setOriginalY(INCINERATOR_HEIGHT);
Widget child = incinerator.getDynamicChildren()[0];
child.setHeight(39);
child.setWidth(48);
child.setOriginalHeight(INCINERATOR_HEIGHT);
child.setOriginalWidth(INCINERATOR_WIDTH);
child.setWidthMode(WidgetSizeMode.ABSOLUTE);
child.setHeightMode(WidgetSizeMode.ABSOLUTE);
child.setType(WidgetType.GRAPHIC);
child.setSpriteId(TabSprites.INCINERATOR.getSpriteId());
incinerator.revalidate();
bounds.setSize(TAB_WIDTH + MARGIN * 2, height - incinerator.getHeight());
}
@@ -900,7 +957,6 @@ public class TabInterface
private void updateWidget(Widget t, int y)
{
t.setOriginalY(y);
t.setRelativeY(y);
t.setHidden(y < (bounds.y + BUTTON_HEIGHT + MARGIN) || y > (bounds.y + bounds.height - TAB_HEIGHT - MARGIN - BUTTON_HEIGHT));
t.revalidate();
}
@@ -913,10 +969,10 @@ public class TabInterface
return itemManager.getItemComposition(item.getId());
}
private void openTag(String tag)
private void openTag(final String tag)
{
bankSearch.search(InputType.SEARCH, tag, true);
activateTab(tabManager.find(tag.substring(TAG_SEARCH.length())));
bankSearch.search(InputType.SEARCH, TAG_SEARCH + tag, true);
activateTab(tabManager.find(tag));
// When tab is selected with search window open, the search window closes but the search button
// stays highlighted, this solves that issue

View File

@@ -115,6 +115,7 @@ class TabManager
{
tagTab.setHidden(true);
tabs.remove(tagTab);
removeIcon(tag);
}
}
@@ -124,6 +125,16 @@ class TabManager
configManager.setConfiguration(CONFIG_GROUP, TAG_TABS_CONFIG, tags);
}
void removeIcon(final String tag)
{
configManager.unsetConfiguration(CONFIG_GROUP, ICON_SEARCH + Text.standardize(tag));
}
void setIcon(final String tag, final String icon)
{
configManager.setConfiguration(CONFIG_GROUP, ICON_SEARCH + Text.standardize(tag), icon);
}
int size()
{
return tabs.size();

View File

@@ -25,17 +25,12 @@
*/
package net.runelite.client.plugins.banktags.tabs;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.SpritePixels;
import net.runelite.client.util.ImageUtil;
import lombok.RequiredArgsConstructor;
import net.runelite.client.game.SpriteOverride;
@Slf4j
public enum TabSprites
@RequiredArgsConstructor
public enum TabSprites implements SpriteOverride
{
INCINERATOR(-200, "incinerator.png"),
TAB_BACKGROUND(-201, "tag-tab.png"),
@@ -46,23 +41,7 @@ public enum TabSprites
@Getter
private final int spriteId;
private final BufferedImage image;
TabSprites(final int spriteId, final String imageName)
{
this.spriteId = spriteId;
this.image = ImageUtil.getResourceStreamFromClass(this.getClass(), imageName);
}
public static Map<Integer, SpritePixels> toMap(Client client)
{
final Map<Integer, SpritePixels> map = new HashMap<>();
for (TabSprites value : values())
{
map.put(value.spriteId, ImageUtil.getImageSpritePixels(value.image, client));
}
return map;
}
@Getter
private final String fileName;
}

View File

@@ -33,7 +33,7 @@ import net.runelite.api.widgets.Widget;
@EqualsAndHashCode(of = "tag")
class TagTab
{
private final String tag;
private String tag;
private int iconItemId;
private Widget background;
private Widget icon;

View File

@@ -26,15 +26,15 @@ package net.runelite.client.plugins.cannon;
import java.awt.Color;
import java.awt.image.BufferedImage;
import net.runelite.client.ui.overlay.infobox.Counter;
import net.runelite.client.ui.overlay.infobox.InfoBox;
public class CannonCounter extends Counter
public class CannonCounter extends InfoBox
{
private final CannonPlugin plugin;
public CannonCounter(BufferedImage img, CannonPlugin plugin)
CannonCounter(BufferedImage img, CannonPlugin plugin)
{
super(img, plugin, String.valueOf(plugin.getCballsLeft()));
super(img, plugin);
this.plugin = plugin;
}

View File

@@ -75,7 +75,8 @@ public class CerberusPlugin extends Plugin
@Subscribe
public void onGameStateChanged(GameStateChanged event)
{
if (event.getGameState() == GameState.LOADING)
GameState gameState = event.getGameState();
if (gameState == GameState.LOGIN_SCREEN || gameState == GameState.HOPPING || gameState == GameState.CONNECTION_LOST)
{
ghosts.clear();
}

View File

@@ -299,7 +299,7 @@ public class ChatCommandsPlugin extends Plugin
Widget boss = bossChildren[i];
Widget kill = killsChildren[i];
String bossName = boss.getText();
String bossName = boss.getText().replace(":", "");
int kc = Integer.parseInt(kill.getText().replace(",", ""));
if (kc != getKc(bossName))
{
@@ -1089,6 +1089,7 @@ public class ChatCommandsPlugin extends Plugin
case "barrows":
return "Barrows Chests";
// cox
case "cox":
case "xeric":
case "chambers":
@@ -1096,6 +1097,15 @@ public class ChatCommandsPlugin extends Plugin
case "raids":
return "Chambers of Xeric";
// cox cm
case "cox cm":
case "xeric cm":
case "chambers cm":
case "olm cm":
case "raids cm":
return "Chambers of Xeric Challenge Mode";
// tob
case "tob":
case "theatre":
case "verzik":

View File

@@ -0,0 +1,55 @@
/*
* Copyright (c) 2018, TheStonedTurtle <https://github.com/TheStonedTurtle>
* 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.chathistory;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
@ConfigGroup("chathistory")
public interface ChatHistoryConfig extends Config
{
@ConfigItem(
keyName = "retainChatHistory",
name = "Retain Chat History",
description = "Retains chat history when logging in/out or world hopping",
position = 0
)
default boolean retainChatHistory()
{
return true;
}
@ConfigItem(
keyName = "pmTargetCycling",
name = "PM Target Cycling",
description = "Pressing Tab while sending a PM will cycle the target username based on PM history",
position = 1
)
default boolean pmTargetCycling()
{
return true;
}
}

View File

@@ -25,47 +25,74 @@
package net.runelite.client.plugins.chathistory;
import com.google.common.collect.EvictingQueue;
import com.google.common.collect.Sets;
import com.google.inject.Provides;
import java.awt.event.KeyEvent;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Iterator;
import java.util.Queue;
import java.util.Set;
import javax.inject.Inject;
import net.runelite.api.ChatMessageType;
import net.runelite.api.Client;
import net.runelite.api.ScriptID;
import net.runelite.api.VarClientInt;
import net.runelite.api.VarClientStr;
import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.MenuOptionClicked;
import net.runelite.api.vars.InputType;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.chat.ChatMessageManager;
import net.runelite.client.chat.QueuedMessage;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.input.KeyListener;
import net.runelite.client.input.KeyManager;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.util.Text;
@PluginDescriptor(
name = "Chat History",
description = "Retain your chat history when logging in/out or world hopping"
description = "Retain your chat history when logging in/out or world hopping",
tags = {"chat", "history", "retain", "cycle", "pm"}
)
public class ChatHistoryPlugin extends Plugin
public class ChatHistoryPlugin extends Plugin implements KeyListener
{
private static final String WELCOME_MESSAGE = "Welcome to Old School RuneScape.";
private static final String CLEAR_HISTORY = "Clear history";
private static final String CLEAR_PRIVATE = "<col=ffff00>Private:";
private static final Set<ChatMessageType> ALLOWED_HISTORY = Sets.newHashSet(
ChatMessageType.PUBLIC,
ChatMessageType.PUBLIC_MOD,
ChatMessageType.CLANCHAT,
ChatMessageType.PRIVATE_MESSAGE_RECEIVED,
ChatMessageType.PRIVATE_MESSAGE_SENT,
ChatMessageType.PRIVATE_MESSAGE_RECEIVED_MOD,
ChatMessageType.GAME
);
private static final int CYCLE_HOTKEY = KeyEvent.VK_TAB;
private Queue<QueuedMessage> messageQueue;
private Deque<String> friends;
@Inject
private Client client;
@Inject
private ClientThread clientThread;
@Inject
private ChatHistoryConfig config;
@Inject
private KeyManager keyManager;
@Inject
private ChatMessageManager chatMessageManager;
@Provides
ChatHistoryConfig getConfig(ConfigManager configManager)
{
return configManager.getConfig(ChatHistoryConfig.class);
}
@Override
protected void startUp()
{
messageQueue = EvictingQueue.create(100);
friends = new ArrayDeque<>(5);
keyManager.registerKeyListener(this);
}
@Override
@@ -73,6 +100,9 @@ public class ChatHistoryPlugin extends Plugin
{
messageQueue.clear();
messageQueue = null;
friends.clear();
friends = null;
keyManager.unregisterKeyListener(this);
}
@Subscribe
@@ -82,6 +112,11 @@ public class ChatHistoryPlugin extends Plugin
// of information that chat history was reset
if (chatMessage.getMessage().equals(WELCOME_MESSAGE))
{
if (!config.retainChatHistory())
{
return;
}
QueuedMessage queuedMessage;
while ((queuedMessage = messageQueue.poll()) != null)
@@ -92,21 +127,33 @@ public class ChatHistoryPlugin extends Plugin
return;
}
if (ALLOWED_HISTORY.contains(chatMessage.getType()))
switch (chatMessage.getType())
{
final QueuedMessage queuedMessage = QueuedMessage.builder()
.type(chatMessage.getType())
.name(chatMessage.getName())
.sender(chatMessage.getSender())
.value(nbsp(chatMessage.getMessage()))
.runeLiteFormattedMessage(nbsp(chatMessage.getMessageNode().getRuneLiteFormatMessage()))
.timestamp(chatMessage.getTimestamp())
.build();
case PRIVATE_MESSAGE_SENT:
case PRIVATE_MESSAGE_RECEIVED:
case PRIVATE_MESSAGE_RECEIVED_MOD:
final String name = Text.removeTags(chatMessage.getName());
// Remove to ensure uniqueness & its place in history
friends.remove(name);
friends.add(name);
// intentional fall-through
case PUBLIC:
case PUBLIC_MOD:
case CLANCHAT:
case GAME:
final QueuedMessage queuedMessage = QueuedMessage.builder()
.type(chatMessage.getType())
.name(chatMessage.getName())
.sender(chatMessage.getSender())
.value(nbsp(chatMessage.getMessage()))
.runeLiteFormattedMessage(nbsp(chatMessage.getMessageNode().getRuneLiteFormatMessage()))
.timestamp(chatMessage.getTimestamp())
.build();
if (!messageQueue.contains(queuedMessage))
{
messageQueue.offer(queuedMessage);
}
if (!messageQueue.contains(queuedMessage))
{
messageQueue.offer(queuedMessage);
}
}
}
@@ -143,4 +190,64 @@ public class ChatHistoryPlugin extends Plugin
return null;
}
@Override
public void keyPressed(KeyEvent e)
{
if (e.getKeyCode() != CYCLE_HOTKEY || !config.pmTargetCycling())
{
return;
}
if (client.getVar(VarClientInt.INPUT_TYPE) != InputType.PRIVATE_MESSAGE.getType())
{
return;
}
clientThread.invoke(() ->
{
final String target = findPreviousFriend();
if (target == null)
{
return;
}
final String currentMessage = client.getVar(VarClientStr.INPUT_TEXT);
client.runScript(ScriptID.OPEN_PRIVATE_MESSAGE_INTERFACE, target);
client.setVar(VarClientStr.INPUT_TEXT, currentMessage);
client.runScript(ScriptID.CHAT_TEXT_INPUT_REBUILD, "");
});
}
@Override
public void keyTyped(KeyEvent e)
{
}
@Override
public void keyReleased(KeyEvent e)
{
}
private String findPreviousFriend()
{
final String currentTarget = client.getVar(VarClientStr.PRIVATE_MESSAGE_TARGET);
if (currentTarget == null || friends.isEmpty())
{
return null;
}
for (Iterator<String> it = friends.descendingIterator(); it.hasNext(); )
{
String friend = it.next();
if (friend.equals(currentTarget))
{
return it.hasNext() ? it.next() : friends.getLast();
}
}
return friends.getLast();
}
}

View File

@@ -133,8 +133,8 @@ public class EmoteClue extends ClueScroll implements TextClueScroll, LocationClu
new EmoteClue("Panic by the pilot on White Wolf Mountain. Beware of double agents! Equip mithril platelegs, a ring of life and a rune axe.", GNOME_GLIDER_ON_WHITE_WOLF_MOUNTAIN, new WorldPoint(2847, 3499, 0), PANIC, item(MITHRIL_PLATELEGS), item(RING_OF_LIFE), item(RUNE_AXE)),
new EmoteClue("Panic by the big egg where no one dare goes and the ground is burnt. Beware of double agents! Equip a dragon med helm, a TokTz-Ket-Xil, a brine sabre, rune platebody and an uncharged amulet of glory.", SOUTHEAST_CORNER_OF_LAVA_DRAGON_ISLE, new WorldPoint(3227, 3831, 0), PANIC, item(DRAGON_MED_HELM), item(TOKTZKETXIL), item(BRINE_SABRE), item(RUNE_PLATEBODY), item(AMULET_OF_GLORY)),
new EmoteClue("Panic at the area flowers meet snow. Equip Blue D'hide vambs, a dragon spear and a rune plateskirt.", HALFWAY_DOWN_TROLLWEISS_MOUNTAIN, new WorldPoint(2776, 3781, 0), PANIC, item(BLUE_DHIDE_VAMB), item(DRAGON_SPEAR), item(RUNE_PLATESKIRT), item(SLED_4084)),
new EmoteClue("Do a push up at the bank of the Warrior's guild. Beware of double agents! Equip a dragon battleaxe, a dragon defender and a slayer helm of any kind.", WARRIORS_GUILD_BANK_29047, new WorldPoint(2843, 3543, 0), PUSH_UP, item(DRAGON_BATTLEAXE), item(DRAGON_DEFENDER), any("Any slayer helmet", item(SLAYER_HELMET), item(BLACK_SLAYER_HELMET), item(GREEN_SLAYER_HELMET), item(PURPLE_SLAYER_HELMET), item(RED_SLAYER_HELMET), item(TURQUOISE_SLAYER_HELMET), item(SLAYER_HELMET_I), item(BLACK_SLAYER_HELMET_I), item(GREEN_SLAYER_HELMET_I), item(PURPLE_SLAYER_HELMET_I), item(RED_SLAYER_HELMET_I), item(TURQUOISE_SLAYER_HELMET_I))),
new EmoteClue("Blow a raspberry at the bank of the Warrior's guild. Beware of double agents! Equip a dragon battleaxe, a dragon defender and a slayer helm of any kind.", WARRIORS_GUILD_BANK_29047, new WorldPoint(2843, 3543, 0), RASPBERRY, item(DRAGON_BATTLEAXE), item(DRAGON_DEFENDER), any("Any slayer helmet", item(SLAYER_HELMET), item(BLACK_SLAYER_HELMET), item(GREEN_SLAYER_HELMET), item(PURPLE_SLAYER_HELMET), item(RED_SLAYER_HELMET), item(TURQUOISE_SLAYER_HELMET), item(SLAYER_HELMET_I), item(BLACK_SLAYER_HELMET_I), item(GREEN_SLAYER_HELMET_I), item(PURPLE_SLAYER_HELMET_I), item(RED_SLAYER_HELMET_I), item(TURQUOISE_SLAYER_HELMET_I))),
new EmoteClue("Do a push up at the bank of the Warrior's guild. Beware of double agents! Equip a dragon battleaxe, a dragon defender and a slayer helm of any kind.", WARRIORS_GUILD_BANK_29047, new WorldPoint(2843, 3543, 0), PUSH_UP, item(DRAGON_BATTLEAXE), item(DRAGON_DEFENDER), any("Any slayer helmet", item(SLAYER_HELMET), item(BLACK_SLAYER_HELMET), item(GREEN_SLAYER_HELMET), item(PURPLE_SLAYER_HELMET), item(RED_SLAYER_HELMET), item(TURQUOISE_SLAYER_HELMET), item(SLAYER_HELMET_I), item(BLACK_SLAYER_HELMET_I), item(GREEN_SLAYER_HELMET_I), item(PURPLE_SLAYER_HELMET_I), item(RED_SLAYER_HELMET_I), item(TURQUOISE_SLAYER_HELMET_I), item(HYDRA_SLAYER_HELMET), item(HYDRA_SLAYER_HELMET_I))),
new EmoteClue("Blow a raspberry at the bank of the Warrior's guild. Beware of double agents! Equip a dragon battleaxe, a dragon defender and a slayer helm of any kind.", WARRIORS_GUILD_BANK_29047, new WorldPoint(2843, 3543, 0), RASPBERRY, item(DRAGON_BATTLEAXE), item(DRAGON_DEFENDER), any("Any slayer helmet", item(SLAYER_HELMET), item(BLACK_SLAYER_HELMET), item(GREEN_SLAYER_HELMET), item(PURPLE_SLAYER_HELMET), item(RED_SLAYER_HELMET), item(TURQUOISE_SLAYER_HELMET), item(SLAYER_HELMET_I), item(BLACK_SLAYER_HELMET_I), item(GREEN_SLAYER_HELMET_I), item(PURPLE_SLAYER_HELMET_I), item(RED_SLAYER_HELMET_I), item(TURQUOISE_SLAYER_HELMET_I), item(HYDRA_SLAYER_HELMET), item(HYDRA_SLAYER_HELMET_I))),
new EmoteClue("Blow a raspberry at the monkey cage in Ardougne Zoo. Equip a studded leather body, bronze platelegs and a normal staff with no orb.", NEAR_THE_PARROTS_IN_ARDOUGNE_ZOO, new WorldPoint(2607, 3282, 0), RASPBERRY, item(STUDDED_BODY), item(BRONZE_PLATELEGS), item(STAFF)),
new EmoteClue("Blow raspberries outside the entrance to Keep Le Faye. Equip a coif, an iron platebody and leather gloves.", OUTSIDE_KEEP_LE_FAYE, new WorldPoint(2757, 3401, 0), RASPBERRY, item(COIF), item(IRON_PLATEBODY), item(LEATHER_GLOVES)),
new EmoteClue("Blow a raspberry in the Fishing Guild bank. Beware of double agents! Equip an elemental shield, blue dragonhide chaps and a rune warhammer.", FISHING_GUILD_BANK, new WorldPoint(2588, 3419, 0), RASPBERRY, item(ELEMENTAL_SHIELD), item(BLUE_DHIDE_CHAPS), item(RUNE_WARHAMMER)),

View File

@@ -78,7 +78,6 @@ class CookingOverlay extends Overlay
return null;
}
panelComponent.setPreferredSize(new Dimension(145, 0));
panelComponent.getChildren().clear();
if (isCooking() || Duration.between(session.getLastCookingAction(), Instant.now()).getSeconds() < COOK_TIMEOUT)

View File

@@ -347,6 +347,12 @@ class DevToolsOverlay extends Overlay
{
graphics.drawPolygon(p);
}
p = decorObject.getConvexHull2();
if (p != null)
{
graphics.drawPolygon(p);
}
}
}

View File

@@ -183,6 +183,9 @@ public class WidgetInfoTableModel extends AbstractTableModel
out.add(new WidgetField<>("ScrollHeight", Widget::getScrollHeight, Widget::setScrollHeight, Integer.class));
out.add(new WidgetField<>("DragDeadZone", Widget::getDragDeadZone, Widget::setDragDeadZone, Integer.class));
out.add(new WidgetField<>("DragDeadTime", Widget::getDragDeadTime, Widget::setDragDeadTime, Integer.class));
out.add(new WidgetField<>("NoClickThrough", Widget::getNoClickThrough, Widget::setNoClickThrough, Boolean.class));
out.add(new WidgetField<>("NoScrollThrough", Widget::getNoScrollThrough, Widget::setNoScrollThrough, Boolean.class));
out.add(new WidgetField<>("TargetVerb", Widget::getTargetVerb, Widget::setTargetVerb, String.class));
return out;
}

View File

@@ -130,6 +130,7 @@ public class DiscordPlugin extends Plugin
clientToolbar.addNavigation(discordButton);
checkForGameStateUpdate();
checkForAreaUpdate();
if (discordService.getCurrentUser() != null)
{

View File

@@ -34,6 +34,7 @@ import java.util.Optional;
import java.util.UUID;
import javax.inject.Inject;
import lombok.Data;
import net.runelite.client.RuneLiteProperties;
import net.runelite.client.discord.DiscordPresence;
import net.runelite.client.discord.DiscordService;
import net.runelite.client.ws.PartyService;
@@ -57,14 +58,16 @@ class DiscordState
private final DiscordService discordService;
private final DiscordConfig config;
private PartyService party;
private final RuneLiteProperties properties;
private DiscordPresence lastPresence;
@Inject
private DiscordState(final DiscordService discordService, final DiscordConfig config, final PartyService party)
private DiscordState(final DiscordService discordService, final DiscordConfig config, final PartyService party, final RuneLiteProperties properties)
{
this.discordService = discordService;
this.config = config;
this.party = party;
this.properties = properties;
}
/**
@@ -90,6 +93,7 @@ class DiscordState
final DiscordPresence.DiscordPresenceBuilder presenceBuilder = DiscordPresence.builder()
.state(lastPresence.getState())
.details(lastPresence.getDetails())
.largeImageText(lastPresence.getLargeImageText())
.startTimestamp(lastPresence.getStartTimestamp())
.smallImageKey(lastPresence.getSmallImageKey())
.partyMax(lastPresence.getPartyMax())
@@ -168,11 +172,15 @@ class DiscordState
}
}
// Replace snapshot with + to make tooltip shorter (so it will span only 1 line)
final String versionShortHand = properties.getVersion().replace("-SNAPSHOT", "+");
final DiscordPresence.DiscordPresenceBuilder presenceBuilder = DiscordPresence.builder()
.state(MoreObjects.firstNonNull(state, ""))
.details(MoreObjects.firstNonNull(details, ""))
.largeImageText(properties.getTitle() + " v" + versionShortHand)
.startTimestamp(event.getStart())
.smallImageKey(MoreObjects.firstNonNull(imageKey, "default"))
.smallImageKey(imageKey)
.partyMax(PARTY_MAX)
.partySize(party.getMembers().size());

View File

@@ -24,10 +24,12 @@
*/
package net.runelite.client.plugins.discord;
import lombok.EqualsAndHashCode;
import lombok.Value;
import net.runelite.http.api.ws.messages.party.PartyMemberMessage;
@Value
@EqualsAndHashCode(callSuper = true)
class DiscordUserInfo extends PartyMemberMessage
{
private final String userId;

View File

@@ -147,7 +147,8 @@ public class FishingPlugin extends Plugin
@Subscribe
public void onGameStateChanged(GameStateChanged gameStateChanged)
{
if (gameStateChanged.getGameState() == GameState.LOADING)
GameState gameState = gameStateChanged.getGameState();
if (gameState == GameState.CONNECTION_LOST || gameState == GameState.LOGIN_SCREEN || gameState == GameState.HOPPING)
{
fishingSpots.clear();
minnowSpots.clear();

View File

@@ -1151,8 +1151,6 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
gl.glTexSubImage2D(gl.GL_TEXTURE_2D, 0, 0, 0, width, height, gl.GL_BGRA, gl.GL_UNSIGNED_INT_8_8_8_8_REV, interfaceBuffer);
}
gl.glBindTexture(gl.GL_TEXTURE_2D, interfaceTexture);
if (client.isStretchedEnabled())
{
Dimension dim = client.getStretchedDimensions();

View File

@@ -1,5 +1,5 @@
/*
*
* Copyright (c) 2019, Adam <Adam@sigterm.info>
* Copyright (c) 2017, Robbie <https://github.com/rbbi>
* Copyright (c) 2018, SomeoneWithAnInternetConnection
* All rights reserved.
@@ -46,6 +46,7 @@ import net.runelite.api.ChatMessageType;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.GrandExchangeOffer;
import net.runelite.api.GrandExchangeOfferState;
import net.runelite.api.ItemComposition;
import net.runelite.api.MenuAction;
import net.runelite.api.MenuEntry;
@@ -56,11 +57,15 @@ import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.GameTick;
import net.runelite.api.events.GrandExchangeOfferChanged;
import net.runelite.api.events.MenuEntryAdded;
import net.runelite.api.events.SessionClose;
import net.runelite.api.events.SessionOpen;
import net.runelite.api.events.WidgetLoaded;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetID;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.Notifier;
import net.runelite.client.account.AccountSession;
import net.runelite.client.account.SessionManager;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.game.ItemManager;
@@ -73,8 +78,10 @@ import net.runelite.client.ui.NavigationButton;
import net.runelite.client.util.ImageUtil;
import net.runelite.client.util.StackFormatter;
import net.runelite.client.util.Text;
import net.runelite.http.api.osbuddy.GrandExchangeClient;
import net.runelite.http.api.osbuddy.GrandExchangeResult;
import net.runelite.http.api.ge.GrandExchangeClient;
import net.runelite.http.api.ge.GrandExchangeTrade;
import net.runelite.http.api.osbuddy.OSBGrandExchangeClient;
import net.runelite.http.api.osbuddy.OSBGrandExchangeResult;
@PluginDescriptor(
name = "Grand Exchange",
@@ -86,7 +93,7 @@ public class GrandExchangePlugin extends Plugin
{
private static final int OFFER_CONTAINER_ITEM = 21;
private static final int OFFER_DEFAULT_ITEM_ID = 6512;
private static final GrandExchangeClient CLIENT = new GrandExchangeClient();
private static final OSBGrandExchangeClient CLIENT = new OSBGrandExchangeClient();
private static final String OSB_GE_TEXT = "<br>OSBuddy Actively traded price: ";
private static final String BUY_LIMIT_GE_TEXT = "<br>Buy limit: ";
@@ -134,10 +141,38 @@ public class GrandExchangePlugin extends Plugin
@Inject
private ScheduledExecutorService executorService;
@Inject
private SessionManager sessionManager;
@Inject
private ConfigManager configManager;
private Widget grandExchangeText;
private Widget grandExchangeItem;
private Map<Integer, Integer> itemGELimits;
private GrandExchangeClient grandExchangeClient;
private SavedOffer getOffer(int slot)
{
String offer = configManager.getConfiguration("geoffer." + client.getUsername().toLowerCase(), Integer.toString(slot));
if (offer == null)
{
return null;
}
return GSON.fromJson(offer, SavedOffer.class);
}
private void setOffer(int slot, SavedOffer offer)
{
configManager.setConfiguration("geoffer." + client.getUsername().toLowerCase(), Integer.toString(slot), GSON.toJson(offer));
}
private void deleteOffer(int slot)
{
configManager.unsetConfiguration("geoffer." + client.getUsername().toLowerCase(), Integer.toString(slot));
}
@Provides
GrandExchangeConfig provideConfig(ConfigManager configManager)
{
@@ -167,6 +202,12 @@ public class GrandExchangePlugin extends Plugin
mouseManager.registerMouseListener(inputListener);
keyManager.registerKeyListener(inputListener);
}
AccountSession accountSession = sessionManager.getAccountSession();
if (accountSession != null)
{
grandExchangeClient = new GrandExchangeClient(accountSession.getUuid());
}
}
@Override
@@ -178,6 +219,27 @@ public class GrandExchangePlugin extends Plugin
grandExchangeText = null;
grandExchangeItem = null;
itemGELimits = null;
grandExchangeClient = null;
}
@Subscribe
public void onSessionOpen(SessionOpen sessionOpen)
{
AccountSession accountSession = sessionManager.getAccountSession();
if (accountSession.getUuid() != null)
{
grandExchangeClient = new GrandExchangeClient(accountSession.getUuid());
}
else
{
grandExchangeClient = null;
}
}
@Subscribe
public void onSessionClose(SessionClose sessionClose)
{
grandExchangeClient = null;
}
@Subscribe
@@ -204,11 +266,79 @@ public class GrandExchangePlugin extends Plugin
@Subscribe
public void onGrandExchangeOfferChanged(GrandExchangeOfferChanged offerEvent)
{
GrandExchangeOffer offer = offerEvent.getOffer();
final int slot = offerEvent.getSlot();
final GrandExchangeOffer offer = offerEvent.getOffer();
ItemComposition offerItem = itemManager.getItemComposition(offer.getItemId());
boolean shouldStack = offerItem.isStackable() || offer.getTotalQuantity() > 1;
BufferedImage itemImage = itemManager.getImage(offer.getItemId(), offer.getTotalQuantity(), shouldStack);
SwingUtilities.invokeLater(() -> panel.getOffersPanel().updateOffer(offerItem, itemImage, offerEvent.getOffer(), offerEvent.getSlot()));
SwingUtilities.invokeLater(() -> panel.getOffersPanel().updateOffer(offerItem, itemImage, offer, slot));
submitTrades(slot, offer);
updateConfig(slot, offer);
}
private void submitTrades(int slot, GrandExchangeOffer offer)
{
if (grandExchangeClient == null)
{
return;
}
// Only interested in offers which are fully bought/sold
if (offer.getState() != GrandExchangeOfferState.BOUGHT && offer.getState() != GrandExchangeOfferState.SOLD)
{
return;
}
SavedOffer savedOffer = getOffer(slot);
if (!shouldUpdate(savedOffer, offer))
{
return;
}
// getPrice() is the price of the offer, not necessarily what the item bought at
int priceEach = offer.getSpent() / offer.getTotalQuantity();
GrandExchangeTrade grandExchangeTrade = new GrandExchangeTrade();
grandExchangeTrade.setBuy(offer.getState() == GrandExchangeOfferState.BOUGHT);
grandExchangeTrade.setItemId(offer.getItemId());
grandExchangeTrade.setQuantity(offer.getTotalQuantity());
grandExchangeTrade.setPrice(priceEach);
log.debug("Submitting trade: {}", grandExchangeTrade);
grandExchangeClient.submit(grandExchangeTrade);
}
private void updateConfig(int slot, GrandExchangeOffer offer)
{
if (offer.getState() == GrandExchangeOfferState.EMPTY)
{
deleteOffer(slot);
}
else
{
SavedOffer savedOffer = new SavedOffer();
savedOffer.setItemId(offer.getItemId());
savedOffer.setQuantitySold(offer.getQuantitySold());
savedOffer.setTotalQuantity(offer.getTotalQuantity());
savedOffer.setPrice(offer.getPrice());
savedOffer.setSpent(offer.getSpent());
savedOffer.setState(offer.getState());
setOffer(slot, savedOffer);
}
}
private boolean shouldUpdate(SavedOffer savedOffer, GrandExchangeOffer grandExchangeOffer)
{
if (savedOffer == null)
{
return false;
}
// Only update offer if state has changed
return savedOffer.getState() != grandExchangeOffer.getState();
}
@Subscribe
@@ -346,7 +476,7 @@ public class GrandExchangePlugin extends Plugin
try
{
final GrandExchangeResult result = CLIENT.lookupItem(itemId);
final OSBGrandExchangeResult result = CLIENT.lookupItem(itemId);
final String text = geText.getText() + OSB_GE_TEXT + StackFormatter.formatNumber(result.getOverall_average());
geText.setText(text);
}

View File

@@ -0,0 +1,39 @@
/*
* 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.grandexchange;
import lombok.Data;
import net.runelite.api.GrandExchangeOfferState;
@Data
class SavedOffer
{
private int itemId;
private int quantitySold;
private int totalQuantity;
private int price;
private int spent;
private GrandExchangeOfferState state;
}

View File

@@ -34,13 +34,13 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import javax.inject.Inject;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import static net.runelite.api.Constants.CHUNK_SIZE;
import net.runelite.api.GameState;
import net.runelite.api.MenuAction;
import net.runelite.api.MenuEntry;
@@ -155,87 +155,23 @@ public class GroundMarkerPlugin extends Plugin
return Collections.EMPTY_LIST;
}
List<WorldPoint> worldPoints = new ArrayList<>();
for (GroundMarkerPoint point : points)
{
int regionId = point.getRegionId();
int regionX = point.getRegionX();
int regionY = point.getRegionY();
int z = point.getZ();
// world point of the tile marker
WorldPoint worldPoint = new WorldPoint(
((regionId >>> 8) << 6) + regionX,
((regionId & 0xff) << 6) + regionY,
z
);
if (!client.isInInstancedRegion())
return points.stream()
.map(point ->
{
worldPoints.add(worldPoint);
continue;
}
int regionId = point.getRegionId();
int regionX = point.getRegionX();
int regionY = point.getRegionY();
int z = point.getZ();
// find instance chunks using the template point. there might be more than one.
int[][][] instanceTemplateChunks = client.getInstanceTemplateChunks();
for (int x = 0; x < instanceTemplateChunks[z].length; ++x)
{
for (int y = 0; y < instanceTemplateChunks[z][x].length; ++y)
{
int chunkData = instanceTemplateChunks[z][x][y];
int rotation = chunkData >> 1 & 0x3;
int templateChunkY = (chunkData >> 3 & 0x7FF) * CHUNK_SIZE;
int templateChunkX = (chunkData >> 14 & 0x3FF) * CHUNK_SIZE;
if (worldPoint.getX() >= templateChunkX && worldPoint.getX() < templateChunkX + CHUNK_SIZE
&& worldPoint.getY() >= templateChunkY && worldPoint.getY() < templateChunkY + CHUNK_SIZE)
{
WorldPoint p = new WorldPoint(client.getBaseX() + x * CHUNK_SIZE + (worldPoint.getX() & (CHUNK_SIZE - 1)),
client.getBaseY() + y * CHUNK_SIZE + (worldPoint.getY() & (CHUNK_SIZE - 1)),
worldPoint.getPlane());
p = rotate(p, rotation);
worldPoints.add(p);
}
}
}
}
return worldPoints;
}
/**
* Rotate the chunk containing the given point to rotation 0
*
* @param point point
* @param rotation rotation
* @return world point
*/
private static WorldPoint rotateInverse(WorldPoint point, int rotation)
{
return rotate(point, 4 - rotation);
}
/**
* Rotate the coordinates in the chunk according to chunk rotation
*
* @param point point
* @param rotation rotation
* @return world point
*/
private static WorldPoint rotate(WorldPoint point, int rotation)
{
int chunkX = point.getX() & ~(CHUNK_SIZE - 1);
int chunkY = point.getY() & ~(CHUNK_SIZE - 1);
int x = point.getX() & (CHUNK_SIZE - 1);
int y = point.getY() & (CHUNK_SIZE - 1);
switch (rotation)
{
case 1:
return new WorldPoint(chunkX + y, chunkY + (CHUNK_SIZE - 1 - x), point.getPlane());
case 2:
return new WorldPoint(chunkX + (CHUNK_SIZE - 1 - x), chunkY + (CHUNK_SIZE - 1 - y), point.getPlane());
case 3:
return new WorldPoint(chunkX + (CHUNK_SIZE - 1 - y), chunkY + x, point.getPlane());
}
return point;
// world point of the tile marker
return new WorldPoint(
((regionId >>> 8) << 6) + regionX,
((regionId & 0xff) << 6) + regionY,
z
);
})
.flatMap(wp -> WorldPoint.toLocalInstance(client, wp).stream())
.collect(Collectors.toList());
}
@Subscribe

View File

@@ -202,6 +202,7 @@ public class IdleNotifierPlugin extends Plugin
case MAGIC_CHARGING_ORBS:
case MAGIC_LUNAR_STRING_JEWELRY:
case MAGIC_MAKE_TABLET:
case MAGIC_ENCHANTING_JEWELRY:
/* Prayer */
case USING_GILDED_ALTAR:
/* Farming */

View File

@@ -40,6 +40,7 @@ import javax.inject.Singleton;
import javax.swing.Box;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.event.HyperlinkEvent;
@@ -48,6 +49,7 @@ import net.runelite.api.events.SessionClose;
import net.runelite.api.events.SessionOpen;
import net.runelite.client.RuneLiteProperties;
import net.runelite.client.account.SessionManager;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.ui.ColorScheme;
@@ -66,9 +68,12 @@ public class InfoPanel extends PluginPanel
private static final ImageIcon DISCORD_ICON;
private static final ImageIcon PATREON_ICON;
private static final ImageIcon WIKI_ICON;
private static final ImageIcon IMPORT_ICON;
private final JLabel loggedLabel = new JLabel();
private final JRichTextPane emailLabel = new JRichTextPane();
private JPanel syncPanel;
private JPanel actionsContainer;
@Inject
@Nullable
@@ -86,6 +91,9 @@ public class InfoPanel extends PluginPanel
@Inject
private ScheduledExecutorService executor;
@Inject
private ConfigManager configManager;
static
{
ARROW_RIGHT_ICON = new ImageIcon(ImageUtil.getResourceStreamFromClass(InfoPanel.class, "/util/arrow_right.png"));
@@ -93,6 +101,7 @@ public class InfoPanel extends PluginPanel
DISCORD_ICON = new ImageIcon(ImageUtil.getResourceStreamFromClass(InfoPanel.class, "discord_icon.png"));
PATREON_ICON = new ImageIcon(ImageUtil.getResourceStreamFromClass(InfoPanel.class, "patreon_icon.png"));
WIKI_ICON = new ImageIcon(ImageUtil.getResourceStreamFromClass(InfoPanel.class, "wiki_icon.png"));
IMPORT_ICON = new ImageIcon(ImageUtil.getResourceStreamFromClass(InfoPanel.class, "import_icon.png"));
}
void init()
@@ -150,11 +159,22 @@ public class InfoPanel extends PluginPanel
versionPanel.add(loggedLabel);
versionPanel.add(emailLabel);
updateLoggedIn();
JPanel actionsContainer = new JPanel();
actionsContainer = new JPanel();
actionsContainer.setBorder(new EmptyBorder(10, 0, 0, 0));
actionsContainer.setLayout(new GridLayout(4, 1, 0, 10));
actionsContainer.setLayout(new GridLayout(0, 1, 0, 10));
syncPanel = buildLinkPanel(IMPORT_ICON, "Import local settings", "to remote RuneLite account", () ->
{
final int result = JOptionPane.showOptionDialog(syncPanel,
"This will replace your current RuneLite account settings with settings from your local profile.",
"Are you sure?", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE,
null, new String[]{"Yes", "No"}, "No");
if (result == JOptionPane.YES_OPTION)
{
configManager.importLocal();
}
});
actionsContainer.add(buildLinkPanel(GITHUB_ICON, "Report an issue or", "make a suggestion", runeLiteProperties.getGithubLink()));
actionsContainer.add(buildLinkPanel(DISCORD_ICON, "Talk to us on our", "discord server", runeLiteProperties.getDiscordInvite()));
@@ -164,6 +184,7 @@ public class InfoPanel extends PluginPanel
add(versionPanel, BorderLayout.NORTH);
add(actionsContainer, BorderLayout.CENTER);
updateLoggedIn();
eventBus.register(this);
}
@@ -171,6 +192,14 @@ public class InfoPanel extends PluginPanel
* Builds a link panel with a given icon, text and url to redirect to.
*/
private static JPanel buildLinkPanel(ImageIcon icon, String topText, String bottomText, String url)
{
return buildLinkPanel(icon, topText, bottomText, () -> LinkBrowser.browse(url));
}
/**
* Builds a link panel with a given icon, text and callable to call.
*/
private static JPanel buildLinkPanel(ImageIcon icon, String topText, String bottomText, Runnable callback)
{
JPanel container = new JPanel();
container.setBackground(ColorScheme.DARKER_GRAY_COLOR);
@@ -193,7 +222,6 @@ public class InfoPanel extends PluginPanel
@Override
public void mousePressed(MouseEvent mouseEvent)
{
LinkBrowser.browse(url);
container.setBackground(pressedColor);
textContainer.setBackground(pressedColor);
}
@@ -201,6 +229,7 @@ public class InfoPanel extends PluginPanel
@Override
public void mouseReleased(MouseEvent e)
{
callback.run();
container.setBackground(hoverColor);
textContainer.setBackground(hoverColor);
}
@@ -252,12 +281,14 @@ public class InfoPanel extends PluginPanel
emailLabel.setContentType("text/plain");
emailLabel.setText(name);
loggedLabel.setText("Logged in as");
actionsContainer.add(syncPanel, 0);
}
else
{
emailLabel.setContentType("text/html");
emailLabel.setText("<a href=\"" + RUNELITE_LOGIN + "\">Login</a> to sync settings to the cloud.");
loggedLabel.setText("Not logged in");
actionsContainer.remove(syncPanel);
}
}

View File

@@ -203,4 +203,15 @@ public interface ItemChargeConfig extends Config
{
return false;
}
@ConfigItem(
keyName = "showInfoboxes",
name = "Show Infoboxes",
description = "Configures whether to show an infobox equipped charge items",
position = 15
)
default boolean showInfoboxes()
{
return false;
}
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright (c) 2018, Hydrox6 <ikada@protonmail.ch>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.itemcharges;
import java.awt.Color;
import java.awt.image.BufferedImage;
import lombok.Getter;
import net.runelite.api.EquipmentInventorySlot;
import net.runelite.client.ui.overlay.infobox.Counter;
@Getter
class ItemChargeInfobox extends Counter
{
private final ItemChargePlugin plugin;
private final ItemWithSlot item;
private final EquipmentInventorySlot slot;
ItemChargeInfobox(
ItemChargePlugin plugin,
BufferedImage image,
String name,
int charges,
ItemWithSlot item,
EquipmentInventorySlot slot)
{
super(image, plugin, charges);
setTooltip(name);
this.plugin = plugin;
this.item = item;
this.slot = slot;
}
@Override
public Color getTextColor()
{
return getPlugin().getColor(getCount());
}
}

View File

@@ -24,7 +24,6 @@
*/
package net.runelite.client.plugins.itemcharges;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Point;
@@ -83,7 +82,7 @@ class ItemChargeOverlay extends Overlay
continue;
}
charges = itemChargePlugin.getDodgyCharges();
charges = config.dodgyNecklace();
}
else
{
@@ -112,7 +111,7 @@ class ItemChargeOverlay extends Overlay
final TextComponent textComponent = new TextComponent();
textComponent.setPosition(new Point(bounds.x, bounds.y + 16));
textComponent.setText(charges < 0 ? "?" : String.valueOf(charges));
textComponent.setColor(getColor(charges));
textComponent.setColor(itemChargePlugin.getColor(charges));
textComponent.render(graphics);
}
return null;
@@ -137,20 +136,6 @@ class ItemChargeOverlay extends Overlay
return jewellery;
}
private Color getColor(int charges)
{
Color color = Color.WHITE;
if (charges <= config.veryLowWarning())
{
color = config.veryLowWarningColor();
}
else if (charges <= config.lowWarning())
{
color = config.lowWarningolor();
}
return color;
}
private boolean displayOverlay()
{
return config.showTeleportCharges() || config.showDodgyCount() || config.showFungicideCharges()

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2017, Seth <Sethtroll3@gmail.com>
* Copyright (c) 2018, Hydrox6 <ikada@protonmail.ch>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,19 +26,29 @@
package net.runelite.client.plugins.itemcharges;
import com.google.inject.Provides;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.inject.Inject;
import lombok.AccessLevel;
import lombok.Getter;
import net.runelite.api.ChatMessageType;
import net.runelite.api.Client;
import net.runelite.api.EquipmentInventorySlot;
import net.runelite.api.InventoryID;
import net.runelite.api.Item;
import net.runelite.api.ItemContainer;
import net.runelite.api.ItemID;
import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.ItemContainerChanged;
import net.runelite.client.Notifier;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.game.ItemManager;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.overlay.OverlayManager;
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
@PluginDescriptor(
name = "Item Charges",
@@ -56,21 +67,27 @@ public class ItemChargePlugin extends Plugin
private static final int MAX_DODGY_CHARGES = 10;
@Inject
private Client client;
@Inject
private OverlayManager overlayManager;
@Inject
private ItemChargeOverlay overlay;
@Inject
private ItemManager itemManager;
@Inject
private InfoBoxManager infoBoxManager;
@Inject
private Notifier notifier;
@Inject
private ItemChargeConfig config;
@Getter(AccessLevel.PACKAGE)
private int dodgyCharges;
@Provides
ItemChargeConfig getConfig(ConfigManager configManager)
{
@@ -81,13 +98,43 @@ public class ItemChargePlugin extends Plugin
protected void startUp()
{
overlayManager.add(overlay);
dodgyCharges = config.dodgyNecklace();
}
@Override
protected void shutDown() throws Exception
{
overlayManager.remove(overlay);
infoBoxManager.removeIf(ItemChargeInfobox.class::isInstance);
}
@Subscribe
public void onConfigChanged(ConfigChanged event)
{
if (!event.getGroup().equals("itemCharge"))
{
return;
}
if (!config.showInfoboxes())
{
infoBoxManager.removeIf(ItemChargeInfobox.class::isInstance);
return;
}
if (!config.showTeleportCharges())
{
removeInfobox(ItemWithSlot.TELEPORT);
}
if (!config.showAbyssalBraceletCharges())
{
removeInfobox(ItemWithSlot.ABYSSAL_BRACELET);
}
if (!config.showDodgyCount())
{
removeInfobox(ItemWithSlot.DODGY_NECKLACE);
}
}
@Subscribe
@@ -110,22 +157,141 @@ public class ItemChargePlugin extends Plugin
notifier.notify("Your dodgy necklace has crumbled to dust.");
}
setDodgyCharges(MAX_DODGY_CHARGES);
updateDodgyNecklaceCharges(MAX_DODGY_CHARGES);
}
else if (dodgyCheckMatcher.find())
{
setDodgyCharges(Integer.parseInt(dodgyCheckMatcher.group(1)));
updateDodgyNecklaceCharges(Integer.parseInt(dodgyCheckMatcher.group(1)));
}
else if (dodgyProtectMatcher.find())
{
setDodgyCharges(Integer.parseInt(dodgyProtectMatcher.group(1)));
updateDodgyNecklaceCharges(Integer.parseInt(dodgyProtectMatcher.group(1)));
}
}
}
private void setDodgyCharges(int dodgyCharges)
@Subscribe
public void onItemContainerChanged(ItemContainerChanged event)
{
this.dodgyCharges = dodgyCharges;
config.dodgyNecklace(dodgyCharges);
if (event.getItemContainer() != client.getItemContainer(InventoryID.EQUIPMENT) || !config.showInfoboxes())
{
return;
}
final Item[] items = event.getItemContainer().getItems();
if (config.showTeleportCharges())
{
updateJewelleryInfobox(ItemWithSlot.TELEPORT, items);
}
if (config.showDodgyCount())
{
updateJewelleryInfobox(ItemWithSlot.DODGY_NECKLACE, items);
}
if (config.showAbyssalBraceletCharges())
{
updateJewelleryInfobox(ItemWithSlot.ABYSSAL_BRACELET, items);
}
}
private void updateDodgyNecklaceCharges(final int value)
{
config.dodgyNecklace(value);
if (config.showInfoboxes() && config.showDodgyCount())
{
final ItemContainer itemContainer = client.getItemContainer(InventoryID.EQUIPMENT);
if (itemContainer == null)
{
return;
}
updateJewelleryInfobox(ItemWithSlot.DODGY_NECKLACE, itemContainer.getItems());
}
}
private void updateJewelleryInfobox(ItemWithSlot item, Item[] items)
{
for (final EquipmentInventorySlot equipmentInventorySlot : item.getSlots())
{
updateJewelleryInfobox(item, items, equipmentInventorySlot);
}
}
private void updateJewelleryInfobox(ItemWithSlot type, Item[] items, EquipmentInventorySlot slot)
{
removeInfobox(type, slot);
if (slot.getSlotIdx() >= items.length)
{
return;
}
final int id = items[slot.getSlotIdx()].getId();
if (id < 0)
{
return;
}
final ItemWithCharge itemWithCharge = ItemWithCharge.findItem(id);
int charges = -1;
if (itemWithCharge == null)
{
if (id == ItemID.DODGY_NECKLACE && type == ItemWithSlot.DODGY_NECKLACE)
{
charges = config.dodgyNecklace();
}
}
else if (itemWithCharge.getType() == type.getType())
{
charges = itemWithCharge.getCharges();
}
if (charges <= 0)
{
return;
}
final String name = itemManager.getItemComposition(id).getName();
final BufferedImage image = itemManager.getImage(id);
final ItemChargeInfobox infobox = new ItemChargeInfobox(this, image, name, charges, type, slot);
infoBoxManager.addInfoBox(infobox);
}
private void removeInfobox(final ItemWithSlot item)
{
infoBoxManager.removeIf(t -> t instanceof ItemChargeInfobox && ((ItemChargeInfobox) t).getItem() == item);
}
private void removeInfobox(final ItemWithSlot item, final EquipmentInventorySlot slot)
{
infoBoxManager.removeIf(t ->
{
if (!(t instanceof ItemChargeInfobox))
{
return false;
}
final ItemChargeInfobox i = (ItemChargeInfobox)t;
return i.getItem() == item && i.getSlot() == slot;
});
}
Color getColor(int charges)
{
Color color = Color.WHITE;
if (charges <= config.veryLowWarning())
{
color = config.veryLowWarningColor();
}
else if (charges <= config.lowWarning())
{
color = config.lowWarningolor();
}
return color;
}
}

View File

@@ -32,5 +32,6 @@ enum ItemChargeType
IMPBOX,
TELEPORT,
WATERCAN,
WATERSKIN
WATERSKIN,
DODGY_NECKLACE
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright (c) 2019, Tomas Slusny <slusnucky@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.itemcharges;
import com.google.common.collect.Sets;
import java.util.Set;
import lombok.Getter;
import net.runelite.api.EquipmentInventorySlot;
@Getter
enum ItemWithSlot
{
ABYSSAL_BRACELET(ItemChargeType.ABYSSAL_BRACELET, EquipmentInventorySlot.GLOVES),
DODGY_NECKLACE(ItemChargeType.DODGY_NECKLACE, EquipmentInventorySlot.AMULET),
TELEPORT(ItemChargeType.TELEPORT, EquipmentInventorySlot.WEAPON, EquipmentInventorySlot.AMULET, EquipmentInventorySlot.GLOVES, EquipmentInventorySlot.RING);
private final ItemChargeType type;
private final Set<EquipmentInventorySlot> slots;
ItemWithSlot(final ItemChargeType type, final EquipmentInventorySlot... slots)
{
this.type = type;
this.slots = Sets.newHashSet(slots);
}
}

View File

@@ -74,4 +74,16 @@ public interface ItemPricesConfig extends Config
{
return true;
}
@ConfigItem(
keyName = "showAlchProfit",
name = "Show High Alchemy Profit",
description = "Show the profit from casting high alchemy on items",
position = 5
)
default boolean showAlchProfit()
{
return false;
}
}

View File

@@ -196,6 +196,7 @@ class ItemPricesOverlay extends Overlay
int gePrice = 0;
int haPrice = 0;
int haProfit = 0;
if (config.showGEPrice())
{
@@ -205,16 +206,20 @@ class ItemPricesOverlay extends Overlay
{
haPrice = Math.round(itemDef.getPrice() * HIGH_ALCHEMY_CONSTANT);
}
if (gePrice > 0 && haPrice > 0 && config.showAlchProfit())
{
haProfit = calculateHAProfit(haPrice, gePrice);
}
if (gePrice > 0 || haPrice > 0)
{
return stackValueText(qty, gePrice, haPrice);
return stackValueText(qty, gePrice, haPrice, haProfit);
}
return null;
}
private String stackValueText(int qty, int gePrice, int haValue)
private String stackValueText(int qty, int gePrice, int haValue, int haProfit)
{
if (gePrice > 0)
{
@@ -246,9 +251,36 @@ class ItemPricesOverlay extends Overlay
}
}
if (haProfit != 0)
{
Color haColor = haProfitColor(haProfit);
itemStringBuilder.append("</br>");
itemStringBuilder.append("HA Profit: ")
.append(ColorUtil.wrapWithColorTag(String.valueOf(haProfit * qty), haColor))
.append(" gp");
if (config.showEA() && qty > 1)
{
itemStringBuilder.append(" (")
.append(ColorUtil.wrapWithColorTag(String.valueOf(haProfit), haColor))
.append(" ea)");
}
}
// Build string and reset builder
final String text = itemStringBuilder.toString();
itemStringBuilder.setLength(0);
return text;
}
private int calculateHAProfit(int haPrice, int gePrice)
{
int natureRunePrice = itemManager.getItemPrice(ItemID.NATURE_RUNE);
return haPrice - gePrice - natureRunePrice;
}
private static Color haProfitColor(int haProfit)
{
return haProfit >= 0 ? Color.GREEN : Color.RED;
}
}

View File

@@ -258,7 +258,7 @@ public class ItemStatOverlay extends Overlay
if (config.relative())
{
b.append(c.getRelative());
b.append(c.getFormattedRelative());
}
if (config.theoretical())
@@ -267,7 +267,7 @@ public class ItemStatOverlay extends Overlay
{
b.append("/");
}
b.append(c.getTheoretical());
b.append(c.getFormattedTheoretical());
}
if (config.absolute() && (config.relative() || config.theoretical()))

View File

@@ -42,33 +42,21 @@ public class RangeStatBoost extends SingleEffect
@Override
public StatChange effect(Client client)
{
final StatChange a = this.a.effect(client);
final StatChange b = this.b.effect(client);
final StatChange changeA = this.a.effect(client);
final StatChange changeB = this.b.effect(client);
final StatChange r = new StatChange();
r.setAbsolute(concat(a.getAbsolute(), b.getAbsolute()));
r.setRelative(concat(a.getRelative(), b.getRelative()));
r.setTheoretical(concat(a.getTheoretical(), b.getTheoretical()));
r.setStat(a.getStat());
final RangeStatChange r = new RangeStatChange();
r.setMinAbsolute(Math.min(changeA.getAbsolute(), changeB.getAbsolute()));
r.setAbsolute(Math.max(changeA.getAbsolute(), changeB.getAbsolute()));
r.setMinRelative(Math.min(changeA.getRelative(), changeB.getRelative()));
r.setRelative(Math.max(changeA.getRelative(), changeB.getRelative()));
r.setMinTheoretical(Math.min(changeA.getTheoretical(), changeB.getTheoretical()));
r.setTheoretical(Math.max(changeA.getTheoretical(), changeB.getTheoretical()));
r.setStat(changeA.getStat());
final int avg = (a.getPositivity().ordinal() + b.getPositivity().ordinal()) / 2;
final int avg = (changeA.getPositivity().ordinal() + changeB.getPositivity().ordinal()) / 2;
r.setPositivity(Positivity.values()[avg]);
return r;
}
private String concat(String a, String b)
{
// If they share a operator, strip b's duplicate
if (a.length() > 1 && b.length() > 1)
{
final char a0 = a.charAt(0);
if ((a0 == '+' || a0 == '-' || a0 == '±') && b.charAt(0) == a0)
{
b = b.substring(1);
}
}
return a + "~" + b;
}
}

View File

@@ -0,0 +1,117 @@
/*
* Copyright (c) 2016-2019, Jordan Atwood <nightfirecat@protonmail.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.itemstats;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* A stat change which can result in different magnitudes of change to the stat
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class RangeStatChange extends StatChange
{
/**
* Minimum relative change that will occur if the stat boost is applied now.
* In this class, {@code relative} is representative of the maximum relative change that will
* occur.
*/
private int minRelative;
/**
* Minimum theoretical change that can occur before boost cap is enforced.
* In this class, {@code theoretical} is representative of the maximum theoretical change that
* will occur.
*/
private int minTheoretical;
/**
* Minimum absolute total of the stat after applying the boost.
* In this class, {@code absolute} is representative of the maximum absolute change that will
* occur.
*/
private int minAbsolute;
/**
* Returns a human-readable formatted relative boost.
* Should be the boost range in the format "±N" (for minimum -N and maximum +N values),
* "+MIN~MAX" (for minimum and maximum values of the same sign),
* "-MIN~+MAX" (for negative minimum and positive maximum values), or
* "+MAX" (for equal minimum and maximum values).
*
* @return The formatted relative boost amount
*/
@Override
public String getFormattedRelative()
{
return concat(minRelative, getRelative());
}
/**
* Returns a human-readable formatted theoretical boost.
* Should be the boost range in the format "±N" (for minimum -N and maximum +N values),
* "+MIN~MAX" (for minimum and maximum values of the same sign),
* "-MIN~+MAX" (for negative minimum and positive maximum values), or
* "+MAX" (for equal minimum and maximum values).
*
* @return The formatted theoretical boost amount
*/
@Override
public String getFormattedTheoretical()
{
return concat(minTheoretical, getTheoretical());
}
private static String concat(int changeA, int changeB)
{
if (changeA == changeB)
{
return formatBoost(changeA);
}
else if (changeA * -1 == changeB)
{
return "±" + Math.abs(changeA);
}
final StringBuilder sb = new StringBuilder();
sb.append(String.format("%+d", changeA));
sb.append('~');
// If they share a operator, strip b's duplicate
if (changeA < 0 && changeB < 0
|| changeA >= 0 && changeB >= 0)
{
sb.append(Math.abs(changeB));
}
else
{
sb.append(String.format("%+d", changeB));
}
return sb.toString();
}
}

View File

@@ -88,10 +88,9 @@ public abstract class StatBoost extends SingleEffect
{
out.setPositivity(Positivity.WORSE);
}
out.setAbsolute(Integer.toString(newValue));
out.setRelative(String.format("%+d", delta));
out.setTheoretical(String.format("%+d", calcedDelta));
out.setAbsolute(newValue);
out.setRelative(delta);
out.setTheoretical(calcedDelta);
return out;
}
}

View File

@@ -40,23 +40,48 @@ public class StatChange
/**
* Relative change that will occur if the stat boost is applied now.
* Should be a number prefixed by "+" or "-".
*/
private String relative;
private int relative;
/**
* Theoretical change that can occur before boost cap is enforced.
* Should be a number prefixed by "+" or "-".
*/
private String theoretical;
private int theoretical;
/**
* Absolute total of the stat after applying the boost.
*/
private String absolute;
private int absolute;
/**
* How beneficial this stat boost will be to the player.
*/
private Positivity positivity;
/**
* Returns a human-readable formatted relative boost.
* Should be the boost amount prefixed by "+" or "-".
*
* @return The formatted relative boost amount
*/
public String getFormattedRelative()
{
return formatBoost(relative);
}
/**
* Returns a human-readable formatted theoretical boost.
* Should be the boost amount prefixed by "+" or "-".
*
* @return The formatted theoretical boost amount
*/
public String getFormattedTheoretical()
{
return formatBoost(theoretical);
}
static String formatBoost(int boost)
{
return String.format("%+d", boost);
}
}

View File

@@ -132,11 +132,14 @@ public class SpicyStew implements Effect
int currentBoost = currentValue - currentBase; // Can be negative
int spiceBoostCapped = (currentBoost <= 0) ? spiceBoost : Math.max(0, spiceBoost - currentBoost);
StatChange change = new StatChange();
final RangeStatChange change = new RangeStatChange();
change.setStat(stat);
change.setRelative("±" + spiceBoostCapped);
change.setTheoretical("±" + spiceBoost);
change.setAbsolute(String.valueOf(stat.getValue(client) + spiceBoostCapped));
change.setMinRelative(-spiceBoost);
change.setRelative(spiceBoostCapped);
change.setMinTheoretical(-spiceBoost);
change.setTheoretical(spiceBoost);
change.setMinAbsolute(Math.max(-spiceBoost, -currentValue));
change.setAbsolute(stat.getValue(client) + spiceBoostCapped);
Positivity positivity;
if (spiceBoostCapped == 0)
@@ -155,5 +158,4 @@ public class SpicyStew implements Effect
return change;
}
}

View File

@@ -32,9 +32,9 @@ public class KingdomCounter extends Counter
{
private final KingdomPlugin plugin;
public KingdomCounter(BufferedImage image, KingdomPlugin plugin)
KingdomCounter(BufferedImage image, KingdomPlugin plugin)
{
super(image, plugin, String.valueOf(plugin.getFavor()));
super(image, plugin, plugin.getFavor());
this.plugin = plugin;
}

View File

@@ -42,4 +42,14 @@ public interface KourendLibraryConfig extends Config
{
return true;
}
@ConfigItem(
keyName = "hideDuplicateBook",
name = "Hide duplicate book",
description = "Don't show the duplicate book locations in the library"
)
default boolean hideDuplicateBook()
{
return true;
}
}

View File

@@ -35,6 +35,7 @@ import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import lombok.AccessLevel;
import lombok.Setter;
import net.runelite.api.Client;
@@ -54,15 +55,19 @@ class KourendLibraryOverlay extends Overlay
private final static int MAXIMUM_DISTANCE = 24;
private final Library library;
private final Client client;
private final KourendLibraryConfig config;
private final KourendLibraryPlugin plugin;
@Setter(AccessLevel.PACKAGE)
private boolean hidden;
@Inject
private KourendLibraryOverlay(Library library, Client client)
private KourendLibraryOverlay(Library library, Client client, KourendLibraryConfig config, KourendLibraryPlugin plugin)
{
this.library = library;
this.client = client;
this.config = config;
this.plugin = plugin;
setPosition(OverlayPosition.DYNAMIC);
setLayer(OverlayLayer.ABOVE_SCENE);
@@ -133,7 +138,7 @@ class KourendLibraryOverlay extends Overlay
Color color = bookIsKnown ? Color.ORANGE : Color.WHITE;
// Render the poly on the floor
if (!(bookIsKnown && book == null) && (library.getState() == SolvedState.NO_DATA || book != null || !possible.isEmpty()))
if (!(bookIsKnown && book == null) && (library.getState() == SolvedState.NO_DATA || book != null || !possible.isEmpty()) && !shouldHideOverlayIfDuplicateBook(book))
{
Polygon poly = getCanvasTilePoly(client, localBookcase);
if (poly != null)
@@ -146,7 +151,7 @@ class KourendLibraryOverlay extends Overlay
// If the book is singled out, render the text and the book's icon
if (bookIsKnown)
{
if (book != null)
if (book != null && !shouldHideOverlayIfDuplicateBook(book))
{
FontMetrics fm = g.getFontMetrics();
Rectangle2D bounds = fm.getStringBounds(book.getShortName(), g);
@@ -216,9 +221,10 @@ class KourendLibraryOverlay extends Overlay
.forEach(n ->
{
Book b = library.getCustomerBook();
boolean doesPlayerContainBook = b != null && plugin.doesPlayerContainBook(b);
LocalPoint local = n.getLocalLocation();
Polygon poly = getCanvasTilePoly(client, local);
OverlayUtil.renderPolygon(g, poly, Color.WHITE);
OverlayUtil.renderPolygon(g, poly, doesPlayerContainBook ? Color.GREEN : Color.WHITE);
Point screen = Perspective.localToCanvas(client, local, client.getPlane(), n.getLogicalHeight());
if (screen != null)
{
@@ -229,4 +235,12 @@ class KourendLibraryOverlay extends Overlay
return null;
}
private boolean shouldHideOverlayIfDuplicateBook(@Nullable Book book)
{
return config.hideDuplicateBook()
&& book != null
&& !book.isDarkManuscript()
&& plugin.doesPlayerContainBook(book);
}
}

View File

@@ -26,6 +26,7 @@ package net.runelite.client.plugins.kourendlibrary;
import com.google.inject.Provides;
import java.awt.image.BufferedImage;
import java.util.EnumSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.inject.Inject;
@@ -34,6 +35,9 @@ import lombok.extern.slf4j.Slf4j;
import net.runelite.api.AnimationID;
import net.runelite.api.ChatMessageType;
import net.runelite.api.Client;
import net.runelite.api.InventoryID;
import net.runelite.api.Item;
import net.runelite.api.ItemContainer;
import net.runelite.api.MenuAction;
import net.runelite.api.Player;
import net.runelite.api.coords.WorldPoint;
@@ -41,6 +45,7 @@ import net.runelite.api.events.AnimationChanged;
import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.GameTick;
import net.runelite.api.events.ItemContainerChanged;
import net.runelite.api.events.MenuOptionClicked;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
@@ -94,6 +99,7 @@ public class KourendLibraryPlugin extends Plugin
private boolean buttonAttached = false;
private WorldPoint lastBookcaseClick = null;
private WorldPoint lastBookcaseAnimatedOn = null;
private EnumSet<Book> playerBooks = null;
@Provides
KourendLibraryConfig provideConfig(ConfigManager configManager)
@@ -120,6 +126,8 @@ public class KourendLibraryPlugin extends Plugin
overlayManager.add(overlay);
updatePlayerBooks();
if (!config.hideButton())
{
clientToolbar.addNavigation(navButton);
@@ -135,6 +143,7 @@ public class KourendLibraryPlugin extends Plugin
buttonAttached = false;
lastBookcaseClick = null;
lastBookcaseAnimatedOn = null;
playerBooks = null;
}
@Subscribe
@@ -271,4 +280,37 @@ public class KourendLibraryPlugin extends Plugin
}
}
}
@Subscribe
public void onItemContainerChanged(ItemContainerChanged itemContainerChangedEvent)
{
updatePlayerBooks();
}
boolean doesPlayerContainBook(Book book)
{
return playerBooks.contains(book);
}
private void updatePlayerBooks()
{
ItemContainer itemContainer = client.getItemContainer(InventoryID.INVENTORY);
if (itemContainer != null)
{
EnumSet<Book> books = EnumSet.noneOf(Book.class);
for (Item item : itemContainer.getItems())
{
Book book = Book.byId(item.getId());
if (book != null)
{
books.add(book);
}
}
playerBooks = books;
}
}
}

View File

@@ -51,11 +51,23 @@ public interface LootTrackerConfig extends Config
@ConfigItem(
keyName = "saveLoot",
name = "Save loot",
description = "Save loot between client sessions (requires being logged in)"
name = "Submit loot tracker data",
description = "Submit loot tracker data (requires being logged in)"
)
default boolean saveLoot()
{
return true;
}
@ConfigItem(
keyName = "syncPanel",
name = "Synchronize panel contents",
description = "Synchronize you local loot tracker with your online (requires being logged in). This means" +
" that panel is filled with portion of your remote data on startup and deleting data in panel deletes them" +
" also on server."
)
default boolean syncPanel()
{
return true;
}
}

View File

@@ -99,6 +99,7 @@ class LootTrackerPanel extends PluginPanel
private final ItemManager itemManager;
private final LootTrackerPlugin plugin;
private final LootTrackerConfig config;
private boolean groupLoot;
private boolean hideIgnoredItems;
@@ -130,10 +131,11 @@ class LootTrackerPanel extends PluginPanel
INVISIBLE_ICON_HOVER = new ImageIcon(ImageUtil.alphaOffset(invisibleImg, -220));
}
LootTrackerPanel(final LootTrackerPlugin plugin, final ItemManager itemManager)
LootTrackerPanel(final LootTrackerPlugin plugin, final ItemManager itemManager, final LootTrackerConfig config)
{
this.itemManager = itemManager;
this.plugin = plugin;
this.config = config;
this.hideIgnoredItems = true;
setBorder(new EmptyBorder(6, 6, 6, 6));
@@ -297,7 +299,7 @@ class LootTrackerPanel extends PluginPanel
// Delete all loot, or loot matching the current view
LootTrackerClient client = plugin.getLootTrackerClient();
if (client != null)
if (client != null && config.syncPanel())
{
client.delete(currentView);
}
@@ -472,7 +474,7 @@ class LootTrackerPanel extends PluginPanel
LootTrackerClient client = plugin.getLootTrackerClient();
// Without loot being grouped we have no way to identify single kills to be deleted
if (client != null && groupLoot)
if (client != null && groupLoot && config.syncPanel())
{
client.delete(box.getId());
}

View File

@@ -28,6 +28,7 @@ package net.runelite.client.plugins.loottracker;
import com.google.inject.Provides;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -194,7 +195,7 @@ public class LootTrackerPlugin extends Plugin
protected void startUp() throws Exception
{
ignoredItems = Text.fromCSV(config.getIgnoredItems());
panel = new LootTrackerPanel(this, itemManager);
panel = new LootTrackerPanel(this, itemManager, config);
spriteManager.getSpriteAsync(SpriteID.TAB_INVENTORY, 0, panel::loadHeaderIcon);
final BufferedImage icon = ImageUtil.getResourceStreamFromClass(getClass(), "panel_icon.png");
@@ -226,9 +227,8 @@ public class LootTrackerPlugin extends Plugin
{
Collection<LootRecord> lootRecords;
if (!config.saveLoot())
if (!config.syncPanel())
{
// don't load loot if we're not saving loot
return;
}
@@ -274,7 +274,7 @@ public class LootTrackerPlugin extends Plugin
if (lootTrackerClient != null && config.saveLoot())
{
LootRecord lootRecord = new LootRecord(name, LootRecordType.NPC, toGameItems(items));
LootRecord lootRecord = new LootRecord(name, LootRecordType.NPC, toGameItems(items), Instant.now());
lootTrackerClient.submit(lootRecord);
}
}
@@ -291,7 +291,7 @@ public class LootTrackerPlugin extends Plugin
if (lootTrackerClient != null && config.saveLoot())
{
LootRecord lootRecord = new LootRecord(name, LootRecordType.PLAYER, toGameItems(items));
LootRecord lootRecord = new LootRecord(name, LootRecordType.PLAYER, toGameItems(items), Instant.now());
lootTrackerClient.submit(lootRecord);
}
}
@@ -350,7 +350,7 @@ public class LootTrackerPlugin extends Plugin
if (lootTrackerClient != null && config.saveLoot())
{
LootRecord lootRecord = new LootRecord(eventType, LootRecordType.EVENT, toGameItems(items));
LootRecord lootRecord = new LootRecord(eventType, LootRecordType.EVENT, toGameItems(items), Instant.now());
lootTrackerClient.submit(lootRecord);
}
}

View File

@@ -45,8 +45,10 @@ import net.runelite.api.events.MenuOptionClicked;
import net.runelite.api.events.PostItemComposition;
import net.runelite.api.events.WidgetMenuOptionClicked;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.game.ItemManager;
import net.runelite.client.game.ItemVariationMapping;
import net.runelite.client.input.KeyManager;
import net.runelite.client.menus.MenuManager;
@@ -101,6 +103,9 @@ public class MenuEntrySwapperPlugin extends Plugin
@Inject
private Client client;
@Inject
private ClientThread clientThread;
@Inject
private MenuEntrySwapperConfig config;
@@ -116,6 +121,9 @@ public class MenuEntrySwapperPlugin extends Plugin
@Inject
private MenuManager menuManager;
@Inject
private ItemManager itemManager;
@Getter
private boolean configuringShiftClick = false;
@@ -146,6 +154,11 @@ public class MenuEntrySwapperPlugin extends Plugin
@Subscribe
public void onConfigChanged(ConfigChanged event)
{
if (!CONFIG_GROUP.equals(event.getGroup()))
{
return;
}
if (event.getKey().equals("shiftClickCustomization"))
{
if (config.shiftClickCustomization())
@@ -157,6 +170,16 @@ public class MenuEntrySwapperPlugin extends Plugin
disableCustomization();
}
}
else if (event.getKey().startsWith(ITEM_KEY_PREFIX))
{
clientThread.invoke(this::resetItemCompositionCache);
}
}
private void resetItemCompositionCache()
{
itemManager.invalidateItemCompositionCache();
client.getItemCompositionCache().reset();
}
private Integer getSwapConfig(int itemId)
@@ -179,6 +202,7 @@ public class MenuEntrySwapperPlugin extends Plugin
private void unsetSwapConfig(int itemId)
{
itemId = ItemVariationMapping.map(itemId);
configManager.unsetConfiguration(CONFIG_GROUP, ITEM_KEY_PREFIX + itemId);
}
@@ -186,6 +210,7 @@ public class MenuEntrySwapperPlugin extends Plugin
{
keyManager.registerKeyListener(inputListener);
refreshShiftClickCustomizationMenus();
clientThread.invoke(this::resetItemCompositionCache);
}
private void disableCustomization()
@@ -193,6 +218,7 @@ public class MenuEntrySwapperPlugin extends Plugin
keyManager.unregisterKeyListener(inputListener);
removeShiftClickCustomizationMenus();
configuringShiftClick = false;
clientThread.invoke(this::resetItemCompositionCache);
}
@Subscribe
@@ -290,7 +316,6 @@ public class MenuEntrySwapperPlugin extends Plugin
if (option.equals(RESET) && target.equals(MENU_TARGET))
{
unsetSwapConfig(itemId);
itemComposition.resetShiftClickActionIndex();
return;
}
@@ -323,7 +348,6 @@ public class MenuEntrySwapperPlugin extends Plugin
if (valid)
{
setSwapConfig(itemId, index);
itemComposition.setShiftClickActionIndex(index);
}
}

View File

@@ -31,22 +31,15 @@ import net.runelite.client.ui.overlay.infobox.Counter;
public class GraveyardCounter extends Counter
{
private int count;
public GraveyardCounter(BufferedImage image, Plugin plugin)
GraveyardCounter(BufferedImage image, Plugin plugin)
{
super(image, plugin, "0");
}
public void setCount(int count)
{
this.count = count;
this.setText(String.valueOf(count));
super(image, plugin, 0);
}
@Override
public Color getTextColor()
{
int count = getCount();
if (count >= GraveyardRoom.MIN_SCORE)
{
return Color.GREEN;

View File

@@ -26,43 +26,27 @@ package net.runelite.client.plugins.nightmarezone;
import java.awt.Color;
import java.awt.image.BufferedImage;
import lombok.Getter;
import lombok.Setter;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.ui.overlay.infobox.Counter;
@Setter
public class AbsorptionCounter extends Counter
{
private int absorption;
@Getter
@Setter
private int threshold;
@Getter
@Setter
private Color aboveThresholdColor = Color.GREEN;
@Getter
@Setter
private Color belowThresholdColor = Color.RED;
public AbsorptionCounter(BufferedImage image, Plugin plugin, int absorption, int threshold)
AbsorptionCounter(BufferedImage image, Plugin plugin, int absorption, int threshold)
{
super(image, plugin, "");
super(image, plugin, absorption);
this.threshold = threshold;
setAbsorption(absorption);
}
public void setAbsorption(int absorption)
{
this.absorption = absorption;
setText(String.valueOf(absorption));
}
@Override
public Color getTextColor()
{
int absorption = getCount();
if (absorption >= threshold)
{
return aboveThresholdColor;
@@ -76,6 +60,7 @@ public class AbsorptionCounter extends Counter
@Override
public String getTooltip()
{
int absorption = getCount();
return "Absorption: " + absorption;
}
}

View File

@@ -129,7 +129,7 @@ class NightmareZoneOverlay extends Overlay
}
else
{
absorptionCounter.setAbsorption(absorptionPoints);
absorptionCounter.setCount(absorptionPoints);
}
}
}

View File

@@ -29,6 +29,7 @@ import java.awt.Graphics2D;
import java.awt.Polygon;
import javax.inject.Inject;
import net.runelite.api.Client;
import net.runelite.api.DecorativeObject;
import net.runelite.api.GameObject;
import net.runelite.api.TileObject;
import net.runelite.client.ui.overlay.Overlay;
@@ -65,22 +66,31 @@ class ObjectIndicatorsOverlay extends Overlay
}
final Polygon polygon;
Polygon polygon2 = null;
if (object instanceof GameObject)
{
polygon = ((GameObject) object).getConvexHull();
}
else if (object instanceof DecorativeObject)
{
polygon = ((DecorativeObject) object).getConvexHull();
polygon2 = ((DecorativeObject) object).getConvexHull2();
}
else
{
polygon = object.getCanvasTilePoly();
}
if (polygon == null)
if (polygon != null)
{
continue;
OverlayUtil.renderPolygon(graphics, polygon, config.markerColor());
}
OverlayUtil.renderPolygon(graphics, polygon, config.markerColor());
if (polygon2 != null)
{
OverlayUtil.renderPolygon(graphics, polygon2, config.markerColor());
}
}
return null;

View File

@@ -43,6 +43,7 @@ import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import static net.runelite.api.Constants.REGION_SIZE;
import net.runelite.api.DecorativeObject;
import net.runelite.api.GameObject;
import net.runelite.api.GameState;
import net.runelite.api.MenuAction;
@@ -58,6 +59,8 @@ import net.runelite.api.events.GameObjectSpawned;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.MenuEntryAdded;
import net.runelite.api.events.MenuOptionClicked;
import net.runelite.api.events.DecorativeObjectSpawned;
import net.runelite.api.events.DecorativeObjectDespawned;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.input.KeyListener;
@@ -158,26 +161,15 @@ public class ObjectIndicatorsPlugin extends Plugin implements KeyListener
@Subscribe
public void onGameObjectSpawned(GameObjectSpawned event)
{
final WorldPoint worldPoint = WorldPoint.fromLocalInstance(client, event.getGameObject().getLocalLocation());
final Set<ObjectPoint> objectPoints = points.get(worldPoint.getRegionID());
final GameObject eventObject = event.getGameObject();
checkObjectPoints(eventObject);
}
if (objectPoints == null)
{
return;
}
for (ObjectPoint objectPoint : objectPoints)
{
if ((worldPoint.getX() & (REGION_SIZE - 1)) == objectPoint.getRegionX()
&& (worldPoint.getY() & (REGION_SIZE - 1)) == objectPoint.getRegionY())
{
if (objectPoint.getName().equals(client.getObjectDefinition(event.getGameObject().getId()).getName()))
{
objects.add(event.getGameObject());
break;
}
}
}
@Subscribe
public void onDecorativeObjectSpawned(DecorativeObjectSpawned event)
{
final DecorativeObject eventObject = event.getDecorativeObject();
checkObjectPoints(eventObject);
}
@Subscribe
@@ -186,6 +178,12 @@ public class ObjectIndicatorsPlugin extends Plugin implements KeyListener
objects.remove(event.getGameObject());
}
@Subscribe
public void onDecorativeObjectDespawned(DecorativeObjectDespawned event)
{
objects.remove(event.getDecorativeObject());
}
@Subscribe
public void onGameStateChanged(GameStateChanged gameStateChanged)
{
@@ -263,6 +261,30 @@ public class ObjectIndicatorsPlugin extends Plugin implements KeyListener
markObject(name, object);
}
private void checkObjectPoints(TileObject object)
{
final WorldPoint worldPoint = WorldPoint.fromLocalInstance(client, object.getLocalLocation());
final Set<ObjectPoint> objectPoints = points.get(worldPoint.getRegionID());
if (objectPoints == null)
{
return;
}
for (ObjectPoint objectPoint : objectPoints)
{
if ((worldPoint.getX() & (REGION_SIZE - 1)) == objectPoint.getRegionX()
&& (worldPoint.getY() & (REGION_SIZE - 1)) == objectPoint.getRegionY())
{
if (objectPoint.getName().equals(client.getObjectDefinition(object.getId()).getName()))
{
objects.add(object);
break;
}
}
}
}
private TileObject findTileObject(Tile tile, int id)
{
if (tile == null)
@@ -271,6 +293,12 @@ public class ObjectIndicatorsPlugin extends Plugin implements KeyListener
}
final GameObject[] tileGameObjects = tile.getGameObjects();
final DecorativeObject tileDecorativeObject = tile.getDecorativeObject();
if (tileDecorativeObject != null && tileDecorativeObject.getId() == id)
{
return tileDecorativeObject;
}
for (GameObject object : tileGameObjects)
{

View File

@@ -191,7 +191,7 @@ public class PartyPlugin extends Plugin implements KeyListener
.build();
chatMessageManager.queue(QueuedMessage.builder()
.type(ChatMessageType.GAME)
.type(ChatMessageType.CLANCHAT_INFO)
.runeLiteFormattedMessage(leaveMessage)
.build());
}
@@ -381,7 +381,7 @@ public class PartyPlugin extends Plugin implements KeyListener
.build();
chatMessageManager.queue(QueuedMessage.builder()
.type(ChatMessageType.GAME)
.type(ChatMessageType.CLANCHAT_INFO)
.runeLiteFormattedMessage(joinMessage)
.build());
@@ -430,7 +430,7 @@ public class PartyPlugin extends Plugin implements KeyListener
.build();
chatMessageManager.queue(QueuedMessage.builder()
.type(ChatMessageType.GAME)
.type(ChatMessageType.CLANCHAT_INFO)
.runeLiteFormattedMessage(joinMessage)
.build());
}
@@ -519,7 +519,7 @@ public class PartyPlugin extends Plugin implements KeyListener
.build();
chatMessageManager.queue(QueuedMessage.builder()
.type(ChatMessageType.GAME)
.type(ChatMessageType.CLANCHAT_INFO)
.runeLiteFormattedMessage(helpMessage)
.build());
}

View File

@@ -27,6 +27,8 @@ package net.runelite.client.plugins.party;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.Map;
import java.util.UUID;
import javax.inject.Inject;
@@ -34,6 +36,7 @@ import net.runelite.api.MenuAction;
import net.runelite.client.plugins.party.data.PartyData;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayMenuEntry;
import net.runelite.client.ui.overlay.components.ComponentConstants;
import net.runelite.client.ui.overlay.components.PanelComponent;
import net.runelite.client.ui.overlay.components.ProgressBarComponent;
import net.runelite.client.ui.overlay.components.TitleComponent;
@@ -58,6 +61,8 @@ public class PartyStatsOverlay extends Overlay
this.plugin = plugin;
this.party = party;
this.config = config;
body.setBorder(new Rectangle());
body.setGap(new Point(0, ComponentConstants.STANDARD_BORDER / 2));
getMenuEntries().add(new OverlayMenuEntry(MenuAction.RUNELITE_OVERLAY, "Leave", "Party"));
}

View File

@@ -24,11 +24,13 @@
*/
package net.runelite.client.plugins.party.messages;
import lombok.EqualsAndHashCode;
import lombok.Value;
import net.runelite.api.coords.WorldPoint;
import net.runelite.http.api.ws.messages.party.PartyMemberMessage;
@Value
@EqualsAndHashCode(callSuper = true)
public class LocationUpdate extends PartyMemberMessage
{
private final WorldPoint worldPoint;

View File

@@ -24,11 +24,13 @@
*/
package net.runelite.client.plugins.party.messages;
import lombok.EqualsAndHashCode;
import lombok.Value;
import net.runelite.api.coords.WorldPoint;
import net.runelite.http.api.ws.messages.party.PartyMemberMessage;
@Value
@EqualsAndHashCode(callSuper = true)
public class TilePing extends PartyMemberMessage
{
private final WorldPoint point;

View File

@@ -92,7 +92,8 @@ public class PestControlPlugin extends Plugin
@Subscribe
public void onGameStateChanged(GameStateChanged event)
{
if (event.getGameState() == GameState.LOADING)
GameState gameState = event.getGameState();
if (gameState == GameState.CONNECTION_LOST || gameState == GameState.LOGIN_SCREEN || gameState == GameState.HOPPING)
{
spinners.clear();
}

View File

@@ -42,4 +42,14 @@ public interface PoisonConfig extends Config
{
return false;
}
@ConfigItem(
keyName = "changeHealthIcon",
name = "Change HP Orb Icon",
description = "Configures whether the hp orb icon should change color to match poison/disease"
)
default boolean changeHealthIcon()
{
return true;
}
}

View File

@@ -35,12 +35,13 @@ import java.time.Instant;
import java.time.temporal.ChronoUnit;
import javax.inject.Inject;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.SpriteID;
import net.runelite.api.VarPlayer;
import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.VarbitChanged;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.game.SpriteManager;
@@ -50,22 +51,36 @@ import net.runelite.client.ui.FontManager;
import net.runelite.client.ui.overlay.OverlayManager;
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
import net.runelite.client.util.ColorUtil;
import net.runelite.client.util.ImageUtil;
@PluginDescriptor(
name = "Poison",
description = "Tracks current damage values for Poison and Venom",
tags = {"combat", "poison", "venom"}
tags = {"combat", "poison", "venom", "heart", "hp"}
)
@Slf4j
public class PoisonPlugin extends Plugin
{
static final int POISON_TICK_MILLIS = 18200;
private static final int VENOM_THRESHOLD = 1000000;
private static final int VENOM_MAXIUMUM_DAMAGE = 20;
private static final BufferedImage HEART_DISEASE;
private static final BufferedImage HEART_POISON;
private static final BufferedImage HEART_VENOM;
static
{
HEART_DISEASE = ImageUtil.resizeCanvas(ImageUtil.getResourceStreamFromClass(PoisonPlugin.class, "1067-DISEASE.png"), 26, 26);
HEART_POISON = ImageUtil.resizeCanvas(ImageUtil.getResourceStreamFromClass(PoisonPlugin.class, "1067-POISON.png"), 26, 26);
HEART_VENOM = ImageUtil.resizeCanvas(ImageUtil.getResourceStreamFromClass(PoisonPlugin.class, "1067-VENOM.png"), 26, 26);
}
@Inject
private Client client;
@Inject
private ClientThread clientThread;
@Inject
private PoisonOverlay poisonOverlay;
@@ -88,6 +103,8 @@ public class PoisonPlugin extends Plugin
private Instant poisonNaturalCure;
private Instant nextPoisonTick;
private int lastValue = -1;
private int lastDiseaseValue = -1;
private BufferedImage heart;
@Provides
PoisonConfig getConfig(ConfigManager configManager)
@@ -99,6 +116,11 @@ public class PoisonPlugin extends Plugin
protected void startUp() throws Exception
{
overlayManager.add(poisonOverlay);
if (client.getGameState() == GameState.LOGGED_IN)
{
clientThread.invoke(this::checkHealthIcon);
}
}
@Override
@@ -117,64 +139,87 @@ public class PoisonPlugin extends Plugin
poisonNaturalCure = null;
nextPoisonTick = null;
lastValue = -1;
lastDiseaseValue = -1;
clientThread.invoke(this::resetHealthIcon);
}
@Subscribe
public void onVarbitChanged(VarbitChanged event)
{
final int poisonValue = client.getVar(VarPlayer.POISON);
if (poisonValue == lastValue)
if (poisonValue != lastValue)
{
return;
}
lastValue = poisonValue;
nextPoisonTick = Instant.now().plus(Duration.of(POISON_TICK_MILLIS, ChronoUnit.MILLIS));
lastValue = poisonValue;
nextPoisonTick = Instant.now().plus(Duration.of(POISON_TICK_MILLIS, ChronoUnit.MILLIS));
final int damage = nextDamage(poisonValue);
this.lastDamage = damage;
final int damage = nextDamage(poisonValue);
this.lastDamage = damage;
envenomed = poisonValue >= VENOM_THRESHOLD;
envenomed = poisonValue >= VENOM_THRESHOLD;
if (poisonValue < VENOM_THRESHOLD)
{
poisonNaturalCure = Instant.now().plus(Duration.of(POISON_TICK_MILLIS * poisonValue, ChronoUnit.MILLIS));
}
else
{
poisonNaturalCure = null;
}
if (config.showInfoboxes())
{
if (infobox != null)
if (poisonValue < VENOM_THRESHOLD)
{
infoBoxManager.removeInfoBox(infobox);
infobox = null;
poisonNaturalCure = Instant.now().plus(Duration.of(POISON_TICK_MILLIS * poisonValue, ChronoUnit.MILLIS));
}
else
{
poisonNaturalCure = null;
}
if (damage > 0)
if (config.showInfoboxes())
{
final BufferedImage image = getSplat(envenomed ? SpriteID.HITSPLAT_DARK_GREEN_VENOM : SpriteID.HITSPLAT_GREEN_POISON, damage);
if (image != null)
if (infobox != null)
{
infobox = new PoisonInfobox(image, this);
infoBoxManager.addInfoBox(infobox);
infoBoxManager.removeInfoBox(infobox);
infobox = null;
}
if (damage > 0)
{
final BufferedImage image = getSplat(envenomed ? SpriteID.HITSPLAT_DARK_GREEN_VENOM : SpriteID.HITSPLAT_GREEN_POISON, damage);
if (image != null)
{
infobox = new PoisonInfobox(image, this);
infoBoxManager.addInfoBox(infobox);
}
}
}
checkHealthIcon();
}
final int diseaseValue = client.getVar(VarPlayer.DISEASE_VALUE);
if (diseaseValue != lastDiseaseValue)
{
lastDiseaseValue = diseaseValue;
checkHealthIcon();
}
}
@Subscribe
public void onConfigChanged(ConfigChanged event)
{
if (event.getGroup().equals(PoisonConfig.GROUP) && !config.showInfoboxes() && infobox != null)
if (!event.getGroup().equals(PoisonConfig.GROUP))
{
return;
}
if (!config.showInfoboxes() && infobox != null)
{
infoBoxManager.removeInfoBox(infobox);
infobox = null;
}
if (config.changeHealthIcon())
{
clientThread.invoke(this::checkHealthIcon);
}
else
{
clientThread.invoke(this::resetHealthIcon);
}
}
private static int nextDamage(int poisonValue)
@@ -250,4 +295,53 @@ public class PoisonPlugin extends Plugin
return line1 + line2;
}
private void checkHealthIcon()
{
if (!config.changeHealthIcon())
{
return;
}
final BufferedImage newHeart;
final int poison = client.getVar(VarPlayer.IS_POISONED);
if (poison >= VENOM_THRESHOLD)
{
newHeart = HEART_VENOM;
}
else if (poison > 0)
{
newHeart = HEART_POISON;
}
else if (client.getVar(VarPlayer.DISEASE_VALUE) > 0)
{
newHeart = HEART_DISEASE;
}
else
{
resetHealthIcon();
return;
}
// Only update sprites when the heart icon actually changes
if (newHeart != heart)
{
heart = newHeart;
client.getWidgetSpriteCache().reset();
client.getSpriteOverrides().put(SpriteID.MINIMAP_ORB_HITPOINTS_ICON, ImageUtil.getImageSpritePixels(heart, client));
}
}
private void resetHealthIcon()
{
if (heart == null)
{
return;
}
client.getWidgetSpriteCache().reset();
client.getSpriteOverrides().remove(SpriteID.MINIMAP_ORB_HITPOINTS_ICON);
heart = null;
}
}

View File

@@ -24,25 +24,32 @@
*/
package net.runelite.client.plugins.prayer;
import java.awt.Color;
import lombok.Getter;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.ui.overlay.infobox.Counter;
import net.runelite.client.ui.overlay.infobox.InfoBox;
class PrayerCounter extends Counter
class PrayerCounter extends InfoBox
{
@Getter
private final PrayerType prayerType;
PrayerCounter(Plugin plugin, PrayerType prayerType)
{
super(null, plugin, "");
super(null, plugin);
this.prayerType = prayerType;
}
@Override
public String toString()
public String getText()
{
return "Counter{" + "prayer=" + prayerType.getName() + '}';
return null;
}
@Override
public Color getTextColor()
{
return null;
}
@Override

View File

@@ -236,7 +236,7 @@ public class RaidsPlugin extends Plugin
{
if (timer != null)
{
timer.timeFloor();
timer.timeOlm();
timer.setStopped(true);
}

View File

@@ -41,6 +41,7 @@ public class RaidsTimer extends InfoBox
private LocalTime time;
private LocalTime firstFloorTime;
private LocalTime secondFloorTime;
private LocalTime thirdFloorTime;
private LocalTime olmTime;
@Setter
@@ -66,14 +67,20 @@ public class RaidsTimer extends InfoBox
{
secondFloorTime = LocalTime.ofSecondOfDay(elapsed.getSeconds());
}
else if (olmTime == null)
else if (thirdFloorTime == null)
{
olmTime = LocalTime.ofSecondOfDay(elapsed.getSeconds());
thirdFloorTime = LocalTime.ofSecondOfDay(elapsed.getSeconds());
}
floorTime = Instant.now();
}
public void timeOlm()
{
Duration elapsed = Duration.between(floorTime, Instant.now());
olmTime = LocalTime.ofSecondOfDay(elapsed.getSeconds());
}
@Override
public String getText()
{
@@ -126,6 +133,12 @@ public class RaidsTimer extends InfoBox
builder.append(secondFloorTime.format(DateTimeFormatter.ofPattern("mm:ss")));
}
if (thirdFloorTime != null)
{
builder.append("</br>Third floor: ");
builder.append(thirdFloorTime.format(DateTimeFormatter.ofPattern("mm:ss")));
}
if (olmTime != null)
{
builder.append("</br>Olm: ");

View File

@@ -229,10 +229,17 @@ public class RunecraftPlugin extends Plugin
@Subscribe
public void onGameStateChanged(GameStateChanged event)
{
if (event.getGameState() == GameState.LOADING)
GameState gameState = event.getGameState();
switch (gameState)
{
abyssObjects.clear();
darkMage = null;
case LOADING:
abyssObjects.clear();
break;
case CONNECTION_LOST:
case HOPPING:
case LOGIN_SCREEN:
darkMage = null;
break;
}
}

View File

@@ -28,6 +28,7 @@ import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Stroke;
import lombok.AccessLevel;
import lombok.Getter;
@@ -55,6 +56,9 @@ public class ScreenMarkerRenderable implements LayoutableRenderableEntity
@Setter(AccessLevel.PACKAGE)
private Stroke stroke;
@Getter
private final Rectangle bounds = new Rectangle();
@Override
public Dimension render(Graphics2D graphics)
{
@@ -72,6 +76,7 @@ public class ScreenMarkerRenderable implements LayoutableRenderableEntity
graphics.setColor(color);
graphics.setStroke(stroke);
graphics.drawRect(offset, offset, width - thickness, height - thickness);
bounds.setSize(preferredSize);
return preferredSize;
}
}

View File

@@ -145,6 +145,8 @@ public class ScreenshotPlugin extends Plugin
private Integer chambersOfXericNumber;
private Integer chambersOfXericChallengeNumber;
private Integer theatreOfBloodNumber;
private boolean shouldTakeScreenshot;
@@ -347,6 +349,16 @@ public class ScreenshotPlugin extends Plugin
}
}
if (chatMessage.startsWith("Your completed Chambers of Xeric Challenge Mode count is:"))
{
Matcher m = NUMBER_PATTERN.matcher(Text.removeTags(chatMessage));
if (m.find())
{
chambersOfXericChallengeNumber = Integer.valueOf(m.group());
return;
}
}
if (chatMessage.startsWith("Your completed Theatre of Blood count is:"))
{
Matcher m = NUMBER_PATTERN.matcher(Text.removeTags(chatMessage));
@@ -453,14 +465,22 @@ public class ScreenshotPlugin extends Plugin
}
case CHAMBERS_OF_XERIC_REWARD_GROUP_ID:
{
if (chambersOfXericNumber == null)
if (chambersOfXericNumber != null)
{
fileName = "Chambers of Xeric(" + chambersOfXericNumber + ")";
chambersOfXericNumber = null;
break;
}
else if (chambersOfXericChallengeNumber != null)
{
fileName = "Chambers of Xeric Challenge Mode(" + chambersOfXericChallengeNumber + ")";
chambersOfXericChallengeNumber = null;
break;
}
else
{
return;
}
fileName = "Chambers of Xeric(" + chambersOfXericNumber + ")";
chambersOfXericNumber = null;
break;
}
case THEATRE_OF_BLOOD_REWARD_GROUP_ID:
{
@@ -720,6 +740,12 @@ public class ScreenshotPlugin extends Plugin
return chambersOfXericNumber;
}
@VisibleForTesting
int getChambersOfXericChallengeNumber()
{
return chambersOfXericChallengeNumber;
}
@VisibleForTesting
int gettheatreOfBloodNumber()
{

View File

@@ -40,7 +40,6 @@ import java.util.concurrent.ScheduledExecutorService;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.inject.Inject;
import javax.swing.SwingUtilities;
import joptsimple.internal.Strings;
import lombok.AccessLevel;
import lombok.Getter;
@@ -48,7 +47,6 @@ import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.ChatMessageType;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.ItemID;
import net.runelite.api.MessageNode;
import net.runelite.api.NPC;
@@ -623,7 +621,7 @@ public class SlayerPlugin extends Plugin
// add and update counter, set timer
addCounter();
counter.setText(String.valueOf(currentTask.getAmount()));
counter.setCount(currentTask.getAmount());
infoTimer = Instant.now();
}
@@ -696,7 +694,7 @@ public class SlayerPlugin extends Plugin
private void setTask(String name, int amt, int initAmt, boolean isNewAssignment)
{
setTask(name, amt, initAmt, isNewAssignment,null);
setTask(name, amt, initAmt, isNewAssignment, null);
}
private void setTask(String name, int amt, int initAmt, boolean isNewAssignment, String location)

View File

@@ -6,7 +6,6 @@ import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import javax.swing.Box;
@@ -15,7 +14,6 @@ import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.FontManager;
@@ -104,7 +102,8 @@ public class SlayerTaskPanel extends PluginPanel
playBtn.setIcon(PLAY);
playBtn.setToolTipText("Resume the current slayer task");
playBtn.addMouseListener(new MouseAdapter() {
playBtn.addMouseListener(new MouseAdapter()
{
@Override
public void mousePressed(MouseEvent mouseEvent)
{
@@ -139,7 +138,8 @@ public class SlayerTaskPanel extends PluginPanel
pauseBtn.setIcon(PAUSE);
pauseBtn.setToolTipText("Pause the current slayer task");
pauseBtn.addMouseListener(new MouseAdapter() {
pauseBtn.addMouseListener(new MouseAdapter()
{
@Override
public void mousePressed(MouseEvent mouseEvent)
{
@@ -300,7 +300,8 @@ public class SlayerTaskPanel extends PluginPanel
if (tasks.isEmpty() || isNewAssignment)
{
// new task so append it to the front of the list
SwingUtilities.invokeLater(() -> {
SwingUtilities.invokeLater(() ->
{
TaskBox newBox = buildBox(slayerPlugin, tasksContainer, newData);
newBox.update(true, newData.isPaused(), newData);
});
@@ -321,7 +322,8 @@ public class SlayerTaskPanel extends PluginPanel
// so this previous task is invalid so delete it then add in the new actually
// correct task
SwingUtilities.invokeLater(() -> {
SwingUtilities.invokeLater(() ->
{
tasksContainer.remove(tasks.get(0));
tasks.remove(0);
TaskBox newBox = buildBox(slayerPlugin, tasksContainer, newData);

View File

@@ -59,7 +59,7 @@ class TargetWeaknessOverlay extends Overlay
this.itemManager = itemManager;
this.npcManager = npcManager;
setPosition(OverlayPosition.DYNAMIC);
setLayer(OverlayLayer.ABOVE_SCENE);
setLayer(OverlayLayer.UNDER_WIDGETS);
}
@Override

View File

@@ -14,7 +14,6 @@ import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;
import lombok.AccessLevel;
import lombok.Getter;
import net.runelite.client.game.AsyncBufferedImage;
import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.DynamicGridLayout;
import net.runelite.client.ui.FontManager;
@@ -78,7 +77,8 @@ public class TaskBox extends JPanel
container.setLayout(new BorderLayout());
container.setBackground(ColorScheme.DARKER_GRAY_COLOR);
SwingUtilities.invokeLater(() -> {
SwingUtilities.invokeLater(() ->
{
BufferedImage taskImg = slayerPlugin.getImageForTask(Task.getTask(taskData.getTaskName()));
JLabel taskIcon = new JLabel(new ImageIcon(taskImg));
taskIcon.setHorizontalAlignment(SwingConstants.CENTER);

View File

@@ -29,10 +29,10 @@ import net.runelite.client.ui.overlay.infobox.Counter;
import java.awt.image.BufferedImage;
public class TaskCounter extends Counter
class TaskCounter extends Counter
{
public TaskCounter(BufferedImage img, Plugin plugin, int amount)
TaskCounter(BufferedImage img, Plugin plugin, int amount)
{
super(img, plugin, String.valueOf(amount));
super(img, plugin, amount);
}
}

View File

@@ -6,7 +6,7 @@ import lombok.Data;
@Data
@AllArgsConstructor
@Builder(toBuilder=true)
@Builder(toBuilder = true)
public class TaskData
{
private long elapsedTime;

View File

@@ -29,30 +29,24 @@ import net.runelite.client.ui.overlay.infobox.Counter;
class SpecialCounter extends Counter
{
private int hitValue;
private SpecialWeapon weapon;
SpecialCounter(BufferedImage image, SpecialCounterPlugin plugin, int hitValue, SpecialWeapon weapon)
{
super(image, plugin, null);
super(image, plugin, hitValue);
this.weapon = weapon;
this.hitValue = hitValue;
}
void addHits(double hit)
{
this.hitValue += hit;
}
@Override
public String getText()
{
return Integer.toString(hitValue);
int count = getCount();
setCount(count + (int) hit);
}
@Override
public String getTooltip()
{
int hitValue = getCount();
if (!weapon.isDamage())
{
if (hitValue == 1)

View File

@@ -24,8 +24,6 @@
*/
package net.runelite.client.plugins.statusbars;
import com.google.common.base.Strings;
import com.google.common.primitives.Ints;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
@@ -196,28 +194,16 @@ class StatusBarsOverlay extends Overlay
for (final StatChange c : statsChanges.getStatChanges())
{
final String strVar = c.getTheoretical();
if (Strings.isNullOrEmpty(strVar))
{
continue;
}
final Integer value = Ints.tryParse(strVar.startsWith("+") ? strVar.substring(1) : strVar);
if (value == null)
{
continue;
}
final int theoreticalBoost = c.getTheoretical();
if (c.getStat().getName().equals(Skill.HITPOINTS.getName()))
{
foodHealValue = value;
foodHealValue = theoreticalBoost;
}
if (c.getStat().getName().equals(Skill.PRAYER.getName()))
{
prayerHealValue = value;
prayerHealValue = theoreticalBoost;
}
if (foodHealValue != 0 && prayerHealValue != 0)

View File

@@ -54,6 +54,17 @@ public interface TileIndicatorsConfig extends Config
return true;
}
@Alpha
@ConfigItem(
keyName = "highlightHoveredColor",
name = "Color of current hovered highlighting",
description = "Configures the highlight color of hovered tile"
)
default Color highlightHoveredColor()
{
return new Color(0, 0, 0, 0);
}
@ConfigItem(
keyName = "highlightHoveredTile",
name = "Highlight hovered tile",

View File

@@ -41,7 +41,6 @@ import net.runelite.client.ui.overlay.OverlayUtil;
public class TileIndicatorsOverlay extends Overlay
{
private static final Color EMPTY = new Color(0, 0, 0, 0);
private final Client client;
private final TileIndicatorsConfig config;
@@ -75,7 +74,7 @@ public class TileIndicatorsOverlay extends Overlay
// If we have tile "selected" render it
if (client.getSelectedSceneTile() != null)
{
renderTile(graphics, client.getSelectedSceneTile().getLocalLocation(), EMPTY);
renderTile(graphics, client.getSelectedSceneTile().getLocalLocation(), config.highlightHoveredColor());
}
}

View File

@@ -0,0 +1,314 @@
/*
* Copyright (c) 2018 Abex
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.wiki;
import com.google.common.primitives.Ints;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.inject.Inject;
import javax.inject.Provider;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.MenuAction;
import net.runelite.api.MenuEntry;
import net.runelite.api.NPC;
import net.runelite.api.NPCComposition;
import net.runelite.api.events.MenuEntryAdded;
import net.runelite.api.events.MenuOptionClicked;
import net.runelite.api.events.WidgetLoaded;
import net.runelite.api.widgets.JavaScriptCallback;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetConfig;
import net.runelite.api.widgets.WidgetID;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.api.widgets.WidgetPositionMode;
import net.runelite.api.widgets.WidgetType;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.game.ItemManager;
import net.runelite.client.game.SpriteManager;
import net.runelite.client.game.chatbox.ChatboxPanelManager;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.util.LinkBrowser;
import net.runelite.client.util.Text;
import okhttp3.HttpUrl;
@Slf4j
@PluginDescriptor(
name = "Wiki",
description = "Adds a Wiki button that takes you to the OSRS Wiki"
)
public class WikiPlugin extends Plugin
{
private static final int[] QUESTLIST_WIDGET_IDS = new int[]
{
WidgetInfo.QUESTLIST_FREE_CONTAINER.getId(),
WidgetInfo.QUESTLIST_MEMBERS_CONTAINER.getId(),
WidgetInfo.QUESTLIST_MINIQUEST_CONTAINER.getId(),
};
static final String WIKI_BASE = "https://oldschool.runescape.wiki";
static final HttpUrl WIKI_RSLOOKUP = HttpUrl.parse(WIKI_BASE + "/w/Special:Lookup");
static final HttpUrl WIKI_API = HttpUrl.parse(WIKI_BASE + "/api.php");
static final String UTM_SORUCE_KEY = "utm_source";
static final String UTM_SORUCE_VALUE = "runelite";
static final String UTM_PARAMS = UTM_SORUCE_KEY + "=" + UTM_SORUCE_VALUE;
private static final String MENUOP_GUIDE = "Guide";
private static final String MENUOP_QUICKGUIDE = "Quick Guide";
private static final String MENUOP_WIKI_SKILL = "Wiki";
private static final Pattern SKILL_REGEX = Pattern.compile("([A-Za-z]+) guide");
@Inject
private SpriteManager spriteManager;
@Inject
private ClientThread clientThread;
@Inject
private Client client;
@Inject
private ChatboxPanelManager chatboxPanelManager;
@Inject
private ItemManager itemManager;
@Inject
private Provider<WikiSearchChatboxTextInput> wikiSearchChatboxTextInputProvider;
private Widget icon;
private boolean wikiSelected = false;
@Override
public void startUp()
{
spriteManager.addSpriteOverrides(WikiSprite.values());
clientThread.invokeLater(this::addWidgets);
}
@Override
public void shutDown()
{
spriteManager.removeSpriteOverrides(WikiSprite.values());
clientThread.invokeLater(() ->
{
Widget minimapOrbs = client.getWidget(WidgetInfo.MINIMAP_ORBS);
if (minimapOrbs == null)
{
return;
}
Widget[] children = minimapOrbs.getChildren();
if (children == null || children.length < 1)
{
return;
}
children[0] = null;
});
}
@Subscribe
private void onWidgetLoaded(WidgetLoaded l)
{
if (l.getGroupId() == WidgetID.MINIMAP_GROUP_ID)
{
addWidgets();
}
}
private void addWidgets()
{
Widget minimapOrbs = client.getWidget(WidgetInfo.MINIMAP_ORBS);
if (minimapOrbs == null)
{
return;
}
icon = minimapOrbs.createChild(0, WidgetType.GRAPHIC);
icon.setSpriteId(WikiSprite.WIKI_ICON.getSpriteId());
icon.setOriginalX(0);
icon.setOriginalY(2);
icon.setXPositionMode(WidgetPositionMode.ABSOLUTE_RIGHT);
icon.setYPositionMode(WidgetPositionMode.ABSOLUTE_BOTTOM);
icon.setOriginalWidth(42);
icon.setOriginalHeight(16);
icon.setTargetVerb("Lookup");
icon.setName("Wiki");
icon.setClickMask(WidgetConfig.USE_GROUND_ITEM | WidgetConfig.USE_ITEM | WidgetConfig.USE_NPC);
icon.setNoClickThrough(true);
icon.setOnTargetEnterListener((JavaScriptCallback) ev ->
{
wikiSelected = true;
icon.setSpriteId(WikiSprite.WIKI_SELECTED_ICON.getSpriteId());
});
icon.setAction(5, "Search"); // Start at option 5 so the target op is ontop
icon.setOnOpListener((JavaScriptCallback) ev ->
{
switch (ev.getOp())
{
case 6:
openSearchInput();
break;
}
});
// This doesn't always run because we cancel the menuop
icon.setOnTargetLeaveListener((JavaScriptCallback) ev -> onDeselect());
icon.revalidate();
}
private void onDeselect()
{
wikiSelected = false;
icon.setSpriteId(WikiSprite.WIKI_ICON.getSpriteId());
}
@Subscribe
private void onMenuOptionClicked(MenuOptionClicked ev)
{
if (wikiSelected)
{
onDeselect();
client.setSpellSelected(false);
ev.consume();
String type;
int id;
String name;
switch (ev.getMenuAction())
{
case CANCEL:
return;
case ITEM_USE_ON_WIDGET:
case SPELL_CAST_ON_GROUND_ITEM:
{
type = "item";
id = itemManager.canonicalize(ev.getId());
name = itemManager.getItemComposition(id).getName();
break;
}
case SPELL_CAST_ON_NPC:
{
type = "npc";
NPC npc = client.getCachedNPCs()[ev.getId()];
NPCComposition nc = npc.getTransformedComposition();
id = nc.getId();
name = nc.getName();
break;
}
default:
log.info("Unknown menu option: {} {} {}", ev, ev.getMenuAction(), ev.getMenuAction() == MenuAction.CANCEL);
return;
}
HttpUrl url = WIKI_RSLOOKUP.newBuilder()
.addQueryParameter("type", type)
.addQueryParameter("id", "" + id)
.addQueryParameter("name", name)
.addQueryParameter(UTM_SORUCE_KEY, UTM_SORUCE_VALUE)
.build();
LinkBrowser.browse(url.toString());
return;
}
if (ev.getMenuAction() == MenuAction.RUNELITE)
{
String quickguide = "";
switch (ev.getMenuOption())
{
case MENUOP_QUICKGUIDE:
quickguide = "/Quick_guide";
//fallthrough;
case MENUOP_GUIDE:
ev.consume();
String quest = Text.removeTags(ev.getMenuTarget());
LinkBrowser.browse(WIKI_BASE + "/w/" + URLEncoder.encode(quest.replace(' ', '_')) + quickguide + "?" + UTM_PARAMS);
break;
case MENUOP_WIKI_SKILL:
Matcher skillRegex = WikiPlugin.SKILL_REGEX.matcher(Text.removeTags(ev.getMenuTarget()));
if (skillRegex.find())
{
LinkBrowser.browse(WIKI_BASE + "/w/" + URLEncoder.encode(skillRegex.group(1)) + "?" + UTM_PARAMS);
}
}
}
}
private void openSearchInput()
{
wikiSearchChatboxTextInputProvider.get()
.build();
}
@Subscribe
public void onMenuEntryAdded(MenuEntryAdded event)
{
int widgetIndex = event.getActionParam0();
int widgetID = event.getActionParam1();
MenuEntry[] menuEntries = client.getMenuEntries();
if (Ints.contains(QUESTLIST_WIDGET_IDS, widgetID) && "Read Journal:".equals(event.getOption()))
{
menuEntries = Arrays.copyOf(menuEntries, menuEntries.length + 2);
MenuEntry menuEntry = menuEntries[menuEntries.length - 1] = new MenuEntry();
menuEntry.setTarget(event.getTarget());
menuEntry.setOption(MENUOP_GUIDE);
menuEntry.setParam0(widgetIndex);
menuEntry.setParam1(widgetID);
menuEntry.setType(MenuAction.RUNELITE.getId());
menuEntry = menuEntries[menuEntries.length - 2] = new MenuEntry();
menuEntry.setTarget(event.getTarget());
menuEntry.setOption(MENUOP_QUICKGUIDE);
menuEntry.setParam0(widgetIndex);
menuEntry.setParam1(widgetID);
menuEntry.setType(MenuAction.RUNELITE.getId());
client.setMenuEntries(menuEntries);
}
if ((WidgetInfo.TO_GROUP(widgetID) == WidgetID.SKILLS_GROUP_ID) && event.getOption().startsWith("View"))
{
menuEntries = Arrays.copyOf(menuEntries, menuEntries.length + 1);
MenuEntry menuEntry = menuEntries[menuEntries.length - 1] = new MenuEntry();
menuEntry.setTarget(event.getOption().replace("View ", ""));
menuEntry.setOption(MENUOP_WIKI_SKILL);
menuEntry.setParam0(widgetIndex);
menuEntry.setParam1(widgetID);
menuEntry.setIdentifier(event.getIdentifier());
menuEntry.setType(MenuAction.RUNELITE.getId());
client.setMenuEntries(menuEntries);
}
}
}

View File

@@ -0,0 +1,303 @@
/*
* Copyright (c) 2018 Abex
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.wiki;
import com.google.common.collect.ImmutableList;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonParseException;
import com.google.gson.JsonParser;
import com.google.inject.Inject;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.inject.Named;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.widgets.JavaScriptCallback;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetPositionMode;
import net.runelite.api.widgets.WidgetSizeMode;
import net.runelite.api.widgets.WidgetTextAlignment;
import net.runelite.api.widgets.WidgetType;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.game.chatbox.ChatboxPanelManager;
import net.runelite.client.game.chatbox.ChatboxTextInput;
import net.runelite.client.util.LinkBrowser;
import net.runelite.http.api.RuneLiteAPI;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.HttpUrl;
import okhttp3.Request;
import okhttp3.Response;
@Slf4j
public class WikiSearchChatboxTextInput extends ChatboxTextInput
{
private static final int LINE_HEIGHT = 20;
private static final int CHATBOX_HEIGHT = 120;
private static final int MAX_NUM_PREDICTIONS = (CHATBOX_HEIGHT / LINE_HEIGHT) - 2; // 1 title, 1 edit
private static final int PREDICTION_DEBOUNCE_DELAY_MS = 200;
private final ChatboxPanelManager chatboxPanelManager;
private final Gson gson = new Gson();
private Future<?> runningRequest = null;
private List<String> predictions = ImmutableList.of();
private int selectedPrediction = -1;
private String offPrediction = null;
@Inject
public WikiSearchChatboxTextInput(ChatboxPanelManager chatboxPanelManager, ClientThread clientThread,
ScheduledExecutorService scheduledExecutorService, @Named("developerMode") final boolean developerMode)
{
super(chatboxPanelManager, clientThread);
this.chatboxPanelManager = chatboxPanelManager;
lines(1);
prompt("OSRS Wiki Search");
onDone(string ->
{
if (string != null && string.length() > 0)
{
search(string);
}
});
onChanged(searchString ->
{
selectedPrediction = -1;
Future<?> rr = runningRequest;
if (rr != null)
{
rr.cancel(false);
}
if (searchString.length() <= 1)
{
runningRequest = null;
clientThread.invokeLater(() ->
{
predictions = ImmutableList.of();
update();
});
return;
}
runningRequest = scheduledExecutorService.schedule(() ->
{
HttpUrl url = WikiPlugin.WIKI_API.newBuilder()
.addQueryParameter("action", "opensearch")
.addQueryParameter("search", searchString)
.addQueryParameter("redirects", "resolve")
.addQueryParameter("format", "json")
.addQueryParameter("warningsaserror", Boolean.toString(developerMode))
.build();
Request req = new Request.Builder()
.url(url)
.build();
RuneLiteAPI.CLIENT.newCall(req).enqueue(new Callback()
{
@Override
public void onFailure(Call call, IOException e)
{
log.warn("error searching wiki", e);
}
@Override
public void onResponse(Call call, Response response) throws IOException
{
String body = response.body().string();
try
{
JsonArray jar = new JsonParser().parse(body).getAsJsonArray();
List<String> apredictions = gson.fromJson(jar.get(1), new TypeToken<List<String>>()
{
}.getType());
if (apredictions.size() > MAX_NUM_PREDICTIONS)
{
apredictions = apredictions.subList(0, MAX_NUM_PREDICTIONS);
}
final List<String> bpredictions = apredictions;
clientThread.invokeLater(() ->
{
predictions = bpredictions;
update();
});
}
catch (JsonParseException | IllegalStateException | IndexOutOfBoundsException e)
{
log.warn("error parsing wiki response {}", body, e);
}
finally
{
response.close();
}
}
});
runningRequest = null;
}, PREDICTION_DEBOUNCE_DELAY_MS, TimeUnit.MILLISECONDS);
});
}
@Override
protected void update()
{
Widget container = chatboxPanelManager.getContainerWidget();
container.deleteAllChildren();
Widget promptWidget = container.createChild(-1, WidgetType.TEXT);
promptWidget.setText(getPrompt());
promptWidget.setTextColor(0x800000);
promptWidget.setFontId(getFontID());
promptWidget.setXPositionMode(WidgetPositionMode.ABSOLUTE_CENTER);
promptWidget.setOriginalX(0);
promptWidget.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP);
promptWidget.setOriginalY(5);
promptWidget.setOriginalHeight(LINE_HEIGHT);
promptWidget.setXTextAlignment(WidgetTextAlignment.CENTER);
promptWidget.setYTextAlignment(WidgetTextAlignment.CENTER);
promptWidget.setWidthMode(WidgetSizeMode.MINUS);
promptWidget.revalidate();
buildEdit(0, 5 + LINE_HEIGHT, container.getWidth(), LINE_HEIGHT);
Widget separator = container.createChild(-1, WidgetType.LINE);
separator.setXPositionMode(WidgetPositionMode.ABSOLUTE_CENTER);
separator.setOriginalX(0);
separator.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP);
separator.setOriginalY(4 + (LINE_HEIGHT * 2));
separator.setOriginalHeight(0);
separator.setOriginalWidth(16);
separator.setWidthMode(WidgetSizeMode.MINUS);
separator.revalidate();
for (int i = 0; i < predictions.size(); i++)
{
String pred = predictions.get(i);
int y = 6 + (LINE_HEIGHT * (2 + i));
Widget bg = container.createChild(-1, WidgetType.RECTANGLE);
bg.setTextColor(0x4444DD);
bg.setFilled(true);
bg.setXPositionMode(WidgetPositionMode.ABSOLUTE_CENTER);
bg.setOriginalX(1);
bg.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP);
bg.setOriginalY(y);
bg.setOriginalHeight(LINE_HEIGHT);
bg.setOriginalWidth(16);
bg.setWidthMode(WidgetSizeMode.MINUS);
bg.revalidate();
bg.setName("<col=ff9040>" + pred);
bg.setAction(0, "Open");
bg.setHasListener(true);
bg.setOnOpListener((JavaScriptCallback) ev -> search(pred));
Widget text = container.createChild(-1, WidgetType.TEXT);
text.setText(pred);
text.setFontId(getFontID());
text.setXPositionMode(WidgetPositionMode.ABSOLUTE_CENTER);
text.setOriginalX(0);
text.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP);
text.setOriginalY(y);
text.setOriginalHeight(LINE_HEIGHT);
text.setXTextAlignment(WidgetTextAlignment.CENTER);
text.setYTextAlignment(WidgetTextAlignment.CENTER);
text.setWidthMode(WidgetSizeMode.MINUS);
text.revalidate();
if (i == selectedPrediction)
{
text.setTextColor(0xFFFFFF);
}
else
{
bg.setOpacity(255);
text.setTextColor(0x000000);
bg.setOnMouseRepeatListener((JavaScriptCallback) ev -> text.setTextColor(0xFFFFFF));
bg.setOnMouseLeaveListener((JavaScriptCallback) ev -> text.setTextColor(0x000000));
}
}
}
@Override
public void keyPressed(KeyEvent ev)
{
switch (ev.getKeyCode())
{
case KeyEvent.VK_UP:
ev.consume();
if (selectedPrediction > -1)
{
selectedPrediction--;
if (selectedPrediction == -1)
{
value(offPrediction);
}
else
{
value(predictions.get(selectedPrediction));
}
}
break;
case KeyEvent.VK_DOWN:
ev.consume();
if (selectedPrediction == -1)
{
offPrediction = getValue();
}
selectedPrediction++;
if (selectedPrediction >= predictions.size())
{
selectedPrediction = predictions.size() - 1;
}
if (selectedPrediction != -1)
{
value(predictions.get(selectedPrediction));
}
break;
default:
super.keyPressed(ev);
}
}
private void search(String search)
{
LinkBrowser.browse(WikiPlugin.WIKI_BASE + "?search=" + URLEncoder.encode(search) + "&" + WikiPlugin.UTM_PARAMS);
chatboxPanelManager.close();
}
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) 2018 Abex
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.wiki;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import net.runelite.api.SpriteID;
import net.runelite.client.game.SpriteOverride;
@RequiredArgsConstructor
public enum WikiSprite implements SpriteOverride
{
WIKI_ICON(-300, "wiki.png"),
WIKI_SELECTED_ICON(-301, "wiki_selected.png"),
FIXED_MODE_MINIMAP_CLICKMASK(SpriteID.MINIMAP_CLICK_MASK, "fixed_mode_minimap_clickmask.png");
@Getter
private final int spriteId;
@Getter
private final String fileName;
}

View File

@@ -1,141 +0,0 @@
/*
* Copyright (c) 2018, Morgan Lewis <https://github.com/MESLewis>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.worldmap;
import lombok.Getter;
import net.runelite.api.coords.WorldPoint;
@Getter
enum AgilityShortcutLocation
{
KARAMJA_GLIDER_LOG("Log Balance", 1, new WorldPoint(2906, 3050, 0)),
FALADOR_CRUMBLING_WALL("Crumbling Wall", 5, new WorldPoint(2936, 3357, 0)),
RIVER_LUM_GRAPPLE_WEST("Grapple Broken Raft", 8, new WorldPoint(3245, 3179, 0)),
RIVER_LUM_GRAPPLE_EAST("Grapple Broken Raft", 8, new WorldPoint(3258, 3179, 0)),
CORSAIR_COVE_ROCKS("Rocks", 10, new WorldPoint(2545, 2871, 0)),
FALADOR_GRAPPLE_WALL("Grapple Wall", 11, new WorldPoint(3031, 3391, 0)),
VARROCK_SOUTH_FENCE("Fence", 13, new WorldPoint(3239, 3334, 0)),
GOBLIN_VILLAGE_WALL("Wall", 14, new WorldPoint(2925, 3523, 0)),
CORSAIR_COVE_DUNGEON_PILLAR("Pillar Jump", 15, new WorldPoint(1980, 8996, 0)),
YANILLE_UNDERWALL_TUNNEL("Underwall Tunnel", 16, new WorldPoint(2574, 3109, 0)),
COAL_TRUCKS_LOG_BALANCE("Log Balance", 20, new WorldPoint(2598, 3475, 0)),
GRAND_EXCHANGE_UNDERWALL_TUNNEL("Underwall Tunnel", 21, new WorldPoint(3139, 3515, 0)),
BRIMHAVEN_DUNGEON_PIPE("Pipe Squeeze", 22, new WorldPoint(2654, 9569, 0)),
OBSERVATORY_SCALE_CLIFF("Grapple Rocks", 23, new WorldPoint(2447, 3155, 0)),
EAGLES_PEAK_ROCK_CLIMB("Rock Climb", 25, new WorldPoint(2320, 3499, 0)),
FALADOR_UNDERWALL_TUNNEL("Underwall Tunnel", 26, new WorldPoint(2947, 3313, 0)),
MOUNT_KARUULM_LOWER("Rocks", 29, new WorldPoint(1324, 3782, 0)),
CORSAIR_COVE_RESOURCE_ROCKS("Rocks", 30, new WorldPoint(2545, 2871, 0)),
SOUTHEAST_KARAJMA_STEPPING_STONES("Stepping Stones", 30, new WorldPoint(2924, 2946, 0)),
DRAYNOR_MANOR_STEPPING_STONES("Stepping Stones", 31, new WorldPoint(3150, 3362, 0)),
CATHERBY_CLIFFSIDE_GRAPPLE("Grapple Rock", 32, new WorldPoint(2868, 3429, 0)),
ARDOUGNE_LOG_BALANCE("Log Balance", 33, new WorldPoint(2602, 3336, 0)),
GNOME_STRONGHOLD_ROCKS("Rocks", 37, new WorldPoint(2485, 3515, 0)),
AL_KHARID_MINING_PITCLIFF_SCRAMBLE("Rocks", 38, new WorldPoint(3305, 3315, 0)),
YANILLE_WALL_GRAPPLE("Grapple Wall", 39, new WorldPoint(2552, 3072, 0)),
NEITIZNOT_BRIDGE_REPAIR("Bridge Repair - Quest", 40, new WorldPoint(2315, 3828, 0)),
KOUREND_LAKE_JUMP_WEST("Stepping Stones", 40, new WorldPoint(1604, 3572, 0)),
KOUREND_LAKE_JUMP_EAST("Stepping Stones", 40, new WorldPoint(1612, 3570, 0)),
TROLLHEIM_EASY_CLIFF_SCRAMBLE("Rocks", 41, new WorldPoint(2869, 3670, 0)),
DWARVEN_MINE_NARROW_CREVICE("Narrow Crevice", 42, new WorldPoint(3034, 9806, 0)),
DRAYNOR_UNDERWALL_TUNNEL("Underwall Tunnel", 42, new WorldPoint(3068, 3261, 0)),
TROLLHEIM_MEDIUM_CLIFF_SCRAMBLE_NORTH("Rocks", 43, new WorldPoint(2886, 3684, 0)),
TROLLHEIM_MEDIUM_CLIFF_SCRAMBLE_SOUTH("Rocks", 43, new WorldPoint(2876, 3666, 0)),
TROLLHEIM_ADVANCED_CLIFF_SCRAMBLE("Rocks", 44, new WorldPoint(2907, 3686, 0)),
KOUREND_RIVER_STEPPING_STONES("Stepping Stones", 45, new WorldPoint(1721, 3509, 0)),
COSMIC_ALTAR_MEDIUM_WALKWAY("Narrow Walkway", 46, new WorldPoint(2399, 4403, 0)),
DEEP_WILDERNESS_DUNGEON_CREVICE_NORTH("Narrow Crevice", 46, new WorldPoint(3047, 10335, 0)),
DEEP_WILDERNESS_DUNGEON_CREVICE_SOUTH("Narrow Crevice", 46, new WorldPoint(3045, 10327, 0)),
TROLLHEIM_HARD_CLIFF_SCRAMBLE("Rocks", 47, new WorldPoint(2902, 3680, 0)),
FREMENNIK_LOG_BALANCE("Log Balance", 48, new WorldPoint(2721, 3591, 0)),
ARCEUUS_ESSENCE_MINE_BOULDER("Boulder", 49, new WorldPoint(1774, 3888, 0)),
MORYTANIA_STEPPING_STONE("Stepping Stone", 50, new WorldPoint(3418, 3326, 0)),
VARROCK_SEWERS_PIPE_SQUEEZE("Pipe Squeeze", 51, new WorldPoint(3152, 9905, 0)),
ARCEUUS_ESSENCE_MINE_EAST_SCRAMBLE("Rock Climb", 52, new WorldPoint(1770, 3851, 0)),
KARAMJA_VOLCANO_GRAPPLE_NORTH("Grapple Rock", 53, new WorldPoint(2873, 3143, 0)),
KARAMJA_VOLCANO_GRAPPLE_SOUTH("Grapple Rock", 53, new WorldPoint(2874, 3128, 0)),
MOTHERLODE_MINE_WALL_WEST("Wall", 54, new WorldPoint(3118, 9702, 0)),
MOTHERLODE_MINE_WALL_EAST("Wall", 54, new WorldPoint(3124, 9703, 0)),
MISCELLANIA_DOCK_STEPPING_STONE("Stepping Stone", 55, new WorldPoint(2572, 3862, 0)),
RELEKKA_EAST_FENCE("Fence", 57, new WorldPoint(2688, 3697, 0)),
ELVEN_OVERPASS_CLIFF_SCRAMBLE("Rocks", 59, new WorldPoint(2345, 3300, 0)),
WILDERNESS_GWD_CLIMB_WEST("Rocks", 60, new WorldPoint(2928, 3760, 0)),
WILDERNESS_GWD_CLIMB_EAST("Rocks", 60, new WorldPoint(2943, 3770, 0)),
MOS_LEHARMLESS_STEPPING_STONE("Stepping Stone", 60, new WorldPoint(3710, 2970, 0)),
WINTERTODT_GAP("Gap", 60, new WorldPoint(1629, 4023, 0)),
SLAYER_TOWER_MEDIUM_CHAIN_FIRST("Spiked Chain (Floor 1)", 61, new WorldPoint(3421, 3550, 0)),
SLAYER_TOWER_MEDIUM_CHAIN_SECOND("Spiked Chain (Floor 2)", 61, new WorldPoint(3420, 3551, 0)),
SLAYER_DUNGEON_CREVICE("Narrow Crevice", 62, new WorldPoint(2729, 10008, 0)),
MOUNT_KARUULM_UPPER("Rocks", 62, new WorldPoint(1322, 3791, 0)),
TAVERLEY_DUNGEON_RAILING("Loose Railing", 63, new WorldPoint(2935, 9811, 0)),
TROLLHEIM_WILDERNESS_ROCKS("Rocks", 64, new WorldPoint(2945, 3678, 0)),
FOSSIL_ISLAND_VOLCANO("Rope", 64, new WorldPoint(3780, 3822, 0)),
MORYTANIA_TEMPLE("Loose Railing", 65, new WorldPoint(3422, 3476, 0)),
REVENANT_CAVES_GREEN_DRAGONS("Jump", 65, new WorldPoint(3220, 10086, 0)),
COSMIC_ALTAR_ADVANCED_WALKWAY("Narrow Walkway", 66, new WorldPoint(2408, 4401, 0)),
LUMBRIDGE_DESERT_STEPPING_STONE("Stepping Stone", 66, new WorldPoint(3210, 3135, 0)),
HEROS_GUILD_TUNNEL_WEST("Crevice", 67, new WorldPoint(2898, 9901, 0)),
HEROS_GUILD_TUNNEL_EAST("Crevice", 67, new WorldPoint(2913, 9895, 0)),
ELVEN_OVERPASS_MEDIUM_CLIFF("Rocks", 68, new WorldPoint(2337, 3288, 0)),
ARCEUUS_ESSENSE_NORTH("Rock Climb", 69, new WorldPoint(1759, 3873, 0)),
TAVERLEY_DUNGEON_PIPE_BLUE_DRAGON("Pipe Squeeze", 70, new WorldPoint(2886, 9798, 0)),
FOSSIL_ISLAND_HARDWOOD("Hole", 70, new WorldPoint(3663, 3810, 0)),
GWD_SARADOMIN_ROPE_FIRST("Rope Descent", 70, new WorldPoint(2912, 5300, 0)),
GWD_SARADOMIN_ROPE_SECOND("Rope Descent", 70, new WorldPoint(2951, 5267, 0)),
SLAYER_TOWER_ADVANCED_CHAIN_FIRST("Spiked Chain (Floor 2)", 71, new WorldPoint(3447, 3578, 0)),
SLAYER_TOWER_ADVANCED_CHAIN_SECOND("Spiked Chain (Floor 3)", 71, new WorldPoint(3446, 3576, 0)),
SLAYER_CAVE_WALL_CLIMB("Tunnel", 72, new WorldPoint(2431, 9806, 0)),
TROLL_STRONGHOLD_WALL_CLIMB("Rocks", 73, new WorldPoint(2841, 3694, 0)),
ARCEUUS_ESSENSE_MINE_WEST("Rock Climb", 73, new WorldPoint(1742, 3853, 0)),
LAVA_DRAGON_ISLE_JUMP("Stepping Stone", 74, new WorldPoint(3200, 3807, 0)),
REVENANT_CAVES_DEMONS_JUMP("Jump", 75, new WorldPoint(3199, 10135, 0)),
REVENANT_CAVES_ANKOU_EAST("Jump", 75, new WorldPoint(3201, 10195, 0)),
REVENANT_CAVES_ANKOU_NORTH("Jump", 75, new WorldPoint(3180, 10209, 0)),
ZUL_ANDRA_ISLAND_CROSSING("Stepping Stone", 76, new WorldPoint(2156, 3073, 0)),
SHILO_VILLAGE_STEPPING_STONES("Stepping Stones", 77, new WorldPoint(2863, 2974, 0)),
KHARAZI_JUNGLE_VINE_CLIMB("Vine", 79, new WorldPoint(2897, 2939, 0)),
TAVERLEY_DUNGEON_SPIKED_BLADES("Strange Floor", 80, new WorldPoint(2877, 9813, 0)),
SLAYER_DUNGEON_CHASM_JUMP("Spiked Blades", 81, new WorldPoint(2770, 10003, 0)),
LAVA_MAZE_NORTH_JUMP("Stepping Stone", 82, new WorldPoint(3092, 3880, 0)),
BRIMHAVEN_DUNGEON_EAST_STEPPING_NORTH("Stepping Stones", 83, new WorldPoint(2685, 9547, 0)),
BRIMHAVEN_DUNGEON_EAST_STEPPING_SOUTH("Stepping Stones", 83, new WorldPoint(2693, 9529, 0)),
ELVEN_ADVANCED_CLIFF_SCRAMBLE("Rocks", 85, new WorldPoint(2337, 3253, 0)),
KALPHITE_WALL("Crevice", 86, new WorldPoint(3214, 9508, 0)),
BRIMHAVEN_DUNGEON_VINE_EAST("Vine", 87, new WorldPoint(2672, 9582, 0)),
BRIMHAVEN_DUNGEON_VINE_WEST("Vine", 87, new WorldPoint(2606, 9584, 0)),
RENEVANT_CAVES("Jump", 89, new WorldPoint(3240, 10144, 0));
private final String tooltip;
private final WorldPoint location;
private final int levelReq;
AgilityShortcutLocation(String description, int level, WorldPoint location)
{
this.tooltip = description + " - Level " + level;
this.location = location;
this.levelReq = level;
}
}

View File

@@ -27,12 +27,13 @@ package net.runelite.client.plugins.worldmap;
import java.awt.image.BufferedImage;
import net.runelite.client.ui.overlay.worldmap.WorldMapPoint;
import net.runelite.client.game.AgilityShortcut;
class AgilityShortcutPoint extends WorldMapPoint
{
AgilityShortcutPoint(AgilityShortcutLocation data, BufferedImage icon, boolean showTooltip)
AgilityShortcutPoint(AgilityShortcut data, BufferedImage icon, boolean showTooltip)
{
super(data.getLocation(), icon);
super(data.getWorldMapLocation(), icon);
if (showTooltip)
{

View File

@@ -30,6 +30,7 @@ import net.runelite.api.coords.WorldPoint;
enum QuestStartLocation
{
//Free Quests
COOKS_ASSISTANT_RFD("Cook's Assistant", new WorldPoint(3211, 3216, 0)),
THE_CORSAIR_CURSE("The Corsair Curse", new WorldPoint(3029, 3273, 0)),
DEMON_SLAYER("Demon Slayer", new WorldPoint(3204, 3424, 0)),
@@ -48,8 +49,12 @@ enum QuestStartLocation
SHIELD_OF_ARRAV("Shield of Arrav", new WorldPoint(3208, 3495, 0)),
VAMPIRE_SLAYER("Vampire Slayer", new WorldPoint(3096, 3266, 0)),
WITCHS_POTION("Witch's Potion", new WorldPoint(2967, 3203, 0)),
X_MARKS_THE_SPOT("X Marks the Spot", new WorldPoint(3227, 3242, 0)),
//Members' Quests
ANIMAL_MAGNETISM("Animal Magnetism", new WorldPoint(3094, 3360, 0)),
ANOTHER_SLICE_OF_HAM("Another Slice of H.A.M.", new WorldPoint(2799, 5428, 0)),
THE_ASCENT_OF_ARCEUUS("The Ascent of Arceuus", new WorldPoint(1700, 3742, 0)),
BETWEEN_A_ROCK("Between a Rock...", new WorldPoint(2823, 10168, 0)),
BIG_CHOMPY_BIRD_HUNTING("Big Chompy Bird Hunting", new WorldPoint(2629, 2981, 0)),
BIOHAZARD("Biohazard", new WorldPoint(2591, 3335, 0)),
@@ -84,6 +89,7 @@ enum QuestStartLocation
FISHING_CONTEST_1("Fishing Contest", new WorldPoint(2875, 3483, 0)),
FISHING_CONTEST_2("Fishing Contest", new WorldPoint(2820, 3487, 0)),
FORGETTABLE_TALE("Forgettable Tale...", new WorldPoint(2826, 10215, 0)),
THE_FORSAKEN_TOWER("The Forsaken Tower", new WorldPoint(1484, 3747, 0)),
THE_FREMENNIK_ISLES("The Fremennik Isles", new WorldPoint(2645, 3711, 0)),
THE_FREMENNIK_TRIALS("The Fremennik Trials", new WorldPoint(2657, 3669, 0)),
GARDEN_OF_TRANQUILLITY("Garden of Tranquillity", new WorldPoint(3227, 3477, 0)),

View File

@@ -140,7 +140,7 @@ enum RareTreeLocation
new WorldPoint(3018, 3316, 0),
new WorldPoint(3041, 3320, 0),
new WorldPoint(3052, 3272, 0),
new WorldPoint(2933, 3234, 0),
new WorldPoint(2931, 3231, 0),
// Misthalin
new WorldPoint(3085, 3481, 0),

View File

@@ -36,6 +36,7 @@ import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.ExperienceChanged;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.game.AgilityShortcut;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.overlay.worldmap.WorldMapPointManager;
@@ -167,9 +168,10 @@ public class WorldMapPlugin extends Plugin
if (config.agilityShortcutLevelIcon() || config.agilityShortcutTooltips())
{
Arrays.stream(AgilityShortcutLocation.values())
Arrays.stream(AgilityShortcut.values())
.filter(value -> value.getWorldMapLocation() != null)
.map(value -> new AgilityShortcutPoint(value,
agilityLevel > 0 && config.agilityShortcutLevelIcon() && value.getLevelReq() > agilityLevel ? NOPE_ICON : BLANK_ICON,
agilityLevel > 0 && config.agilityShortcutLevelIcon() && value.getLevel() > agilityLevel ? NOPE_ICON : BLANK_ICON,
config.agilityShortcutTooltips()))
.forEach(worldMapPointManager::add);
}

View File

@@ -73,7 +73,7 @@ public class XpTrackerPlugin extends Plugin
/**
* Amount of EXP that must be gained for an update to be submitted.
*/
private static final int XP_THRESHOLD = 1000;
private static final int XP_THRESHOLD = 10_000;
static final List<Skill> COMBAT = ImmutableList.of(
Skill.ATTACK,

View File

@@ -27,7 +27,9 @@ package net.runelite.client.ui.overlay.components;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
@@ -36,6 +38,10 @@ import lombok.Setter;
public class ImageComponent implements LayoutableRenderableEntity
{
private final BufferedImage image;
@Getter
private final Rectangle bounds = new Rectangle();
private Point preferredLocation = new Point();
@Override
@@ -47,7 +53,10 @@ public class ImageComponent implements LayoutableRenderableEntity
}
graphics.drawImage(image, preferredLocation.x, preferredLocation.y, null);
return new Dimension(image.getWidth(), image.getHeight());
final Dimension dimension = new Dimension(image.getWidth(), image.getHeight());
bounds.setLocation(preferredLocation);
bounds.setSize(dimension);
return dimension;
}
@Override

Some files were not shown because too many files have changed in this diff Show More