Merge branch 'master' into true-current-tile

This commit is contained in:
Jesse Serrao
2019-03-26 01:09:09 +00:00
committed by GitHub
419 changed files with 15414 additions and 6200 deletions

View File

@@ -29,7 +29,7 @@
<parent>
<groupId>net.runelite</groupId>
<artifactId>runelite-parent</artifactId>
<version>1.5.12-SNAPSHOT</version>
<version>1.5.18-SNAPSHOT</version>
</parent>
<artifactId>client</artifactId>

View File

@@ -154,13 +154,13 @@ public class Notifier
public void processFlash(final Graphics2D graphics)
{
if (flashStart == null)
if (flashStart == null || client.getGameCycle() % 40 >= 20)
{
return;
}
if (client.getGameCycle() % 40 >= 20)
else if (client.getGameState() != GameState.LOGGED_IN)
{
flashStart = null;
return;
}

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

@@ -36,8 +36,8 @@ import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.events.SessionClose;
import net.runelite.api.events.SessionOpen;
import net.runelite.client.events.SessionClose;
import net.runelite.client.events.SessionOpen;
import net.runelite.client.RuneLite;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.EventBus;
@@ -155,7 +155,7 @@ public class SessionManager
private void closeSession()
{
wsClient.close();
wsClient.changeSession(null);
if (accountSession == null)
{

View File

@@ -186,8 +186,8 @@ public class Hooks implements Callbacks
* When the world map opens it loads about ~100mb of data into memory, which
* represents about half of the total memory allocated by the client.
* This gets cached and never released, which causes GC pressure which can affect
* performance. This method reinitailzies the world map cache, which allows the
* data to be garbage collecged, and causes the map data from disk each time
* performance. This method reinitializes the world map cache, which allows the
* data to be garbage collected, and causes the map data from disk each time
* is it opened.
*/
private void checkWorldMap()

View File

@@ -28,7 +28,7 @@ import java.util.function.BiConsumer;
import java.util.function.BiPredicate;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.runelite.api.events.SetMessage;
import net.runelite.api.events.ChatMessage;
import net.runelite.client.events.ChatInput;
@AllArgsConstructor
@@ -37,6 +37,6 @@ class ChatCommand
{
private final String name;
private boolean async;
private final BiConsumer<SetMessage, String> execute;
private final BiConsumer<ChatMessage, String> execute;
private final BiPredicate<ChatInput, String> input;
}

View File

@@ -34,7 +34,7 @@ import javax.inject.Singleton;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.events.SetMessage;
import net.runelite.api.events.ChatMessage;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.events.ChatInput;
@@ -59,22 +59,22 @@ public class ChatCommandManager implements ChatboxInputListener
commandManager.register(this);
}
public void registerCommand(String command, BiConsumer<SetMessage, String> execute)
public void registerCommand(String command, BiConsumer<ChatMessage, String> execute)
{
registerCommand(command, execute, null);
}
public void registerCommand(String command, BiConsumer<SetMessage, String> execute, BiPredicate<ChatInput, String> input)
public void registerCommand(String command, BiConsumer<ChatMessage, String> execute, BiPredicate<ChatInput, String> input)
{
commands.put(command.toLowerCase(), new ChatCommand(command, false, execute, input));
}
public void registerCommandAsync(String command, BiConsumer<SetMessage, String> execute)
public void registerCommandAsync(String command, BiConsumer<ChatMessage, String> execute)
{
registerCommandAsync(command, execute, null);
}
public void registerCommandAsync(String command, BiConsumer<SetMessage, String> execute, BiPredicate<ChatInput, String> input)
public void registerCommandAsync(String command, BiConsumer<ChatMessage, String> execute, BiPredicate<ChatInput, String> input)
{
commands.put(command.toLowerCase(), new ChatCommand(command, true, execute, input));
}
@@ -85,14 +85,14 @@ public class ChatCommandManager implements ChatboxInputListener
}
@Subscribe
public void onSetMessage(SetMessage setMessage)
public void onChatMessage(ChatMessage chatMessage)
{
if (client.getGameState() != GameState.LOGGED_IN)
{
return;
}
switch (setMessage.getType())
switch (chatMessage.getType())
{
case PUBLIC:
case PUBLIC_MOD:
@@ -104,7 +104,7 @@ public class ChatCommandManager implements ChatboxInputListener
return;
}
String message = setMessage.getValue();
String message = chatMessage.getMessage();
String command = extractCommand(message);
if (command == null)
@@ -120,11 +120,11 @@ public class ChatCommandManager implements ChatboxInputListener
if (chatCommand.isAsync())
{
scheduledExecutorService.execute(() -> chatCommand.getExecute().accept(setMessage, message));
scheduledExecutorService.execute(() -> chatCommand.getExecute().accept(chatMessage, message));
}
else
{
chatCommand.getExecute().accept(setMessage, message);
chatCommand.getExecute().accept(chatMessage, message);
}
}

View File

@@ -42,10 +42,10 @@ import net.runelite.api.ChatMessageType;
import net.runelite.api.Client;
import net.runelite.api.MessageNode;
import net.runelite.api.Varbits;
import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.ResizeableChanged;
import net.runelite.api.events.ScriptCallbackEvent;
import net.runelite.api.events.SetMessage;
import net.runelite.api.events.VarbitChanged;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.config.ChatColorConfig;
@@ -103,10 +103,10 @@ public class ChatMessageManager
}
@Subscribe
public void onSetMessage(SetMessage setMessage)
public void onChatMessage(ChatMessage chatMessage)
{
MessageNode messageNode = setMessage.getMessageNode();
ChatMessageType chatMessageType = setMessage.getType();
MessageNode messageNode = chatMessage.getMessageNode();
ChatMessageType chatMessageType = chatMessage.getType();
boolean isChatboxTransparent = client.isResized() && client.getVar(Varbits.TRANSPARENT_CHATBOX) == 1;
Color usernameColor = null;
@@ -125,7 +125,7 @@ public class ChatMessageManager
case PUBLIC:
case PUBLIC_MOD:
{
boolean isFriend = client.isFriended(setMessage.getName(), true) && !client.getLocalPlayer().getName().equals(setMessage.getName());
boolean isFriend = client.isFriended(chatMessage.getName(), true) && !client.getLocalPlayer().getName().equals(chatMessage.getName());
if (isFriend)
{
@@ -149,7 +149,7 @@ public class ChatMessageManager
messageNode.setName(ColorUtil.wrapWithColorTag(messageNode.getName(), usernameColor));
}
String sender = setMessage.getSender();
String sender = chatMessage.getSender();
if (senderColor != null && !Strings.isNullOrEmpty(sender))
{
messageNode.setSender(ColorUtil.wrapWithColorTag(sender, senderColor));

View File

@@ -43,8 +43,12 @@ 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.Duration;
import java.time.Instant;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -56,6 +60,7 @@ import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.coords.WorldPoint;
import net.runelite.api.events.ConfigChanged;
import net.runelite.client.RuneLite;
import net.runelite.client.account.AccountSession;
@@ -70,6 +75,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;
@@ -95,6 +101,9 @@ public class ConfigManager
public final void switchSession(AccountSession session)
{
// Ensure existing config is saved
sendConfig();
if (session == null)
{
this.session = null;
@@ -111,12 +120,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
{
@@ -146,7 +160,7 @@ public class ConfigManager
return;
}
if (configuration.getConfig().isEmpty())
if (configuration.getConfig() == null || configuration.getConfig().isEmpty())
{
log.debug("No configuration from client, using saved configuration on disk");
loadFromFile();
@@ -158,7 +172,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 +194,7 @@ public class ConfigManager
try
{
saveToFile();
saveToFile(propertiesFile);
log.debug("Updated configuration on disk with the latest version");
}
@@ -184,6 +204,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 +320,7 @@ public class ConfigManager
}
}
private synchronized void saveToFile() throws IOException
private void saveToFile(final File propertiesFile) throws IOException
{
propertiesFile.getParentFile().mkdirs();
@@ -294,8 +383,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,24 +390,13 @@ public class ConfigManager
return;
}
log.debug("Setting configuration value for {}.{} to {}", groupName, key, value);
synchronized (pendingChanges)
{
pendingChanges.put(groupName + "." + key, value);
}
Runnable task = () ->
{
try
{
saveToFile();
}
catch (IOException ex)
{
log.warn("unable to save configuration file", ex);
}
};
executor.execute(task);
ConfigChanged configChanged = new ConfigChanged();
configChanged.setGroup(groupName);
configChanged.setKey(key);
@@ -337,8 +413,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,24 +420,13 @@ public class ConfigManager
return;
}
log.debug("Unsetting configuration value for {}.{}", groupName, key);
synchronized (pendingChanges)
{
pendingChanges.put(groupName + "." + key, null);
}
Runnable task = () ->
{
try
{
saveToFile();
}
catch (IOException ex)
{
log.warn("unable to save configuration file", ex);
}
};
executor.execute(task);
ConfigChanged configChanged = new ConfigChanged();
configChanged.setGroup(groupName);
configChanged.setKey(key);
@@ -527,6 +590,18 @@ public class ConfigManager
}
return new Keybind(code, mods);
}
if (type == WorldPoint.class)
{
String[] splitStr = str.split(":");
int x = Integer.parseInt(splitStr[0]);
int y = Integer.parseInt(splitStr[1]);
int plane = Integer.parseInt(splitStr[2]);
return new WorldPoint(x, y, plane);
}
if (type == Duration.class)
{
return Duration.ofMillis(Long.parseLong(str));
}
return str;
}
@@ -564,11 +639,21 @@ public class ConfigManager
Keybind k = (Keybind) object;
return k.getKeyCode() + ":" + k.getModifiers();
}
if (object instanceof WorldPoint)
{
WorldPoint wp = (WorldPoint) object;
return wp.getX() + ":" + wp.getY() + ":" + wp.getPlane();
}
if (object instanceof Duration)
{
return Long.toString(((Duration) object).toMillis());
}
return object.toString();
}
public void sendConfig()
{
boolean changed;
synchronized (pendingChanges)
{
if (client != null)
@@ -588,7 +673,20 @@ public class ConfigManager
}
}
}
changed = !pendingChanges.isEmpty();
pendingChanges.clear();
}
if (changed)
{
try
{
saveToFile(propertiesFile);
}
catch (IOException ex)
{
log.warn("unable to save configuration file", 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,40 @@
/*
* Copyright (c) 2017, 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.events;
import lombok.Data;
/**
* An event where a new RuneLite account session has been closed,
* typically when logging out of the account.
* <p>
* Note: This event is not to be confused with a RuneScape session,
* it has nothing to do with whether an account is being logged out.
*/
@Data
public class SessionClose
{
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Levi <me@levischuck.com>
* Copyright (c) 2017, Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -22,34 +22,19 @@
* (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.xptracker;
package net.runelite.client.events;
import lombok.Data;
/**
* An event where a new RuneLite account session has been opened
* with the server.
* <p>
* Note: This event is not to be confused with a RuneScape session,
* it has nothing to do with whether an account is being logged in.
*/
@Data
class XpStateTotal
public class SessionOpen
{
private int xpGainedInSession = 0;
private int xpPerHour = 0;
void reset()
{
xpGainedInSession = 0;
xpPerHour = 0;
}
void addXpGainedInSession(int skillXpGainedInSession)
{
xpGainedInSession += skillXpGainedInSession;
}
void addXpPerHour(int skillXpGainedPerHour)
{
xpPerHour += skillXpGainedPerHour;
}
XpSnapshotTotal snapshot()
{
return new XpSnapshotTotal(xpGainedInSession, xpPerHour);
}
}

View File

@@ -0,0 +1,244 @@
/*
* 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),
MOUNT_KARUULM_PIPE_SOUTH(88, "Pipe", new WorldPoint(1316, 10214, 0), MYSTERIOUS_PIPE),
MOUNT_KARUULM_PIPE_NORTH(88, "Pipe", new WorldPoint(1346, 10231, 0), MYSTERIOUS_PIPE),
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

@@ -1,158 +0,0 @@
/*
* 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 com.google.inject.Inject;
import com.google.inject.Singleton;
import java.util.function.Consumer;
import lombok.Getter;
import net.runelite.api.Client;
import net.runelite.api.ScriptID;
import net.runelite.api.events.ScriptCallbackEvent;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.eventbus.Subscribe;
@Singleton
public class ChatboxInputManager
{
public static final int NO_LIMIT = Integer.MAX_VALUE;
private final Client client;
private final ClientThread clientThread;
private Consumer<String> done;
private Consumer<String> changed;
private int characterLimit = NO_LIMIT;
@Getter
private boolean open = false;
@Inject
public ChatboxInputManager(Client client, ClientThread clientThread, EventBus eventBus)
{
this.client = client;
this.clientThread = clientThread;
eventBus.register(this);
}
/**
* Opens a RuneScape-style chatbox input
*
* @param text Text to show at the top of the window
* @param defaul Default text in the editable field
* @param done Callback when the text box has been exited, called with "" on esc
*/
public void openInputWindow(String text, String defaul, Consumer<String> done)
{
openInputWindow(text, defaul, NO_LIMIT, done);
}
public void openInputWindow(String text, String defaul, int characterLimit, Consumer<String> done)
{
openInputWindow(text, defaul, characterLimit, null, done);
}
public void openInputWindow(String text, String defaul, int characterLimit, Consumer<String> changed, Consumer<String> done)
{
this.done = done;
this.changed = changed;
this.characterLimit = characterLimit;
this.open = true;
clientThread.invoke(() -> client.runScript(
ScriptID.RUNELITE_CHATBOX_INPUT_INIT,
text,
defaul
));
}
/**
* Closes the RuneScape-style chatbox input
*/
public void closeInputWindow()
{
if (!this.open)
{
return;
}
this.open = false;
clientThread.invoke(() -> client.runScript(
ScriptID.RESET_CHATBOX_INPUT,
1,
1
));
}
@Subscribe
public void onScriptCallbackEvent(ScriptCallbackEvent ev)
{
// This replaces script 74 and most of 112
if ("chatboxInputHandler".equals(ev.getEventName()))
{
int intStackSize = client.getIntStackSize();
int stringStackSize = client.getStringStackSize();
int typedKey = client.getIntStack()[--intStackSize];
String str = client.getStringStack()[--stringStackSize];
boolean isDone = false;
switch (typedKey)
{
case 27: // Escape
str = "";
// fallthrough
case '\n':
this.open = false;
isDone = true;
break;
case '\b':
if (!str.isEmpty())
{
str = str.substring(0, str.length() - 1);
}
break;
default:
// If we wanted to do numbers only, we could add a limit here
if (typedKey >= 32 && (str.length() < characterLimit))
{
str += Character.toString((char) typedKey);
}
}
if (changed != null)
{
changed.accept(str);
}
if (isDone && done != null)
{
done.accept(str);
}
client.getStringStack()[stringStackSize++] = str;
client.getIntStack()[intStackSize++] = isDone ? 1 : 0;
client.setIntStackSize(intStackSize);
client.setStringStackSize(stringStackSize);
}
}
}

View File

@@ -84,7 +84,7 @@ public class ItemManager
private final ItemClient itemClient = new ItemClient();
private Map<Integer, ItemPrice> itemPrices = Collections.emptyMap();
private Map<String, ItemStats> itemStats = Collections.emptyMap();
private Map<Integer, ItemStats> itemStats = Collections.emptyMap();
private final LoadingCache<ImageKey, AsyncBufferedImage> itemImages;
private final LoadingCache<Integer, ItemComposition> itemCompositions;
private final LoadingCache<OutlineKey, BufferedImage> itemOutlines;
@@ -226,7 +226,7 @@ public class ItemManager
{
try
{
final Map<String, ItemStats> stats = itemClient.getStats();
final Map<Integer, ItemStats> stats = itemClient.getStats();
if (stats != null)
{
itemStats = ImmutableMap.copyOf(stats);
@@ -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
*
@@ -298,16 +307,16 @@ public class ItemManager
* @return item stats
*/
@Nullable
public ItemStats getItemStats(int itemId)
public ItemStats getItemStats(int itemId, boolean allowNote)
{
ItemComposition itemComposition = getItemComposition(itemId);
if (itemComposition == null || itemComposition.getName() == null)
if (itemComposition == null || itemComposition.getName() == null || (!allowNote && itemComposition.getNote() != -1))
{
return null;
}
return itemStats.get(itemComposition.getName());
return itemStats.get(canonicalize(itemId));
}
/**

View File

@@ -195,7 +195,7 @@ public enum ItemMapping
BLACK_MASK, BLACK_MASK_I, BLACK_MASK_1, BLACK_MASK_1_I, BLACK_MASK_2, BLACK_MASK_2_I, BLACK_MASK_3, BLACK_MASK_3_I, BLACK_MASK_4, BLACK_MASK_4_I, BLACK_MASK_5,
BLACK_MASK_5_I, BLACK_MASK_6, BLACK_MASK_6_I, BLACK_MASK_7, BLACK_MASK_7_I, BLACK_MASK_8, BLACK_MASK_8_I, BLACK_MASK_9, BLACK_MASK_9_I, BLACK_MASK_10_I,
SLAYER_HELMET, SLAYER_HELMET_I, BLACK_SLAYER_HELMET, BLACK_SLAYER_HELMET_I, PURPLE_SLAYER_HELMET, PURPLE_SLAYER_HELMET_I, RED_SLAYER_HELMET, RED_SLAYER_HELMET_I,
GREEN_SLAYER_HELMET, GREEN_SLAYER_HELMET_I, TURQUOISE_SLAYER_HELMET, TURQUOISE_SLAYER_HELMET_I),
GREEN_SLAYER_HELMET, GREEN_SLAYER_HELMET_I, TURQUOISE_SLAYER_HELMET, TURQUOISE_SLAYER_HELMET_I, HYDRA_SLAYER_HELMET, HYDRA_SLAYER_HELMET_I),
// Pharaoh's Sceptres
ITEM_PHARAOHS_SCEPTRE_1(PHARAOHS_SCEPTRE, PHARAOHS_SCEPTRE_1),

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

@@ -93,6 +93,10 @@ public class ChatboxPanelManager
0,
1
);
if (currentInput != null)
{
killCurrentPanel();
}
}
private void unsafeOpenInput(ChatboxInput input)
@@ -113,6 +117,11 @@ public class ChatboxPanelManager
mouseManager.registerMouseWheelListener((MouseWheelListener) input);
}
if (currentInput != null)
{
killCurrentPanel();
}
currentInput = input;
client.setVar(VarClientInt.INPUT_TYPE, InputType.RUNELITE_CHATBOX_PANEL.getType());
client.getWidget(WidgetInfo.CHATBOX_TITLE).setHidden(true);

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

@@ -57,8 +57,8 @@ import javax.inject.Singleton;
import javax.swing.SwingUtilities;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.events.SessionClose;
import net.runelite.api.events.SessionOpen;
import net.runelite.client.events.SessionClose;
import net.runelite.client.events.SessionOpen;
import net.runelite.client.RuneLite;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;

View File

@@ -29,11 +29,11 @@ import java.util.concurrent.ScheduledExecutorService;
import javax.inject.Inject;
import javax.swing.JOptionPane;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.events.SessionClose;
import net.runelite.api.events.SessionOpen;
import net.runelite.client.account.AccountSession;
import net.runelite.client.account.SessionManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.events.SessionClose;
import net.runelite.client.events.SessionOpen;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.ClientToolbar;
@@ -113,10 +113,10 @@ public class AccountPlugin extends Plugin
private void logoutClick()
{
if (JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(null,
"Are you sure you want to logout from RuneLite?", "Logout Confirmation",
JOptionPane.YES_NO_OPTION))
"Are you sure you want to logout from RuneLite?", "Logout Confirmation",
JOptionPane.YES_NO_OPTION))
{
sessionManager.logout();
executor.execute(sessionManager::logout);
}
}

View File

@@ -40,8 +40,10 @@ public class ArdougneDiaryRequirement extends GenericDiaryRequirement
new QuestRequirement(Quest.RUNE_MYSTERIES));
add("Steal a cake from the Ardougne market stalls.",
new SkillRequirement(Skill.THIEVING, 5));
add("Enter the Combat Training Camp north of W. Ardougne",
add("Enter the Combat Training Camp north of W. Ardougne.",
new QuestRequirement(Quest.BIOHAZARD));
add("Go out fishing on the Fishing Trawler.",
new SkillRequirement(Skill.FISHING, 15));
// MEDIUM
add("Enter the Unicorn pen in Ardougne zoo using Fairy rings.",

View File

@@ -94,6 +94,8 @@ public class FaladorDiaryRequirement extends GenericDiaryRequirement
new SkillRequirement(Skill.AGILITY, 50));
add("Enter the mining guild wearing full prospector.",
new SkillRequirement(Skill.MINING, 60));
add("Kill the Blue Dragon under the Heroes' Guild.",
new QuestRequirement(Quest.HEROES_QUEST));
add("Crack a wall safe within Rogues Den.",
new SkillRequirement(Skill.THIEVING, 50));
add("Recharge your prayer in the Port Sarim church while wearing full Proselyte.",

View File

@@ -50,9 +50,9 @@ public class FremennikDiaryRequirement extends GenericDiaryRequirement
add("Steal from the Keldagrim crafting or baker's stall.",
new SkillRequirement(Skill.THIEVING, 5),
new QuestRequirement(Quest.THE_GIANT_DWARF, true));
add("Enter the Troll Stronghold",
add("Enter the Troll Stronghold.",
new QuestRequirement(Quest.DEATH_PLATEAU),
new QuestRequirement(Quest.TROLL_STRONGHOLD));
new QuestRequirement(Quest.TROLL_STRONGHOLD, true));
add("Chop and burn some oak logs in the Fremennik Province.",
new SkillRequirement(Skill.WOODCUTTING, 15),
new SkillRequirement(Skill.FIREMAKING, 15));

View File

@@ -40,7 +40,7 @@ public class KandarinDiaryRequirement extends GenericDiaryRequirement
new SkillRequirement(Skill.FISHING, 16));
add("Plant some Jute seeds in the patch north of McGrubor's Wood.",
new SkillRequirement(Skill.FARMING, 13));
add("Defeat on of each elemental in the workshop.",
add("Defeat one of each elemental in the workshop.",
new QuestRequirement(Quest.ELEMENTAL_WORKSHOP_I, true));
add("Cross the Coal truck log shortcut.",
new SkillRequirement(Skill.AGILITY, 20));
@@ -96,6 +96,9 @@ public class KandarinDiaryRequirement extends GenericDiaryRequirement
new SkillRequirement(Skill.MAGIC, 56));
add("Burn some Maple logs with a bow in Seers' Village.",
new SkillRequirement(Skill.FIREMAKING, 65));
add("Kill a Shadow Hound in the Shadow dungeon.",
new SkillRequirement(Skill.THIEVING, 53),
new QuestRequirement(Quest.DESERT_TREASURE, true));
add("Purchase and equip a granite body from Barbarian Assault.",
new SkillRequirement(Skill.STRENGTH, 50),
new SkillRequirement(Skill.DEFENCE, 50));

View File

@@ -128,7 +128,6 @@ public class KourendDiaryRequirement extends GenericDiaryRequirement
new SkillRequirement(Skill.MAGIC, 90),
new SkillRequirement(Skill.MINING, 38),
new SkillRequirement(Skill.CRAFTING, 38),
new QuestRequirement(Quest.MONKEY_MADNESS_I),
new FavourRequirement(Favour.ARCEUUS, 100));
add("Create your own Battlestaff from scratch within the Farming Guild.",
new SkillRequirement(Skill.FARMING, 85),

View File

@@ -48,6 +48,8 @@ public class MorytaniaDiaryRequirement extends GenericDiaryRequirement
new SkillRequirement(Skill.SLAYER, 15));
add("Place a Scarecrow in the Morytania flower patch.",
new SkillRequirement(Skill.FARMING, 23));
add("Kill a werewolf in its human form using the Wolfbane Dagger.",
new QuestRequirement(Quest.PRIEST_IN_PERIL));
add("Restore your prayer points at the nature altar.",
new QuestRequirement(Quest.NATURE_SPIRIT));
@@ -74,7 +76,7 @@ public class MorytaniaDiaryRequirement extends GenericDiaryRequirement
add("Use an ectophial to return to Port Phasmatys.",
new QuestRequirement(Quest.GHOSTS_AHOY));
add("Mix a Guthix Balance potion while in Morytania.",
new SkillRequirement(Skill.HERBLORE, 36),
new SkillRequirement(Skill.HERBLORE, 22),
new QuestRequirement(Quest.IN_AID_OF_THE_MYREQUE, true));
// HARD

View File

@@ -88,7 +88,7 @@ public class WesternDiaryRequirement extends GenericDiaryRequirement
// HARD
add("Kill an Elf with a Crystal bow.",
new SkillRequirement(Skill.RANGED, 70),
new SkillRequirement(Skill.AGILITY, 50),
new SkillRequirement(Skill.AGILITY, 56),
new QuestRequirement(Quest.ROVING_ELVES));
add("Catch and cook a Monkfish in Piscatoris.",
new SkillRequirement(Skill.FISHING, 62),

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

@@ -97,11 +97,22 @@ public interface AttackStylesConfig extends Config
return false;
}
@ConfigItem(
keyName = "hideAutoRetaliate",
name = "Hide auto retaliate",
description = "Hide auto retaliate from the combat options tab",
position = 7
)
default boolean hideAutoRetaliate()
{
return false;
}
@ConfigItem(
keyName = "removeWarnedStyles",
name = "Remove warned styles",
description = "Remove warned styles from the combat options tab",
position = 7
position = 8
)
default boolean removeWarnedStyles()
{

View File

@@ -126,6 +126,7 @@ public class AttackStylesPlugin extends Plugin
overlayManager.remove(overlay);
hideWarnedStyles(false);
processWidgets();
hideWidget(client.getWidget(WidgetInfo.COMBAT_AUTO_RETALIATE), false);
}
public AttackStyle getAttackStyle()
@@ -174,6 +175,7 @@ public class AttackStylesPlugin extends Plugin
hideWidget(client.getWidget(widgetKey), widgetsToHide.get(equippedWeaponType, widgetKey));
}
}
hideWidget(client.getWidget(WidgetInfo.COMBAT_AUTO_RETALIATE), config.hideAutoRetaliate());
}
@Subscribe

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;
@@ -130,6 +130,8 @@ public class TabInterface
private int currentTabIndex;
private TagTab iconToSet = null;
private Instant startScroll = Instant.now();
private String rememberedSearch;
private boolean waitSearchTick;
@Getter
private Widget upButton;
@@ -148,7 +150,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 +160,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 +211,7 @@ public class TabInterface
if (config.rememberTab() && !Strings.isNullOrEmpty(config.tab()))
{
openTag(TAG_SEARCH + config.tab());
openTag(config.tab());
}
}
@@ -239,7 +239,7 @@ public class TabInterface
tagManager.addTag(item, activeTab.getTag(), false);
}
openTag(TAG_SEARCH + activeTab.getTag());
openTag(activeTab.getTag());
}
return;
@@ -292,7 +292,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 +306,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 +336,7 @@ public class TabInterface
}
else
{
openTag(TAG_SEARCH + Text.removeTags(clicked.getName()));
openTag(Text.removeTags(clicked.getName()));
}
client.playSoundEffect(SoundEffectID.UI_BOOP);
@@ -373,6 +373,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;
}
}
@@ -382,6 +386,8 @@ public class TabInterface
currentTabIndex = 0;
maxTabs = 0;
parent = null;
waitSearchTick = false;
rememberedSearch = "";
if (upButton != null)
{
@@ -398,6 +404,8 @@ public class TabInterface
if (isHidden())
{
parent = null;
waitSearchTick = false;
rememberedSearch = "";
// If bank window was just hidden, update last active tab position
if (currentTabIndex != config.position())
@@ -462,6 +470,20 @@ public class TabInterface
activateTab(null);
}
if (!waitSearchTick
&& activeTab == null
&& !Strings.isNullOrEmpty(rememberedSearch)
&& client.getVar(VarClientInt.INPUT_TYPE) == InputType.NONE.getType())
{
bankSearch.reset(true);
bankSearch.search(InputType.NONE, rememberedSearch, true);
rememberedSearch = "";
}
else if (waitSearchTick)
{
waitSearchTick = false;
}
updateBounds();
scrollTab(0);
}
@@ -542,6 +564,15 @@ public class TabInterface
return;
}
if (event.getWidgetId() == WidgetInfo.BANK_ITEM_CONTAINER.getId()
&& event.getMenuAction() == MenuAction.EXAMINE_ITEM_BANK_EQ
&& event.getMenuOption().equalsIgnoreCase("withdraw-x"))
{
waitSearchTick = true;
rememberedSearch = client.getVar(VarClientStr.INPUT_TEXT);
bankSearch.search(InputType.NONE, rememberedSearch, true);
}
if (iconToSet != null)
{
if (event.getMenuOption().startsWith(CHANGE_ICON + " ("))
@@ -550,7 +581,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 +628,7 @@ public class TabInterface
{
if (activeTab != null && tags.contains(activeTab.getTag()))
{
openTag(TAG_SEARCH + activeTab.getTag());
openTag(activeTab.getTag());
}
}
@@ -683,6 +714,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 +744,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 +890,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 +986,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 +998,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

@@ -77,7 +77,7 @@ class BarrowsOverlay extends Overlay
{
final NPCComposition composition = npc.getComposition();
if (composition != null && !composition.isMinimapVisable())
if (composition != null && !composition.isMinimapVisible())
{
continue;
}
@@ -90,10 +90,16 @@ class BarrowsOverlay extends Overlay
}
// Player dots
graphics.setColor(npcColor);
graphics.setColor(playerColor);
final List<Player> players = client.getPlayers();
for (Player player : players)
{
if (player == local)
{
// Skip local player as we draw square for it later
continue;
}
net.runelite.api.Point minimapLocation = player.getMinimapLocation();
if (minimapLocation != null)
{

View File

@@ -49,7 +49,9 @@ import net.runelite.api.events.WallObjectChanged;
import net.runelite.api.events.WallObjectDespawned;
import net.runelite.api.events.WallObjectSpawned;
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.chat.ChatColorType;
import net.runelite.client.chat.ChatMessageBuilder;
import net.runelite.client.chat.ChatMessageManager;
@@ -128,6 +130,19 @@ public class BarrowsPlugin extends Plugin
overlayManager.remove(brotherOverlay);
walls.clear();
ladders.clear();
// Restore widgets
final Widget potential = client.getWidget(WidgetInfo.BARROWS_POTENTIAL);
if (potential != null)
{
potential.setHidden(false);
}
final Widget barrowsBrothers = client.getWidget(WidgetInfo.BARROWS_BROTHERS);
if (barrowsBrothers != null)
{
barrowsBrothers.setHidden(false);
}
}
@Subscribe

View File

@@ -137,7 +137,7 @@ class BoostsOverlay extends Overlay
return new Color(238, 51, 51);
}
return boost < config.boostThreshold() ? Color.YELLOW : Color.GREEN;
return boost <= config.boostThreshold() ? Color.YELLOW : Color.GREEN;
}
}

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.LOGIN_SCREEN || event.getGameState() == GameState.HOPPING)
GameState gameState = event.getGameState();
if (gameState == GameState.LOGIN_SCREEN || gameState == GameState.HOPPING || gameState == GameState.CONNECTION_LOST)
{
ghosts.clear();
}

View File

@@ -43,7 +43,6 @@ import net.runelite.api.MessageNode;
import net.runelite.api.VarPlayer;
import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.GameTick;
import net.runelite.api.events.SetMessage;
import net.runelite.api.events.VarbitChanged;
import net.runelite.api.events.WidgetLoaded;
import net.runelite.api.vars.AccountType;
@@ -300,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))
{
@@ -360,14 +359,19 @@ public class ChatCommandsPlugin extends Plugin
return true;
}
private void killCountLookup(SetMessage setMessage, String message)
private void killCountLookup(ChatMessage chatMessage, String message)
{
if (!config.killcount())
{
return;
}
ChatMessageType type = setMessage.getType();
if (message.length() <= KILLCOUNT_COMMAND_STRING.length())
{
return;
}
ChatMessageType type = chatMessage.getType();
String search = message.substring(KILLCOUNT_COMMAND_STRING.length() + 1);
final String player;
@@ -377,7 +381,7 @@ public class ChatCommandsPlugin extends Plugin
}
else
{
player = sanitize(setMessage.getName());
player = sanitize(chatMessage.getName());
}
search = longBossName(search);
@@ -403,20 +407,20 @@ public class ChatCommandsPlugin extends Plugin
.build();
log.debug("Setting response {}", response);
final MessageNode messageNode = setMessage.getMessageNode();
final MessageNode messageNode = chatMessage.getMessageNode();
messageNode.setRuneLiteFormatMessage(response);
chatMessageManager.update(messageNode);
client.refreshChat();
}
private void questPointsLookup(SetMessage setMessage, String message)
private void questPointsLookup(ChatMessage chatMessage, String message)
{
if (!config.qp())
{
return;
}
ChatMessageType type = setMessage.getType();
ChatMessageType type = chatMessage.getType();
final String player;
if (type.equals(ChatMessageType.PRIVATE_MESSAGE_SENT))
@@ -425,7 +429,7 @@ public class ChatCommandsPlugin extends Plugin
}
else
{
player = sanitize(setMessage.getName());
player = sanitize(chatMessage.getName());
}
int qp;
@@ -447,7 +451,7 @@ public class ChatCommandsPlugin extends Plugin
.build();
log.debug("Setting response {}", response);
final MessageNode messageNode = setMessage.getMessageNode();
final MessageNode messageNode = chatMessage.getMessageNode();
messageNode.setRuneLiteFormatMessage(response);
chatMessageManager.update(messageNode);
client.refreshChat();
@@ -477,14 +481,19 @@ public class ChatCommandsPlugin extends Plugin
return true;
}
private void personalBestLookup(SetMessage setMessage, String message)
private void personalBestLookup(ChatMessage chatMessage, String message)
{
if (!config.pb())
{
return;
}
ChatMessageType type = setMessage.getType();
if (message.length() <= PB_COMMAND.length())
{
return;
}
ChatMessageType type = chatMessage.getType();
String search = message.substring(PB_COMMAND.length() + 1);
final String player;
@@ -494,7 +503,7 @@ public class ChatCommandsPlugin extends Plugin
}
else
{
player = sanitize(setMessage.getName());
player = sanitize(chatMessage.getName());
}
search = longBossName(search);
@@ -523,7 +532,7 @@ public class ChatCommandsPlugin extends Plugin
.build();
log.debug("Setting response {}", response);
final MessageNode messageNode = setMessage.getMessageNode();
final MessageNode messageNode = chatMessage.getMessageNode();
messageNode.setRuneLiteFormatMessage(response);
chatMessageManager.update(messageNode);
client.refreshChat();
@@ -565,17 +574,22 @@ public class ChatCommandsPlugin extends Plugin
* Looks up the item price and changes the original message to the
* response.
*
* @param setMessage The chat message containing the command.
* @param chatMessage The chat message containing the command.
* @param message The chat message
*/
private void itemPriceLookup(SetMessage setMessage, String message)
private void itemPriceLookup(ChatMessage chatMessage, String message)
{
if (!config.price())
{
return;
}
MessageNode messageNode = setMessage.getMessageNode();
if (message.length() <= PRICE_COMMAND_STRING.length())
{
return;
}
MessageNode messageNode = chatMessage.getMessageNode();
String search = message.substring(PRICE_COMMAND_STRING.length() + 1);
List<ItemPrice> results = itemManager.search(search);
@@ -621,10 +635,10 @@ public class ChatCommandsPlugin extends Plugin
* Looks up the player skill and changes the original message to the
* response.
*
* @param setMessage The chat message containing the command.
* @param chatMessage The chat message containing the command.
* @param message The chat message
*/
private void playerSkillLookup(SetMessage setMessage, String message)
private void playerSkillLookup(ChatMessage chatMessage, String message)
{
if (!config.lvl())
{
@@ -638,6 +652,11 @@ public class ChatCommandsPlugin extends Plugin
}
else
{
if (message.length() <= LEVEL_COMMAND_STRING.length())
{
return;
}
search = message.substring(LEVEL_COMMAND_STRING.length() + 1);
}
@@ -652,7 +671,7 @@ public class ChatCommandsPlugin extends Plugin
return;
}
final HiscoreLookup lookup = getCorrectLookupFor(setMessage);
final HiscoreLookup lookup = getCorrectLookupFor(chatMessage);
try
{
@@ -682,7 +701,7 @@ public class ChatCommandsPlugin extends Plugin
.build();
log.debug("Setting response {}", response);
final MessageNode messageNode = setMessage.getMessageNode();
final MessageNode messageNode = chatMessage.getMessageNode();
messageNode.setRuneLiteFormatMessage(response);
chatMessageManager.update(messageNode);
client.refreshChat();
@@ -693,14 +712,14 @@ public class ChatCommandsPlugin extends Plugin
}
}
private void combatLevelLookup(SetMessage setMessage, String message)
private void combatLevelLookup(ChatMessage chatMessage, String message)
{
if (!config.lvl())
{
return;
}
ChatMessageType type = setMessage.getType();
ChatMessageType type = chatMessage.getType();
String player;
if (type == ChatMessageType.PRIVATE_MESSAGE_SENT)
@@ -709,7 +728,7 @@ public class ChatCommandsPlugin extends Plugin
}
else
{
player = sanitize(setMessage.getName());
player = sanitize(chatMessage.getName());
}
try
@@ -767,7 +786,7 @@ public class ChatCommandsPlugin extends Plugin
.build();
log.debug("Setting response {}", response);
final MessageNode messageNode = setMessage.getMessageNode();
final MessageNode messageNode = chatMessage.getMessageNode();
messageNode.setRuneLiteFormatMessage(response);
chatMessageManager.update(messageNode);
client.refreshChat();
@@ -778,7 +797,7 @@ public class ChatCommandsPlugin extends Plugin
}
}
private void clueLookup(SetMessage setMessage, String message)
private void clueLookup(ChatMessage chatMessage, String message)
{
if (!config.clue())
{
@@ -799,7 +818,7 @@ public class ChatCommandsPlugin extends Plugin
try
{
final Skill hiscoreSkill;
final HiscoreLookup lookup = getCorrectLookupFor(setMessage);
final HiscoreLookup lookup = getCorrectLookupFor(chatMessage);
final HiscoreResult result = hiscoreClient.lookup(lookup.getName(), lookup.getEndpoint());
if (result == null)
@@ -858,7 +877,7 @@ public class ChatCommandsPlugin extends Plugin
String response = chatMessageBuilder.build();
log.debug("Setting response {}", response);
final MessageNode messageNode = setMessage.getMessageNode();
final MessageNode messageNode = chatMessage.getMessageNode();
messageNode.setRuneLiteFormatMessage(response);
chatMessageManager.update(messageNode);
client.refreshChat();
@@ -872,22 +891,22 @@ public class ChatCommandsPlugin extends Plugin
/**
* Gets correct lookup data for message
*
* @param setMessage chat message
* @param chatMessage chat message
* @return hiscore lookup data
*/
private HiscoreLookup getCorrectLookupFor(final SetMessage setMessage)
private HiscoreLookup getCorrectLookupFor(final ChatMessage chatMessage)
{
final String player;
final HiscoreEndpoint ironmanStatus;
if (setMessage.getType().equals(ChatMessageType.PRIVATE_MESSAGE_SENT))
if (chatMessage.getType().equals(ChatMessageType.PRIVATE_MESSAGE_SENT))
{
player = client.getLocalPlayer().getName();
ironmanStatus = hiscoreEndpoint;
}
else
{
player = sanitize(setMessage.getName());
player = sanitize(chatMessage.getName());
if (player.equals(client.getLocalPlayer().getName()))
{
@@ -897,7 +916,7 @@ public class ChatCommandsPlugin extends Plugin
else
{
// Get ironman status from their icon in chat
ironmanStatus = getHiscoreEndpointByName(setMessage.getName());
ironmanStatus = getHiscoreEndpointByName(chatMessage.getName());
}
}
@@ -1090,6 +1109,7 @@ public class ChatCommandsPlugin extends Plugin
case "barrows":
return "Barrows Chests";
// cox
case "cox":
case "xeric":
case "chambers":
@@ -1097,6 +1117,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,66 @@
/*
* Copyright (c) 2018, Magic fTail
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 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.chatfilter;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
@ConfigGroup("chatfilter")
public interface ChatFilterConfig extends Config
{
@ConfigItem(
keyName = "filterType",
name = "Filter type",
description = "Configures how the messages are filtered",
position = 1
)
default ChatFilterType filterType()
{
return ChatFilterType.CENSOR_WORDS;
}
@ConfigItem(
keyName = "filteredWords",
name = "Filtered Words",
description = "List of filtered words, separated by commas",
position = 2
)
default String filteredWords()
{
return "";
}
@ConfigItem(
keyName = "filteredRegex",
name = "Filtered Regex",
description = "List of regular expressions to filter, one per line",
position = 3
)
default String filteredRegex()
{
return "";
}
}

View File

@@ -0,0 +1,219 @@
/*
* Copyright (c) 2018, Magic fTail
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 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.chatfilter;
import com.google.common.base.Splitter;
import com.google.inject.Provides;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import javax.inject.Inject;
import net.runelite.api.ChatMessageType;
import net.runelite.api.Client;
import net.runelite.api.Player;
import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.OverheadTextChanged;
import net.runelite.api.events.ScriptCallbackEvent;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.util.Text;
import org.apache.commons.lang3.StringUtils;
@PluginDescriptor(
name = "Chat Filter",
description = "Censor user configurable words or patterns from chat",
enabledByDefault = false
)
public class ChatFilterPlugin extends Plugin
{
private static final Splitter NEWLINE_SPLITTER = Splitter
.on("\n")
.omitEmptyStrings()
.trimResults();
private static final String CENSOR_MESSAGE = "Hey, everyone, I just tried to say something very silly!";
private final JagexPrintableCharMatcher jagexPrintableCharMatcher = new JagexPrintableCharMatcher();
private final List<Pattern> filteredPatterns = new ArrayList<>();
@Inject
private Client client;
@Inject
private ChatFilterConfig config;
@Provides
ChatFilterConfig provideConfig(ConfigManager configManager)
{
return configManager.getConfig(ChatFilterConfig.class);
}
@Override
protected void startUp() throws Exception
{
updateFilteredPatterns();
}
@Override
protected void shutDown() throws Exception
{
filteredPatterns.clear();
}
@Subscribe
public void onScriptCallbackEvent(ScriptCallbackEvent event)
{
if (!"chatFilterCheck".equals(event.getEventName()))
{
return;
}
int[] intStack = client.getIntStack();
int intStackSize = client.getIntStackSize();
ChatMessageType chatMessageType = ChatMessageType.of(intStack[intStackSize - 1]);
// Only filter public chat and private messages
switch (chatMessageType)
{
case PUBLIC:
case PUBLIC_MOD:
case AUTOCHAT:
case PRIVATE_MESSAGE_RECEIVED:
case PRIVATE_MESSAGE_RECEIVED_MOD:
case CLANCHAT:
break;
default:
return;
}
String[] stringStack = client.getStringStack();
int stringStackSize = client.getStringStackSize();
String message = stringStack[stringStackSize - 1];
String censoredMessage = censorMessage(message);
if (censoredMessage == null)
{
// Block the message
intStack[intStackSize - 2] = 0;
}
else
{
// Replace the message
stringStack[stringStackSize - 1] = censoredMessage;
}
}
@Subscribe
public void onOverheadTextChanged(OverheadTextChanged event)
{
if (!(event.getActor() instanceof Player))
{
return;
}
String message = censorMessage(event.getOverheadText());
if (message == null)
{
message = " ";
}
event.getActor().setOverheadText(message);
}
String censorMessage(final String message)
{
String strippedMessage = jagexPrintableCharMatcher.retainFrom(message)
.replace('\u00A0', ' ');
boolean filtered = false;
for (Pattern pattern : filteredPatterns)
{
Matcher m = pattern.matcher(strippedMessage);
StringBuffer sb = new StringBuffer();
while (m.find())
{
switch (config.filterType())
{
case CENSOR_WORDS:
m.appendReplacement(sb, StringUtils.repeat("*", m.group(0).length()));
filtered = true;
break;
case CENSOR_MESSAGE:
return CENSOR_MESSAGE;
case REMOVE_MESSAGE:
return null;
}
}
m.appendTail(sb);
strippedMessage = sb.toString();
}
return filtered ? strippedMessage : message;
}
void updateFilteredPatterns()
{
filteredPatterns.clear();
Text.fromCSV(config.filteredWords()).stream()
.map(s -> Pattern.compile(Pattern.quote(s), Pattern.CASE_INSENSITIVE))
.forEach(filteredPatterns::add);
NEWLINE_SPLITTER.splitToList(config.filteredRegex()).stream()
.map(s ->
{
try
{
return Pattern.compile(s, Pattern.CASE_INSENSITIVE);
}
catch (PatternSyntaxException ex)
{
return null;
}
})
.filter(Objects::nonNull)
.forEach(filteredPatterns::add);
}
@Subscribe
public void onConfigChanged(ConfigChanged event)
{
if (!"chatfilter".equals(event.getGroup()))
{
return;
}
updateFilteredPatterns();
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) 2018, Magic fTail
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 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.chatfilter;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
public enum ChatFilterType
{
CENSOR_WORDS("Censor words"),
CENSOR_MESSAGE("Censor message"),
REMOVE_MESSAGE("Remove message");
private final String name;
@Override
public String toString()
{
return name;
}
}

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.chatfilter;
import com.google.common.base.CharMatcher;
class JagexPrintableCharMatcher extends CharMatcher
{
@Override
public boolean matches(char c)
{
// Characters which are printable
return (c >= 32 && c <= 126)
|| c == 128
|| (c >= 161 && c <= 255);
}
}

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.events.SetMessage;
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,15 +100,23 @@ public class ChatHistoryPlugin extends Plugin
{
messageQueue.clear();
messageQueue = null;
friends.clear();
friends = null;
keyManager.unregisterKeyListener(this);
}
@Subscribe
public void onSetMessage(SetMessage message)
public void onChatMessage(ChatMessage chatMessage)
{
// Start sending old messages right after the welcome message, as that is most reliable source
// of information that chat history was reset
if (message.getValue().equals(WELCOME_MESSAGE))
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(message.getType()))
switch (chatMessage.getType())
{
final QueuedMessage queuedMessage = QueuedMessage.builder()
.type(message.getType())
.name(message.getName())
.sender(message.getSender())
.value(nbsp(message.getValue()))
.runeLiteFormattedMessage(nbsp(message.getMessageNode().getRuneLiteFormatMessage()))
.timestamp(message.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

@@ -35,9 +35,9 @@ import java.util.stream.Collectors;
import javax.inject.Inject;
import net.runelite.api.Client;
import net.runelite.api.MessageNode;
import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.SetMessage;
import net.runelite.client.Notifier;
import net.runelite.client.RuneLiteProperties;
import net.runelite.client.chat.ChatColorType;
@@ -124,29 +124,29 @@ public class ChatNotificationsPlugin extends Plugin
}
@Subscribe
public void onSetMessage(SetMessage event)
public void onChatMessage(ChatMessage chatMessage)
{
MessageNode messageNode = event.getMessageNode();
MessageNode messageNode = chatMessage.getMessageNode();
String nodeValue = Text.removeTags(messageNode.getValue());
boolean update = false;
switch (event.getType())
switch (chatMessage.getType())
{
case TRADE:
if (event.getValue().contains("wishes to trade with you.") && config.notifyOnTrade())
if (chatMessage.getMessage().contains("wishes to trade with you.") && config.notifyOnTrade())
{
notifier.notify(event.getValue());
notifier.notify(chatMessage.getMessage());
}
break;
case DUEL:
if (event.getValue().contains("wishes to duel with you.") && config.notifyOnDuel())
if (chatMessage.getMessage().contains("wishes to duel with you.") && config.notifyOnDuel())
{
notifier.notify(event.getValue());
notifier.notify(chatMessage.getMessage());
}
break;
case GAME:
// Don't notify for notification messages
if (event.getName().equals(runeLiteProperties.getTitle()))
if (chatMessage.getName().equals(runeLiteProperties.getTitle()))
{
return;
}
@@ -170,7 +170,7 @@ public class ChatNotificationsPlugin extends Plugin
if (config.notifyOnOwnName())
{
sendNotification(event);
sendNotification(chatMessage);
}
}
}
@@ -196,7 +196,7 @@ public class ChatNotificationsPlugin extends Plugin
if (config.notifyOnHighlight())
{
sendNotification(event);
sendNotification(chatMessage);
}
}
}
@@ -208,7 +208,7 @@ public class ChatNotificationsPlugin extends Plugin
}
}
private void sendNotification(SetMessage message)
private void sendNotification(ChatMessage message)
{
String name = Text.removeTags(message.getName());
String sender = message.getSender();
@@ -224,7 +224,7 @@ public class ChatNotificationsPlugin extends Plugin
stringBuilder.append(name).append(": ");
}
stringBuilder.append(Text.removeTags(message.getValue()));
stringBuilder.append(Text.removeTags(message.getMessage()));
String notification = stringBuilder.toString();
notifier.notify(notification);
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright (c) 2018, trimbe <github.com/trimbe>
* 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.clanchat;
enum ClanActivityType
{
JOINED,
LEFT
}

View File

@@ -24,6 +24,7 @@
*/
package net.runelite.client.plugins.clanchat;
import net.runelite.api.ClanMemberRank;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
@@ -31,17 +32,39 @@ import net.runelite.client.config.ConfigItem;
@ConfigGroup("clanchat")
public interface ClanChatConfig extends Config
{
@ConfigItem(
keyName = "clanChatIcons",
name = "Clan Chat Icons",
description = "Show clan chat icons next to clan members.",
position = 1
)
default boolean clanChatIcons()
{
return true;
}
@ConfigItem(
keyName = "recentChats",
name = "Recent Chats",
description = "Show recent clan chats.",
position = 1
position = 2
)
default boolean recentChats()
{
return true;
}
@ConfigItem(
keyName = "clanCounter",
name = "Clan Members Counter",
description = "Show the amount of clan members near you.",
position = 3
)
default boolean showClanCounter()
{
return false;
}
@ConfigItem(
keyName = "chatsData",
name = "",
@@ -59,4 +82,48 @@ public interface ClanChatConfig extends Config
description = ""
)
void chatsData(String str);
@ConfigItem(
keyName = "showJoinLeave",
name = "Show Join/Leave",
description = "Adds a temporary message notifying when a member joins or leaves.",
position = 4
)
default boolean showJoinLeave()
{
return false;
}
@ConfigItem(
keyName = "joinLeaveRank",
name = "Join/Leave rank",
description = "Only show join/leave messages for members at or above this rank.",
position = 5
)
default ClanMemberRank joinLeaveRank()
{
return ClanMemberRank.UNRANKED;
}
@ConfigItem(
keyName = "privateMessageIcons",
name = "Private Message Icons",
description = "Add clan chat rank icons to private messages received from clan mates.",
position = 6
)
default boolean privateMessageIcons()
{
return false;
}
@ConfigItem(
keyName = "publicChatIcons",
name = "Public Chat Icons",
description = "Add clan chat rank icons to public chat messages from clan mates.",
position = 7
)
default boolean publicChatIcons()
{
return false;
}
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright (c) 2018 Sebastiaan <https://github.com/SebastiaanVanspauwen>
* 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.clanchat;
import java.awt.Color;
import java.awt.image.BufferedImage;
import net.runelite.client.ui.overlay.infobox.Counter;
class ClanChatIndicator extends Counter
{
private final ClanChatPlugin plugin;
ClanChatIndicator(BufferedImage image, ClanChatPlugin plugin)
{
super(image, plugin, plugin.getClanAmount());
this.plugin = plugin;
}
@Override
public int getCount()
{
return plugin.getClanAmount();
}
@Override
public String getTooltip()
{
return plugin.getClanAmount() + " clan member(s) near you";
}
@Override
public Color getTextColor()
{
return Color.WHITE;
}
}

View File

@@ -1,5 +1,7 @@
/*
* Copyright (c) 2017, Devin French <https://github.com/devinfrench>
* Copyright (c) 2019, Adam <Adam@sigterm.info>
* Copyright (c) 2018, trimbe <github.com/trimbe>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -27,26 +29,55 @@ package net.runelite.client.plugins.clanchat;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.inject.Provides;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import net.runelite.api.ChatLineBuffer;
import net.runelite.api.ChatMessageType;
import net.runelite.api.ClanMember;
import net.runelite.api.ClanMemberRank;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.MessageNode;
import net.runelite.api.Player;
import net.runelite.api.ScriptID;
import net.runelite.api.SpriteID;
import net.runelite.api.VarClientStr;
import net.runelite.api.widgets.WidgetType;
import net.runelite.api.Varbits;
import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.ClanChanged;
import net.runelite.api.events.ClanMemberJoined;
import net.runelite.api.events.ClanMemberLeft;
import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.GameTick;
import net.runelite.api.events.SetMessage;
import net.runelite.api.events.PlayerDespawned;
import net.runelite.api.events.PlayerSpawned;
import net.runelite.api.events.VarClientStrChanged;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.api.widgets.WidgetType;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.chat.ChatMessageBuilder;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.game.ClanManager;
import net.runelite.client.game.SpriteManager;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import static net.runelite.client.ui.JagexColors.CHAT_CLAN_NAME_OPAQUE_BACKGROUND;
import static net.runelite.client.ui.JagexColors.CHAT_CLAN_NAME_TRANSPARENT_BACKGROUND;
import static net.runelite.client.ui.JagexColors.CHAT_CLAN_TEXT_OPAQUE_BACKGROUND;
import static net.runelite.client.ui.JagexColors.CHAT_CLAN_TEXT_TRANSPARENT_BACKGROUND;
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
import net.runelite.client.util.ColorUtil;
import net.runelite.client.util.Text;
@PluginDescriptor(
@@ -59,6 +90,8 @@ public class ClanChatPlugin extends Plugin
private static final int MAX_CHATS = 10;
private static final String CLAN_CHAT_TITLE = "Clan Chat";
private static final String RECENT_TITLE = "Recent Clan Chats";
private static final int JOIN_LEAVE_DURATION = 20;
private static final int MESSAGE_DELAY = 10;
@Inject
private Client client;
@@ -69,7 +102,24 @@ public class ClanChatPlugin extends Plugin
@Inject
private ClanChatConfig config;
@Inject
private InfoBoxManager infoBoxManager;
@Inject
private SpriteManager spriteManager;
@Inject
private ClientThread clientThread;
private List<String> chats = new ArrayList<>();
private List<Player> clanMembers = new ArrayList<>();
private ClanChatIndicator clanMemberCounter;
/**
* queue of temporary messages added to the client
*/
private final Deque<ClanJoinMessage> clanJoinMessages = new ArrayDeque<>();
private Map<String, ClanMemberActivity> activityBuffer = new HashMap<>();
private int clanJoinedTick;
@Provides
ClanChatConfig getConfig(ConfigManager configManager)
@@ -86,15 +136,118 @@ public class ClanChatPlugin extends Plugin
@Override
public void shutDown()
{
clanMembers.clear();
removeClanCounter();
resetClanChats();
}
@Subscribe
public void onConfigChanged(ConfigChanged configChanged)
{
if (configChanged.getGroup().equals("clanchat") && !config.recentChats())
if (configChanged.getGroup().equals("clanchat"))
{
resetClanChats();
if (!config.recentChats())
{
resetClanChats();
}
if (config.showClanCounter())
{
clientThread.invoke(this::addClanCounter);
}
else
{
removeClanCounter();
}
}
}
@Subscribe
public void onClanMemberJoined(ClanMemberJoined event)
{
final ClanMember member = event.getMember();
if (member.getWorld() == client.getWorld())
{
final String memberName = Text.toJagexName(member.getUsername());
for (final Player player : client.getPlayers())
{
if (player != null && memberName.equals(Text.toJagexName(player.getName())))
{
clanMembers.add(player);
addClanCounter();
break;
}
}
}
// clan members getting initialized isn't relevant
if (clanJoinedTick == client.getTickCount())
{
return;
}
if (!config.showJoinLeave() ||
member.getRank().getValue() < config.joinLeaveRank().getValue())
{
return;
}
// attempt to filter out world hopping joins
if (!activityBuffer.containsKey(member.getUsername()))
{
ClanMemberActivity joinActivity = new ClanMemberActivity(ClanActivityType.JOINED,
member, client.getTickCount());
activityBuffer.put(member.getUsername(), joinActivity);
}
else
{
activityBuffer.remove(member.getUsername());
}
}
@Subscribe
public void onClanMemberLeft(ClanMemberLeft event)
{
final ClanMember member = event.getMember();
if (member.getWorld() == client.getWorld())
{
final String memberName = Text.toJagexName(member.getUsername());
final Iterator<Player> each = clanMembers.iterator();
while (each.hasNext())
{
if (memberName.equals(Text.toJagexName(each.next().getName())))
{
each.remove();
if (clanMembers.isEmpty())
{
removeClanCounter();
}
break;
}
}
}
if (!config.showJoinLeave() ||
member.getRank().getValue() < config.joinLeaveRank().getValue())
{
return;
}
if (!activityBuffer.containsKey(member.getUsername()))
{
ClanMemberActivity leaveActivity = new ClanMemberActivity(ClanActivityType.LEFT,
member, client.getTickCount());
activityBuffer.put(member.getUsername(), leaveActivity);
}
else
{
activityBuffer.remove(member.getUsername());
}
}
@@ -122,6 +275,112 @@ public class ClanChatPlugin extends Plugin
loadClanChats();
}
}
if (!config.showJoinLeave())
{
return;
}
timeoutClanMessages();
addClanActivityMessages();
}
private void timeoutClanMessages()
{
if (clanJoinMessages.isEmpty())
{
return;
}
boolean removed = false;
for (Iterator<ClanJoinMessage> it = clanJoinMessages.iterator(); it.hasNext(); )
{
ClanJoinMessage clanJoinMessage = it.next();
MessageNode messageNode = clanJoinMessage.getMessageNode();
final int createdTick = clanJoinMessage.getTick();
if (client.getTickCount() > createdTick + JOIN_LEAVE_DURATION)
{
it.remove();
// If this message has been reused since, it will get a different id
if (clanJoinMessage.getGetMessageId() == messageNode.getId())
{
ChatLineBuffer ccInfoBuffer = client.getChatLineMap().get(ChatMessageType.CLANCHAT_INFO.getType());
if (ccInfoBuffer != null)
{
ccInfoBuffer.removeMessageNode(messageNode);
removed = true;
}
}
}
else
{
// Everything else in the deque is newer
break;
}
}
if (removed)
{
clientThread.invoke(() -> client.runScript(ScriptID.BUILD_CHATBOX));
}
}
private void addClanActivityMessages()
{
Iterator<ClanMemberActivity> activityIt = activityBuffer.values().iterator();
while (activityIt.hasNext())
{
ClanMemberActivity activity = activityIt.next();
if (activity.getTick() < client.getTickCount() - MESSAGE_DELAY)
{
activityIt.remove();
addActivityMessage(activity.getMember(), activity.getActivityType());
}
}
}
private void addActivityMessage(ClanMember member, ClanActivityType activityType)
{
final String activityMessage = activityType == ClanActivityType.JOINED ? " has joined." : " has left.";
final ClanMemberRank rank = member.getRank();
String rankTag = "";
Color textColor = CHAT_CLAN_TEXT_OPAQUE_BACKGROUND;
Color channelColor = CHAT_CLAN_NAME_OPAQUE_BACKGROUND;
if (client.isResized() && client.getVar(Varbits.TRANSPARENT_CHATBOX) == 1)
{
textColor = CHAT_CLAN_TEXT_TRANSPARENT_BACKGROUND;
channelColor = CHAT_CLAN_NAME_TRANSPARENT_BACKGROUND;
}
if (config.clanChatIcons() && rank != null && rank != ClanMemberRank.UNRANKED)
{
int iconNumber = clanManager.getIconNumber(rank);
rankTag = " <img=" + iconNumber + ">";
}
ChatMessageBuilder message = new ChatMessageBuilder();
String messageString = message
.append("[")
.append(ColorUtil.wrapWithColorTag(client.getClanChatName(), channelColor) + rankTag)
.append("] ")
.append(ColorUtil.wrapWithColorTag(member.getUsername() + activityMessage, textColor))
.build();
client.addChatMessage(ChatMessageType.CLANCHAT_INFO, "", messageString, "");
final ChatLineBuffer chatLineBuffer = client.getChatLineMap().get(ChatMessageType.CLANCHAT_INFO.getType());
final MessageNode[] lines = chatLineBuffer.getLines();
final MessageNode line = lines[0];
ClanJoinMessage clanJoinMessage = new ClanJoinMessage(line, line.getId(), client.getTickCount());
clanJoinMessages.addLast(clanJoinMessage);
}
@Subscribe
@@ -134,28 +393,119 @@ public class ClanChatPlugin extends Plugin
}
@Subscribe
public void onSetMessage(SetMessage setMessage)
public void onChatMessage(ChatMessage chatMessage)
{
if (client.getGameState() != GameState.LOADING && client.getGameState() != GameState.LOGGED_IN)
{
return;
}
if (setMessage.getType() == ChatMessageType.CLANCHAT && client.getClanChatCount() > 0)
if (client.getClanChatCount() <= 0)
{
insertClanRankIcon(setMessage);
return;
}
switch (chatMessage.getType())
{
case PRIVATE_MESSAGE_RECEIVED:
case PRIVATE_MESSAGE_RECEIVED_MOD:
if (!config.privateMessageIcons())
{
return;
}
break;
case PUBLIC:
case PUBLIC_MOD:
if (!config.publicChatIcons())
{
return;
}
break;
case CLANCHAT:
if (!config.clanChatIcons())
{
return;
}
break;
default:
return;
}
insertClanRankIcon(chatMessage);
}
@Subscribe
public void onGameStateChanged(GameStateChanged state)
{
GameState gameState = state.getGameState();
if (gameState == GameState.LOGIN_SCREEN || gameState == GameState.CONNECTION_LOST || gameState == GameState.HOPPING)
{
clanMembers.clear();
removeClanCounter();
clanJoinMessages.clear();
}
}
private void insertClanRankIcon(final SetMessage message)
@Subscribe
public void onPlayerSpawned(PlayerSpawned event)
{
if (event.getPlayer().isClanMember())
{
clanMembers.add(event.getPlayer());
addClanCounter();
}
}
@Subscribe
public void onPlayerDespawned(PlayerDespawned event)
{
if (clanMembers.remove(event.getPlayer()) && clanMembers.isEmpty())
{
removeClanCounter();
}
}
@Subscribe
public void onClanChanged(ClanChanged event)
{
if (event.isJoined())
{
clanJoinedTick = client.getTickCount();
}
else
{
clanMembers.clear();
removeClanCounter();
}
activityBuffer.clear();
}
int getClanAmount()
{
return clanMembers.size();
}
private void insertClanRankIcon(final ChatMessage message)
{
final ClanMemberRank rank = clanManager.getRank(message.getName());
if (rank != null && rank != ClanMemberRank.UNRANKED)
{
int iconNumber = clanManager.getIconNumber(rank);
message.getMessageNode()
.setSender(message.getMessageNode().getSender() + " <img=" + iconNumber + ">");
final String img = "<img=" + iconNumber + ">";
if (message.getType() == ChatMessageType.CLANCHAT)
{
message.getMessageNode()
.setSender(message.getMessageNode().getSender() + " " + img);
}
else
{
message.getMessageNode()
.setName(img + message.getMessageNode().getName());
}
client.refreshChat();
}
}
@@ -223,4 +573,22 @@ public class ClanChatPlugin extends Plugin
config.chatsData(Text.toCSV(chats));
}
private void removeClanCounter()
{
infoBoxManager.removeInfoBox(clanMemberCounter);
clanMemberCounter = null;
}
private void addClanCounter()
{
if (!config.showClanCounter() || clanMemberCounter != null || clanMembers.isEmpty())
{
return;
}
final BufferedImage image = spriteManager.getSprite(SpriteID.TAB_CLAN_CHAT, 0);
clanMemberCounter = new ClanChatIndicator(image, this);
infoBoxManager.addInfoBox(clanMemberCounter);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Levi <me@levischuck.com>
* Copyright (c) 2019, Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -22,18 +22,15 @@
* (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.xptracker;
package net.runelite.client.plugins.clanchat;
import lombok.Value;
import net.runelite.api.MessageNode;
@Value
class XpSnapshotTotal
class ClanJoinMessage
{
private final int xpGainedInSession;
private final int xpPerHour;
static XpSnapshotTotal zero()
{
return new XpSnapshotTotal(0, 0);
}
private final MessageNode messageNode;
private final int getMessageId;
private final int tick;
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 2018, trimbe <github.com/trimbe>
* 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.clanchat;
import lombok.AllArgsConstructor;
import lombok.Value;
import net.runelite.api.ClanMember;
@Value
@AllArgsConstructor
class ClanMemberActivity
{
private ClanActivityType activityType;
private ClanMember member;
private Integer tick;
}

View File

@@ -49,7 +49,7 @@ public class AnagramClue extends ClueScroll implements TextClueScroll, NpcClueSc
{
private static final Set<AnagramClue> CLUES = ImmutableSet.of(
new AnagramClue("A BAKER", "Baraek", new WorldPoint(3217, 3434, 0), "Varrock square", "5"),
new AnagramClue("A BASIC ANTI POT", "Captain Tobias", new WorldPoint(3026, 3216, 0), "Port Sarim", "7"),
new AnagramClue("A BASIC ANTI POT", "Captain Tobias", new WorldPoint(3026, 3216, 0), "Port Sarim", "6"),
new AnagramClue("A HEART", "Aretha", new WorldPoint(1814, 3851, 0), "Soul altar", "2"),
new AnagramClue("A ZEN SHE", "Zenesha", new WorldPoint(2652, 3295, 0), "Platebody Southern Ardougne centre square"),
new AnagramClue("ACE MATCH ELM", "Cam The Camel", new WorldPoint(3300, 3231, 0), "North of the glider in Al Kharid"),
@@ -257,4 +257,4 @@ public class AnagramClue extends ClueScroll implements TextClueScroll, NpcClueSc
{
return new int[] {objectId};
}
}
}

View File

@@ -24,6 +24,7 @@
*/
package net.runelite.client.plugins.cluescrolls.clues;
import com.google.common.collect.ImmutableMap;
import java.awt.Color;
import java.awt.Graphics2D;
import lombok.AllArgsConstructor;
@@ -43,6 +44,154 @@ import net.runelite.client.ui.overlay.components.TitleComponent;
@AllArgsConstructor
public class CoordinateClue extends ClueScroll implements TextClueScroll, LocationClueScroll
{
private static final ImmutableMap<WorldPoint, String> CLUES = new ImmutableMap.Builder<WorldPoint, String>()
// Medium
.put(new WorldPoint(2479, 3158, 0), "South of fruit tree patch, west of Tree Gnome Village.")
.put(new WorldPoint(2887, 3154, 0), "West of Banana plantation on Karamja.")
.put(new WorldPoint(2743, 3151, 0), "Entrance of Brimhaven dungeon.")
.put(new WorldPoint(3184, 3150, 0), "South of Lumbridge Swamp.")
.put(new WorldPoint(3217, 3177, 0), "East of Lumbridge Swamp.")
.put(new WorldPoint(3007, 3144, 0), "Near the entrance to the Asgarnian Ice Dungeon, south of Port Sarim (AIQ).")
.put(new WorldPoint(2896, 3119, 0), "Near Karambwan fishing spot (DKP).")
.put(new WorldPoint(2697, 3207, 0), "Centre of Moss Giant Island, west of Brimhaven.")
.put(new WorldPoint(2679, 3110, 0), "North of Hazelmere's house (CLS).")
.put(new WorldPoint(3510, 3074, 0), "East of Uzer (DLQ).")
.put(new WorldPoint(3160, 3251, 0), "West of trapdoor leading to H.A.M Hideout.")
.put(new WorldPoint(2643, 3252, 0), "South of Ardougne Zoo, North of Tower of Life (DJP).")
.put(new WorldPoint(2322, 3061, 0), "South-west of Castle wars (BKP).")
.put(new WorldPoint(2875, 3046, 0), "North of nature altar, north of Shilo Village (CKR).")
.put(new WorldPoint(2849, 3033, 0), "West of nature altar, north of Shilo Village (CKR).")
.put(new WorldPoint(2848, 3296, 0), "North of Crandor island.")
.put(new WorldPoint(2583, 2990, 0), "Feldip Hills, south-east of Gu'Thanoth (AKS).")
.put(new WorldPoint(3179, 3344, 0), "South of the Champions' Guild, opposite side of the River Lum.")
.put(new WorldPoint(2383, 3370, 0), "South-west of Tree Gnome Stronghold.")
.put(new WorldPoint(3312, 3375, 0), "North-west of Exam Centre, on the hill.")
.put(new WorldPoint(3121, 3384, 0), "North-east of Draynor Manor, near River Lum.")
.put(new WorldPoint(3430, 3388, 0), "West of Mort Myre Swamp.")
.put(new WorldPoint(2920, 3403, 0), "South-east of Taverley, near Lady of the Lake.")
.put(new WorldPoint(2594, 2899, 0), "South-east of Feldip Hills, by the crimson swifts (AKS).")
.put(new WorldPoint(2387, 3435, 0), "West of Tree Gnome Stronghold, near the pen containing terrorbirds.")
.put(new WorldPoint(2512, 3467, 0), "Baxtorian Falls (Bring rope).")
.put(new WorldPoint(2381, 3468, 0), "West of Tree Gnome Stronghold, north of the pen with terrorbirds.")
.put(new WorldPoint(3005, 3475, 0), "Ice Mountain, west of Edgeville.")
.put(new WorldPoint(2585, 3505, 0), "By the shore line north of the Coal Trucks.")
.put(new WorldPoint(3443, 3515, 0), "South of Slayer Tower.")
.put(new WorldPoint(2416, 3516, 0), "Tree Gnome Stronghold, west of Grand Tree, near swamp.")
.put(new WorldPoint(3429, 3523, 0), "South of Slayer Tower.")
.put(new WorldPoint(2363, 3531, 0), "North-east of Eagles' Peak.")
.put(new WorldPoint(2919, 3535, 0), "East of Burthorpe pub.")
.put(new WorldPoint(3548, 3560, 0), "Inside Fenkenstrain's Castle.")
.put(new WorldPoint(1456, 3620, 0), "Graveyard west of Shayzien House.")
.put(new WorldPoint(2735, 3638, 0), "East of Rellekka, north-west of Golden Apple Tree (AJR).")
.put(new WorldPoint(2681, 3653, 0), "Rellekka, in the garden of the south-east house.")
.put(new WorldPoint(2537, 3881, 0), "Miscellania.")
// Hard
.put(new WorldPoint(2209, 3161, 0), "North-east of Tyras Camp.")
.put(new WorldPoint(2181, 3206, 0), "South of Elf Camp.")
.put(new WorldPoint(3081, 3209, 0), "Small Island (CLP).")
.put(new WorldPoint(3374, 3250, 0), "Duel Arena combat area.")
.put(new WorldPoint(2699, 3251, 0), "Little island (AIR).")
.put(new WorldPoint(3546, 3251, 0), "North-east of Burgh de Rott.")
.put(new WorldPoint(3544, 3256, 0), "North-east of Burgh de Rott.")
.put(new WorldPoint(2841, 3267, 0), "Crandor island.")
.put(new WorldPoint(3168, 3041, 0), "Bedabin Camp.")
.put(new WorldPoint(2542, 3031, 0), "Gu'Tanoth.")
.put(new WorldPoint(2581, 3030, 0), "Gu'Tanoth island, enter cave north-west of Feldip Hills (AKS).")
.put(new WorldPoint(2961, 3024, 0), "Ship yard (DKP).")
.put(new WorldPoint(2339, 3311, 0), "East of Tirannwn on Arandar mountain pass.")
.put(new WorldPoint(3440, 3341, 0), "Nature Spirit's grotto.")
.put(new WorldPoint(2763, 2974, 0), "Cairn Isle, west of Shilo Village.")
.put(new WorldPoint(3138, 2969, 0), "West of Bandit Camp.")
.put(new WorldPoint(2924, 2963, 0), "On the southern part of eastern Karamja.")
.put(new WorldPoint(2838, 2914, 0), "Kharazi Jungle, near water pool.")
.put(new WorldPoint(3441, 3419, 0), "Mort Myre Swamp.")
.put(new WorldPoint(2950, 2902, 0), "South-east of Kharazi Jungle.")
.put(new WorldPoint(2775, 2891, 0), "South-west of Kharazi Jungle.")
.put(new WorldPoint(3113, 3602, 0), "Wilderness. North of Edgeville (level 11).")
.put(new WorldPoint(2892, 3675, 0), "On the summit of Trollheim.")
.put(new WorldPoint(3168, 3677, 0), "Wilderness. Graveyard of Shadows.")
.put(new WorldPoint(2853, 3690, 0), "Entrance to the troll Stronghold.")
.put(new WorldPoint(3305, 3692, 0), "Wilderness. West of eastern green dragon.")
.put(new WorldPoint(3055, 3696, 0), "Wilderness. Bandit Camp.")
.put(new WorldPoint(3302, 3696, 0), "Wilderness. West of eastern green dragon.")
.put(new WorldPoint(1479, 3696, 0), "Lizardman Canyon.")
.put(new WorldPoint(2712, 3732, 0), "North-east of Rellekka.")
.put(new WorldPoint(2970, 3749, 0), "Wilderness. Forgotten Cemetery.")
.put(new WorldPoint(3094, 3764, 0), "Wilderness. Mining site north of Bandit Camp.")
.put(new WorldPoint(3311, 3769, 0), "Wilderness. North of Venenatis.")
.put(new WorldPoint(1460, 3782, 0), "Lovakengj, near burning man.")
.put(new WorldPoint(3244, 3792, 0), "Wilderness. South-east of Lava Dragon Isle by some Chaos Dwarves.")
.put(new WorldPoint(3140, 3804, 0), "Wilderness. North of Ruins.")
.put(new WorldPoint(2946, 3819, 0), "Wilderness. Chaos Temple (level 38).")
.put(new WorldPoint(3771, 3825, 0), "Fossil Island. East of Museum Camp.")
.put(new WorldPoint(3013, 3846, 0), "Wilderness. West of Lava Maze, before KBD's lair.")
.put(new WorldPoint(3058, 3884, 0), "Wilderness. Near runite ore north of Lava Maze.")
.put(new WorldPoint(3290, 3889, 0), "Wilderness. Demonic Ruins.")
.put(new WorldPoint(3770, 3897, 0), "Small Island north of Fossil Island.")
.put(new WorldPoint(2505, 3899, 0), "Small Island north-east of Miscellania (AJS).")
.put(new WorldPoint(3285, 3942, 0), "Wilderness. Rogues' Castle.")
.put(new WorldPoint(3159, 3959, 0), "Wilderness. North of Deserted Keep, west of Resource Area.")
.put(new WorldPoint(3039, 3960, 0), "Wilderness. Pirates' Hideout.")
.put(new WorldPoint(2987, 3963, 0), "Wilderness. West of Wilderness Agility Course.")
.put(new WorldPoint(3189, 3963, 0), "Wilderness. North of Resource Area, near magic axe hut.")
// Elite
.put(new WorldPoint(2357, 3151, 0), "Lletya.")
.put(new WorldPoint(3587, 3180, 0), "Meiyerditch.")
.put(new WorldPoint(2820, 3078, 0), "Tai Bwo Wannai. Hardwood Grove.")
.put(new WorldPoint(3811, 3060, 0), "Small island north-east of Mos Le'Harmless.")
.put(new WorldPoint(2180, 3282, 0), "North of Elf Camp.")
.put(new WorldPoint(2870, 2997, 0), "North-east of Shilo Village.")
.put(new WorldPoint(3302, 2988, 0), "On top of a cliff to the west of Pollnivneach.")
.put(new WorldPoint(2511, 2980, 0), "Just south of Gu'Tanoth, west of gnome glider.")
.put(new WorldPoint(2732, 3372, 0), "Legends' Guild.")
.put(new WorldPoint(3573, 3425, 0), "North of Dessous's tomb from Desert Treasure.")
.put(new WorldPoint(3828, 2848, 0), "East of Harmony Island.")
.put(new WorldPoint(3225, 2838, 0), "South of Desert Treasure pyramid.")
.put(new WorldPoint(1773, 3510, 0), "Between magic trees South of Tithe Farm.")
.put(new WorldPoint(3822, 3562, 0), "North-east of Dragontooth Island.")
.put(new WorldPoint(3603, 3564, 0), "North of the wrecked ship, outside of Port Phasmatys.")
.put(new WorldPoint(2936, 2721, 0), "Eastern shore of Crash Island.")
.put(new WorldPoint(2697, 2705, 0), "South-west of Ape Atoll.")
.put(new WorldPoint(2778, 3678, 0), "Mountain Camp.")
.put(new WorldPoint(2827, 3740, 0), "West of the entrance to the Ice Path, where the Troll child resides.")
.put(new WorldPoint(2359, 3799, 0), "Neitiznot.")
.put(new WorldPoint(2194, 3807, 0), "Pirates' Cove.")
.put(new WorldPoint(2700, 3808, 0), "Northwestern part of the Trollweiss and Rellekka Hunter area (DKS).")
.put(new WorldPoint(3215, 3835, 0), "Wilderness. Lava Dragon Isle.")
.put(new WorldPoint(3369, 3894, 0), "Wilderness. Fountain of Rune.")
.put(new WorldPoint(2065, 3923, 0), "Outside the western wall on Lunar Isle.")
.put(new WorldPoint(3188, 3933, 0), "Wilderness. Resource Area.")
.put(new WorldPoint(2997, 3953, 0), "Wilderness. Inside Agility Training Area.")
.put(new WorldPoint(3380, 3963, 0), "Wilderness. North of Volcano.")
// Master
.put(new WorldPoint(2178, 3209, 0), "South of Elf Camp.")
.put(new WorldPoint(2155, 3100, 0), "South of Port Tyras (BJS).")
.put(new WorldPoint(2217, 3092, 0), "Poison Waste island (DLR).")
.put(new WorldPoint(3830, 3060, 0), "Small island located north-east of Mos Le'Harmless.")
.put(new WorldPoint(2834, 3271, 0), "Crandor island.")
.put(new WorldPoint(2732, 3284, 0), "Witchaven.")
.put(new WorldPoint(3622, 3320, 0), "Meiyerditch. Outside mine.")
.put(new WorldPoint(2303, 3328, 0), "East of Prifddinas.")
.put(new WorldPoint(3570, 3405, 0), "North of Dessous's tomb from Desert Treasure.")
.put(new WorldPoint(2840, 3423, 0), "Water Obelisk Island.")
.put(new WorldPoint(3604, 3564, 0), "North of the wrecked ship, outside of Port Phasmatys (ALQ).")
.put(new WorldPoint(3085, 3569, 0), "Wilderness. Obelisk of Air.")
.put(new WorldPoint(2934, 2727, 0), "Eastern shore of Crash Island.")
.put(new WorldPoint(1451, 3695, 0), "West side of Lizardman Canyon with Lizardman shaman.")
.put(new WorldPoint(2538, 3739, 0), "Waterbirth Island.")
.put(new WorldPoint(1248, 3751, 0), "Farming Guild.")
.put(new WorldPoint(1698, 3792, 0), "Arceuus church.")
.put(new WorldPoint(2951, 3820, 0), "Wilderness. Chaos Temple (level 38).")
.put(new WorldPoint(2202, 3825, 0), "Pirates' Cove, between Lunar Isle and Rellekka.")
.put(new WorldPoint(1761, 3853, 0), "Arceuus essence mine.")
.put(new WorldPoint(2090, 3863, 0), "South of Lunar Isle, west of Astral altar.")
.put(new WorldPoint(1442, 3878, 0), "Sulphur Mine.")
.put(new WorldPoint(3380, 3929, 0), "Wilderness. Near Volcano.")
.put(new WorldPoint(3188, 3939, 0), "Wilderness. Resource Area.")
.put(new WorldPoint(3304, 3941, 0), "Wilderness. East of Rogues' Castle.")
.put(new WorldPoint(2994, 3961, 0), "Wilderness. Inside Agility Training Area.")
.build();
private String text;
private WorldPoint location;
private static final ItemRequirement HAS_SPADE = new SingleItemRequirement(ItemID.SPADE);
@@ -52,8 +201,18 @@ public class CoordinateClue extends ClueScroll implements TextClueScroll, Locati
{
panelComponent.getChildren().add(TitleComponent.builder().text("Coordinate Clue").build());
String solution = CLUES.get(location);
if (solution != null)
{
panelComponent.getChildren().add(LineComponent.builder()
.left(solution)
.build());
panelComponent.getChildren().add(LineComponent.builder().build());
}
panelComponent.getChildren().add(LineComponent.builder()
.left("Click the clue scroll along the edge of your world map to see where you should dig.")
.left("Click the clue scroll on your world map to see dig location.")
.build());
if (plugin.getInventoryItems() != null)

View File

@@ -300,8 +300,9 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc
new CrypticClue("Does one really need a fire to stay warm here?", new WorldPoint(3816, 3810, 0), "Dig next to the fire near the Volcanic Mine entrance."),
new CrypticClue("Search the open crate found in a small farmhouse in Hosidius. Cabbages grow outside.", CRATE_27533, new WorldPoint(1687, 3628, 0), "The house is east of the Mess in Great Kourend."),
new CrypticClue("Dig under Ithoi's cabin.", new WorldPoint(2529, 2838, 0), "Dig under Ithoi's cabin in the Corsair Cove."),
new CrypticClue("Search the drawers, upstairs in the bank to the East of Varrock.", new WorldPoint(3250, 3420, 1), "Search the drawers upstairs in Varrock east bank"),
new CrypticClue("Speak to Hazelmere.", "Hazelmere", new WorldPoint(2677, 3088, 1), "Located upstairs in the house to the north of fairy ring CLS. Answer: 6859")
new CrypticClue("Search the drawers, upstairs in the bank to the East of Varrock.", DRAWERS_7194, new WorldPoint(3250, 3420, 1), "Search the drawers upstairs in Varrock east bank."),
new CrypticClue("Speak to Hazelmere.", "Hazelmere", new WorldPoint(2677, 3088, 1), "Located upstairs in the house to the north of fairy ring CLS. Answer: 6859"),
new CrypticClue("The effects of this fire are magnified.", new WorldPoint(1179, 3626, 0), "Dig by the fire beside Ket'sal K'uk in the westernmost part of the Kebos Swamp. ")
);
private String text;

View File

@@ -76,7 +76,7 @@ public class EmoteClue extends ClueScroll implements TextClueScroll, LocationClu
new EmoteClue("Show your anger towards the Statue of Saradomin in Ellamaria's garden. Beware of double agents! Equip a zamorak godsword.", BY_THE_BEAR_CAGE_IN_VARROCK_PALACE_GARDENS, new WorldPoint(3230, 3478, 0), ANGRY, item(ZAMORAK_GODSWORD)),
new EmoteClue("Show your anger at the Wise old man. Beware of double agents! Equip an abyssal whip, a legend's cape and some spined chaps.", BEHIND_MISS_SCHISM_IN_DRAYNOR_VILLAGE, new WorldPoint(3088, 3254, 0), ANGRY, any("Abyssal whip", item(ABYSSAL_WHIP), item(VOLCANIC_ABYSSAL_WHIP), item(FROZEN_ABYSSAL_WHIP)), item(CAPE_OF_LEGENDS), item(SPINED_CHAPS)),
new EmoteClue("Beckon in the Digsite, near the eastern winch. Bow before you talk to me. Equip a green gnome hat, snakeskin boots and an iron pickaxe.", DIGSITE, new WorldPoint(3370, 3425, 0), BECKON, BOW, item(GREEN_HAT), item(SNAKESKIN_BOOTS), item(IRON_PICKAXE)),
new EmoteClue("Beckon in Tai Bwo Wannai. Clap before you talk to me. Equip green dragonhide chaps, a ring of dueling and a mithril medium helmet.", SOUTH_OF_THE_SHRINE_IN_TAI_BWO_WANNAI_VILLAGE, new WorldPoint(2784, 3065, 0), BECKON, CLAP, item(GREEN_DHIDE_CHAPS), any("Ring of dueling", item(RING_OF_DUELING1), item(RING_OF_DUELING2), item(RING_OF_DUELING3), item(RING_OF_DUELING4), item(RING_OF_DUELING5), item(RING_OF_DUELING6), item(RING_OF_DUELING7), item(RING_OF_DUELING8)), item(MITHRIL_MED_HELM)),
new EmoteClue("Beckon in Tai Bwo Wannai. Clap before you talk to me. Equip green dragonhide chaps, a ring of dueling and a mithril medium helmet.", SOUTH_OF_THE_SHRINE_IN_TAI_BWO_WANNAI_VILLAGE, new WorldPoint(2803, 3073, 0), BECKON, CLAP, item(GREEN_DHIDE_CHAPS), any("Ring of dueling", item(RING_OF_DUELING1), item(RING_OF_DUELING2), item(RING_OF_DUELING3), item(RING_OF_DUELING4), item(RING_OF_DUELING5), item(RING_OF_DUELING6), item(RING_OF_DUELING7), item(RING_OF_DUELING8)), item(MITHRIL_MED_HELM)),
new EmoteClue("Beckon in the combat ring of Shayzien. Show your anger before you talk to me. Equip an adamant platebody, adamant full helm and adamant platelegs.", WEST_OF_THE_SHAYZIEN_COMBAT_RING, new WorldPoint(1545, 3594, 0), BECKON, ANGRY, item(ADAMANT_PLATELEGS), item(ADAMANT_PLATEBODY), item(ADAMANT_FULL_HELM)),
new EmoteClue("Bow near Lord Iorwerth. Beware of double agents! Equip a new imbued crystal bow.", TENT_IN_LORD_IORWERTHS_ENCAMPMENT, new WorldPoint(2205, 3252, 0), BOW, any("Imbued crystal bow", item(NEW_CRYSTAL_BOW_I), item(CRYSTAL_BOW_FULL_I), item(CRYSTAL_BOW_910_I), item(CRYSTAL_BOW_810_I), item(CRYSTAL_BOW_710_I), item(CRYSTAL_BOW_610_I), item(CRYSTAL_BOW_510_I), item(CRYSTAL_BOW_410_I), item(CRYSTAL_BOW_310_I), item(CRYSTAL_BOW_210_I), item(CRYSTAL_BOW_110_I))),
new EmoteClue("Bow outside the entrance to the Legends' Guild. Equip iron platelegs, an emerald amulet and an oak longbow.", OUTSIDE_THE_LEGENDS_GUILD_GATES, new WorldPoint(2729, 3349, 0), BOW, item(IRON_PLATELEGS), item(OAK_LONGBOW), item(EMERALD_AMULET)),
@@ -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

@@ -170,7 +170,6 @@ public enum HotColdLocation
ZEAH_MESS_HALL(new WorldPoint(1658, 3621, 0), ZEAH, "East of Mess hall."),
ZEAH_WATSONS_HOUSE(new WorldPoint(1653, 3573, 0), ZEAH, "East of Watson's house."),
ZEAH_VANNAHS_FARM_STORE(new WorldPoint(1806, 3521, 0), ZEAH, "North of Vannah's Farm Store, between the chicken coop and willow trees."),
ZEAH_FARMING_GUILD_SW(new WorldPoint(1227, 3712, 0), ZEAH, "South-west of the Farming Guild."),
ZEAH_FARMING_GUILD_W(new WorldPoint(1209, 3737, 0), ZEAH, "West of the Farming Guild."),
ZEAH_DAIRY_COW(new WorldPoint(1320, 3718, 0), ZEAH, "North-east of the Kebos Lowlands, east of the dairy cow."),
ZEAH_CRIMSON_SWIFTS(new WorldPoint(1186, 3583, 0), ZEAH, "South-west of the Kebos Swamp, below the crimson swifts.");

View File

@@ -40,4 +40,14 @@ public interface CombatLevelConfig extends Config
{
return true;
}
@ConfigItem(
keyName = "wildernessAttackLevelRange",
name = "Show level range in wilderness",
description = "Displays a PVP-world-like attack level range in the wilderness"
)
default boolean wildernessAttackLevelRange()
{
return true;
}
}

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2017, Devin French <https://github.com/devinfrench>
* Copyright (c) 2019, Jordan Atwood <nightfirecat@protonmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -26,14 +27,20 @@ package net.runelite.client.plugins.combatlevel;
import com.google.inject.Provides;
import java.text.DecimalFormat;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.inject.Inject;
import net.runelite.api.Client;
import net.runelite.api.Experience;
import net.runelite.api.GameState;
import net.runelite.api.Skill;
import net.runelite.api.WorldType;
import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.GameTick;
import net.runelite.api.events.ScriptCallbackEvent;
import net.runelite.api.widgets.Widget;
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.plugins.Plugin;
@@ -42,15 +49,31 @@ import net.runelite.client.ui.overlay.OverlayManager;
@PluginDescriptor(
name = "Combat Level",
description = "Show a more accurate combat level in Combat Options panel"
description = "Show a more accurate combat level in Combat Options panel and other combat level functions",
tags = {"wilderness", "attack", "range"}
)
public class CombatLevelPlugin extends Plugin
{
private final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#.###");
private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#.###");
private static final String CONFIG_GROUP = "combatlevel";
private static final String ATTACK_RANGE_CONFIG_KEY = "wildernessAttackLevelRange";
private static final Pattern WILDERNESS_LEVEL_PATTERN = Pattern.compile("^Level: (\\d+)$");
private static final int SKULL_CONTAINER_ADJUSTED_ORIGINAL_Y = 6;
private static final int WILDERNESS_LEVEL_TEXT_ADJUSTED_ORIGINAL_Y = 3;
private static final int MIN_COMBAT_LEVEL = 3;
private int originalWildernessLevelTextPosition = -1;
private int originalSkullContainerPosition = -1;
@Inject
private Client client;
@Inject
private ClientThread clientThread;
@Inject
private CombatLevelConfig config;
@Inject
private CombatLevelOverlay overlay;
@@ -67,6 +90,11 @@ public class CombatLevelPlugin extends Plugin
protected void startUp() throws Exception
{
overlayManager.add(overlay);
if (config.wildernessAttackLevelRange())
{
appendAttackLevelRangeText();
}
}
@Override
@@ -84,6 +112,8 @@ public class CombatLevelPlugin extends Plugin
combatLevelWidget.setText(widgetText.substring(0, widgetText.indexOf(".")));
}
}
shutDownAttackLevelRange();
}
@Subscribe
@@ -112,4 +142,103 @@ public class CombatLevelPlugin extends Plugin
combatLevelWidget.setText("Combat Lvl: " + DECIMAL_FORMAT.format(combatLevelPrecise));
}
@Subscribe
public void onConfigChanged(ConfigChanged event)
{
if (!CONFIG_GROUP.equals(event.getGroup()) || !ATTACK_RANGE_CONFIG_KEY.equals(event.getKey()))
{
return;
}
if (config.wildernessAttackLevelRange())
{
appendAttackLevelRangeText();
}
else
{
shutDownAttackLevelRange();
}
}
@Subscribe
public void onScriptCallbackEvent(ScriptCallbackEvent event)
{
if (config.wildernessAttackLevelRange()
&& "wildernessWidgetTextSet".equals(event.getEventName()))
{
appendAttackLevelRangeText();
}
}
private void appendAttackLevelRangeText()
{
final Widget wildernessLevelWidget = client.getWidget(WidgetInfo.PVP_WILDERNESS_LEVEL);
if (wildernessLevelWidget == null)
{
return;
}
final String wildernessLevelText = wildernessLevelWidget.getText();
final Matcher m = WILDERNESS_LEVEL_PATTERN.matcher(wildernessLevelText);
if (!m.matches()
|| WorldType.isPvpWorld(client.getWorldType()))
{
return;
}
final Widget skullContainer = client.getWidget(WidgetInfo.PVP_SKULL_CONTAINER);
if (originalWildernessLevelTextPosition == -1)
{
originalWildernessLevelTextPosition = wildernessLevelWidget.getOriginalY();
}
if (originalSkullContainerPosition == -1)
{
originalSkullContainerPosition = skullContainer.getRelativeY();
}
final int wildernessLevel = Integer.parseInt(m.group(1));
final int combatLevel = client.getLocalPlayer().getCombatLevel();
wildernessLevelWidget.setText(wildernessLevelText + "<br>" + combatAttackRange(combatLevel, wildernessLevel));
wildernessLevelWidget.setOriginalY(WILDERNESS_LEVEL_TEXT_ADJUSTED_ORIGINAL_Y);
skullContainer.setOriginalY(SKULL_CONTAINER_ADJUSTED_ORIGINAL_Y);
clientThread.invoke(wildernessLevelWidget::revalidate);
clientThread.invoke(skullContainer::revalidate);
}
private void shutDownAttackLevelRange()
{
if (WorldType.isPvpWorld(client.getWorldType()))
{
return;
}
final Widget wildernessLevelWidget = client.getWidget(WidgetInfo.PVP_WILDERNESS_LEVEL);
if (wildernessLevelWidget != null)
{
String wildernessLevelText = wildernessLevelWidget.getText();
if (wildernessLevelText.contains("<br>"))
{
wildernessLevelWidget.setText(wildernessLevelText.substring(0, wildernessLevelText.indexOf("<br>")));
}
wildernessLevelWidget.setOriginalY(originalWildernessLevelTextPosition);
clientThread.invoke(wildernessLevelWidget::revalidate);
}
originalWildernessLevelTextPosition = -1;
final Widget skullContainer = client.getWidget(WidgetInfo.PVP_SKULL_CONTAINER);
if (skullContainer != null)
{
skullContainer.setOriginalY(originalSkullContainerPosition);
clientThread.invoke(skullContainer::revalidate);
}
originalSkullContainerPosition = -1;
}
private static String combatAttackRange(final int combatLevel, final int wildernessLevel)
{
return Math.max(MIN_COMBAT_LEVEL, combatLevel - wildernessLevel) + "-" + Math.min(Experience.MAX_COMBAT_LEVEL, combatLevel + wildernessLevel);
}
}

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

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018, Infinitay <https://github.com/Infinitay>
* Copyright (c) 2018, Shaun Dreclin <https://github.com/ShaunDreclin>
* Copyright (c) 2018-2019, Shaun Dreclin <https://github.com/ShaunDreclin>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -86,10 +86,15 @@ public class DailyTasksPlugin extends Plugin
}
@Override
protected void shutDown() throws Exception
public void startUp()
{
loggingIn = true;
}
@Override
public void shutDown()
{
lastReset = 0L;
loggingIn = false;
}
@Subscribe
@@ -108,7 +113,6 @@ public class DailyTasksPlugin extends Plugin
boolean dailyReset = !loggingIn && currentTime - lastReset > ONE_DAY;
if ((dailyReset || loggingIn)
&& client.getGameState() == GameState.LOGGED_IN
&& client.getVar(VarClientInt.MEMBERSHIP_STATUS) == 1)
{
// Round down to the nearest day

View File

@@ -31,7 +31,7 @@ import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.SessionOpen;
import net.runelite.client.events.SessionOpen;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.plugins.Plugin;
@@ -43,7 +43,8 @@ import net.runelite.http.api.worlds.WorldResult;
@PluginDescriptor(
name = "Default World",
description = "Enable a default world to be selected when launching the client"
description = "Enable a default world to be selected when launching the client",
tags = {"home"}
)
@Slf4j
public class DefaultWorldPlugin extends Plugin

View File

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

View File

@@ -238,7 +238,9 @@ public class DevToolsPlugin extends Plugin
int value = Integer.parseInt(args[1]);
client.setVarpValue(client.getVarps(), varp, value);
client.addChatMessage(ChatMessageType.SERVER, "", "Set VarPlayer " + varp + " to " + value, null);
eventBus.post(new VarbitChanged()); // fake event
VarbitChanged varbitChanged = new VarbitChanged();
varbitChanged.setIndex(varp);
eventBus.post(varbitChanged); // fake event
break;
}
case "getvarb":

View File

@@ -32,6 +32,8 @@ import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import javax.swing.BorderFactory;
import javax.swing.JButton;
@@ -95,8 +97,7 @@ class VarInspector extends JFrame
private int[] oldVarps2 = null;
private int numVarbits = 10000;
private int[] oldIntVarcs = null;
private String[] oldStrVarcs = null;
private Map<Integer, Object> varcs = null;
@Inject
VarInspector(Client client, EventBus eventBus, DevToolsPlugin plugin)
@@ -279,9 +280,9 @@ class VarInspector extends JFrame
public void onVarClientIntChanged(VarClientIntChanged e)
{
int idx = e.getIndex();
int neew = client.getIntVarcs()[idx];
int old = oldIntVarcs[idx];
oldIntVarcs[idx] = neew;
int neew = (Integer) client.getVarcMap().getOrDefault(idx, 0);
int old = (Integer) varcs.getOrDefault(idx, 0);
varcs.put(idx, neew);
if (old != neew)
{
@@ -302,9 +303,9 @@ class VarInspector extends JFrame
public void onVarClientStrChanged(VarClientStrChanged e)
{
int idx = e.getIndex();
String neew = client.getStrVarcs()[idx];
String old = oldStrVarcs[idx];
oldStrVarcs[idx] = neew;
String neew = (String) client.getVarcMap().getOrDefault(idx, "");
String old = (String) varcs.getOrDefault(idx, "");
varcs.put(idx, neew);
if (!Objects.equals(old, neew))
{
@@ -343,14 +344,11 @@ class VarInspector extends JFrame
{
oldVarps = new int[client.getVarps().length];
oldVarps2 = new int[client.getVarps().length];
oldIntVarcs = new int[client.getIntVarcs().length];
oldStrVarcs = new String[client.getStrVarcs().length];
}
System.arraycopy(client.getVarps(), 0, oldVarps, 0, oldVarps.length);
System.arraycopy(client.getVarps(), 0, oldVarps2, 0, oldVarps2.length);
System.arraycopy(client.getIntVarcs(), 0, oldIntVarcs, 0, oldIntVarcs.length);
System.arraycopy(client.getStrVarcs(), 0, oldStrVarcs, 0, oldStrVarcs.length);
varcs = new HashMap<>(client.getVarcMap());
eventBus.register(this);
setVisible(true);

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

@@ -167,7 +167,7 @@ public class FriendNotesPlugin extends Plugin
if (groupId == WidgetInfo.FRIENDS_LIST.getGroupId() && event.getOption().equals("Message"))
{
// Friends have color tags
setHoveredFriend(Text.removeTags(event.getTarget()));
setHoveredFriend(Text.toJagexName(Text.removeTags(event.getTarget())));
// Build "Add Note" or "Edit Note" menu entry
final MenuEntry addNote = new MenuEntry();
@@ -197,13 +197,13 @@ public class FriendNotesPlugin extends Plugin
return;
}
//Friends have color tags
final String sanitizedTarget = Text.removeTags(event.getMenuTarget());
// Handle clicks on "Add Note" or "Edit Note"
if (event.getMenuOption().equals(ADD_NOTE) || event.getMenuOption().equals(EDIT_NOTE))
{
event.consume();
//Friends have color tags
final String sanitizedTarget = Text.toJagexName(Text.removeTags(event.getMenuTarget()));
final String note = getFriendNote(sanitizedTarget);
// Open the new chatbox input dialog
@@ -234,7 +234,16 @@ public class FriendNotesPlugin extends Plugin
{
// Migrate a friend's note to their new display name
final Friend friend = (Friend) nameable;
migrateFriendNote(friend.getName(), friend.getPrevName());
String name = friend.getName();
String prevName = friend.getPrevName();
if (prevName != null)
{
migrateFriendNote(
Text.toJagexName(name),
Text.toJagexName(prevName)
);
}
}
}
@@ -242,7 +251,7 @@ public class FriendNotesPlugin extends Plugin
public void onRemovedFriend(RemovedFriend event)
{
// Delete a friend's note if they are removed
final String displayName = event.getName();
final String displayName = Text.toJagexName(event.getName());
log.debug("Remove friend: '{}'", displayName);
setFriendNote(displayName, null);
}

View File

@@ -37,7 +37,9 @@ import com.jogamp.opengl.GLException;
import com.jogamp.opengl.GLProfile;
import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.nio.ByteBuffer;
@@ -46,6 +48,7 @@ import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.function.Function;
import javax.inject.Inject;
import jogamp.nativewindow.SurfaceScaleUtils;
import jogamp.nativewindow.jawt.x11.X11JAWTWindow;
import jogamp.newt.awt.NewtFactoryAWT;
import lombok.extern.slf4j.Slf4j;
@@ -71,18 +74,7 @@ import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.plugins.PluginInstantiationException;
import net.runelite.client.plugins.PluginManager;
import static net.runelite.client.plugins.gpu.GLUtil.glDeleteBuffer;
import static net.runelite.client.plugins.gpu.GLUtil.glDeleteFrameBuffer;
import static net.runelite.client.plugins.gpu.GLUtil.glDeleteRenderbuffers;
import static net.runelite.client.plugins.gpu.GLUtil.glDeleteTexture;
import static net.runelite.client.plugins.gpu.GLUtil.glDeleteVertexArrays;
import static net.runelite.client.plugins.gpu.GLUtil.glGenBuffers;
import static net.runelite.client.plugins.gpu.GLUtil.glGetInteger;
import static net.runelite.client.plugins.gpu.GLUtil.glGenFrameBuffer;
import static net.runelite.client.plugins.gpu.GLUtil.glGenRenderbuffer;
import static net.runelite.client.plugins.gpu.GLUtil.glGenTexture;
import static net.runelite.client.plugins.gpu.GLUtil.glGenVertexArrays;
import static net.runelite.client.plugins.gpu.GLUtil.inputStreamToString;
import static net.runelite.client.plugins.gpu.GLUtil.*;
import net.runelite.client.plugins.gpu.config.AntiAliasingMode;
import net.runelite.client.plugins.gpu.template.Template;
import net.runelite.client.ui.DrawManager;
@@ -1021,7 +1013,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
renderWidthOff = (int) Math.floor(scaleFactorX * (renderWidthOff )) - padding;
}
gl.glViewport(renderWidthOff, renderCanvasHeight - renderViewportHeight - renderHeightOff, renderViewportWidth, renderViewportHeight);
glDpiAwareViewport(renderWidthOff, renderCanvasHeight - renderViewportHeight - renderHeightOff, renderViewportWidth, renderViewportHeight);
gl.glUseProgram(glProgram);
@@ -1151,16 +1143,14 @@ 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();
gl.glViewport(0, 0, dim.width, dim.height);
glDpiAwareViewport(0, 0, dim.width, dim.height);
}
else
{
gl.glViewport(0, 0, canvasWidth, canvasHeight);
glDpiAwareViewport(0, 0, canvasWidth, canvasHeight);
}
// Use the texture bound in the first pass
@@ -1455,4 +1445,18 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
}
}
private int getScaledValue(final double scale, final int value)
{
return SurfaceScaleUtils.scale(value, (float) scale);
}
private void glDpiAwareViewport(final int x, final int y, final int width, final int height)
{
final AffineTransform t = ((Graphics2D) canvas.getGraphics()).getTransform();
gl.glViewport(
getScaledValue(t.getScaleX(), x),
getScaledValue(t.getScaleY(), y),
getScaledValue(t.getScaleX(), width),
getScaledValue(t.getScaleY(), height));
}
}

View File

@@ -300,7 +300,7 @@ class SceneUploader
int vertexCx = localX + Perspective.LOCAL_TILE_SIZE;
int vertexCy = localY;
int vertexCz = seHeight;
final int c2 = nwColor;
final int c2 = seColor;
// 1,1
int vertexAx = localX + Perspective.LOCAL_TILE_SIZE;
@@ -312,7 +312,7 @@ class SceneUploader
int vertexBx = localX;
int vertexBy = localY + Perspective.LOCAL_TILE_SIZE;
int vertexBz = nwHeight;
final int c4 = seColor;
final int c4 = nwColor;
vertexBuffer.put(vertexAx, vertexAz, vertexAy, c3);
vertexBuffer.put(vertexBx, vertexBz, vertexBy, c4);

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.client.events.SessionClose;
import net.runelite.client.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

@@ -0,0 +1,40 @@
/*
* Copyright (c) 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.groundmarkers;
import java.awt.Color;
import lombok.Value;
import net.runelite.api.coords.WorldPoint;
/**
* Used to denote marked tiles and their colors.
* Note: This is not used for serialization of ground markers; see {@link GroundMarkerPoint}
*/
@Value
class ColorTileMarker
{
private WorldPoint worldPoint;
private Color color;
}

View File

@@ -23,7 +23,6 @@
* (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.groundmarkers;
import java.awt.Color;
@@ -45,4 +44,14 @@ public interface GroundMarkerConfig extends Config
{
return Color.YELLOW;
}
@ConfigItem(
keyName = "rememberTileColors",
name = "Remember color per tile",
description = "Color tiles using the color from time of placement"
)
default boolean rememberTileColors()
{
return false;
}
}

View File

@@ -64,4 +64,4 @@ public class GroundMarkerInputListener implements KeyListener
plugin.setHotKeyPressed(false);
}
}
}
}

