Merge branch 'master' into true-current-tile
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.",
|
||||
|
||||
@@ -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.",
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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":
|
||||
|
||||
@@ -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 "";
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)),
|
||||
|
||||
@@ -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.");
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -347,6 +347,12 @@ class DevToolsOverlay extends Overlay
|
||||
{
|
||||
graphics.drawPolygon(p);
|
||||
}
|
||||
|
||||
p = decorObject.getConvexHull2();
|
||||
if (p != null)
|
||||
{
|
||||
graphics.drawPolygon(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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":
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -130,6 +130,7 @@ public class DiscordPlugin extends Plugin
|
||||
|
||||
clientToolbar.addNavigation(discordButton);
|
||||
checkForGameStateUpdate();
|
||||
checkForAreaUpdate();
|
||||
|
||||
if (discordService.getCurrentUser() != null)
|
||||
{
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,4 +64,4 @@ public class GroundMarkerInputListener implements KeyListener
|
||||
plugin.setHotKeyPressed(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -32,5 +32,6 @@ enum ItemChargeType
|
||||
IMPBOX,
|
||||
TELEPORT,
|
||||
WATERCAN,
|
||||
WATERSKIN
|
||||
WATERSKIN,
|
||||
DODGY_NECKLACE
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -74,4 +74,16 @@ public interface ItemPricesConfig extends Config
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "showAlchProfit",
|
||||
name = "Show High Alchemy Profit",
|
||||
description = "Show the profit from casting high alchemy on items",
|
||||
position = 5
|
||||
)
|
||||
default boolean showAlchProfit()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user