View File

@@ -25,10 +25,11 @@
*/
package net.runelite.client.plugins.groundmarkers;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.util.List;
import java.util.Collection;
import javax.inject.Inject;
import net.runelite.api.Client;
import net.runelite.api.Perspective;
@@ -42,6 +43,8 @@ import net.runelite.client.ui.overlay.OverlayUtil;
public class GroundMarkerOverlay extends Overlay
{
private static final int MAX_DRAW_DISTANCE = 32;
private final Client client;
private final GroundMarkerConfig config;
private final GroundMarkerPlugin plugin;
@@ -60,25 +63,33 @@ public class GroundMarkerOverlay extends Overlay
@Override
public Dimension render(Graphics2D graphics)
{
List<WorldPoint> points = plugin.getPoints();
for (WorldPoint point : points)
final Collection<ColorTileMarker> points = plugin.getPoints();
for (final ColorTileMarker point : points)
{
if (point.getPlane() != client.getPlane())
WorldPoint worldPoint = point.getWorldPoint();
if (worldPoint.getPlane() != client.getPlane())
{
continue;
}
drawTile(graphics, point);
Color tileColor = point.getColor();
if (tileColor == null || !config.rememberTileColors())
{
// If this is an old tile which has no color, or rememberTileColors is off, use marker color
tileColor = config.markerColor();
}
drawTile(graphics, worldPoint, tileColor);
}
return null;
}
private void drawTile(Graphics2D graphics, WorldPoint point)
private void drawTile(Graphics2D graphics, WorldPoint point, Color color)
{
WorldPoint playerLocation = client.getLocalPlayer().getWorldLocation();
if (point.distanceTo(playerLocation) >= 32)
if (point.distanceTo(playerLocation) >= MAX_DRAW_DISTANCE)
{
return;
}
@@ -95,6 +106,6 @@ public class GroundMarkerOverlay extends Overlay
return;
}
OverlayUtil.renderPolygon(graphics, poly, config.markerColor());
OverlayUtil.renderPolygon(graphics, poly, color);
}
}
}

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;
@@ -69,19 +69,23 @@ public class GroundMarkerPlugin extends Plugin
private static final String CONFIG_GROUP = "groundMarker";
private static final String MARK = "Mark tile";
private static final String WALK_HERE = "Walk here";
private static final String REGION_PREFIX = "region_";
private static final Gson gson = new Gson();
private static final Gson GSON = new Gson();
@Getter(AccessLevel.PACKAGE)
@Setter(AccessLevel.PACKAGE)
private boolean hotKeyPressed;
@Getter(AccessLevel.PACKAGE)
private final List<WorldPoint> points = new ArrayList<>();
private final List<ColorTileMarker> points = new ArrayList<>();
@Inject
private Client client;
@Inject
private GroundMarkerConfig config;
@Inject
private GroundMarkerInputListener inputListener;
@@ -101,24 +105,25 @@ public class GroundMarkerPlugin extends Plugin
{
if (points == null || points.isEmpty())
{
configManager.unsetConfiguration(CONFIG_GROUP, "region_" + regionId);
configManager.unsetConfiguration(CONFIG_GROUP, REGION_PREFIX + regionId);
return;
}
String json = gson.toJson(points);
configManager.setConfiguration(CONFIG_GROUP, "region_" + regionId, json);
String json = GSON.toJson(points);
configManager.setConfiguration(CONFIG_GROUP, REGION_PREFIX + regionId, json);
}
private Collection<GroundMarkerPoint> getPoints(int regionId)
{
String json = configManager.getConfiguration(CONFIG_GROUP, "region_" + regionId);
String json = configManager.getConfiguration(CONFIG_GROUP, REGION_PREFIX + regionId);
if (Strings.isNullOrEmpty(json))
{
return Collections.EMPTY_LIST;
return Collections.emptyList();
}
return gson.fromJson(json, new TypeToken<List<GroundMarkerPoint>>()
{
}.getType());
// CHECKSTYLE:OFF
return GSON.fromJson(json, new TypeToken<List<GroundMarkerPoint>>(){}.getType());
// CHECKSTYLE:ON
}
@Provides
@@ -132,110 +137,46 @@ public class GroundMarkerPlugin extends Plugin
points.clear();
int[] regions = client.getMapRegions();
if (regions == null)
{
return;
}
for (int regionId : regions)
{
// load points for region
log.debug("Loading points for region {}", regionId);
Collection<GroundMarkerPoint> regionPoints = getPoints(regionId);
Collection<WorldPoint> worldPoints = translateToWorld(regionPoints);
points.addAll(worldPoints);
Collection<ColorTileMarker> colorTileMarkers = translateToColorTileMarker(regionPoints);
points.addAll(colorTileMarkers);
}
}
/**
* Translate a collection of ground marker points to world points, accounting for instances
* Translate a collection of ground marker points to color tile markers, accounting for instances
*
* @param points
* @return
* @param points {@link GroundMarkerPoint}s to be converted to {@link ColorTileMarker}s
* @return A collection of color tile markers, converted from the passed ground marker points, accounting for local
* instance points. See {@link WorldPoint#toLocalInstance(Client, WorldPoint)}
*/
private Collection<WorldPoint> translateToWorld(Collection<GroundMarkerPoint> points)
private Collection<ColorTileMarker> translateToColorTileMarker(Collection<GroundMarkerPoint> points)
{
if (points.isEmpty())
{
return Collections.EMPTY_LIST;
return Collections.emptyList();
}
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 -> new ColorTileMarker(
WorldPoint.fromRegion(point.getRegionId(), point.getRegionX(), point.getRegionY(), point.getZ()),
point.getColor()))
.flatMap(colorTile ->
{
worldPoints.add(worldPoint);
continue;
}
// 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;
final Collection<WorldPoint> localWorldPoints = WorldPoint.toLocalInstance(client, colorTile.getWorldPoint());
return localWorldPoints.stream().map(wp -> new ColorTileMarker(wp, colorTile.getColor()));
})
.collect(Collectors.toList());
}
@Subscribe
@@ -298,6 +239,7 @@ public class GroundMarkerPlugin extends Plugin
{
overlayManager.add(overlay);
keyManager.registerKeyListener(inputListener);
loadPoints();
}
@Override
@@ -305,10 +247,10 @@ public class GroundMarkerPlugin extends Plugin
{
overlayManager.remove(overlay);
keyManager.unregisterKeyListener(inputListener);
points.clear();
}
protected void markTile(LocalPoint localPoint)
private void markTile(LocalPoint localPoint)
{
if (localPoint == null)
{
@@ -318,21 +260,21 @@ public class GroundMarkerPlugin extends Plugin
WorldPoint worldPoint = WorldPoint.fromLocalInstance(client, localPoint);
int regionId = worldPoint.getRegionID();
GroundMarkerPoint point = new GroundMarkerPoint(regionId, worldPoint.getX() & 0x3f, worldPoint.getY() & 0x3f, client.getPlane());
GroundMarkerPoint point = new GroundMarkerPoint(regionId, worldPoint.getRegionX(), worldPoint.getRegionY(), client.getPlane(), config.markerColor());
log.debug("Updating point: {} - {}", point, worldPoint);
List<GroundMarkerPoint> points = new ArrayList<>(getPoints(regionId));
if (points.contains(point))
List<GroundMarkerPoint> groundMarkerPoints = new ArrayList<>(getPoints(regionId));
if (groundMarkerPoints.contains(point))
{
points.remove(point);
groundMarkerPoints.remove(point);
}
else
{
points.add(point);
groundMarkerPoints.add(point);
}
savePoints(regionId, points);
savePoints(regionId, groundMarkerPoints);
loadPoints();
}
}
}

View File

@@ -23,16 +23,22 @@
* (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.groundmarkers;
import java.awt.Color;
import lombok.EqualsAndHashCode;
import lombok.Value;
/**
* Used for serialization of ground marker points.
*/
@Value
public class GroundMarkerPoint
@EqualsAndHashCode(exclude = { "color" })
class GroundMarkerPoint
{
private int regionId;
private int regionX;
private int regionY;
private int z;
}
private Color color;
}

View File

@@ -47,6 +47,7 @@ import net.runelite.api.Varbits;
import net.runelite.api.events.AnimationChanged;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.GameTick;
import net.runelite.api.events.GraphicChanged;
import net.runelite.api.events.HitsplatApplied;
import net.runelite.api.events.InteractingChanged;
import net.runelite.client.Notifier;
@@ -196,12 +197,14 @@ public class IdleNotifierPlugin extends Plugin
case MINING_MOTHERLODE_INFERNAL:
case MINING_MOTHERLODE_3A:
/* Herblore */
case HERBLORE_PESTLE_AND_MORTAR:
case HERBLORE_POTIONMAKING:
case HERBLORE_MAKE_TAR:
/* Magic */
case MAGIC_CHARGING_ORBS:
case MAGIC_LUNAR_STRING_JEWELRY:
case MAGIC_MAKE_TABLET:
case MAGIC_ENCHANTING_JEWELRY:
/* Prayer */
case USING_GILDED_ALTAR:
/* Farming */
@@ -329,6 +332,22 @@ public class IdleNotifierPlugin extends Plugin
}
}
@Subscribe
public void onGraphicChanged(GraphicChanged event)
{
Actor actor = event.getActor();
if (actor != client.getLocalPlayer())
{
return;
}
if (actor.getGraphic() == GraphicID.SPLASH)
{
lastCombatCountdown = HIGHEST_MONSTER_ATTACK_SPEED;
}
}
@Subscribe
public void onGameTick(GameTick event)
{

View File

@@ -40,14 +40,16 @@ 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;
import net.runelite.api.Client;
import net.runelite.api.events.SessionClose;
import net.runelite.api.events.SessionOpen;
import net.runelite.client.events.SessionClose;
import net.runelite.client.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);
}
}

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